196 lines
6.0 KiB
C
196 lines
6.0 KiB
C
/**
|
|
* @file bsp_usart.c
|
|
* @brief USART1 init, printf retarget (fputc, polling TX), DMA TX and
|
|
* RX interrupt byte queue.
|
|
*/
|
|
#include "bsp_usart.h"
|
|
#include <stdio.h>
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "semphr.h"
|
|
|
|
#define RX_QUEUE_LENGTH 64
|
|
|
|
static QueueHandle_t s_rxQueue = NULL;
|
|
static SemaphoreHandle_t s_txMutex = NULL;
|
|
|
|
/**
|
|
* @brief Initialize USART1 (1000000 8N1) on PB6(TX)/PB7(RX),
|
|
* DMA TX channel and the RX interrupt queue.
|
|
*/
|
|
void bsp_usart_init(void)
|
|
{
|
|
GPIO_InitType GPIO_InitStructure;
|
|
USART_InitType USART_InitStructure;
|
|
NVIC_InitType NVIC_InitStructure;
|
|
|
|
/* Enable GPIOB and USART1 clocks */
|
|
RCC_EnableAPB2PeriphClk(BSP_USART_GPIO_CLK, ENABLE);
|
|
RCC_EnableAPB2PeriphClk(BSP_USART_CLK, ENABLE);
|
|
|
|
/* Configure USART1 TX (PB6) as alternate function push-pull */
|
|
GPIO_InitStruct(&GPIO_InitStructure);
|
|
GPIO_InitStructure.Pin = BSP_USART_TX_PIN;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStructure.GPIO_Alternate = BSP_USART_TX_GPIO_AF;
|
|
GPIO_InitPeripheral(BSP_USART_GPIO, &GPIO_InitStructure);
|
|
|
|
/* Configure USART1 RX (PB7) as alternate function */
|
|
GPIO_InitStructure.Pin = BSP_USART_RX_PIN;
|
|
GPIO_InitStructure.GPIO_Alternate = BSP_USART_RX_GPIO_AF;
|
|
GPIO_InitPeripheral(BSP_USART_GPIO, &GPIO_InitStructure);
|
|
|
|
USART_InitStructure.BaudRate = BSP_USART_BAUDRATE;
|
|
USART_InitStructure.WordLength = USART_WL_8B;
|
|
USART_InitStructure.StopBits = USART_STPB_1;
|
|
USART_InitStructure.Parity = USART_PE_NO;
|
|
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
|
|
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
|
|
|
|
USART_Init(BSP_USARTx, &USART_InitStructure);
|
|
|
|
/* USART1 TX DMA: CH1 remapped to USART1_TX, configured per transfer */
|
|
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
|
|
DMA_DeInit(BSP_USART_TX_DMA_CH);
|
|
DMA_RequestRemap(BSP_USART_TX_DMA_REMAP, DMA, BSP_USART_TX_DMA_CH, ENABLE);
|
|
USART_EnableDMA(BSP_USARTx, USART_DMAREQ_TX, ENABLE);
|
|
|
|
/* RX byte queue fed by the RXDNE interrupt */
|
|
s_rxQueue = xQueueCreate(RX_QUEUE_LENGTH, sizeof(uint8_t));
|
|
s_txMutex = xSemaphoreCreateMutex();
|
|
|
|
USART_ConfigInt(BSP_USARTx, USART_INT_RXDNE, ENABLE);
|
|
/* Lowest priority: the ISR calls FreeRTOS FromISR APIs */
|
|
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
|
|
NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
|
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
|
NVIC_Init(&NVIC_InitStructure);
|
|
|
|
USART_Enable(BSP_USARTx, ENABLE);
|
|
}
|
|
|
|
/**
|
|
* @brief Send a buffer over USART1 TX using DMA, polled completion.
|
|
*/
|
|
void bsp_usart_write_dma(const uint8_t* data, uint16_t len)
|
|
{
|
|
DMA_InitType DMA_InitStructure;
|
|
|
|
if (data == NULL || len == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DMA_EnableChannel(BSP_USART_TX_DMA_CH, DISABLE);
|
|
DMA_ClearFlag(BSP_USART_TX_DMA_TC, DMA);
|
|
|
|
DMA_InitStructure.PeriphAddr = BSP_USART_DAT_ADDR;
|
|
DMA_InitStructure.MemAddr = (uint32_t)data;
|
|
DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
|
|
DMA_InitStructure.BufSize = len;
|
|
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
|
|
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
|
|
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
|
|
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
|
|
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
|
|
DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
|
|
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
|
|
DMA_Init(BSP_USART_TX_DMA_CH, &DMA_InitStructure);
|
|
|
|
DMA_EnableChannel(BSP_USART_TX_DMA_CH, ENABLE);
|
|
while (DMA_GetFlagStatus(BSP_USART_TX_DMA_TC, DMA) == RESET)
|
|
{
|
|
}
|
|
DMA_EnableChannel(BSP_USART_TX_DMA_CH, DISABLE);
|
|
DMA_ClearFlag(BSP_USART_TX_DMA_TC, DMA);
|
|
|
|
/* Wait for the last byte to leave the shift register */
|
|
while (USART_GetFlagStatus(BSP_USARTx, USART_FLAG_TXC) == RESET)
|
|
{
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Fetch one byte received by the RX interrupt.
|
|
* @param ch output byte
|
|
* @param timeout_ms BSP_USART_WAIT_FOREVER or a timeout in ms
|
|
* @return 1 on success, 0 on timeout
|
|
*/
|
|
int bsp_usart_read_byte(uint8_t* ch, uint32_t timeout_ms)
|
|
{
|
|
TickType_t ticks;
|
|
|
|
if (s_rxQueue == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
ticks = (timeout_ms == BSP_USART_WAIT_FOREVER) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
|
|
return (xQueueReceive(s_rxQueue, ch, ticks) == pdPASS) ? 1 : 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Take the TX mutex (no-op before the scheduler runs).
|
|
*/
|
|
void bsp_usart_tx_lock(void)
|
|
{
|
|
if (s_txMutex != NULL && xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
|
|
{
|
|
xSemaphoreTake(s_txMutex, portMAX_DELAY);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Give the TX mutex.
|
|
*/
|
|
void bsp_usart_tx_unlock(void)
|
|
{
|
|
if (s_txMutex != NULL && xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
|
|
{
|
|
xSemaphoreGive(s_txMutex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief RXDNE interrupt handler, pushes the received byte into the RX queue.
|
|
* Called from USART1_IRQHandler (see n32wb03x_it.c).
|
|
*/
|
|
void bsp_usart_rx_isr_handler(void)
|
|
{
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
if (USART_GetIntStatus(BSP_USARTx, USART_INT_RXDNE) != RESET)
|
|
{
|
|
/* Reading DAT clears the RXDNE flag */
|
|
uint8_t ch = (uint8_t)USART_ReceiveData(BSP_USARTx);
|
|
|
|
if (s_rxQueue != NULL)
|
|
{
|
|
xQueueSendFromISR(s_rxQueue, &ch, &xHigherPriorityTaskWoken);
|
|
}
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
}
|
|
}
|
|
|
|
/* Retarget the C library printf function to USART1 (polling TX) */
|
|
int fputc(int ch, FILE* f)
|
|
{
|
|
/* Send '\r' before '\n' so that serial terminals display correctly */
|
|
if (ch == '\n')
|
|
{
|
|
USART_SendData(BSP_USARTx, (uint8_t)'\r');
|
|
while (USART_GetFlagStatus(BSP_USARTx, USART_FLAG_TXDE) == RESET)
|
|
{
|
|
}
|
|
}
|
|
|
|
USART_SendData(BSP_USARTx, (uint8_t)ch);
|
|
while (USART_GetFlagStatus(BSP_USARTx, USART_FLAG_TXDE) == RESET)
|
|
{
|
|
}
|
|
|
|
return ch;
|
|
}
|