0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅析新塘031 串口PDMA通信

Q4MP_gh_c472c21 来源:嵌入式ARM 作者:呐咯密密 2021-07-06 17:16 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

环境搭建这里就跳过了,没啥用,我还是用KEIL 5 开发,自行下载个PACK包安装就好了。点此前往新塘官网。搜索自己的MCU型号,打开页面,在资源中有文档和软件。

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

从上到下依次是:官方例程库,Nu_link驱动,外设引脚配置软件,时钟配置软件。

外设引脚配置软件用于快速配置引脚以及复用,该软件只能配置引脚及其功能,不能配置外设等功能呢,例如串口的相关配置,这些事实现不了的。

时钟配置软件仅用于配置系统时钟以及各外设时钟。这两个软件支持导出.c代码。可复制粘贴到自己的工程。

这两个软件都是非常简单的,这里就不赘述了。

但是有一个时钟配置软件有BUG,以我用的M031SE3AE为例,外部时钟最大可使用32M,但是软件中最大只支持24M,希望官方可以修复。

开始代码

下载官方的例程,固件库代码在文件夹:D:M031_Series_BSP_CMSIS_V3.03.000SampleCodeStdDriver,寄存器代码在D:M031_Series_BSP_CMSIS_V3.03.000SampleCodeRegBased

这里采用固件库的方式开发,方便快捷。

时钟初始化:

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行修改宏定义。

be35f37e-d9a0-11eb-9e57-12bb97331649.png

在初始化时钟时会将需要的外设时钟一起初始化,这里初始化了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页面,发现中断函数并未被编译。

be81c966-d9a0-11eb-9e57-12bb97331649.png

尝试了很多方法都不能进行编译,后来去看UART1_IRQn的定义,发现这个宏定义下面还有一个UART13_IRQn。于是明白过来了,

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

beaff2be-d9a0-11eb-9e57-12bb97331649.png

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,好用!

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);}

END

本文为21ic论坛蓝V作者呐咯密密原创撰写

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    147

    文章

    19314

    浏览量

    405716
  • 函数
    +关注

    关注

    3

    文章

    4425

    浏览量

    68227
  • 代码
    +关注

    关注

    30

    文章

    4986

    浏览量

    74656
  • BUG
    BUG
    +关注

    关注

    0

    文章

    156

    浏览量

    16344
  • pack
    +关注

    关注

    14

    文章

    76

    浏览量

    10318

原文标题:缺货下,又换MCU了:新塘031 串口PDMA通信。

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    低功耗串口通信蓝牙模块

    屏蔽。开发者只需安装驱动,即可使用常规串口调试工具直接通信,即连即用,兼容现有串口应用程序,让三路“串口”之间快速实现双向传输。
    的头像 发表于 06-09 16:01 85次阅读

    工业串口通信利器:研华PCI系列通信卡深度剖析

    工业串口通信利器:研华PCI系列通信卡深度剖析 在工业自动化和数据通信领域,串口通信卡是实现设备
    的头像 发表于 05-13 10:40 285次阅读

    SN65LBC031、SN65LBC031Q、SN75LBC031高速CAN收发器详解

    SN65LBC031、SN65LBC031Q、SN75LBC031高速CAN收发器详解 在高速控制器局域网(CAN)的应用中,合适的收发器至关重要。今天我们就来详细探讨一下德州仪器(TI
    的头像 发表于 03-17 11:20 419次阅读

    请问CW32W031每次传输建议发送最大多少个字节?

    我看介绍,CW32W031(Sub-1G)空旷区域通信距离可以达到5km,主要实现小数据量、低功耗、复杂环境长距离通信。相比于NBIoT技术,Sub-1G节省了资讯费 那么,如果想使用CW32W
    发表于 12-10 07:09

    CW32W031射频芯片的AT指令都有哪些功能?

    我在网上看到一个,基于CW32W031射频芯片的AT指令无线串口模块,这个模块是官方开源的吗?有源码吗?还有这个AT指令都支持啥功能?
    发表于 12-05 07:27

    串口通信基石:Air8000下Modbus RTU串口初始化详解!

    串口初始化是Modbus RTU通信稳定可靠的关键起点。本篇深入剖析Air8000开发板串口参数配置、初始化代码实现及调试要点,结合master_rtu示例,分享实际操作中的经验与避坑指南,让您
    的头像 发表于 10-28 16:33 1894次阅读
    <b class='flag-5'>串口</b><b class='flag-5'>通信</b>基石:Air8000下Modbus RTU<b class='flag-5'>串口</b>初始化详解!

    基于FPGA开发板TSP的串口通信设计

    本文详细介绍基于Terasic FPGA开发板TSP(又名C5P和OSK)和其板载CP2102N USB-UART桥接芯片的串口通信系统设计与实现。系统采用Verilog HDL编写UART收发控制器,通过CP2102N实现FPGA与PC间的快速稳定
    的头像 发表于 10-15 11:05 5037次阅读
    基于FPGA开发板TSP的<b class='flag-5'>串口</b><b class='flag-5'>通信</b>设计

    串口通信有哪些方式

    串口通信(Serial Communication)是一种通过串行方式逐位传输数据的通信方式,广泛应用于嵌入式系统、工业控制、仪器仪表等领域。其通信方式可根据不同的分类标准划分为多种类
    的头像 发表于 09-28 18:02 1520次阅读

    什么是 PDMA 步幅模式?

    什么是 PDMA 步幅模式?如何使用它?
    发表于 08-21 06:56

    如何使用 M031 系列微控制器 (MCU) 的 PDMA 将 SPI 闪存中的图片数据移动到 TFT 显示器?

    使用 M031 系列微控制器 (MCU) 的 PDMA 将 SPI 闪存中的图片数据移动到 TFT 显示器
    发表于 08-19 08:08

    如何使用带有PDMA的M251 QSPI来模拟PWM输出信号?

    使用带有PDMA的M251 QSPI来模拟PWM输出信号
    发表于 08-19 07:00

    如何使用带有 PDMA 的 NUC1262 LLSI 来控制 ARGB Gen 1 LED 灯?

    使用带有 PDMA 的 NUC1262 LLSI 来控制 ARGB Gen 1 LED 灯
    发表于 08-19 06:26

    PLC串口自由协议通信概述

    串口自由协议通信是一种灵活的串行通信方式。在该模式下,开发者无需遵循特定标准协议,可根据实际需求自由定义数据格式与交互规则。
    的头像 发表于 08-07 09:15 2510次阅读
    PLC<b class='flag-5'>串口</b>自由协议<b class='flag-5'>通信</b>概述

    智嵌物联串口转光纤转换器-延长串口通信距离,增强抗干扰性能

    智嵌物联研发的串口光纤收发器是将RS-485/422/RS232接口信号转换为光纤接口传输,通信距离可达20Km,大大延长串口通信距离以及抗干扰性能。设备可自适应
    的头像 发表于 06-27 17:08 1018次阅读
    智嵌物联<b class='flag-5'>串口</b>转光纤转换器-延长<b class='flag-5'>串口</b><b class='flag-5'>通信</b>距离,增强抗干扰性能

    ESP32用作经典蓝牙串口透传模块与手机进行串口通信

    本文介绍了如何把ESP32用作一个蓝牙串口透传设备使用,其功能和常用的HC-05/06串口蓝牙设备一样。并与手机蓝牙串口APP进行双向蓝牙通信
    的头像 发表于 06-20 17:45 3661次阅读
    ESP32用作经典蓝牙<b class='flag-5'>串口</b>透传模块与手机进行<b class='flag-5'>串口</b><b class='flag-5'>通信</b>