本帖最后由 gowow 于 2017-3-20 17:16 编辑
谢绝amobbs转载!
收发全用DMA实现
发送先丢进FIFO,然后触发DMA发送到FIFO尾,再从FIFO头发送
接收直接使用循环DMA,用DMA指针去确认是否有数据到达
已测试过DMA1的UART2/3/4/5,但是UART1有问题,应该是和DMA2有关的UART未调好,哪位有闲就改进一下吧
串口定义样例 注意FIFO大小必须为2的幂,如256 512 1024//PC10 TX4 DMA1.4.4
//PC11 RX4 DMA1.2.4
DMA_TX_IRQH_INIT_FUNC(UART4, 1,4,4);
DMA_RX_INIT_FUNC(UART4, 1,2,4);
UART_INIT(uart_xxx, UART4, GPIOC, 11, 1024, GPIOC, 10, 1024, 1);
调用样例
uart_xxx->init(57600);
uart_xxx->read(............
头文件
#ifndef _UART_DMA_H_
#define _UART_DMA_H_
typedef const struct
{
u32 (*write_space)();
u32 (*read_valid_len)();
bool (*read)(u8 *ptr);
u32 (*reads)(u8 *ptr, u32 len);
bool (*write)(u8 data);
u32 (*writes)(const u8 *ptr, u32 len);
void (*init)(u32 bps);
}UART_OPS;
extern const UART_OPS *uart_xxx;
extern const UART_OPS *uart_yyy;
extern const UART_OPS *uart_zzz;
#endif
C文件typedef struct _fifo
{
u32 size; /* the size of the allocated buffer */
u32 in; /* data is added at offset (in % size) */
u32 out; /* data is extracted from off. (out % size) */
u8 *buffer; /* the buffer holding the data */
}FIFO;
uint32_t is2n(uint32_t un)
{
return un&(un-1);
}
uint32_t max2n(uint32_t un)
{
//下面的函数返回不大于un的2的最大幂
uint32_t mi = is2n(un);
return mi?max2n(mi):un;
}
static void fifo_init(FIFO *fifo, u8 *buff, u32 size)
{
if (!is2n(size))
{
size = max2n(size);
}
fifo->size = size;
fifo->in = fifo->out = 0;
fifo->buffer = buff;
}
static u32 kfifo_put(FIFO *fifo, const u8 *buffer, u32 len)
{
u32 l;
len = min(len, fifo->size - fifo->in + fifo->out); //剩余空间
l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); //从in到fifo尾剩余空间
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
static u32 kfifo_get(FIFO *fifo, u8 *buffer, u32 len)
{
u32 l;
len = min(len, fifo->in - fifo->out); //数据长度
l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); //out到fifo尾数据长度
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); //先拷队尾
memcpy(buffer + l, fifo->buffer, len - l); //再拷前面
fifo->out += len;
return len;
}
//tx fifo
static u32 txfifo_put(FIFO *fifo, const u8 *buffer, u32 len)
{
u32 l;
len = min(len, fifo->size - fifo->in + fifo->out);
l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
static u32 txfifo_dma_get_valid(FIFO *fifo, u8 **pptr, u32 *plen)
{
u32 len;
len = min((fifo->in - fifo->out),
fifo->size - (fifo->out & (fifo->size - 1)));
*pptr = fifo->buffer + (fifo->out & (fifo->size - 1));
*plen = len;
fifo->out += len;
return len;
}
static u32 txfifo_write_space(FIFO *fifo)
{
s32 valid_len;
valid_len = (fifo->in - fifo->out);
if (valid_len >= 0)
return fifo->size - valid_len;
else
return fifo->size;
}
//rx fifo
static u32 rxfifo_get_valid_len(FIFO *fifo, u32 dma_ndtr)
{
s32 valid_len;
valid_len = (fifo->size - dma_ndtr) - (fifo->out & (fifo->size - 1));
if (valid_len < 0)
valid_len += fifo->size;
return valid_len;
}
static u32 rxfifo_get(FIFO *fifo, u32 dma_ndtr, u8 *buffer, u32 len)
{
u32 l;
len = min(len, rxfifo_get_valid_len(fifo, dma_ndtr));
l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
memcpy(buffer + l, fifo->buffer, len - l);
fifo->out += len;
return len;
}
typedef struct _UART_CONTEXT{
USART_TypeDef *uart_type;
FIFO *fifo_rx;
FIFO *fifo_tx;
DMA_Stream_TypeDef *dma_tx;
DMA_Stream_TypeDef *dma_rx;
}UART_CONTEXT;
static u32 uart_write_space(UART_CONTEXT *context)
{
return txfifo_write_space(context->fifo_tx);
}
static u32 uart_read_valid_len(UART_CONTEXT *context)
{
return rxfifo_get_valid_len(context->fifo_rx, context->dma_rx->NDTR);
}
static bool uart_read(UART_CONTEXT *context, u8 *ptr)
{
return (1 == rxfifo_get(context->fifo_rx, context->dma_rx->NDTR, ptr, 1));
}
static u32 uart_reads(UART_CONTEXT *context, u8 *ptr, u32 len)
{
return rxfifo_get(context->fifo_rx, context->dma_rx->NDTR, ptr, len);
}
static void uart_tx_try_start_dma(UART_CONTEXT *context, DMA_Stream_TypeDef *dma_stream_tx)
{
u8 *memptr;
u32 len;
txfifo_dma_get_valid(context->fifo_tx, &memptr, &len);
if ((len > 0) && ((dma_stream_tx->CR & (uint32_t)DMA_SxCR_EN) == 0))
{
dma_stream_tx->M0AR = (u32)memptr;
dma_stream_tx->NDTR = len;
dma_stream_tx->CR |= (uint32_t)DMA_SxCR_EN;
}
}
static bool uart_write(UART_CONTEXT *context, u8 data)
{
bool result;
result = (1 == txfifo_put(context->fifo_tx, &data, 1));
uart_tx_try_start_dma(context, context->dma_tx);
return result;
}
static u32 uart_writes(UART_CONTEXT *context, const u8 *ptr, u32 len)
{
u32 txed_len;
txed_len = txfifo_put(context->fifo_tx, ptr, len);
uart_tx_try_start_dma(context, context->dma_tx);
return txed_len;
}
static void uart_txdma_tc_callback(UART_CONTEXT *context, USART_TypeDef *uart_type, DMA_Stream_TypeDef *dma_stream_tx)
{
u8 *memptr;
u32 len;
txfifo_dma_get_valid(context->fifo_tx, &memptr, &len);
if (len > 0)
{
dma_stream_tx->M0AR = (u32)memptr;
dma_stream_tx->NDTR = len;
dma_stream_tx->CR |= (uint32_t)DMA_SxCR_EN;
}
}
#define DMA_TX_IRQH_INIT_FUNC(uart, dma, stream, channel) \
void DMA##dma##_Stream##stream##_IRQHandler(void) \
{ \
extern UART_CONTEXT struct_##uart; \
if (DMA_GetFlagStatus(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream) != RESET) \
{ \
DMA_ClearFlag(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream); \
uart_txdma_tc_callback(&struct_##uart, uart, DMA##dma##_Stream##stream); \
} \
} \
\
static void uart##_TXDMA_init(u32 memory_addr, u32 memory_size, u8 priority) \
{ \
extern UART_CONTEXT struct_##uart; \
NVIC_InitTypeDef NVIC_InitStructure; \
DMA_InitTypeDef DMA_InitStructure; \
\
struct_##uart.dma_tx = DMA##dma##_Stream##stream; \
\
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA##dma, ENABLE); \
\
DMA_Cmd(DMA##dma##_Stream##stream, DISABLE); \
\
DMA_DeInit(DMA##dma##_Stream##stream); \
\
DMA_InitStructure.DMA_Channel = DMA_Channel_##channel; \
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(uart##->DR)); \
DMA_InitStructure.DMA_Memory0BaseAddr = memory_addr; \
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; \
DMA_InitStructure.DMA_BufferSize = (uint32_t)memory_size; \
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; \
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; \
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; \
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; \
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; \
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; \
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; \
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; \
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; \
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; \
DMA_Init(DMA##dma##_Stream##stream, &DMA_InitStructure); \
\
DMA_ClearFlag(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream); \
DMA_ITConfig(DMA##dma##_Stream##stream, DMA_IT_TC, ENABLE); \
\
NVIC_InitStructure.NVIC_IRQChannel = DMA##dma##_Stream##stream##_IRQn; \
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = priority >> 4; \
NVIC_InitStructure.NVIC_IRQChannelSubPriority = priority & 0x0F; \
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; \
NVIC_Init(&NVIC_InitStructure); \
\
DMA_Cmd(DMA##dma##_Stream##stream, DISABLE); \
}
#define DMA_RX_INIT_FUNC(uart, dma, stream, channel) \
static void uart##_RXDMA_init(u32 memory_addr, u32 memory_size) \
{ \
extern UART_CONTEXT struct_##uart; \
DMA_InitTypeDef DMA_InitStructure; \
\
struct_##uart.dma_rx = DMA##dma##_Stream##stream; \
\
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA##dma, ENABLE); \
\
DMA_Cmd(DMA##dma##_Stream##stream, DISABLE); \
\
DMA_DeInit(DMA##dma##_Stream##stream); \
\
DMA_InitStructure.DMA_Channel = DMA_Channel_##channel; \
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(uart##->DR)); \
DMA_InitStructure.DMA_Memory0BaseAddr = memory_addr; \
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; \
DMA_InitStructure.DMA_BufferSize = memory_size; \
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; \
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; \
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; \
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; \
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; \
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; \
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; \
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; \
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; \
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; \
DMA_Init(DMA##dma##_Stream##stream, &DMA_InitStructure); \
DMA_Cmd(DMA##dma##_Stream##stream, ENABLE); \
}
#define UART_INIT(ops_ptr, uart, gpio_rx, pin_rx, fifosize_rx, gpio_tx, pin_tx, fifosize_tx, tx_dma_irq_priority) \
static UART_CONTEXT struct_##uart = {.uart_type = uart, }; \
static void _##uart##_init(u32 bps) \
{ \
USART_InitTypeDef USART_InitStructure; \
GPIO_InitTypeDef GPIO_InitStructure; \
\
static FIFO rxfifo, txfifo; \
static u8 rxbuff[fifosize_rx], txbuff[fifosize_tx]; \
\
fifo_init(&rxfifo, rxbuff, fifosize_rx); \
struct_##uart.fifo_rx = &rxfifo; \
fifo_init(&txfifo, txbuff, fifosize_tx); \
struct_##uart.fifo_tx = &txfifo; \
\
GPIO_PinAFConfig(gpio_tx, GPIO_PinSource##pin_tx, GPIO_AF_##uart); \
\
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; \
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; \
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; \
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; \
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_##pin_tx; \
GPIO_Init(gpio_tx, &GPIO_InitStructure); \
\
GPIO_PinAFConfig(gpio_rx, GPIO_PinSource##pin_rx, GPIO_AF_##uart); \
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_##pin_rx; \
GPIO_Init(gpio_rx, &GPIO_InitStructure); \
\
USART_InitStructure.USART_BaudRate = bps; \
USART_InitStructure.USART_WordLength = USART_WordLength_8b; \
USART_InitStructure.USART_StopBits = USART_StopBits_1; \
USART_InitStructure.USART_Parity = USART_Parity_No; \
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; \
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; \
USART_Init(uart, &USART_InitStructure); \
\
USART_DMACmd(uart, USART_DMAReq_Tx, ENABLE); \
USART_DMACmd(uart, USART_DMAReq_Rx, ENABLE); \
USART_Cmd(uart, ENABLE); \
uart##_RXDMA_init((u32)(rxfifo.buffer), fifosize_rx); \
uart##_TXDMA_init((u32)(txfifo.buffer), fifosize_tx, tx_dma_irq_priority); \
} \
\
static u32 _##uart##_write_space(){return uart_write_space(&struct_##uart);} \
static u32 _##uart##_read_valid_len(){return uart_read_valid_len(&struct_##uart);} \
static bool _##uart##_read(u8 *ptr){return uart_read(&struct_##uart, ptr);} \
static u32 _##uart##_reads(u8 *ptr, u32 len){return uart_reads(&struct_##uart, ptr, len);} \
static bool _##uart##_write(u8 data){return uart_write(&struct_##uart, data);} \
static u32 _##uart##_writes(const u8 *ptr, u32 len){return uart_writes(&struct_##uart, ptr, len);} \
static UART_OPS _##uart##ops={ \
.write_space = _##uart##_write_space, \
.read_valid_len = _##uart##_read_valid_len, \
.read = _##uart##_read, \
.reads = _##uart##_reads, \
.write = _##uart##_write, \
.writes = _##uart##_writes, \
.init = _##uart##_init}; \
const UART_OPS *ops_ptr = &_##uart##ops;
|
共1人点赞
|