用DMA双缓冲给PC发送串口数据 和 接收PC串口数据。
理解双缓冲概念:就是利用两个数组轮流导出或导进数据。
比如定义两个缓冲区数组usart_buffer0[USART_NUM] 和 usart_buffer1[USART_NUM],数组大小USART_NUM要设置一样。
给PC发送数据时:
DMA先从usart_buffer0(先假设从usart_buffer0)缓冲区拿数据发给PC,usart_buffer0发完后,DMA再从usart_buffer1中拿数据发给PC,usart_buffer1发完后,DMA再次回到usart_buffer0拿数据发给PC,循环操作。
注意:DMA在对usart_buffer1拿数据的同时,CPU可以更新usart_buffer0中的数据,同理,DMA在对usart_buffer0拿数据的同时,CPU也可以更新usart_buffer1中的数据。
接收数据也是同样的道理。
先看看几个问题:
(1)、DMA先从哪个地址拿数据发给PC?
答:按照正常思路,觉得是先打印Memory0中的数据,而按照下面程序的配置,实测,PC先打印的数据是Memory1,这地方让我有点迷糊,有点像“后进先出”。所以后面传数组地址时,稍微注意一下。
(2)、怎么知道DMA当前在对哪个缓冲区拿数据?
答:可通过DMA_GetCurrentMemoryTarget(DMA_Stream_TypeDef* DMAy_Streamx);函数获取信息,
这里使用寄存器if (DMA1_Stream5->CR&(1<<19) ) 来判断,也就是检测CR寄存器中的第bit19位。
(3)、当DMA发送完usart_buffer0后,会不会进入中断,还是等usart_buffer1发送完后进中断?
答:每当发送完一个缓冲就会进入一次中断。
(4)、配置DMA缓冲区大小时,是配置USART_NUM还是 2*USART_NUM?
答: 配置大小是 USART_NUM
(5)、DMA切换缓冲区需要每次配置吗?
答:只需配置一次,软件会自动切换。
先是头文件
#ifndef __DEBUG_USART_H #define __DEBUG_USART_H #include "stm32f4xx.h" #include <stdio.h> #define NEW_BOARD 1 #define OLD_BOARD 0 #if NEW_BOARD //USART2 DMA1 µÚ6¸öÊý¾ÝÁ÷ µÚ4¸öͨµÀ #define USART_ADDRESS 0x40004404 #define DEBUG_USART USART2 #define DEBUG_USART_CLK RCC_APB1Periph_USART2 #define DEBUG_USART_BAUDRATE 115200 #define DEBUG_USART_RX_GPIO_PORT GPIOD #define DEBUG_USART_RX_GPIO_CLK RCC_AHB1Periph_GPIOD #define DEBUG_USART_RX_PIN GPIO_Pin_6 #define DEBUG_USART_RX_AF GPIO_AF_USART2 #define DEBUG_USART_RX_SOURCE GPIO_PinSource6 #define DEBUG_USART_TX_GPIO_PORT GPIOD #define DEBUG_USART_TX_GPIO_CLK RCC_AHB1Periph_GPIOD #define DEBUG_USART_TX_PIN GPIO_Pin_5 #define DEBUG_USART_TX_AF GPIO_AF_USART2 #define DEBUG_USART_TX_SOURCE GPIO_PinSource5 #define RCC_AHB1Periph_DMAx RCC_AHB1Periph_DMA1 #define DMAx_Streamx DMA1_Stream6 #define Rx_DMAx_Streamx DMA1_Stream5 #define DMA_ALL_IT_FLAG DMA_IT_FEIF6|DMA_IT_DMEIF6|DMA_IT_TEIF6|DMA_IT_HTIF6|DMA_IT_TCIF6 #define DMA_Channel_x DMA_Channel_4 #define DMAx_Streamx_IRQn DMA1_Stream6_IRQn #define DMAx_Streamx_IRQHandler DMA1_Stream6_IRQHandler #define DMA_IT_TCIFx DMA_IT_TCIF6 #endif #if OLD_BOARD //USART1 DMA2 µÚ7¸öÊý¾ÝÁ÷ µÚ4¸öͨµÀ #define USART_ADDRESS 0x40011004 #define DEBUG_USART USART1 #define DEBUG_USART_CLK RCC_APB2Periph_USART1 #define DEBUG_USART_BAUDRATE 115200 #define DEBUG_USART_RX_GPIO_PORT GPIOA #define DEBUG_USART_RX_GPIO_CLK RCC_AHB1Periph_GPIOA #define DEBUG_USART_RX_PIN GPIO_Pin_10 #define DEBUG_USART_RX_AF GPIO_AF_USART1 #define DEBUG_USART_RX_SOURCE GPIO_PinSource10 #define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_CLK RCC_AHB1Periph_GPIOA #define DEBUG_USART_TX_PIN GPIO_Pin_9 #define DEBUG_USART_TX_AF GPIO_AF_USART1 #define DEBUG_USART_TX_SOURCE GPIO_PinSource9 #define RCC_AHB1Periph_DMAx RCC_AHB1Periph_DMA2 #define DMAx_Streamx DMA2_Stream7 #define DMA_ALL_IT_FLAG DMA_IT_FEIF7|DMA_IT_DMEIF7|DMA_IT_TEIF7|DMA_IT_HTIF7|DMA_IT_TCIF7 #define DMA_Channel_x DMA_Channel_4 #define DMAx_Streamx_IRQn DMA2_Stream7_IRQn #define DMAx_Streamx_IRQHandler DMA2_Stream7_IRQHandler #define DMA_IT_TCIFx DMA_IT_TCIF7 #endif #define __DEBUG //¿ªÆô´®¿Úµ÷ÊÔ #ifdef __DEBUG #define DEBUG(format,...) printf("File:"__FILE__",Line:%03d:"format"\n",__LINE__,##__VA_ARGS__) #else #define DEBUG(format,...) #endif void Debug_USART_Config(void); void USART_Tx_DMA_Init(uint8_t *buffer0, uint8_t*buffer1, uint32_t num); void USART_Rx_DMA_Init(uint8_t *buffer0, uint8_t*buffer1, uint32_t num); #endif /* __USART1_H */