/*============================================================================== * Инициализация тактирования с использованием бибилотеки PLIB035 *------------------------------------------------------------------------------ * ЦНИИ СЭТ, Разваляев Алексей *============================================================================== * ЦНИИ СЭТ *============================================================================== */ //-- Includes ------------------------------------------------------------------ #include "periph_config.h" UART_HandleTypeDef huart0; UART_HandleTypeDef huart1; static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode); static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode); //-- Defines ------------------------------------------------------------------- //-- Peripheral init functions ------------------------------------------------- void uart_init_first(void) { #if (USE_UART0==1) // Настройка пинов для UART0 uart0_gpio_init(); // Включаем тактирование UART0 RCU_UARTClkConfig(UART0_Num, RCU_PeriphClk_PLLClk, 0, DISABLE); RCU_UARTClkCmd(UART0_Num, ENABLE); UART_DeInit(UART0); // Инициализируем UART0 huart0.UART = UART0; uart_init(&huart0, &uart0_config); NVIC_EnableIRQ(UART0_TD_IRQn); NVIC_EnableIRQ(UART0_RX_IRQn); NVIC_EnableIRQ(UART0_TX_IRQn); NVIC_EnableIRQ(UART0_E_RT_IRQn); #endif #if (USE_UART1==1) // Настройка пинов для UART1 uart1_gpio_init(); // Включаем тактирование UART1 RCU_UARTClkConfig(UART1_Num, RCU_PeriphClk_PLLClk, 0, DISABLE); RCU_UARTClkCmd(UART1_Num, ENABLE); UART_DeInit(UART1); // Инициализируем UART1 NVIC_EnableIRQ(UART1_TD_IRQn); NVIC_EnableIRQ(UART1_RX_IRQn); NVIC_EnableIRQ(UART1_TX_IRQn); NVIC_EnableIRQ(UART1_E_RT_IRQn); huart1.UART = UART1; uart_init(&huart1, &uart1_config); #endif } /** * @brief Инициализация UART * @param htmr указатель на хендл UART * @param NewConfig указатель на новую конфигурацию UART, иначе используется та, что в структуре * @retval OperationStatus OK - если всё хорошо, ERROR - если ошибка */ OperationStatus uart_init(UART_HandleTypeDef *huart, UART_ExtInitTypeDef *NewConfig) { if(huart->UART == NULL) { return ERROR; } if(NewConfig != NULL) { huart->Config = NewConfig; } if(huart->Config == NULL) { return ERROR; } UART_Init(huart->UART, &huart->Config->UART_Init); return OK; } OperationStatus uart_start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel) { if (huart == NULL) return ERROR; UART_ITFIFOLevelRxConfig(huart->UART, RxFifoLevel); UART_ITFIFOLevelTxConfig(huart->UART, TxFifoLevel); huart->TxBufPtr = NULL; huart->TxCount = 0; huart->TxSize = 0; huart->TxBusy = 0; huart->RxBufPtr = NULL; huart->RxCount = 0; huart->RxSize = 0; huart->RxBusy = 0; UART_Cmd(huart->UART, ENABLE); return OK; } OperationStatus uart_transmit(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout) { if (!huart || !buf || size == 0) return ERROR; // Если TX занят, возвращаем ERROR if (huart->TxBusy) return ERROR; huart->TxBufPtr = buf; huart->TxSize = size; huart->TxCount = 0; huart->TxBusy = 1; uint32_t starttick = millis(); // Отправляем пока всё не отправится while(__uart_fifo_transmit(huart, 0) == 0) { if(millis() - starttick > timeout) return ERROR; } return OK; } OperationStatus uart_receive(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size, uint32_t timeout) { if (!huart || !buf || size == 0) return ERROR; // Если RX занят, возвращаем ERROR if (huart->RxBusy) return ERROR; huart->RxBufPtr = buf; huart->RxSize = size; huart->RxCount = 0; huart->RxBusy = 1; uint32_t starttick = millis(); // Принимаем всё пока всё не примется while(__uart_fifo_transmit(huart, 0) == 0) { if(millis() - starttick > timeout) return ERROR;; } return OK; } OperationStatus uart_transmit_it(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size) { if (!huart || !buf || size == 0) return ERROR; // Если TX занят, возвращаем ERROR if (huart->TxBusy) return ERROR; huart->TxBufPtr = buf; huart->TxSize = size; huart->TxCount = 0; huart->TxBusy = 1; // Включаем прерывания по TX FIFO UART_ITCmd(huart->UART, UART_ITSource_TxFIFOLevel, ENABLE); __uart_fifo_transmit(huart, 1); return OK; } OperationStatus uart_receive_it(UART_HandleTypeDef *huart, uint8_t *buf, uint16_t size) { if (!huart || !buf || size == 0) return ERROR; // Если RX занят, возвращаем ERROR if (huart->RxBusy) return ERROR; huart->RxBufPtr = buf; huart->RxSize = size; huart->RxCount = 0; huart->RxBusy = 1; // Включаем только RX прерывания UART_ITCmd(huart->UART, UART_ITSource_RxFIFOLevel | UART_ITSource_RecieveTimeout | UART_ITSource_ErrorFrame | UART_ITSource_ErrorParity | UART_ITSource_ErrorOverflow | UART_ITSource_ErrorBreak, ENABLE); return OK; } void uart_handler(UART_HandleTypeDef *huart) { if (!huart || !huart->UART || !huart->Config) return; UART_TypeDef *uart = huart->UART; uint32_t mis = uart->MIS; // Ошибки if (mis & (UART_ITSource_ErrorFrame | UART_ITSource_ErrorParity | UART_ITSource_ErrorOverflow | UART_ITSource_ErrorBreak)) { if (huart->Config->ErrCallback) huart->Config->ErrCallback(); UART_ErrorStatusClear(uart, UART_Error_All); UART_ITStatusClear(uart, mis); } // RX FIFO if (mis & UART_ITSource_RxFIFOLevel) { // Принимаем if(__uart_fifo_receive(huart, 1)) { // Когда всё приняли, флаги сбросили внутри функции } UART_ITStatusClear(uart, UART_ITSource_RxFIFOLevel); } // IDLE / Receive Timeout if (mis & UART_ITSource_RecieveTimeout) { UART_ITStatusClear(uart, UART_ITSource_RecieveTimeout); huart->RxBusy = 0; // Выключаем RX прерывания до следующего вызова uart_receive_it UART_ITCmd(uart, UART_ITSource_RxFIFOLevel | UART_ITSource_RecieveTimeout, DISABLE); if (huart->Config->IdleCallback) huart->Config->IdleCallback(); } // TX FIFO if (mis & UART_ITSource_TxFIFOLevel) { // Отправляем if(__uart_fifo_transmit(huart, 1)) { // Когда всё отправили, флаги сбросили внутри функции } UART_ITStatusClear(uart, UART_ITSource_TxFIFOLevel); } // Конец передачи if (mis & UART_ITSource_TransmitDone) { UART_ITStatusClear(uart, UART_ITSource_TransmitDone); huart->TxBusy = 0; if (huart->Config->TxCallback) huart->Config->TxCallback(); } } /** * @brief Установка коллбека UART * @param htmr указатель на хендл UART * @param cb_type Тип коллбека * @param Callback Функция коллбека * @retval void */ OperationStatus uart_set_callback(UART_HandleTypeDef* huart, UART_CallbackTypeDef cb_type, void (*Callback)(void)) { if((huart->UART == NULL) || (huart->Config == NULL)) { return ERROR; } switch(cb_type) { case UART_Callback_Rx: huart->Config->RxCallback = Callback; break; case UART_Callback_Tx: huart->Config->TxCallback = Callback; break; case UART_Callback_Idle: huart->Config->IdleCallback = Callback; break; case UART_Callback_Error: huart->Config->ErrCallback = Callback; break; default: return ERROR; } return OK; } void uart0_gpio_init(void) { #if USE_UART0==1 // Получаем структуры GPIO_Init_TypeDef *tx_config = gpio_get_init(UART0_GPIO_Port, UART0_Tx_Pin); GPIO_Init_TypeDef *rx_config = gpio_get_init(UART0_GPIO_Port, UART0_Rx_Pin); // TX пин if (uart0_config.UART_Init.Tx == ENABLE && tx_config != NULL) { GPIO_StructInit(tx_config); tx_config->AltFunc = ENABLE; tx_config->Digital = ENABLE; tx_config->Pin = UART0_Tx_Pin; GPIO_Init(UART0_GPIO_Port, tx_config); } // RX пин if (uart0_config.UART_Init.Rx == ENABLE && rx_config != NULL) { GPIO_StructInit(rx_config); rx_config->AltFunc = ENABLE; rx_config->Digital = ENABLE; rx_config->Pin = UART0_Rx_Pin; GPIO_Init(UART0_GPIO_Port, rx_config); } #endif } void uart0_gpio_deinit(void) { #if USE_UART0==1 // Получаем структуры GPIO_Init_TypeDef *tx_config = gpio_get_init(UART0_GPIO_Port, UART0_Tx_Pin); GPIO_Init_TypeDef *rx_config = gpio_get_init(UART0_GPIO_Port, UART0_Rx_Pin); // Восстанавливаем оригинальные настройки из таблицы if (tx_config != NULL) { GPIO_StructInit(rx_config); rx_config->Pin = UART0_Tx_Pin; GPIO_Init(UART0_GPIO_Port, tx_config); } if (rx_config != NULL) { GPIO_StructInit(rx_config); rx_config->Pin = UART0_Rx_Pin; GPIO_Init(UART0_GPIO_Port, rx_config); } #endif } void uart1_gpio_init(void) { #if USE_UART1==1 // Получаем структуры GPIO_Init_TypeDef *tx_config = gpio_get_init(UART1_GPIO_Port, UART1_Tx_Pin); GPIO_Init_TypeDef *rx_config = gpio_get_init(UART1_GPIO_Port, UART1_Rx_Pin); // TX пин if (uart1_config.UART_Init.Tx == ENABLE && tx_config != NULL) { GPIO_StructInit(tx_config); tx_config->AltFunc = ENABLE; tx_config->Digital = ENABLE; tx_config->Pin = UART1_Tx_Pin; GPIO_Init(UART1_GPIO_Port, tx_config); } // RX пин if (uart1_config.UART_Init.Rx == ENABLE && rx_config != NULL) { ; GPIO_StructInit(rx_config); rx_config->AltFunc = ENABLE; rx_config->Digital = ENABLE; rx_config->Pin = UART1_Rx_Pin; GPIO_Init(UART1_GPIO_Port, rx_config); } #endif } void uart1_gpio_deinit(void) { #if USE_UART1==1 // Получаем структуры GPIO_Init_TypeDef *tx_config = gpio_get_init(UART1_GPIO_Port, UART1_Tx_Pin); GPIO_Init_TypeDef *rx_config = gpio_get_init(UART1_GPIO_Port, UART1_Rx_Pin); // Восстанавливаем оригинальные настройки из таблицы if (tx_config != NULL) { GPIO_StructInit(rx_config); rx_config->Pin = UART1_Tx_Pin; GPIO_Init(UART1_GPIO_Port, tx_config); } if (rx_config != NULL) { GPIO_StructInit(rx_config); rx_config->Pin = UART1_Rx_Pin; GPIO_Init(UART1_GPIO_Port, rx_config); } #endif } static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode) { while (!UART_FlagStatus(huart->UART, UART_Flag_RxFIFOEmpty) && huart->RxCount < huart->RxSize) { huart->RxBufPtr[huart->RxCount++] = UART_RecieveData(huart->UART); if (huart->RxCount == huart->RxSize) { huart->RxBusy = 0; if(it_mode) { // Выключаем RX прерывания UART_ITCmd(huart->UART, UART_ITSource_RxFIFOLevel | UART_ITSource_RecieveTimeout, DISABLE); } if (huart->Config->RxCallback) huart->Config->RxCallback(); return 1; } } return 0; } static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode) { while (!UART_FlagStatus(huart->UART, UART_Flag_TxFIFOFull) && huart->TxCount < huart->TxSize) { UART_SendData(huart->UART, huart->TxBufPtr[huart->TxCount++]); } if (huart->TxCount == huart->TxSize) { if(it_mode) { // Выключаем FIFO прерывание UART_ITCmd(huart->UART, UART_ITSource_TxFIFOLevel, DISABLE); // Включаем TransmitDone прерывание, коллбек будет по нему UART_ITCmd(huart->UART, UART_ITSource_TransmitDone, ENABLE); } else { while(!UART_FlagStatus(huart->UART, UART_Flag_TxFIFOEmpty)); // ждем пока не опустошится буфер huart->TxBusy = 0; if (huart->Config->TxCallback) huart->Config->TxCallback(); } return 1; } return 0; }