[STM32F4] 原创 STM32F4 DMA串口收发驱动

[复制链接]
5719|22
 楼主| gowow 发表于 2017-3-20 10:18 | 显示全部楼层 |阅读模式
本帖最后由 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
  1. //PC10  TX4                                DMA1.4.4
  2. //PC11  RX4                                DMA1.2.4
  3. DMA_TX_IRQH_INIT_FUNC(UART4, 1,4,4);
  4. DMA_RX_INIT_FUNC(UART4, 1,2,4);
  5. UART_INIT(uart_xxx, UART4, GPIOC, 11, 1024, GPIOC, 10, 1024, 1);
调用样例

  1. uart_xxx->init(57600);
  2. uart_xxx->read(............


头文件
  1. #ifndef _UART_DMA_H_
  2. #define _UART_DMA_H_

  3. typedef const struct
  4. {
  5.   u32 (*write_space)();
  6.   u32 (*read_valid_len)();
  7.   bool (*read)(u8 *ptr);
  8.   u32 (*reads)(u8 *ptr, u32 len);
  9.   bool (*write)(u8 data);
  10.   u32 (*writes)(const u8 *ptr, u32 len);
  11.   void (*init)(u32 bps);
  12. }UART_OPS;

  13. extern const UART_OPS *uart_xxx;
  14. extern const UART_OPS *uart_yyy;
  15. extern const UART_OPS *uart_zzz;
  16. #endif


C文件
  1. typedef struct _fifo
  2. {
  3.   u32 size;    /* the size of the allocated buffer */
  4.   u32 in;    /* data is added at offset (in % size) */
  5.   u32 out;    /* data is extracted from off. (out % size) */
  6.   u8 *buffer;    /* the buffer holding the data */
  7. }FIFO;

  8. uint32_t is2n(uint32_t un)
  9. {
  10.   return un&(un-1);
  11. }

  12. uint32_t max2n(uint32_t un)
  13. {
  14.   //下面的函数返回不大于un的2的最大幂
  15.   uint32_t mi = is2n(un);
  16.   return mi?max2n(mi):un;
  17. }

  18. static void fifo_init(FIFO *fifo, u8 *buff, u32 size)
  19. {
  20.   if (!is2n(size))
  21.   {
  22.     size = max2n(size);
  23.   }

  24.   fifo->size = size;
  25.   fifo->in = fifo->out = 0;
  26.   fifo->buffer = buff;
  27. }

  28. static u32 kfifo_put(FIFO *fifo, const u8 *buffer, u32 len)
  29. {
  30.   u32 l;

  31.   len = min(len, fifo->size - fifo->in + fifo->out);                //剩余空间
  32.   l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));         //从in到fifo尾剩余空间

  33.   memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
  34.   memcpy(fifo->buffer, buffer + l, len - l);

  35.   fifo->in += len;

  36.   return len;
  37. }

  38. static u32 kfifo_get(FIFO *fifo, u8 *buffer, u32 len)
  39. {
  40.   u32 l;

  41.   len = min(len, fifo->in - fifo->out);                           //数据长度
  42.   l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));      //out到fifo尾数据长度

  43.   memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);   //先拷队尾
  44.   memcpy(buffer + l, fifo->buffer, len - l);                            //再拷前面

  45.   fifo->out += len;

  46.   return len;
  47. }

  48. //tx fifo
  49. static u32 txfifo_put(FIFO *fifo, const u8 *buffer, u32 len)
  50. {
  51.   u32 l;

  52.   len = min(len, fifo->size - fifo->in + fifo->out);
  53.   l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));

  54.   memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
  55.   memcpy(fifo->buffer, buffer + l, len - l);

  56.   fifo->in += len;

  57.   return len;
  58. }

  59. static u32 txfifo_dma_get_valid(FIFO *fifo, u8 **pptr, u32 *plen)
  60. {

  61.   u32 len;
  62.   len = min((fifo->in - fifo->out),
  63.             fifo->size - (fifo->out & (fifo->size - 1)));

  64.   *pptr = fifo->buffer + (fifo->out & (fifo->size - 1));
  65.   *plen = len;

  66.   fifo->out += len;

  67.   return len;
  68. }

  69. static u32 txfifo_write_space(FIFO *fifo)
  70. {
  71.   s32 valid_len;
  72.   valid_len = (fifo->in - fifo->out);
  73.   if (valid_len >= 0)
  74.     return fifo->size - valid_len;
  75.   else
  76.     return fifo->size;
  77. }

  78. //rx fifo
  79. static u32 rxfifo_get_valid_len(FIFO *fifo, u32 dma_ndtr)
  80. {
  81.   s32 valid_len;
  82.   valid_len = (fifo->size - dma_ndtr) - (fifo->out & (fifo->size - 1));
  83.   if (valid_len < 0)
  84.     valid_len += fifo->size;
  85.   return valid_len;
  86. }

  87. static u32 rxfifo_get(FIFO *fifo, u32 dma_ndtr, u8 *buffer, u32 len)
  88. {
  89.   u32 l;

  90.   len = min(len, rxfifo_get_valid_len(fifo, dma_ndtr));
  91.   l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));

  92.   memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
  93.   memcpy(buffer + l, fifo->buffer, len - l);
  94.   fifo->out += len;

  95.   return len;
  96. }

  97. typedef  struct _UART_CONTEXT{
  98.   USART_TypeDef *uart_type;
  99.   FIFO *fifo_rx;
  100.   FIFO *fifo_tx;
  101.   DMA_Stream_TypeDef *dma_tx;
  102.         DMA_Stream_TypeDef *dma_rx;
  103. }UART_CONTEXT;

  104. static u32 uart_write_space(UART_CONTEXT *context)
  105. {
  106.   return txfifo_write_space(context->fifo_tx);
  107. }

  108. static u32 uart_read_valid_len(UART_CONTEXT *context)
  109. {
  110.   return rxfifo_get_valid_len(context->fifo_rx, context->dma_rx->NDTR);
  111. }

  112. static bool uart_read(UART_CONTEXT *context, u8 *ptr)
  113. {
  114.   return (1 == rxfifo_get(context->fifo_rx, context->dma_rx->NDTR, ptr, 1));
  115. }

  116. static u32 uart_reads(UART_CONTEXT *context, u8 *ptr, u32 len)
  117. {
  118.   return rxfifo_get(context->fifo_rx, context->dma_rx->NDTR, ptr, len);
  119. }

  120. static void uart_tx_try_start_dma(UART_CONTEXT *context, DMA_Stream_TypeDef *dma_stream_tx)
  121. {
  122.   u8 *memptr;
  123.   u32 len;

  124.   txfifo_dma_get_valid(context->fifo_tx, &memptr, &len);

  125.   if ((len > 0) && ((dma_stream_tx->CR & (uint32_t)DMA_SxCR_EN) == 0))
  126.   {
  127.     dma_stream_tx->M0AR = (u32)memptr;
  128.     dma_stream_tx->NDTR = len;
  129.     dma_stream_tx->CR |= (uint32_t)DMA_SxCR_EN;
  130.   }
  131. }

  132. static bool uart_write(UART_CONTEXT *context, u8 data)
  133. {
  134.   bool result;
  135.   result = (1 == txfifo_put(context->fifo_tx, &data, 1));
  136.   uart_tx_try_start_dma(context, context->dma_tx);
  137.   return result;
  138. }

  139. static u32 uart_writes(UART_CONTEXT *context, const u8 *ptr, u32 len)
  140. {
  141.   u32 txed_len;
  142.   txed_len = txfifo_put(context->fifo_tx, ptr, len);
  143.   uart_tx_try_start_dma(context, context->dma_tx);
  144.   return txed_len;
  145. }

  146. static void uart_txdma_tc_callback(UART_CONTEXT *context, USART_TypeDef *uart_type, DMA_Stream_TypeDef *dma_stream_tx)
  147. {
  148.   u8 *memptr;
  149.   u32 len;

  150.   txfifo_dma_get_valid(context->fifo_tx, &memptr, &len);

  151.   if (len > 0)
  152.   {
  153.     dma_stream_tx->M0AR = (u32)memptr;
  154.     dma_stream_tx->NDTR = len;
  155.     dma_stream_tx->CR |= (uint32_t)DMA_SxCR_EN;
  156.   }
  157. }

  158. #define DMA_TX_IRQH_INIT_FUNC(uart, dma, stream, channel)  \
  159.   void DMA##dma##_Stream##stream##_IRQHandler(void) \
  160.   { \
  161.     extern UART_CONTEXT struct_##uart; \
  162.     if (DMA_GetFlagStatus(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream) != RESET) \
  163.     { \
  164.       DMA_ClearFlag(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream); \
  165.       uart_txdma_tc_callback(&struct_##uart, uart, DMA##dma##_Stream##stream); \
  166.     } \
  167.   } \
  168.     \
  169.   static void uart##_TXDMA_init(u32 memory_addr, u32 memory_size, u8 priority)  \
  170.   { \
  171.     extern UART_CONTEXT struct_##uart; \
  172.     NVIC_InitTypeDef NVIC_InitStructure;  \
  173.     DMA_InitTypeDef DMA_InitStructure;  \
  174.     \
  175.     struct_##uart.dma_tx = DMA##dma##_Stream##stream; \
  176.     \
  177.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA##dma, ENABLE);  \
  178.     \
  179.     DMA_Cmd(DMA##dma##_Stream##stream, DISABLE);  \
  180.     \
  181.     DMA_DeInit(DMA##dma##_Stream##stream);  \
  182.     \
  183.     DMA_InitStructure.DMA_Channel = DMA_Channel_##channel;  \
  184.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(uart##->DR)); \
  185.     DMA_InitStructure.DMA_Memory0BaseAddr = memory_addr;  \
  186.     DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;  \
  187.     DMA_InitStructure.DMA_BufferSize = (uint32_t)memory_size;  \
  188.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  \
  189.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  \
  190.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  \
  191.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  \
  192.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  \
  193.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  \
  194.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;  \
  195.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;  \
  196.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;  \
  197.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  \
  198.     DMA_Init(DMA##dma##_Stream##stream, &DMA_InitStructure);  \
  199.     \
  200.     DMA_ClearFlag(DMA##dma##_Stream##stream, DMA_FLAG_TCIF##stream); \
  201.     DMA_ITConfig(DMA##dma##_Stream##stream, DMA_IT_TC, ENABLE);  \
  202.     \
  203.     NVIC_InitStructure.NVIC_IRQChannel = DMA##dma##_Stream##stream##_IRQn;  \
  204.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = priority >> 4;  \
  205.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = priority & 0x0F;  \
  206.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  \
  207.     NVIC_Init(&NVIC_InitStructure);  \
  208.     \
  209.     DMA_Cmd(DMA##dma##_Stream##stream, DISABLE);  \
  210.   }

  211. #define DMA_RX_INIT_FUNC(uart, dma, stream, channel)  \
  212.   static void uart##_RXDMA_init(u32 memory_addr, u32 memory_size)  \
  213.   { \
  214.     extern UART_CONTEXT struct_##uart; \
  215.     DMA_InitTypeDef DMA_InitStructure;  \
  216.     \
  217.     struct_##uart.dma_rx = DMA##dma##_Stream##stream; \
  218.     \
  219.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA##dma, ENABLE);  \
  220.     \
  221.     DMA_Cmd(DMA##dma##_Stream##stream, DISABLE);  \
  222.     \
  223.     DMA_DeInit(DMA##dma##_Stream##stream);  \
  224.     \
  225.     DMA_InitStructure.DMA_Channel = DMA_Channel_##channel;  \
  226.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&(uart##->DR));  \
  227.     DMA_InitStructure.DMA_Memory0BaseAddr = memory_addr;  \
  228.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;  \
  229.     DMA_InitStructure.DMA_BufferSize = memory_size;  \
  230.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  \
  231.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  \
  232.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  \
  233.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  \
  234.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  \
  235.     DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  \
  236.     DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  \
  237.     DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;  \
  238.     DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;  \
  239.     DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  \
  240.     DMA_Init(DMA##dma##_Stream##stream, &DMA_InitStructure);  \
  241.     DMA_Cmd(DMA##dma##_Stream##stream, ENABLE);  \
  242.   }

  243. #define UART_INIT(ops_ptr, uart, gpio_rx, pin_rx, fifosize_rx, gpio_tx, pin_tx, fifosize_tx, tx_dma_irq_priority)  \
  244.   static UART_CONTEXT struct_##uart = {.uart_type = uart, }; \
  245.   static void _##uart##_init(u32 bps)  \
  246.   { \
  247.     USART_InitTypeDef USART_InitStructure; \
  248.     GPIO_InitTypeDef GPIO_InitStructure; \
  249.     \
  250.     static FIFO rxfifo, txfifo; \
  251.     static u8 rxbuff[fifosize_rx], txbuff[fifosize_tx]; \
  252.     \
  253.     fifo_init(&rxfifo, rxbuff, fifosize_rx); \
  254.     struct_##uart.fifo_rx = &rxfifo; \
  255.     fifo_init(&txfifo, txbuff, fifosize_tx); \
  256.     struct_##uart.fifo_tx = &txfifo; \
  257.     \
  258.     GPIO_PinAFConfig(gpio_tx, GPIO_PinSource##pin_tx, GPIO_AF_##uart); \
  259.     \
  260.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; \
  261.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; \
  262.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; \
  263.     GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP; \
  264.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_##pin_tx; \
  265.     GPIO_Init(gpio_tx, &GPIO_InitStructure); \
  266.     \
  267.     GPIO_PinAFConfig(gpio_rx, GPIO_PinSource##pin_rx, GPIO_AF_##uart); \
  268.     GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_##pin_rx; \
  269.     GPIO_Init(gpio_rx, &GPIO_InitStructure); \
  270.     \
  271.     USART_InitStructure.USART_BaudRate = bps; \
  272.     USART_InitStructure.USART_WordLength = USART_WordLength_8b; \
  273.     USART_InitStructure.USART_StopBits = USART_StopBits_1; \
  274.     USART_InitStructure.USART_Parity = USART_Parity_No; \
  275.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; \
  276.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; \
  277.     USART_Init(uart, &USART_InitStructure); \
  278.     \
  279.     USART_DMACmd(uart, USART_DMAReq_Tx, ENABLE); \
  280.     USART_DMACmd(uart, USART_DMAReq_Rx, ENABLE); \
  281.     USART_Cmd(uart, ENABLE); \
  282.     uart##_RXDMA_init((u32)(rxfifo.buffer), fifosize_rx); \
  283.     uart##_TXDMA_init((u32)(txfifo.buffer), fifosize_tx, tx_dma_irq_priority); \
  284.   } \
  285.    \
  286.   static u32 _##uart##_write_space(){return uart_write_space(&struct_##uart);} \
  287.   static u32 _##uart##_read_valid_len(){return uart_read_valid_len(&struct_##uart);} \
  288.   static bool _##uart##_read(u8 *ptr){return uart_read(&struct_##uart, ptr);} \
  289.   static u32 _##uart##_reads(u8 *ptr, u32 len){return uart_reads(&struct_##uart, ptr, len);} \
  290.   static bool _##uart##_write(u8 data){return uart_write(&struct_##uart, data);} \
  291.   static u32 _##uart##_writes(const u8 *ptr, u32 len){return uart_writes(&struct_##uart, ptr, len);} \
  292.   static UART_OPS _##uart##ops={ \
  293.   .write_space = _##uart##_write_space, \
  294.   .read_valid_len = _##uart##_read_valid_len, \
  295.   .read = _##uart##_read, \
  296.   .reads = _##uart##_reads, \
  297.   .write = _##uart##_write, \
  298.   .writes = _##uart##_writes, \
  299.   .init = _##uart##_init}; \
  300.   const UART_OPS *ops_ptr = &_##uart##ops;



whtwhtw 发表于 2017-3-20 10:20 | 显示全部楼层
支持一下
mmuuss586 发表于 2017-3-20 11:05 | 显示全部楼层

谢谢分享;
nyszx 发表于 2017-3-20 11:22 | 显示全部楼层
谢谢分享。看来楼主对莫坛意见很大呀。
aspoke 发表于 2017-3-20 13:19 | 显示全部楼层
aspoke 发表于 2017-3-20 13:23 | 显示全部楼层
不用再中断执行了。
@若水 发表于 2017-3-20 18:21 | 显示全部楼层
我想问,你跟**的仇恨到底有多大?不过我也不喜欢**,当初想注册时,居然要钱,所以拒绝**,顶起……
@若水 发表于 2017-3-20 18:22 | 显示全部楼层
我想问,你跟amobbs的仇恨到底有多大?不过我也不喜欢amobbs,当初想注册时,居然要钱,所以拒绝amobbs,顶起……
戈卫东 发表于 2017-3-20 19:03 | 显示全部楼层
amobbs是什么?
Raeka 发表于 2017-3-20 22:48 | 显示全部楼层
顶红字加粗部分!!希望本论坛越来越好!!
pkuzhx 发表于 2017-3-21 09:07 | 显示全部楼层
第一句霸气
xyz549040622 发表于 2017-3-21 09:27 | 显示全部楼层
@21小喇叭 建议推荐。
boming 发表于 2017-3-21 14:46 | 显示全部楼层
收和发都用了中断吗?我做了个DMA的,但收和发都用了中断。能共享整个项目工程吗?还是看不懂
WZQ3 发表于 2017-3-21 22:43 | 显示全部楼层
谢谢分享!
suzhanhua 发表于 2017-3-21 23:19 | 显示全部楼层
跟着楼主多多学习一下。
suzhanhua 发表于 2017-3-21 23:21 | 显示全部楼层
不使用中断触发了吗?
 楼主| gowow 发表于 2017-3-24 10:04 | 显示全部楼层
@若水 发表于 2017-3-20 18:22
我想问,你跟amobbs的仇恨到底有多大?不过我也不喜欢amobbs,当初想注册时,居然要钱,所以拒绝amobbs,顶 ...

一个一直在用的账号名,应该是08年或更早注册的,被封了,说是密码简单,好,认了
后来注册的账号,有次交钱预定了春风电源,当初应该是说3个月后交货,后来应该是过了一年多,我问了问进度,没有辱骂没有质疑,我很尊重春风的,注意只是问了问进度,直接封账号,钱倒是退了,但是也白等了。其他等那些雕刻机之类的朋友,你们也知道怎么回事。
后来一个账号,也写过原创精华帖,被封了,理由是我三个月未回复帖子,认为我只会索取不会付出再后来就要注册费,我去你吗的,一分钱也不给你
 楼主| gowow 发表于 2017-3-24 10:10 | 显示全部楼层
boming 发表于 2017-3-21 14:46
收和发都用了中断吗?我做了个DMA的,但收和发都用了中断。能共享整个项目工程吗?还是看不懂 ...

收没有中断,直接放在循环的DMA接收里
发有中断,但是是一段字节的DMA中断

例如你先发送10个字节,DMA就开始发这10个字节。你在DMA发送过程中又分两次把20个字节和30个字节放进去FIFO里。那等最先的10个字节发送完,触发DMA完成中断,接着就会把余下的20+30=50个字节一次性用DMA发送出去。

按这个例子,就是本来要触发10+20+30=60次的UART字节发送中断,用这个驱动就变成了1+1次DMA发送中断。发的越多,发的越整块,效率就越高
 楼主| gowow 发表于 2017-3-24 10:14 | 显示全部楼层
把头文件保存到uart.h文件里,把C文件保存在到uart.c文件里

在uart.c最后用下面这样方式定义一个串口
  1. //PC10  TX4                                DMA1.4.4
  2. //PC11  RX4                                DMA1.2.4
  3. DMA_TX_IRQH_INIT_FUNC(UART4, 1,4,4);
  4. DMA_RX_INIT_FUNC(UART4, 1,2,4);
  5. UART_INIT(uart_xxx, UART4, GPIOC, 11, 1024, GPIOC, 10, 1024, 1);


在uart.h文件里把handler声明一下
extern const UART_OPS *uart_xxx;

就可以在其他地方用这个uart_xxx句柄来调用uart驱动了,例如init和read
uart_xxx->init(57600);
uart_xxx->read(............
@若水 发表于 2017-3-24 11:21 | 显示全部楼层
gowow 发表于 2017-3-24 10:04
一个一直在用的账号名,应该是08年或更早注册的,被封了,说是密码简单,好,认了
后来注册的账号,有次 ...

这样说,真的好恶心,大家的付出,为amobbs铺了条发财路,如果没有大家的付出,里面哪来的资源?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

121

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部