Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F84574131
uart.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Mon, Sep 23, 17:02
Size
9 KB
Mime Type
text/x-c
Expires
Wed, Sep 25, 17:02 (2 d)
Engine
blob
Format
Raw Data
Handle
20874605
Attached To
R2671 HHRI-software
uart.c
View Options
#include "uart.h"
#include "../lib/utils.h"
#include "../communication.h" // TODO: REMOVE. DEBUG ONLY.
#define UART_RX_DMA DMA1_Stream5
#define UART_RX_DMA_CHANNEL DMA_Channel_4
#define UART_TX_DMA DMA1_Stream6
#define UART_TX_DMA_CHANNEL DMA_Channel_4
#define UART_TX_BUFFER_SIZE 4096
#define UART_RX_BUFFER_SIZE 512
#define UART_USER_RX_QUEUE_SIZE 512
uint8_t uart_txBuffer[2][UART_TX_BUFFER_SIZE];
uint8_t uart_currentTxBufferToWriteTo;
uint16_t uart_txBufferIndex;
uint16_t uart_nBytesToTransferDma;
uint8_t uart_rxBuffer[UART_RX_BUFFER_SIZE];
uint8_t const * uart_rxBuffTail;
uint8_t uart_userRxQueue[UART_USER_RX_QUEUE_SIZE];
cb_CircularBuffer uart_rxQueue;
#define UART_DMA_TX_IS_BUSY (DMA_GetCmdStatus(UART_TX_DMA) == ENABLE && DMA_GetCurrDataCounter(UART_TX_DMA) > 0)
/**
* @brief Initializes the UART module.
*/
void uart_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStruct;
// Enable UART and DMA peripherals clocks.
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
// Setup GPIOs as UART pins.
GPIO_InitStruct.GPIO_Pin = USART_TX_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USART_TX_Port, &GPIO_InitStruct);
GPIO_PinAFConfig(USART_TX_Port, USART_TX_PinSource, GPIO_AF_USART2);
GPIO_InitStruct.GPIO_Pin = USART_RX_Pin;
GPIO_Init(USART_RX_Port, &GPIO_InitStruct);
GPIO_PinAFConfig(USART_RX_Port, USART_RX_PinSource, GPIO_AF_USART2);
// Setup the UART peripheral.
USART_InitStruct.USART_BaudRate = UART_BAUDRATE;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART_PC_COMM, &USART_InitStruct);
USART_Cmd(USART_PC_COMM, ENABLE);
// Setup the DMA for RX.
DMA_DeInit(UART_RX_DMA);
DMA_InitStruct.DMA_Channel = UART_RX_DMA_CHANNEL;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_rxBuffer[0];
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_BufferSize = UART_RX_BUFFER_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(UART_RX_DMA, &DMA_InitStruct);
USART_DMACmd(USART_PC_COMM, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
DMA_ITConfig(UART_RX_DMA, DMA_IT_TC, ENABLE);
DMA_Cmd(UART_RX_DMA, ENABLE);
uart_rxBuffTail = &uart_rxBuffer[0];
// Setup the DMA for TX.
DMA_DeInit(UART_TX_DMA);
DMA_InitStruct.DMA_Channel = UART_TX_DMA_CHANNEL;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_txBuffer[0][0];
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = UART_TX_BUFFER_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(UART_TX_DMA, &DMA_InitStruct);
USART_DMACmd(USART_PC_COMM, USART_DMAReq_Rx | USART_DMAReq_Tx, ENABLE);
DMA_ITConfig(UART_TX_DMA, DMA_IT_TC, ENABLE);
//DMA_Cmd(UART_TX_DMA, ENABLE);
// Initialize the RX circular buffer.
cb_Init(&uart_rxQueue, uart_userRxQueue, UART_USER_RX_QUEUE_SIZE);
// Initialize the variables for the UART TX.
uart_currentTxBufferToWriteTo = 0;
uart_txBufferIndex = 0;
uart_nBytesToTransferDma = 0;
}
/**
* @brief Copies the received bytes into the user-accessible queue.
* Reads all the available bytes in the DMA RX buffer, and copies them to the
* user-accessible queue.
* @remark This function must called often, otherwise the DMA RX buffer may be
* full.
*/
void uart_Step(void)
{
// Get the location of the location currently pointed by the DMA.
uint8_t const * head = uart_rxBuffer + UART_RX_BUFFER_SIZE
- DMA_GetCurrDataCounter(UART_RX_DMA);
// Even if the STM32F4 reference manual (RM0090) states that the NDTR
// register is decremented after the transfer, this is not the case.
// So we wait a few cycles to be sure that the DMA actually performed the
// transfer.
utils_DelayUs(1);
// RX: add the received bytes into the user queue.
while(uart_rxBuffTail != head)
{
uint8_t b = *uart_rxBuffTail;
cb_Push(&uart_rxQueue, b);
uart_rxBuffTail++;
if(uart_rxBuffTail >= uart_rxBuffer + UART_RX_BUFFER_SIZE)
uart_rxBuffTail -= UART_RX_BUFFER_SIZE;
}
}
/**
* @brief Gets the user-accessible queue of the received bytes.
* @return the address of the queue.
*/
cb_CircularBuffer* uart_GetRxQueue(void)
{
return &uart_rxQueue;
}
/**
* @brief Starts the DMA transfer to send bytes to UART peripheral.
*/
void uart_StartDma(void)
{
DMA_InitTypeDef DMA_InitStruct;
//
uart_nBytesToTransferDma = uart_txBufferIndex;
uart_currentTxBufferToWriteTo = !uart_currentTxBufferToWriteTo;
uart_txBufferIndex = 0;
// Start the DMA transfer.
DMA_DeInit(UART_TX_DMA);
DMA_InitStruct.DMA_Channel = UART_TX_DMA_CHANNEL;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&uart_txBuffer[!uart_currentTxBufferToWriteTo][0];
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStruct.DMA_BufferSize = uart_nBytesToTransferDma;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(UART_TX_DMA, &DMA_InitStruct);
DMA_Cmd(UART_TX_DMA, ENABLE);
}
/**
* @brief Asynchronously sends the given byte through the UART bus.
* @param data the data byte to send.
*/
void uart_SendByteAsync(uint8_t data)
{
// Check that it is possible to write in the current buffer.
if(uart_txBufferIndex >= UART_TX_BUFFER_SIZE)
{
// If the DMA is idle, switch to the other buffer.
if(UART_DMA_TX_IS_BUSY)
{
utils_TrapCpu(); // Error, can't write anywhere!
return;
}
else
uart_StartDma();
}
// Write the byte in the buffer.
uart_txBuffer[uart_currentTxBufferToWriteTo][uart_txBufferIndex] = data;
uart_txBufferIndex++;
// If the buffer is full, start the DMA transfer.
if(uart_txBufferIndex == UART_TX_BUFFER_SIZE)
uart_StartDma();
}
/**
* @brief Asynchronously sends the given bytes through the UART bus.
* @param data pointer to the data bytes array to send.
* @param length number of bytes to send (array size).
* @remark The bytes may not be send immediately, they are stored temporarily in
* an intermediate buffer that the DMA will copy to UART peripheral, when it is
* full. Call uart_FlushTx() to start the DMA transfer immediately.
*/
void uart_SendBytesAsync(uint8_t *data, int length)
{
while(length > 0)
{
uint16_t nBytesToWriteInBuf;
// Check that it is possible to write in the current buffer.
if(uart_txBufferIndex >= UART_TX_BUFFER_SIZE)
{
// If the DMA is idle, switch to the other buffer.
if(UART_DMA_TX_IS_BUSY)
{
utils_TrapCpu(); // Error, can't write anywhere!
return;
}
else
uart_StartDma();
}
// Write as many bytes as possible in the current buffer.
nBytesToWriteInBuf = UART_TX_BUFFER_SIZE - uart_txBufferIndex;
if(nBytesToWriteInBuf > length)
nBytesToWriteInBuf = length;
memcpy(&uart_txBuffer[uart_currentTxBufferToWriteTo][uart_txBufferIndex],
data, nBytesToWriteInBuf);
uart_txBufferIndex += nBytesToWriteInBuf;
data += nBytesToWriteInBuf;
length -= nBytesToWriteInBuf;
// If the buffer is full, start the DMA transfer.
if(uart_txBufferIndex == UART_TX_BUFFER_SIZE)
uart_StartDma();
}
}
/**
* @brief Start the DMA to send the bytes waiting in the intermediate buffer.
*/
void uart_FlushTx(void)
{
if(uart_txBufferIndex > 0 && !UART_DMA_TX_IS_BUSY)
uart_StartDma();
}
Event Timeline
Log In to Comment