老规矩,发帖先吐槽!!!
从入职新公司后,一个项目我折腾了两年,看了一下自己的帖子,都是泪,每次以为开发完了,就会出事故,这次保守点,用新塘一定没问题,一定会成功量产,一定不要重新来过。这一个项目我从ST换到GD,中间穿插灵动微,GD断货后又开始寻找新的替代,一开始是盯到了瑞萨,这是上头给的方案,直接给我整吐了,瑞萨是真的难用啊,于是给我备选恩智浦的PLC系列,也是老大难。最后联系到今天的主角新塘。在上周选用了NUC029,下载资料,搭建环境,串口测试,SPI测试,然后突然发现这玩意没有DMA,白瞎了这么长时间啊,样板都做好了,结果出幺蛾子。然后在换M031,这次深思熟虑,认为不会有问题了才开搞。作为一个半成熟的程序猿,肯定不能helloword起手了,直接上UART吧。
事前BB,好用!
环境搭建这里就跳过了,没啥用,我还是用KEIL 5 开发,自行下载个PACK包安装就好了。点此前往新塘官网。搜索自己的MCU型号,打开页面,在资源中有文档和软件

在文档中下载数据手册等文档,在软件中下载例程和工具,软件中最实用的是以下几个软件:

从上到下依次是:官方例程库,Nu_link驱动,外设引脚配置软件,时钟配置软件。
外设引脚配置软件用于快速配置引脚以及复用,该软件只能配置引脚及其功能,不能配置外设等功能呢,例如串口的相关配置,这些事实现不了的。
时钟配置软件仅用于配置系统时钟以及各外设时钟。这两个软件支持导出.c代码。可复制粘贴到自己的工程。
这两个软件都是非常简单的,这里就不赘述了。
但是有一个时钟配置软件有BUG,以我用的M031SE3AE为例,外部时钟最大可使用32M,但是软件中最大只支持24M,希望官方可以修复。

开始代码
下载官方的例程,固件库代码在文件夹:D:\M031_Series_BSP_CMSIS_V3.03.000\SampleCode\StdDriver,寄存器代码在D:\M031_Series_BSP_CMSIS_V3.03.000\SampleCode\RegBased
这里采用固件库的方式开发,方便快捷。
时钟初始化:

void SYS_Init(void){/*---------------------------------------------------------------------------------------------------------*//* Init System Clock                                                                                       *//*---------------------------------------------------------------------------------------------------------*//* Unlock protected registers */SYS_UnlockReg();/* Enable HIRC clock (Internal RC 48MHz) */CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);/* Wait for HIRC clock ready */CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);/* Select HCLK clock source as HIRC and HCLK source divider as 1 */CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1));/* Set both PCLK0 and PCLK1 as HCLK */CLK->PCLKDIV = CLK_PCLKDIV_APB0DIV_DIV1 | CLK_PCLKDIV_APB1DIV_DIV1;/* Select IP clock source *//* Select UART0 clock source is HIRC */CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));/* Select UART1 clock source is HIRC */CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART1SEL_HIRC, CLK_CLKDIV0_UART1(1));/* Enable UART0 peripheral clock */CLK_EnableModuleClock(UART0_MODULE);/* Enable UART1 peripheral clock */CLK_EnableModuleClock(UART1_MODULE);/* Enable PDMA module clock */CLK_EnableModuleClock(PDMA_MODULE);/* Update System Core Clock *//* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */SystemCoreClockUpdate();/*---------------------------------------------------------------------------------------------------------*//* Init I/O Multi-function                                                                                 *//*---------------------------------------------------------------------------------------------------------*//* Set PB multi-function pins for UART0 RXD=PB.12 and TXD=PB.13 */SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk))    |       \(SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);/* Set PB multi-function pins for UART1 RXD(PB.2) and TXD(PB.3) */SYS->GPB_MFPL = (SYS->GPB_MFPL & ~(SYS_GPB_MFPL_PB2MFP_Msk | SYS_GPB_MFPL_PB3MFP_Msk))    |       \(SYS_GPB_MFPL_PB2MFP_UART1_RXD | SYS_GPB_MFPL_PB3MFP_UART1_TXD);/* Lock protected registers */SYS_LockReg();}

在初始化时钟之前需要确认自己的外部晶振的频率,然后在system_M031Series.h文件的第38行修改宏定义。

在初始化时钟时会将需要的外设时钟一起初始化,这里初始化了UART0和UART1的时钟以及PDMA的时钟。

初始化UART
由于时钟已经配置,在初始化UART的配置时会显得特别简单。如果你的UART没有特殊要求,两行代码即可完成UART的初始化。

void UART0_Init(){/*---------------------------------------------------------------------------------------------------------*//* Init UART                                                                                               *//*---------------------------------------------------------------------------------------------------------*//* Reset UART0 */SYS_ResetModule(UART0_RST);/* Configure UART0 and set UART0 baud rate */UART_Open(UART0, 115200);}void UART1_Init(){/*---------------------------------------------------------------------------------------------------------*//* Init UART                                                                                               *//*---------------------------------------------------------------------------------------------------------*//* Reset UART1 */SYS_ResetModule(UART1_RST);/* Configure UART1 and set UART1 Baudrate */UART_Open(UART1, 2500000);/* Enable Interrupt and install the call back function */NVIC_EnableIRQ(UART13_IRQn);UART_EnableInt(UART1, UART_INTEN_RDAIEN_Msk);}

串口0用于printf的调试。串口1 是我需要与其他串口设备通信的接口。除了我在串口1设置了串口接收中断以外,初始化一个串口仅仅需要两个函数,非常方便,这里使用的串口默认配置:一个停止位,无校验位,8位数据,如果需要修改可自行进入函数修改。
在配置串口1的接收中断时遇到了问题:调用NVIC_EnableIRQ()函数初始化中断线时,参数我填的是UART1_IRQn,无报错,编译可通过,但是测试没现象,于是进入debug页面,发现中断函数并未被编译。

尝试了很多方法都不能进行编译,后来去看UART1_IRQn的定义,发现这个宏定义下面还有一个UART13_IRQn。于是明白过来了,
UART0和UART2共用一个中断函数UART02_IRQHandler(),

UART1和3共用中断函数UART13_IRQHandler()
这里区别于其他家的库,不能用UART1_IRQn,需要用UART13_IRQn。

PDMA配置

void PDMA_UART_TxTest(void){/* UART Tx PDMA channel configuration *//* Set transfer width (8 bits) and transfer count */PDMA_SetTransferCnt(PDMA, UART_TX_DMA_CH, PDMA_WIDTH_8, UART_TEST_LENGTH);/* Set source/destination address and attributes */PDMA_SetTransferAddr(PDMA, UART_TX_DMA_CH, (uint32_t)SrcArray, PDMA_SAR_INC, (uint32_t)&UART1->DAT, PDMA_DAR_FIX);/* Set request source; set basic mode. */PDMA_SetTransferMode(PDMA, UART_TX_DMA_CH, PDMA_UART1_TX, FALSE, 0);/* Single request type */PDMA_SetBurstType(PDMA, UART_TX_DMA_CH, PDMA_REQ_SINGLE, 0);/* Disable table interrupt */PDMA_DisableInt(PDMA,UART_TX_DMA_CH, PDMA_INT_TEMPTY );}

这里有几个需要自行修改的地方,PDMA_SetTransferCnt(PDMA, UART_TX_DMA_CH, PDMA_WIDTH_8, UART_TEST_LENGTH);修改PDMA_WIDTH_8为修改数据宽度,这里默认8位,UART_TEST_LENGTH为发送长度,我这里设置为11个。PDMA_SetTransferAddr(PDMA, UART_TX_DMA_CH, (uint32_t)SrcArray, PDMA_SAR_INC, (uint32_t)&UART1->DAT, PDMA_DAR_FIX);  SrcArray为数组的地址。因为我是发送的DMA,这里配置为内存到外设,如果是接收DMA则做以下设置:    PDMA_SetTransferAddr(PDMA, UART_RX_DMA_CH, (uint32_t)&UART1->DAT, PDMA_SAR_FIX, (uint32_t)DestArray, PDMA_DAR_INC);
配置完后再主函数打开DMA:

 SYS_ResetModule(PDMA_RST);PDMA_Open(PDMA, (1 << UART_TX_DMA_CH));中断函数配置及启动DMA
void UART13_IRQHandler(void){uint8_t res;//        uint32_t u32IntSts = UART1->ISR;PB1 = 0;res = UART_READ(UART1);//读UART_DAT寄存器自动清除中断标志if(res == 0x1A){UART_DISABLE_INT(UART1, UART_INTEN_TXPDMAEN_Msk);PDMA_UART_TxTest();UART_ENABLE_INT(UART1, UART_INTEN_TXPDMAEN_Msk);while (PDMA->DSCT[UART_TX_DMA_CH].CTL & PDMA_DSCT_CTL_TXCNT_Msk) ;}PB1 = 1;}

在M031中,区别于我之前用过的其他MCU,在进入中断函数之后,只要读取串口接收寄存器UART_DAT中的值,便可自动清除中断标志,并不需要去操作其他寄存器。非常好用。
DMA的启动和其他的MCU类似,[size=14.6667px]需重新配置传输个数,[size=14.6667px]RAM[size=14.6667px]地址等,再调用一次初始化函数就行。然后利用[size=14.6667px]while (PDMA->DSCT[UART_TX_DMA_CH].CTL & PDMA_DSCT_CTL_TXCNT_Msk) ;判断数据是否发送完成,实际上就是等待传输个数计数器为0。
这里插一句PB1的作用,PBI就是gpio PB1口。初始化就一句话GPIO_SetMode(PB, BIT1, GPIO_MODE_OUTPUT);这里方便示波器观察时间。在使用库函数初始化PWM时,因为每一次的启动都要调用该函数,库函数的操作很费时间,在触发串口接收中断后将PB1拉低,发送完拉高,在示波器观察到从触发接收中断到第一个串口数据发送出去,也就是DMA启动完成,大约耗时8us,效率低下。于是我将DMA初始化改用寄存器的方式,时间缩小到2.8us,好用!!
---------------------
作者:呐咯密密
链接:https://bbs.21ic.com/icview-3143228-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

void PDMA_UART_TxTest(void){/* UART Tx PDMA channel configuration */PDMA->DSCT[UART_TX_DMA_CH].CTL =(UART_TEST_LENGTH - 1) << PDMA_DSCT_CTL_TXCNT_Pos | /* Transfer count */PDMA_WIDTH_8 |  /* Transfer width 8 bits */PDMA_DAR_FIX  | /* Fixed destination address */PDMA_SAR_INC  | /* Increment source address */PDMA_DSCT_CTL_TBINTDIS_Msk  | /* Table interrupt disabled */PDMA_REQ_SINGLE  | /* Single request type */PDMA_OP_BASIC;     /* Basic mode */PDMA->DSCT[UART_TX_DMA_CH].SA = (uint32_t)SrcArray;     /* Source address */PDMA->DSCT[UART_TX_DMA_CH].DA = (uint32_t)&UART1->DAT;  /* Destination address *//* Request source selection */PDMA->REQSEL0_3 = (PDMA->REQSEL0_3 & (~PDMA_REQSEL0_3_REQSRC1_Msk)) | (PDMA_UART1_TX << PDMA_REQSEL0_3_REQSRC1_Pos);}

[应用方案]【又换MCU】越来越好用系列,新塘031 串口PDMA通信。相关推荐

  1. 【又换MCU】越来越好用系列,新塘031 SPI PDMA通信

    开篇废话 依旧是开篇的逼逼叨叨. 自从上周换了新塘的M031,现在对这个MCU真的喜欢,写代码巨舒适,简单快速就能上手.上周写了入门的UART的DMA,今天来搞一个SPI 的DMA通信,实用的外设,咱 ...

  2. 行泊一体方案「换道超车」,TOP10本土供应商领跑新赛道

    从2021年开始,行泊一体智能驾驶方案成为中国本土供应商「换道超车」的标签.从公开信息显示,有超过20家供应商已经对外发布行泊一体方案,部分企业已经开始进入前装量产阶段. 同时,基于域控制器架构的模式 ...

  3. PKE 汽车无钥匙门禁系统解决方案芯片方案-LF+UHF+MCU

    汽车钥匙经历了机械钥匙.遥控钥匙.PEPS(无钥匙进入/启动系统).数字钥匙(分为NFC/BLE/UWB 三种技术)四个阶段. 现在给大家介绍PEPS(无钥匙进入/启动系统)芯片方案,目前PKE 汽车 ...

  4. 方案解读:为什么要选择LPC55系列做电竞鼠标键盘

    电竞一词越来越热,农药.LOL.吃鸡不但在手游端大热无比,PC端也是热的发紫,电竞奥运会也指日可待. 随之而来的是电竞类的键盘.鼠标以及耳麦的热销.玩家拼手速的时代要求着键盘鼠标USB Report ...

  5. 重磅!兆易创新推出中国首款Cortex®-M7内核超高性能MCU GD32H737/757/759系列

    关注.星标公众号,精彩内容每日送达 来源:网络素材 中国北京(2023年5月11日)--业界领先的半导体器件供应商兆易创新GigaDevice (股票代码 603986) 今日宣布,正式推出中国首款基 ...

  6. 视频会议系统EasyRTC常见的几种架构方式及应用场景:MCU/SFU、视频会议、应急指挥、即时通信

    我们这里常说的RTC可以理解为WebRTC技术,因为WebRTC技术是目前使用最广泛的即时通信技术,虽然在早期我们提到WebRTC.提到视频通话就会想到P2P的方式,但实际的视频通话方式背后的逻辑有很 ...

  7. 树莓派ubuntu18.04server安装摄像头不成换ubuntu mate继续安装系列

    因为这个版本没有自带raspi-config,因此需要先安装 64位内核树莓派安装raspi-config 和 语言设置 在上面帖子中的raspi的版本换为新版本 http://archive.ras ...

  8. php扩容方案,PHP程序员玩转Linux系列-腾讯云硬盘扩容挂载

    网站搜盘子运行在腾讯云的服务器上,前几天忽然打不开了,我就登陆服务器去瞅一眼咋回事,看了下发现硬盘满了,现在就来记录一下怎么解决 查看硬盘空间大小 使用df命令查看硬盘的使用情况 , 参数是df -h ...

  9. 苹果6换屏多钱_iPhone12系列屏幕维修价格公布 苹果12换屏多少钱

    iPhone12系列屏幕维修价格公布.虽然iPhone12 全系都使用了超瓷晶面板,苹果公司称其"比任何智能手机玻璃都要坚韧",抗跌落损坏的能力是其四倍,但依然有碎屏的风险.苹果1 ...

最新文章

  1. Ubuntu 系统打不开图片提示Fatal error reading PNG image File: Not a PNG file
  2. 京东智能内容创作算法的演进与实践:基于关键词自动生成摘要
  3. Java常用四大线程池用法以及ThreadPoolExecutor详解
  4. 终端安全工具 gartner 排名
  5. 2021中青杯数学建模A题 汽车组装车间流水线物料配送问题
  6. Android 4.0 SDK下载安装
  7. figma设计_如何在Figma中构建设计入门套件(第二部分)
  8. AWS re:Invent 2018的5大公告
  9. Hibernate查询缓存如何工作
  10. Java中注解学习系列教程-1
  11. ContextLoader,ContextLoaderListener解读
  12. Ubuntu 下压缩软件的安装
  13. Javascript中try finally的细微差别
  14. 提高开发效率的 Eclipse 实用操作
  15. Linux 实现与宿主机共享文件夹 Centos7
  16. 英语学习/词典app行业top5简要分析
  17. cocos creator--DragonBones 骨骼动画入门
  18. 汇编语言--在屏幕上显示名字
  19. 难以置信!一篇文章就梳理清楚了 Python OpenCV 的知识体系
  20. Djano3.0使用-CBV使用实例

热门文章

  1. REDMINE/SVN安装、配置、集成和应用(二)
  2. 搜狗词库的批量下载#Python
  3. sumo添加车辆_SUMO仿真快速入门系列三:产生车辆移动模型
  4. ArcGIS Server发布GP
  5. 常用数据库连接URL地址大全
  6. PHP使用preg_split函数分割含换行和分号字符串
  7. Google啊,你伤不起啊伤不起
  8. bim出图软件,能够一键开洞的revit插件
  9. dota改高清分辨率mark
  10. 性能测试(Performance)