复旦微FM33LE0x单片机之串口DMA接收

news/2024/11/7 22:48:12/

一、简介

  本例程以FM33LE026为例,已经过验证,其他型号不保证适用。
  FM33LE0xx集成了多种不同类型的UART(LPUART),其差异如下表所示:

UART特性UART0/1UART2UART4/5LPUART0/1
DMA支持YYYY
半双工/全双工YYYY
红外发射YYY-
双时钟域(工作时钟独立于总线)YY-Y
休眠唤醒YYYY
接收超时YY--
发送延迟YY--
数据长度6、7、8、9bits6、7、8、9bits6、7、8、9bits6、7、8、9bits
LIN supportNYNN

  根据表格信息可知,FM33LE0xx不支持串口空闲中断,同时DMA中断只能通过溢出中断读取,看起来无法实现不定长数据接收。再回去仔细阅读手册,其中关于接收超时的描述如下:

  针对 MODBUS 等时间敏感型应用,设计了接超时机制。当使能 RXTOEN 寄存器后,超时计数器以波特率时钟计数,当每次收到一个完整的数据帧,将清零超时计数器并重新开始计数。超时溢出的上限值可以由软件配置,最大 255 波特。
  注: UART4 和 UART5 不支持接收超时功能。

  根据以上描述,通过串口的超时中断结合DMA搬运是否能够实现不定长数据接收,下面进行功能验证。

二、验证

  基于FL库,以UART0为例:

#define     UART0_BAUDRATE			115200
#define     UART0_DMA_MAX_LEN		128uint8_t uart0_dma_buf[UART0_DMA_MAX_LEN] = {0};static void uart0_gpio_init(void)
{FL_GPIO_InitTypeDef    GPIO_InitStruct;FL_UART_InitTypeDef    UART0_InitStruct;/* PA2 RXD, PA3 TXD */ GPIO_InitStruct.pin = FL_GPIO_PIN_2 | FL_GPIO_PIN_3;GPIO_InitStruct.mode = FL_GPIO_MODE_DIGITAL;GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;GPIO_InitStruct.pull = FL_DISABLE;GPIO_InitStruct.remapPin = FL_DISABLE;FL_GPIO_Init(GPIOA, &GPIO_InitStruct);UART0_InitStruct.clockSrc = FL_RCC_UART0_CLK_SOURCE_APB1CLK;UART0_InitStruct.baudRate = UART0_BAUDRATE;UART0_InitStruct.dataWidth = FL_UART_DATA_WIDTH_8B;UART0_InitStruct.stopBits = FL_UART_STOP_BIT_WIDTH_1B;UART0_InitStruct.parity = FL_UART_PARITY_NONE;UART0_InitStruct.transferDirection = FL_UART_DIRECTION_TX_RX;FL_UART_Init(UART0, &UART0_InitStruct);   
}static void uart0_dma_init(void)
{FL_DMA_InitTypeDef      DMAInitStruct;FL_DMA_ConfigTypeDef    DMA_ConfigStruct = {0};DMAInitStruct.periphAddress        = FL_DMA_PERIPHERAL_FUNCTION1;DMAInitStruct.direction            = FL_DMA_DIR_PERIPHERAL_TO_RAM;DMAInitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE;DMAInitStruct.flashAddressIncMode  = FL_DMA_CH7_FLASH_INC_MODE_INCREASE;DMAInitStruct.dataSize             = FL_DMA_BANDWIDTH_8B;DMAInitStruct.priority             = FL_DMA_PRIORITY_HIGH;DMAInitStruct.circMode             = FL_DISABLE;FL_DMA_Init(DMA, &DMAInitStruct, FL_DMA_CHANNEL_1);			// uart0_rx dma通道DMA_ConfigStruct.memoryAddress = (uint32_t)uart0_dma_buf;   // 映射dma缓存地址DMA_ConfigStruct.transmissionCount = UART0_DMA_MAX_LEN- 1; 	// dma搬运长度FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_1);FL_DMA_Enable(DMA);
}static void uart0_nvic_init(void)
{FL_NVIC_ConfigTypeDef   NVICConfigStruct;FL_UART_WriteRXTimeout(UART0, 30);          // 设置接收超时时长FL_UART_EnableRXTimeout(UART0);             // 使能接收超时NVICConfigStruct.preemptPriority = 2;FL_NVIC_Init(&NVICConfigStruct, UART0_IRQn);    // 开启uart0中断   FL_UART_ClearFlag_RXBuffTimeout(UART0);  	// 清接收超时中断FL_UART_EnableIT_RXTimeout(UART0);       	// 使能接收超时中断
}void uart0_init(void)
{uart0_gpio_init();uart0_dma_init();uart0_nvic_init();
}static void uart0_dma_deinit(void)
{FL_DMA_WriteMemoryAddress(DMA, (uint32_t)uart0_dma_buf, FL_DMA_CHANNEL_1);   // 重置dma缓存指针
}void UART0_IRQHandler(void)
{uint16_t len;/* 接收超时中断 */if((FL_ENABLE == FL_UART_IsEnabledIT_RXTimeout(UART0)) \&& (FL_SET == FL_UART_IsActiveFlag_RXBuffTimeout(UART0))){len = FL_DMA_ReadMemoryAddress(DMA, FL_DMA_CHANNEL_1) - (uint32_t)uart0_dma_buf;  // 计算dma长度// data push queue;memset(uart0_dma_buf, 0, UART0_DMA_MAX_LEN);/* restart dma */FL_DMA_DisableChannel(DMA, FL_DMA_CHANNEL_1);      uart0_dma_deinit();FL_DMA_EnableChannel(DMA, FL_DMA_CHANNEL_1);FL_UART_ClearFlag_RXBuffTimeout(UART0);   // clear it flag}
}

三、总结

  经过验证,通过串口超时中断结合DMA搬运可以实现串口不定长数据搬运。需要注意的是:

  1. DMA搬运映射缓存的长度定义需大于最长数据帧;
  2. 当传输的数据包含连续的0x00,则会误触发超时中断,无法使用此方式接收;
  3. 触发超时时间需小于数据帧间隔时间;
  4. 进入超时中断后只需将数据和接收长度一起入队即可;

  在实际测试中,UART0可以实现DMA搬运。而UART1在实测中其他中断向量不断置位,导致无法正常搬运,经分析可能是芯片bug或者外设对总线的异常操作引起,将在后续测试中继续验证


  20221207更新,之前UART1接收错误问题是由外部引起,因此,UART0/1均可实现DMA搬运。


http://www.ppmy.cn/news/601466.html

相关文章

SpringSecurity基础入门详解

【1】SpringSecurity是什么 Spring 是非常流行和成功的 Java 应用开发框架,Spring Security正是Spring家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。 正如你可能知道的关于安全方面的两个主要区域是“认…

延迟队列商业版RocketMQ和Pulsar的对比

目录 一、商业版RocketMQ和Pulsar的基本对比 二、核心差异 三、使用倾向 三、RocketMQ使用注意问题 一、商业版RocketMQ和Pulsar的基本对比 系统 实现原理 使用限制 成本 业务支持及使用 监控报警 容灾高可用 自动扩缩容(弹性) 鉴权 schema…

1.1.1 Qt信号槽之connect介绍(上)

关于Qt信号槽中connect与disconnect介绍 首先我们要知道,如果想要使用Qt中的信号槽机制, 那么必须继承QObject类,因为QObject类中包含了信号槽的一系列操作,今天我们来讲解的是信号与槽怎么建立连接以及断开连接。 一、connect …

Java正则表达式匹配方括号

Java代码: String s "[1,2,3][4,5,6]"; System.out.println(s.replaceAll("(\\[)","")); //匹配左方括号 System.out.println(s.replaceAll("(\\])","")); //匹配右方括号 System.out.println…

25匹马5个跑道,选出最快的5匹马?

回顾之前问题:25匹马5个跑道,怎样选出最快的3匹? 答:先分成5组比赛并组内排序(从1到5速度减慢),再让每组第一名比赛,按照每组第一名的比赛结果从快到慢对每组排序(从A到E…

100匹马驮100块石头

现在共有100 匹马和100石头,马分三种,大马,中马,小马.其中,每匹大马每次可以驮三块石头,中马可以驮两块石头,而小马两匹才能驮一块,问需要多少匹大马,中马和小马? // 用java来帮你计算// 先写一个main方法public static void main(String[] args) {//大马每次三块石头int a …

64匹马,8个赛道,找出跑得最快的4匹马

64匹马,8个赛道,找出跑得最快的4匹马,至少比赛几场? 第一步 全部马分为8组,每组8匹,每组各跑一次,然后淘汰掉每组的后四名,如下图(需要比赛8场) 第二步 …

MATLAB:单轴晶体的相位匹配角计算

MATLAB:单轴晶体的相位匹配角计算 对于相位匹配来说,计算相位匹配角是一个繁琐的过程。 以下是通过matlab来辅助计算单轴晶体的相位匹配角。 可以简单计算单轴晶体的一类相位匹配以及二类相位匹配。 懒得检查代码了,各位大神欢迎指出错误。 …