Проект перенесен в папку MDK-ARM
This commit is contained in:
776
MDK-ARM/Core/App/uart.c
Normal file
776
MDK-ARM/Core/App/uart.c
Normal file
@@ -0,0 +1,776 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file uart.c
|
||||
* @author Разваляев Алексей
|
||||
* @brief Драйвер UART на основе PLIB035.
|
||||
* Этот файл содержит:
|
||||
* + Инициализацию UART0/UART1
|
||||
* + Управление FIFO
|
||||
* + Передачу и приём данных в blocking и interrupt режимах
|
||||
* + Общий обработчик прерываний UART
|
||||
* + Функции настройки GPIO для UART
|
||||
* + Очередь передачи для предотвращения потери данных
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Использование этого драйвера предполагает наличие корректных настроек:
|
||||
* - Определены конфигурационные структуры uartx_config в periph_config.h
|
||||
* - Определены пины TX/RX для UART0/UART1
|
||||
*
|
||||
******************************************************************************
|
||||
* @verbatim
|
||||
==============================================================================
|
||||
##### Как использовать этот драйвер #####
|
||||
==============================================================================
|
||||
|
||||
1. Настройка в periph_config.h:
|
||||
(+) Определите uart0_config, uart1_config для нужных UART
|
||||
(+) Используйте макросы для направления:
|
||||
• UART_Direction_None - прием и передача отключены
|
||||
• UART_Direction_RxTx - полный дуплекс
|
||||
• UART_Direction_Tx - только передача
|
||||
• UART_Direction_Rx - только прием
|
||||
|
||||
2. Инициализация:
|
||||
(+) uart_init_first() - настройка GPIO, тактирования и прерываний
|
||||
(+) uart_init(&huart, &config) - инициализация конкретного UART
|
||||
|
||||
3. Callback-функции:
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Rx, func) - при завершении приема
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Tx, func) - при завершении передачи
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Idle, func) - при обнаружении IDLE
|
||||
(+) UART_Set_Callback(&huart, UART_Callback_Error, func) - при ошибках
|
||||
|
||||
4. Запуск UART:
|
||||
(+) UART_Start(&huart, TxFifoLevel, RxFifoLevel) - включение UART и настройка FIFO
|
||||
|
||||
5. Передача и приём данных:
|
||||
- Режим Polling:
|
||||
(+) UART_Transmit(&huart, buf, size, timeout) - блокирующая передача
|
||||
(+) UART_Receive(&huart, buf, size, timeout) - блокирующий прием
|
||||
- Режим Interrupt:
|
||||
(+) UART_Transmit_IT(&huart, buf, size) - неблокирующая передача
|
||||
(+) UART_Receive_IT(&huart, buf, size) - неблокирующий прием
|
||||
|
||||
6. Обработка прерываний:
|
||||
(+) Прерывания обрабатывают TX FIFO, RX FIFO, ошибки и состояние IDLE
|
||||
|
||||
7. GPIO для UART:
|
||||
(+) Пины настраиваются автоматически при вызове uart_init_first()
|
||||
(+) При необходимости можно вызвать uart0_gpio_deinit() для восстановления
|
||||
|
||||
==============================================================================
|
||||
##### Особенности работы #####
|
||||
==============================================================================
|
||||
|
||||
- Очередь передачи (USE_TX_QUEUE):
|
||||
- Циклический буфер на 32 сообщения (TX_QUEUE_SIZE)
|
||||
- Предотвращает потерю данных при частой отправке
|
||||
- Включается автоматически при USE_TX_QUEUE=1 в uart.h
|
||||
- Сообщения обрабатываются последовательно по завершении предыдущей передачи
|
||||
|
||||
- FIFO и прерывания:
|
||||
- Аппаратный FIFO 16 байт для приема и передачи
|
||||
- Уровни прерываний настраиваются через TxFifoLevel и RxFifoLevel
|
||||
- Прерывание TX FIFO генерируется когда FIFO не полон
|
||||
- Прерывание RX FIFO генерируется когда FIFO не пуст
|
||||
|
||||
- Состояние IDLE:
|
||||
- Обнаруживается по таймауту приема (32 бит-времени)
|
||||
- Генерирует прерывание RecieveTimeout
|
||||
- Полезно для определения конца пакета переменной длины
|
||||
|
||||
- Обработка ошибок:
|
||||
- Обрабатываются все типы ошибок UART: фрейм, паритет, переполнение, break
|
||||
- При ошибке вызывается ErrCallback и сбрасываются флаги ошибок
|
||||
- Ошибки не останавливают работу UART
|
||||
|
||||
- GPIO автоматическая настройка:
|
||||
- Пины TX/RX настраиваются в AltFunc режим при инициализации
|
||||
- Поддерживаются стандартные пины (PB10/PB11 для UART0, PB8/PB9 для UART1)
|
||||
|
||||
- Режимы работы:
|
||||
- Polling: простой, но блокирующий, подходит для инициализации и отладки
|
||||
- Interrupt: неблокирующий, требует прерываний и поддерживает callback-функций
|
||||
- Queue: расширенный interrupt режим с буферизацией сообщений
|
||||
|
||||
@endverbatim
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//-- Includes ------------------------------------------------------------------
|
||||
#include "periph_config.h"
|
||||
|
||||
UART_HandleTypeDef huart0; /*!< Хендл UART0 */
|
||||
UART_HandleTypeDef huart1; /*!< Хендл UART1 */
|
||||
|
||||
|
||||
//-- Private function prototypes -----------------------------------------------
|
||||
static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode);
|
||||
static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode);
|
||||
#if USE_TX_QUEUE==1
|
||||
static void __uart_tx_queue_process(UART_HandleTypeDef *huart);
|
||||
static OperationStatus __uart_tx_queue_push(UART_HandleTypeDef *huart, const uint8_t *buf, uint16_t size);
|
||||
static OperationStatus __uart_tx_queue_pop(UART_HandleTypeDef *huart);
|
||||
#endif
|
||||
//-- Defines -------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
//-- UART Init functions -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Первичная инициализация UART (UART0 / UART1)
|
||||
* @details Настройка UART и хендлов: GPIO, тактирование и прерывания
|
||||
*/
|
||||
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.Instance = 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.Instance = 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_ExtInit_TypeDef *NewConfig)
|
||||
{
|
||||
if(!huart || !huart->Instance)
|
||||
return ERROR;
|
||||
|
||||
if(NewConfig != NULL)
|
||||
{
|
||||
huart->Config = NewConfig;
|
||||
}
|
||||
if(huart->Config == NULL)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
UART_Init(huart->Instance, &huart->Config->UART_Init);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Установка коллбека UART
|
||||
* @param htmr указатель на хендл UART
|
||||
* @param CallbackType Тип коллбека
|
||||
* @param Callback Функция коллбека
|
||||
* @retval void
|
||||
*/
|
||||
OperationStatus UART_Set_Callback(UART_HandleTypeDef* huart, UART_CallbackTypeDef CallbackType, void (*Callback)(void))
|
||||
{
|
||||
if (!huart || !huart->Instance || !huart->Config)
|
||||
return ERROR;
|
||||
|
||||
switch(CallbackType)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-- UART API functions --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Запуск UART и инициализация FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param TxFifoLevel уровень прерывания TX FIFO
|
||||
* @param RxFifoLevel уровень прерывания RX FIFO
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке
|
||||
*/
|
||||
OperationStatus UART_Start(UART_HandleTypeDef *huart, UART_FIFOLevel_TypeDef TxFifoLevel, UART_FIFOLevel_TypeDef RxFifoLevel)
|
||||
{
|
||||
if (!huart)
|
||||
return ERROR;
|
||||
|
||||
UART_ITFIFOLevelRxConfig(huart->Instance, RxFifoLevel);
|
||||
UART_ITFIFOLevelTxConfig(huart->Instance, 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;
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
huart->TxQueue.QueueHead = 0;
|
||||
huart->TxQueue.QueueTail = 0;
|
||||
huart->TxQueue.QueueCount = 0;
|
||||
huart->TxQueue.QueueEmpty = 1;
|
||||
huart->TxQueue.QueueFull = 0;
|
||||
|
||||
for (uint8_t i = 0; i < TX_QUEUE_SIZE; i++)
|
||||
{
|
||||
huart->TxQueue.Queue[i].Buf = NULL;
|
||||
huart->TxQueue.Queue[i].Size = 0;
|
||||
huart->TxQueue.Queue[i].InUse = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
UART_Cmd(huart->Instance, ENABLE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
/**
|
||||
* @brief Передача данных по UART (блокирующий режим)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер данных
|
||||
* @param size размер данных в байтах
|
||||
* @param timeout таймаут ожидания (мс)
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
|
||||
*/
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* @brief Приём данных по UART (блокирующий режим)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер приёма
|
||||
* @param size количество принимаемых байт
|
||||
* @param timeout таймаут ожидания (мс)
|
||||
* @retval OperationStatus OK - если успешно, ERROR - при ошибке или таймауте
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Передача данных по UART (прерывания)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер данных
|
||||
* @param size размер данных в байтах
|
||||
* @retval OperationStatus OK - если успешно, ERROR - если передача уже идёт
|
||||
*/
|
||||
OperationStatus UART_Transmit_IT(UART_HandleTypeDef *huart,
|
||||
uint8_t *buf,
|
||||
uint16_t size)
|
||||
{
|
||||
if (!huart || !buf || size == 0)
|
||||
return ERROR;
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
// Автоматически используем очередь
|
||||
if (huart->TxQueue.QueueFull)
|
||||
return ERROR;
|
||||
|
||||
OperationStatus status = __uart_tx_queue_push(huart, buf, size);
|
||||
if (status != OK)
|
||||
return ERROR;
|
||||
|
||||
if (!huart->TxBusy)
|
||||
{
|
||||
__uart_tx_queue_process(huart);
|
||||
}
|
||||
|
||||
return OK;
|
||||
#else
|
||||
// Без очереди
|
||||
// Если TX занят, возвращаем ERROR
|
||||
if (huart->TxBusy)
|
||||
return ERROR;
|
||||
|
||||
huart->TxBufPtr = buf;
|
||||
huart->TxSize = size;
|
||||
huart->TxCount = 0;
|
||||
huart->TxBusy = 1;
|
||||
|
||||
// Включаем прерывания по TX FIFO
|
||||
UART_ITCmd(huart->Instance, UART_ITSource_TxFIFOLevel, ENABLE);
|
||||
|
||||
__uart_fifo_transmit(huart, 1);
|
||||
|
||||
return OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Приём данных по UART (прерывания)
|
||||
* @param huart указатель на хендл UART
|
||||
* @param buf указатель на буфер приёма
|
||||
* @param size количество принимаемых байт
|
||||
* @retval OperationStatus OK - если успешно, ERROR - если приём уже идёт
|
||||
*/
|
||||
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->Instance,
|
||||
UART_ITSource_RxFIFOLevel |
|
||||
UART_ITSource_RecieveTimeout |
|
||||
UART_ITSource_ErrorFrame |
|
||||
UART_ITSource_ErrorParity |
|
||||
UART_ITSource_ErrorOverflow |
|
||||
UART_ITSource_ErrorBreak,
|
||||
ENABLE);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-- UART Handler functions ---------------------------------------------------
|
||||
/**
|
||||
* @brief Общий обработчик прерываний UART
|
||||
* @param huart указатель на хендл UART
|
||||
* @details Обрабатывает RX/TX FIFO, ошибки и события Idle
|
||||
* @retval void
|
||||
*/
|
||||
void uart_irq_handler(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart || !huart->Instance || !huart->Config)
|
||||
return;
|
||||
|
||||
// GPIO_SetBits(GPIOA, GPIO_Pin_7);
|
||||
|
||||
UART_TypeDef *uart = huart->Instance;
|
||||
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();
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
// Если есть очередь, обрабатываем следующий пакет
|
||||
__uart_tx_queue_process(huart);
|
||||
#endif
|
||||
|
||||
}
|
||||
// GPIO_ClearBits(GPIOA, GPIO_Pin_7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-- UART GPIO functions -------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Инициализация GPIO для UART0
|
||||
*/
|
||||
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
|
||||
}
|
||||
/**
|
||||
* @brief Деинициализация GPIO для UART0
|
||||
*/
|
||||
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
|
||||
}
|
||||
/**
|
||||
* @brief Инициализация GPIO для UART1
|
||||
*/
|
||||
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
|
||||
}
|
||||
/**
|
||||
* @brief Деинициализация GPIO для UART1
|
||||
*/
|
||||
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
|
||||
}
|
||||
|
||||
//-- UART private functions ----------------------------------------------------
|
||||
/**
|
||||
* @brief Приём данных из RX FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param it_mode режим работы (0 — polling, 1 — прерывания)
|
||||
* @retval int 1 — приём завершён, 0 — данные ещё принимаются
|
||||
*/
|
||||
static int __uart_fifo_receive(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
{
|
||||
while (!UART_FlagStatus(huart->Instance, UART_Flag_RxFIFOEmpty) &&
|
||||
huart->RxCount < huart->RxSize)
|
||||
{
|
||||
huart->RxBufPtr[huart->RxCount++] = UART_RecieveData(huart->Instance);
|
||||
|
||||
if (huart->RxCount == huart->RxSize)
|
||||
{
|
||||
huart->RxBusy = 0;
|
||||
|
||||
if(it_mode)
|
||||
{
|
||||
// Выключаем RX прерывания
|
||||
UART_ITCmd(huart->Instance,
|
||||
UART_ITSource_RxFIFOLevel |
|
||||
UART_ITSource_RecieveTimeout,
|
||||
DISABLE);
|
||||
}
|
||||
|
||||
if (huart->Config->RxCallback)
|
||||
huart->Config->RxCallback();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief Передача данных в TX FIFO
|
||||
* @param huart указатель на хендл UART
|
||||
* @param it_mode режим работы (0 — polling, 1 — прерывания)
|
||||
* @retval int 1 — передача завершена, 0 — данные ещё передаются
|
||||
*/
|
||||
static int __uart_fifo_transmit(UART_HandleTypeDef *huart, uint8_t it_mode)
|
||||
{
|
||||
while (!UART_FlagStatus(huart->Instance, UART_Flag_TxFIFOFull) &&
|
||||
huart->TxCount < huart->TxSize)
|
||||
{
|
||||
UART_SendData(huart->Instance, huart->TxBufPtr[huart->TxCount++]);
|
||||
}
|
||||
|
||||
if (huart->TxCount == huart->TxSize)
|
||||
{
|
||||
if(it_mode)
|
||||
{
|
||||
// Выключаем FIFO прерывание
|
||||
UART_ITCmd(huart->Instance, UART_ITSource_TxFIFOLevel, DISABLE);
|
||||
// Включаем TransmitDone прерывание, коллбек будет по нему
|
||||
UART_ITCmd(huart->Instance, UART_ITSource_TransmitDone, ENABLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!UART_FlagStatus(huart->Instance, UART_Flag_TxFIFOEmpty)); // ждем пока не опустошится буфер
|
||||
|
||||
huart->TxBusy = 0;
|
||||
if (huart->Config->TxCallback)
|
||||
huart->Config->TxCallback();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if USE_TX_QUEUE==1
|
||||
static void __uart_tx_queue_process(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart->TxBusy && !huart->TxQueue.QueueEmpty)
|
||||
{
|
||||
__uart_tx_queue_pop(huart);
|
||||
}
|
||||
}
|
||||
|
||||
static OperationStatus __uart_tx_queue_push(UART_HandleTypeDef *huart, const uint8_t *buf, uint16_t size)
|
||||
{
|
||||
if (!huart || !buf || size == 0 || huart->TxQueue.QueueFull)
|
||||
return ERROR;
|
||||
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].Buf = buf;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].Size = size;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueHead].InUse = 1;
|
||||
|
||||
huart->TxQueue.QueueHead = (huart->TxQueue.QueueHead + 1) % TX_QUEUE_SIZE;
|
||||
huart->TxQueue.QueueCount++;
|
||||
|
||||
huart->TxQueue.QueueEmpty = 0;
|
||||
if (huart->TxQueue.QueueCount == TX_QUEUE_SIZE)
|
||||
huart->TxQueue.QueueFull = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
static OperationStatus __uart_tx_queue_pop(UART_HandleTypeDef *huart)
|
||||
{
|
||||
if (!huart || huart->TxQueue.QueueEmpty)
|
||||
return ERROR;
|
||||
|
||||
const uint8_t *buf = huart->TxQueue.Queue[huart->TxQueue.QueueTail].Buf;
|
||||
uint16_t size = huart->TxQueue.Queue[huart->TxQueue.QueueTail].Size;
|
||||
|
||||
if (huart->TxBusy)
|
||||
return ERROR;
|
||||
|
||||
huart->TxBufPtr = buf;
|
||||
huart->TxSize = size;
|
||||
huart->TxCount = 0;
|
||||
huart->TxBusy = 1;
|
||||
|
||||
UART_ITCmd(huart->Instance, UART_ITSource_TxFIFOLevel, ENABLE);
|
||||
__uart_fifo_transmit(huart, 1);
|
||||
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].Buf = NULL;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].Size = 0;
|
||||
huart->TxQueue.Queue[huart->TxQueue.QueueTail].InUse = 0;
|
||||
|
||||
huart->TxQueue.QueueTail = (huart->TxQueue.QueueTail + 1) % TX_QUEUE_SIZE;
|
||||
huart->TxQueue.QueueCount--;
|
||||
|
||||
huart->TxQueue.QueueFull = 0;
|
||||
if (huart->TxQueue.QueueCount == 0)
|
||||
huart->TxQueue.QueueEmpty = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user