发新帖我要提问
12
返回列表
打印
[应用相关]

一个严谨的STM32串口DMA发送&接收(1.5Mbps波特率)机制

[复制链接]
楼主: qcliu
手机看帖
扫描二维码
随时随地手机跟帖
21
qcliu|  楼主 | 2021-7-7 10:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
8 完整源码



串口&DMA底层配置:

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "stm32f0xx.h"
#include "bsp_uart.h"

/**
* @brief  
* @param  
* @retval
*/
static void bsp_uart1_gpio_init(void)
{
    GPIO_InitTypeDef    GPIO_InitStructure;
#if 0
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
       
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_0);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_0);
       
        GPIO_InitStructure.GPIO_Pin         = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode         = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed          = GPIO_Speed_Level_3;
    GPIO_InitStructure.GPIO_PuPd         = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
#else
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
       
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
       
        GPIO_InitStructure.GPIO_Pin         = GPIO_Pin_9 | GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode         = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed          = GPIO_Speed_Level_3;
    GPIO_InitStructure.GPIO_PuPd         = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
#endif
}


使用特权

评论回复
22
qcliu|  楼主 | 2021-7-7 10:24 | 只看该作者
/**
* @brief  
* @param  
* @retval
*/
static void bsp_uart2_gpio_init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
       
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_1);
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_1);
       
        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2 | GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
}


使用特权

评论回复
23
qcliu|  楼主 | 2021-7-7 10:25 | 只看该作者
/**
* @brief  
* @param  
* @retval
*/
void bsp_uart1_init(void)
{
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        bsp_uart1_gpio_init();
       
        /* 使能串口和DMA时钟 */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
       
        USART_InitStructure.USART_BaudRate            = 57600;
        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(USART1, &USART_InitStructure);
       
        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);        /* 使能空闲中断 */
        USART_OverrunDetectionConfig(USART1, USART_OVRDetection_Disable);
       
        USART_Cmd(USART1, ENABLE);
        USART_DMACmd(USART1, USART_DMAReq_Rx|USART_DMAReq_Tx, ENABLE); /* 使能DMA收发 */

        /* 串口中断 */
        NVIC_InitStructure.NVIC_IRQChannel         = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        /* DMA中断 */
          NVIC_InitStructure.NVIC_IRQChannel                    = DMA1_Channel2_3_IRQn;      
          NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;
          NVIC_Init(&NVIC_InitStructure);
}


使用特权

评论回复
24
qcliu|  楼主 | 2021-7-7 10:26 | 只看该作者
/**
* @brief  
* @param  
* @retval
*/
void bsp_uart2_init(void)
{
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        bsp_uart2_gpio_init();
       
        /* 使能串口和DMA时钟 */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

        USART_InitStructure.USART_BaudRate            = 57600;
        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(USART2, &USART_InitStructure);
       
        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);        /* 使能空闲中断 */
        USART_OverrunDetectionConfig(USART2, USART_OVRDetection_Disable);
       
        USART_Cmd(USART2, ENABLE);
        USART_DMACmd(USART2, USART_DMAReq_Rx|USART_DMAReq_Tx, ENABLE);         /* 使能DMA收发 */

        /* 串口中断 */
        NVIC_InitStructure.NVIC_IRQChannel         = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        /* DMA中断 */
        NVIC_InitStructure.NVIC_IRQChannel         = DMA1_Channel4_5_IRQn;      
          NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd      = ENABLE;
          NVIC_Init(&NVIC_InitStructure);
}


使用特权

评论回复
25
qcliu|  楼主 | 2021-7-7 10:27 | 只看该作者
void bsp_uart1_dmatx_config(uint8_t *mem_addr, uint32_t mem_size)
{
          DMA_InitTypeDef DMA_InitStructure;
       
        DMA_DeInit(DMA1_Channel2);
        DMA_Cmd(DMA1_Channel2, DISABLE);
        DMA_InitStructure.DMA_PeripheralBaseAddr         = (uint32_t)&(USART1->TDR);
        DMA_InitStructure.DMA_MemoryBaseAddr                 = (uint32_t)mem_addr;
        DMA_InitStructure.DMA_DIR                                         = DMA_DIR_PeripheralDST;         /* 传输方向:内存->外设 */
        DMA_InitStructure.DMA_BufferSize                         = mem_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_High;
        DMA_InitStructure.DMA_M2M                                         = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel2, &DMA_InitStructure);  
        DMA_ITConfig(DMA1_Channel2, DMA_IT_TC|DMA_IT_TE, ENABLE);
        DMA_ClearFlag(DMA1_IT_TC2);        /* 清除发送完成标识 */
        DMA_Cmd(DMA1_Channel2, ENABLE);
}


使用特权

评论回复
26
qcliu|  楼主 | 2021-7-7 10:27 | 只看该作者
void bsp_uart1_dmarx_config(uint8_t *mem_addr, uint32_t mem_size)
{
          DMA_InitTypeDef DMA_InitStructure;
       
        DMA_DeInit(DMA1_Channel3);
        DMA_Cmd(DMA1_Channel3, DISABLE);
        DMA_InitStructure.DMA_PeripheralBaseAddr         = (uint32_t)&(USART1->RDR);
        DMA_InitStructure.DMA_MemoryBaseAddr                 = (uint32_t)mem_addr;
        DMA_InitStructure.DMA_DIR                                         = DMA_DIR_PeripheralSRC;         /* 传输方向:外设->内存 */
        DMA_InitStructure.DMA_BufferSize                         = mem_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_VeryHigh;
        DMA_InitStructure.DMA_M2M                                         = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel3, &DMA_InitStructure);
        DMA_ITConfig(DMA1_Channel3, DMA_IT_TC|DMA_IT_HT|DMA_IT_TE, ENABLE);/* 使能DMA半满、全满、错误中断 */
        DMA_ClearFlag(DMA1_IT_TC3);
        DMA_ClearFlag(DMA1_IT_HT3);
        DMA_Cmd(DMA1_Channel3, ENABLE);
}


使用特权

评论回复
27
qcliu|  楼主 | 2021-7-7 10:28 | 只看该作者
uint16_t bsp_uart1_get_dmarx_buf_remain_size(void)
{
        return DMA_GetCurrDataCounter(DMA1_Channel3);        /* 获取DMA接收buf剩余空间 */
}

void bsp_uart2_dmatx_config(uint8_t *mem_addr, uint32_t mem_size)
{
          DMA_InitTypeDef DMA_InitStructure;
       
        DMA_DeInit(DMA1_Channel4);
        DMA_Cmd(DMA1_Channel4, DISABLE);
        DMA_InitStructure.DMA_PeripheralBaseAddr         = (uint32_t)&(USART2->TDR);
        DMA_InitStructure.DMA_MemoryBaseAddr                 = (uint32_t)mem_addr;
        DMA_InitStructure.DMA_DIR                                         = DMA_DIR_PeripheralDST;         /* 传输方向:内存->外设 */
        DMA_InitStructure.DMA_BufferSize                         = mem_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_High;
        DMA_InitStructure.DMA_M2M                                         = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel4, &DMA_InitStructure);  
        DMA_ITConfig(DMA1_Channel4, DMA_IT_TC|DMA_IT_TE, ENABLE);
        DMA_ClearFlag(DMA1_IT_TC4);        /* 清除发送完成标识 */
        DMA_Cmd(DMA1_Channel4, ENABLE);
}


使用特权

评论回复
28
qcliu|  楼主 | 2021-7-7 10:29 | 只看该作者
void bsp_uart2_dmarx_config(uint8_t *mem_addr, uint32_t mem_size)
{
          DMA_InitTypeDef DMA_InitStructure;
       
        DMA_DeInit(DMA1_Channel5);
        DMA_Cmd(DMA1_Channel5, DISABLE);
        DMA_InitStructure.DMA_PeripheralBaseAddr         = (uint32_t)&(USART2->RDR);
        DMA_InitStructure.DMA_MemoryBaseAddr                 = (uint32_t)mem_addr;
        DMA_InitStructure.DMA_DIR                                         = DMA_DIR_PeripheralSRC;         /* 传输方向:外设->内存 */
        DMA_InitStructure.DMA_BufferSize                         = mem_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_VeryHigh;
        DMA_InitStructure.DMA_M2M                                         = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel5, &DMA_InitStructure);
        DMA_ITConfig(DMA1_Channel5, DMA_IT_TC|DMA_IT_HT|DMA_IT_TE, ENABLE);/* 使能DMA半满、全满、错误中断 */
        DMA_ClearFlag(DMA1_IT_TC5);
        DMA_ClearFlag(DMA1_IT_HT5);
        DMA_Cmd(DMA1_Channel5, ENABLE);
}

uint16_t bsp_uart2_get_dmarx_buf_remain_size(void)
{
        return DMA_GetCurrDataCounter(DMA1_Channel5);        /* 获取DMA接收buf剩余空间 */
}


使用特权

评论回复
29
qcliu|  楼主 | 2021-7-7 10:31 | 只看该作者
压力测试:

  • 1.5Mbps波特率,串口助手每毫秒发送1k字节数据,stm32f0 DMA接收数据,再通过DMA发送回串口助手,毫无压力。
  • 1.5Mbps波特率,可传输大文件测试,将接收数据保存为文件,与源文件比较。
  • 串口高波特率测试需要USB转TLL工具及串口助手都支持才可行,推荐CP2102、FT232芯片的USB转TTL工具。




1.5Mbps串口回环压力测试


使用特权

评论回复
30
dql2015| | 2021-7-7 10:44 | 只看该作者
有测试的图吗

使用特权

评论回复
31
mingxie| | 2021-7-7 20:39 | 只看该作者
必须点赞!!!

使用特权

评论回复
32
xiaoqizi| | 2021-8-6 13:58 | 只看该作者
非常不错 的一种机制

使用特权

评论回复
33
wowu| | 2021-8-6 14:02 | 只看该作者
请问严谨在何处呢

使用特权

评论回复
34
wakayi| | 2021-8-6 14:06 | 只看该作者
每一步都有理有据啊

使用特权

评论回复
35
renzheshengui| | 2021-8-6 14:09 | 只看该作者
应用实在是很广泛了

使用特权

评论回复
36
qcliu|  楼主 | 2021-9-4 18:15 | 只看该作者
没有详细额测试图

使用特权

评论回复
37
ceiven| | 2021-9-6 02:35 | 只看该作者
非常感谢分享,请问能把完整工程发出来吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则