你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L4使用DMA发送串口数据

[复制链接]
STMCU小助手 发布时间:2022-8-27 15:00
一、CubeMX的配置
依次点击Configuration->DMA即可进入DMA口详细配置界面。
20200104190918651.png

点击【Add】添加DMA传输请求,然后选择USART1_TX请求;

20200104191228913.png

其他设置如下即可

20200104191837475.png

然后依旧是工程设置里,将HAL改成HAL

20200104192127235.png

然后便可以生成代码

20200104192752796.png

二、用户代码修改
代码生成后打开工程,我们可以看到,在static void MX_USART1_UART_Init(void)函数中多了这些和USART_TX的DMA相关配置代码

20200104204929943.png

然后我们将其复制,在usart.c文件中添加static void USART1_DMA_Init(void)函数并粘贴,另外将static void MX_DMA_Init(void) 函数中的DMA时钟使能代码复制到USART1_DMA_Init()函数头部;

20200104205147660.png

另外添加外设和内存地址设置函数到USART1_DMA_Init()函数中,得到

  1. //USART1_TX DMA Init
  2. static void USART1_DMA_Init(void)
  3. {
  4.         //使能DMA1时钟
  5.         LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
  6.         //DMA1通道4选择为USART1_TX请求
  7.         LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_4, LL_DMA_REQUEST_2);
  8.         //数据传输方向为存储器到外设
  9.         LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
  10.         //通道优先级
  11.         LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PRIORITY_LOW);
  12.         //不执行循环操作
  13.         LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MODE_NORMAL);
  14.         //不执行外设地址增量操作
  15.         LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PERIPH_NOINCREMENT);
  16.         //执行存储器地址增量操作
  17.         LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MEMORY_INCREMENT);
  18.         //外设数据宽度
  19.         LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_PDATAALIGN_BYTE);
  20.         //存储器数据宽度
  21.         LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE);
  22.         //DMA内存基地址
  23.         LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4,(u32)USART1_TX_BUF);
  24.         //DMA外设基地址
  25.         LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4,(u32)&USART1->TDR);
  26. }
复制代码

然后将其添加到uart_init()函数中,并添加串口1的DMA发送使能函数,如下图

20200104205905455.png

可见,我们需要声明USART1_DMA_EN,我们在usart.c头部添加一下代码:

20200104210135397.png

然后重写一个串口1打印函数:

  1. //串口1,printf 函数
  2. //确保一次发送数据不超过USART1_TX_LEN字节
  3. void u1_printf(char* fmt,...)  
  4. {  
  5.         static u8 first = 1;
  6.         u16 i;
  7.         va_list ap;
  8.         va_start(ap,fmt);
  9.         
  10.         if(first == 0)
  11.                 while(LL_DMA_IsActiveFlag_TC4(DMA1) == RESET);        //等待通道4传输完成
  12.         else
  13.                 first = 0;
  14.         
  15.         vsprintf((char*)USART1_TX_BUF,fmt,ap);
  16.         va_end(ap);
  17.         USART1_TX_BUF[USART1_TX_LEN-1] = '\0';
  18.         i=strlen((const char*)USART1_TX_BUF);                //此次发送数据的长度

  19.         LL_DMA_ClearFlag_TC4(DMA1);        //清除通道4传输完成标志
  20.         LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_4 );  //关闭USART1 TX DMA1 所指示的通道      
  21.          LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_4,i);        //DMA通道的DMA缓存的大小
  22.          LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);  //使能USART1 TX DMA1 所指示的通道
  23. }
复制代码

然后将主函数中的printf()换成u1_printf()

20200104210603837.png

编译下载到小熊派开发板,通过串口调试助手可以看到

20200104211654519.png

三、代码的优化修改

在stm32l4xx_ll_dma.c文件中我发现了LL_DMA_DeInit()和LL_DMA_Init()两个函数,和标识外设库的及其相似,所以我想着使用这两个函数重写USART1_DMA_Init()函数,重写后如下

  1. //USART1_TX DMA Init
  2. static void USART1_DMA_Init(void)
  3. {
  4.         LL_DMA_InitTypeDef DMA_InitStructure;
  5.                                                 
  6.         LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);        //使能DMA1时钟
  7.         LL_DMA_DeInit(DMA1,LL_DMA_CHANNEL_4);//将DMA1的通道4寄存器重设为缺省值
  8.         
  9.         DMA_InitStructure.PeriphRequest=LL_DMA_REQUEST_2;        //选择为USART1_TX请求
  10.         DMA_InitStructure.Priority=LL_DMA_PRIORITY_LOW;                //通道优先级
  11.         DMA_InitStructure.Direction=LL_DMA_DIRECTION_MEMORY_TO_PERIPH;//数据传输方向为存储器到外设
  12.         DMA_InitStructure.MemoryOrM2MDstAddress=(u32)USART1_TX_BUF;                //DMA内存基地址
  13.         DMA_InitStructure.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_BYTE;//存储器数据宽度
  14.         DMA_InitStructure.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;//执行存储器地址增量操作
  15.         DMA_InitStructure.Mode=LL_DMA_MODE_NORMAL;        //正常模式,不执行循环操作
  16.         DMA_InitStructure.NbData=USART1_TX_LEN;                //数据传输量
  17.         DMA_InitStructure.PeriphOrM2MSrcAddress=(u32)&USART1->TDR;                        //DMA外设基地址
  18.         DMA_InitStructure.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_BYTE;        //外设数据宽度
  19.         DMA_InitStructure.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;        //不执行外设地址增量操作
  20.         LL_DMA_Init(DMA1, LL_DMA_CHANNEL_4,&DMA_InitStructure);
  21. }
复制代码

是不是有一种莫名的熟悉感。
同样,串口助手验证成功

20200104215241547.png

四、源码下载
————————————————
转载:Willliam_william


收藏 评论0 发布时间:2022-8-27 15:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版