TI RM57 如何使用DMA进行串口接收

文章介绍了在RM57处理器上,为满足2ms内传输32个字节的串口通信需求,如何使用DMA代替中断接收以降低对系统资源的影响。作者详细记录了配置串口DMA的过程,包括使能串口DMA请求、初始化DMA通道、设置传输参数等,解释了DMA传输的关键概念如端口、通道、触发信号和数据组织形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

尊重原创,转载请署名来源谢谢!

引言

最近项目中需要用到串口对传感器数据采集,需求上要求在2ms完成32个字节的传输,前后测试发现算上传感器的响应时间,RM57要使用高达420000波特率进行传输才能勉强满足上述要求,而如果使用中断接收串口数据,就会及其频繁的触发串口中断,这将影响到其他正常的运算。为了解决这个问题,这里提出了DMA的方式进行串口数据接收的方案。

相比较中断触发方式进行串口处理,DMA并不支持通过HalCoGen配置生成相关代码,所以如果想要用起来DMA,就要仔细阅读芯片手册,这个过程很煎熬,并不是说个人英文水平如何,而是TI关于DMA的描述非常碎片化,而且没有一个全局的描述去帮助使用者去理解如何正确使用串口DMA功能。既然如此,这里做一个详细的记录就显得十分有价值了。

目录

引言

代码实现

理解DMA传输以及串口DMA传输如何实现


代码实现

#include <HL_sci.h>
#include <HL_sys_dma.h>
#include <string.h>

uint8 recv_queue_buf[24];

void sciEnableRxDmaRequest()
{
    sciREG1->SETINT &= ~(uint32)((uint32)1U << 9U);  /*rx dma*/
    sciREG1->SETINT |= (uint32)((uint32)1U << 17U);  /*rx dma*/
    sciREG1->SETINT |= (uint32)((uint32)1U << 18U);  /*rx dma*/
}


void scidmaInit(){
    sciInit();
    dmaReset();
    dmaEnable();
    sciEnableRxDmaRequest();
    g_dmaCTRL ch_ctrl_pkt ;
    ch_ctrl_pkt.SADD = (uint32)&sciREG1->RD;
    ch_ctrl_pkt.DADD = (uint32)&recv_queue_buf[0];
    ch_ctrl_pkt.CHCTRL = 0; /*no need trig next channel*/
    ch_ctrl_pkt.FRCNT = 24U; /*24 frames in block*/
    ch_ctrl_pkt.ELCNT = 1U;  /*1 elements in frame*/
    ch_ctrl_pkt.ELDOFFSET = 0U;
    ch_ctrl_pkt.ELSOFFSET = 0U;
    ch_ctrl_pkt.FRDOFFSET = 0U;
    ch_ctrl_pkt.FRSOFFSET = 0U;
    ch_ctrl_pkt.PORTASGN = (uint32)PORTB_READ_PORTA_WRITE;
    ch_ctrl_pkt.RDSIZE = (uint32)ACCESS_8_BIT;
    ch_ctrl_pkt.WRSIZE = (uint32)ACCESS_8_BIT;
    ch_ctrl_pkt.TTYPE = (uint32)FRAME_TRANSFER;
    ch_ctrl_pkt.ADDMODERD = (uint32)ADDR_FIXED;
    ch_ctrl_pkt.ADDMODEWR = (uint32)ADDR_INC1;
    ch_ctrl_pkt.AUTOINIT = (uint32)AUTOINIT_OFF;
    dmaSetCtrlPacket(DMA_CH3, ch_ctrl_pkt);
    dmaReqAssign(DMA_CH3, DMA_REQ28); /*sci1/lin1 dma request 28*/
    dmaSetChEnable(DMA_CH3, DMA_HW);
    dmaSetPriority(DMA_CH3, HIGHPRIORITY);
}

void resetReceiveBuffer() {
    dmaReset();
    dmaEnable();
    dmaReqAssign(DMA_CH3, DMA_REQ28); /*sci1/lin1 dma request 28*/
    dmaSetPriority(DMA_CH3, HIGHPRIORITY);
    dmaSetChEnable(DMA_CH3, DMA_HW);
    memset(&recv_queue_buf[0], 0, sizeof(recv_queue_buf));
}

void handleReceivedSciBytes() {
    if (dmaGetInterruptStatus(DMA_CH3, BTC)){ /*all byte receive finished*/
        //read and handle recv_queue_buf[]
    }
    else{
        LOCAL_LOG_WARNING("recieve bytes not finished");
    }
}

/*this function called every 2ms*/
void procHandler(){
    handleReceivedSciBytes();
    resetReceiveBuffer();
}

理解DMA传输以及串口DMA传输如何实现

示例代码中串口DMA传输的完整路径是这样的:

  1.  初始化并使能串口1,复位并使能DMA模块
  2. 从DMA的32个传输通道中选用CH3作为串口接收使用;
  3. 配置CH3读取源地址为串口1接收数据寄存器地址
  4. 配置CH3写入目标地址为接收缓冲区地址
  5. 配置CH3每次DMA传输1个字节,即Element尺寸为8bits、Frame尺寸为1Element、每次传输1Frame
  6. 配置CH3传输完成所需字节数为24字节,即Block尺寸为24个Frame
  7. 配置CH3的DMA请求信号为串口1(请求ID28)
  8. 配置CH3读端口为PORTB、写端口为PORTA
  9. 打开CH3硬件使能开关
  10. 打开串口1DMA接收中断
  11. 串口完成1个字节接收后,将触发DMA请求信号,DMACH3接收到该请求,执行一次Frame传输即从串口接收寄存器读取1字节数据并写入到应用程序的接收缓冲区中,然后将写指针地址加1;
  12. 完成24次DMA传输后,DMACH3完成1次Block传输,DMACH3的Block传输完成标志位置1,同时DMACH3自动关闭使能。
  13. 应用程序通过再次使能DMACHA3硬件使能开关,开启一次新的DMA传输。

理解RM57的DMA传输有以下几个关键概念:端口、通道、触发信号和数据组织形式。

端口PORT:RM57有2个端口,分别为PORTA和PORTB,用于访问不同地址。需要明确的是二者分工完全不同,不可以混用。PORTA用于读写Flash、内部和外部RAM;PORTB用于包括串口在内的各种外设地址空间。关于端口的映射关系可以参考手册SPNU562(page 678)。基于这种限制,我们在配置串口接收DMA的时候就要选用PORTB作为串口接收数据寄存器的访问端口,PORTA作为应用程序串口数据缓冲区的访问端口。

通道CHANNEL:DMA传输操作是通过通道实现的,RM57支持32个通道,每个通道定义了其DMA传输从哪里读取数据、读取的数据向哪里写入、读取后的指针如何变化、写入后的指针如何变化、每次触发请求的数据传输量、如何触发一次传输以及读取和写入的端口选择等信息。

触发请求REQUEST:DMA支持3中触发方式,包括程序软触发、硬件触发和链式触发。其中软触发的方式为程序控制,通过写寄存器的方式手动触发1次dma传输,这种方式比较适合从一片内存拷贝数据到另一片内存;硬件触发方式为支持DMA的硬件外设,比如串口,在接收到数据后发起触发信号的触发方式,这种触发方式需要查询各个外设对应的触发信号ID,具体参考手册SPNS215C(page 122)。以串口1为例,其触发ID为28;最后的链式触发方式为某一通道触发后,会触发其关联的其他通道,具体可以通过通道配置寄存器设置。

数据组织形式:DMA传输的数据从逻辑上分为3层,从低到高分别为元素Element、帧Frame、块Block。其中元素的大小可以配置成8、16、32、64位,每个帧包含若干个元素、每个块又由若干的帧组成。在前面的“通道CHANNEL”中描述的每次触发请求数据传输量,实际上就是通过配置每一次请求发出后,要传输一个帧还是一个块。以串口DMA传输为例,每次成功接收一个字节,将发起1次DMA请求,以一次完整通讯所需接收的数据量为8字节为例,合适的DMA数据组织形式应该为,ELEMENT大小:8bits;Frame尺寸:1 Elements;Block尺寸:8Frames;Channel每次请求传输Frame。具体可参考手册SPNU562(page 680)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值