rt-thread 驱动篇(四)serialX 多架构适配

发布时间:2024-06-25  

前言

自笔者提出 serialX 串口驱动到今天近半年了,当初只在 STM32F4 NUC970 两个系列芯片上做过理论验证。一个是 ARM CM4 核心架构,一个是 ARM9。这两款芯片能完美实现笔者的需求。


经过这半年的实践考验,笔者还是相信 serialX 的实力的,最近这几天笔者尝试在 N32 AB32 RA6M4 上适配 serialX,下面就向各位汇报一下适配结果。

芯片 STM32F4 NUC970 N32 AB32 RA6M4 GD32F4
架构 CM4 ARM9 CM4 RISC-V CM33 CM4

N32G45

因为这个也是 CM4,和 STM32F4 相较而言,可能差别很小。让笔者感到欣慰的是用`DMA_GetFlagStatus(uart->dma_tx.dma_flag, uart->dma_tx.dma_module) == SET` 代替了 `uart->dmaTxing` 。这是一处小改进。

除此之外,没啥可说的了。


已实现的功能有:


轮询收发

中断收发(可阻塞可非阻塞)

DMA 收发(可阻塞可非阻塞)

AB32VG1

这个是 RISC-V 架构的 CPU。


从芯片手册我们可以看到,它的串口外设只有“接收一个字节完成”和“发送一个字节完成”两个中断。

在 serialX 的设计构想里,我们希望有个“发送寄存器空”中断。因为这样很容易启动一次中断,在中断里判断是否有数据需要发送,进而启动一次发送过程。

假如没有这个中断,我们必须通过先写一个字节引起一次“发送完成中断”,然后借助这次中断继续判断是否有数据需要发送。在数据所有数据发送完之前,我们还需要有个 flag 标识一下现在处于发送流程中。

因此,serialX 需要进行一些改动:

`_serial_int_tx` 函数


       // TODO: start tx

#if defined (RT_SERIAL_NO_TXEIT)

       if (serial->ops->is_int_txing != RT_NULL && serial->ops->is_int_txing(serial) == RT_FALSE) {

           ch = _serial_fifo_pop_data(tx_fifo);

           serial->ops->start_tx(serial, ch);

       }

#else

       serial->ops->start_tx(serial);

#endif

```

`struct rt_uart_ops`

```

#if defined (RT_SERIAL_NO_TXEIT)

   rt_bool_t (*is_int_txing)(struct rt_serial_device *serial);

   void (*start_tx)(struct rt_serial_device *serial, rt_uint8_t ch);

#else

   void (*start_tx)(struct rt_serial_device *serial);

#endif

因为这些改动,AB32VG1 的底层驱动写法也就不一样了,多了一个判断是否处于发送流程中的 api。start_tx stop_tx 也不仅仅是开关中断那么简单了,需要改变 intTxing 这个 flag 标识发送流程状态。


rt_bool_t ab32_int_txing(struct rt_serial_device *serial)

{

   struct ab32_uart *uart;


   RT_ASSERT(serial != RT_NULL);


   uart = rt_container_of(serial, struct ab32_uart, serial);


   return uart->intTxing;

}


static void ab32_start_tx(struct rt_serial_device *serial, rt_uint8_t ch)

{

   struct ab32_uart *uart;


   RT_ASSERT(serial != RT_NULL);


   uart = rt_container_of(serial, struct ab32_uart, serial);

   uart->intTxing = RT_TRUE;

   hal_uart_control(uart->handle.instance, UART_TXIT_ENABLE, HAL_ENABLE);

   hal_uart_write(uart->handle.instance, ch);

}


static void ab32_stop_tx(struct rt_serial_device *serial)

{

   struct ab32_uart *uart;


   RT_ASSERT(serial != RT_NULL);


   uart = rt_container_of(serial, struct ab32_uart, serial);

   hal_uart_control(uart->handle.instance, UART_TXIT_ENABLE, HAL_DISABLE);

   uart->intTxing = RT_FALSE;

}

为此,我们需要添加个新配置,components/drivers/Kconfig


           config RT_SERIAL_NO_TXEIT

               bool "No TX Empty interrupt"

               default n

               help

                   Useful only if the chip hasn't Transmit Register Empty interrupt

                   Such as: AB32 RA6M4

意思是说,当芯片没有“发送寄存器空中断”支持的时候,我们需要用 `intTxing` 代替实现控制发送过程。


另外,发送寄存器也没有空状态,`putc` 函数倒是可以判断发送完成标志,但是这样就不能在中断里调用 `putc` 了;不加发送完成判断,就不能在轮询发送中调用它。总之,轮询发送和中断发送不用用一样的 `putc` 函数了。


已实现的功能有:


中断收发(可阻塞可非阻塞)


RA6M4

RA6M4 是一款 CM33 核 ARM 芯片,本以为它比 CM4 高级可以很容易实现 CM4 上实现的操作。


但是,笔者也没有从手册中找到“发送寄存器空中断”。所以 RA6M4 和 AB32VG1 有一样的补救处理。

但是,笔者还发现另外一个问题,**如果是中断发送,每次写完 TDR 寄存器后,必须重新使能发送中断**。不这样做,就不会出现发送完成中断。


虽然如此,连续发送多个字节仍然会出现发送中断不触发(或丢失)的情况,导致发送功能完全瘫痪(这也是 `intTxing` 引入的隐患)。


已实现的功能有:


中断接收(可阻塞可非阻塞)

中断发送(未完),暂时可以用轮询发送代替

多说两句,RA6M4 的 SCI 好像可以启用 FIFO ,这样一来串口收发寄存器就是带 FIFO 的。遗憾的是笔者不会用啊,有会用的大佬可以尝试移植一下,用 FIFO 了就相当于用 DMA 了。


GD32F4

这个也可以做到和 STM32F4 一样的程度,DMA 没有发送标志,只能继续用 `dmaTxing` 。


已实现的功能有:


轮询收发

中断收发(可阻塞可非阻塞)

DMA收发(可阻塞可非阻塞)

注:只分配了 UART0 的 DMA 通道,如果其它的也需要开启 DMA 请自行修改 `struct gd32_uart uarts` 数组变量分配 DMA 通道。


注:还有一点,rt-studio 里下载的 GD32F4 firmware 库版本是很多年前的,现在已经改动过好几次了。笔者使用的 `gd32f4xx_usart.h` 版本是 “2020-09-30, V2.1.0, firmware for GD32F4xx” 。如有编译错误请升级 firmware 库。


结束语

关于 serialX 理论的部分,之前的文章已经说的够多了。这次是想在多种平台上用实践检验一下 serialX 理论的可行性。经过这几天的投入,最终多多少少有些收获,还是很欣慰的。


汇总一下,目前可以适配的芯片包括如下几类

1. 没有 DMA ,只有串口接收发送中断

2. 没有“发送寄存器空”状态或没有“发送寄存器空”中断

3. 带接收 IDLE 检测,带“发送寄存器空”中断

4. 带 DMA ,并且至少有 DMA 半传输中断和全传输中断

5. 串口外设自带收发 FIFO (可认为是 DMA ,但是比 DMA 使用更简单)


在此,特别感谢[嚜軒公告](https://club.rt-thread.org/u/7c37fff6229d1ccd)支援的开发板,最终完成了 serialX 在这些平台上的实现。


下期预告,我们来扒一扒 serialX 的缺陷,对,它的缺陷。准确的讲是在 RTOS 上引入的坑有哪些以及怎么避免。


附 [serialX](https://gitee.com/thewon/serialX) 仓库地址,感兴趣的可以下载最新版 serialX 源码。本文提到的几种芯片的驱动也都已提交。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>