当前位置: 首页 > news >正文

nuttx串口驱动框架设计

以STM32为例,来说明nuttx串口驱动框架设计:
先看通用串口驱动定义:

struct uart_buffer_s
{mutex_t          lock;   /* Used to control exclusive access to the buffer */volatile int16_t head;   /* Index to the head [IN] index in the buffer */volatile int16_t tail;   /* Index to the tail [OUT] index in the buffer */int16_t          size;   /* The allocated size of the buffer */FAR char        *buffer; /* Pointer to the allocated buffer memory */
};
struct uart_dev_s
{...struct uart_buffer_s recv; 
...
}

其中recv的的buffer初始化的时候,被初始化一块内存:

static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE];
static char g_usart1rxfifo[RXDMA_BUFFER_SIZE];
static struct up_dev_s g_usart1priv ={....recv        ={.size      = sizeof(g_usart1rxbuffer),.buffer    = g_usart1rxbuffer,},.rxfifo        = g_usart1rxfifo,...
}

接下里你是不是会想,如果芯片有DMA的话,把buffer内存给到DMA,如果没有DMA的话,每次读取寄存器复制到buffer中?
不好意思,不是。stm32的芯片驱动中又搞了一个FIFO,此FIFO是软件FIFO不是硬件FIFO,芯片是这么初始化的:

static int up_dma_setup(struct uart_dev_s *dev)
{
....rxdmacfg.paddr  = priv->usartbase + STM32_USART_RDR_OFFSET;rxdmacfg.maddr  = (uint32_t)priv->rxfifo;rxdmacfg.ndata  = RXDMA_BUFFER_SIZE;rxdmacfg.cfg1   = SERIAL_RXDMA_CONTROL_WORD;rxdmacfg.cfg2   = 0;stm32_dmasetup(priv->rxdma, &rxdmacfg);
.....
}

就是说把FIFO的地址给到了DMA,先接收到FIFO中

接收中断回调
static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
{...uart_recvchars(&priv->dev);...
}
void uart_recvchars(FAR uart_dev_t *dev)
{...while(底层有数据?){ch = uart_receive(dev, &status);dev->recv->buffer[索引++]=ch;注意这句话}...
}

其中uart_receive 是芯片驱动实现的:

static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status)
{...返回FIFO[索引++];...
}

看到这里大家就明白了,FIFO作为DMA接收内存,然后复制给buffer。那么buffer到时候还会复制到user buffer中,数据复制了两次。

我看了nuttx对于STM32的芯片驱动实现,用了IDLE+DMA空闲中断实现不定长数据,但是仍然存在FIFO ->BUFFER->UserBuffer的场景。此实现包括所有的STM32芯片。

其他芯片的实现没有用IDLE,比如AT32,GD32这种(这些芯片都带IDLE)。

read(...user buffer..)
{while(等待信号量或者有数据){memcpy user buffer,串口驱动buffer,长度;}
}

对的。就是这么实现的。几乎所有的nuttx的串口驱动都是这么实现。包括GD32,AT32,RISCV架构的芯片。

我认为一个良好的设计:

read(...user buffer...)
{if(查询buffer是否可以作为串口的DMA(userbuffer)==是的,可以){up_dma_set_up(user buffer);  如果这一步,不涉及复制}else{tempbuffer=串口alloc(len);up_dma_set_up(user buffer);memcpy userbuffer temp buffer len;拷贝一次}
}
串口alloc(len)
{当前可能有几块内存,某些内存可作为串口DMA。找一找,返回;
}
up_dma_set_up(buffer)
{将buffer给DMA
}串口中断()
{uart_recvchars_dma(...,接收到的数据长度)
}

http://www.lryc.cn/news/602481.html

相关文章:

  • HCIP笔记(第一、二章)
  • 设计模式(十六)行为型:解释器模式详解
  • 自定义View学习记录 plinko游戏View
  • 6、CentOS 9 安装 Docker
  • 状态反馈极点配置
  • 第三阶段—8天Python从入门到精通【itheima】-139节(pysqark实战-前言介绍)
  • mac电脑如何关闭防火墙
  • 本地大语言模型部署指南
  • 分布式渲染效能探析:关键网络性能要素
  • 前端基础之《Vue(25)—Vue3简介》
  • NSGA-II(Non-dominated Sorting Genetic Algorithm II) 算法求解 ZDT1 双目标优化问题
  • 【Java基础面试题】Java特点,八种基本数据类型
  • 【Zustand】从复杂到简洁:Zustand 状态管理简化实战指南
  • GTSuite许可证兼容性及要求
  • 【数据标注】详解使用 Labelimg 进行数据标注的 Conda 环境搭建与操作流程
  • 修改gitlab默认的语言
  • GitLab 18.2 发布几十项与 DevSecOps 有关的功能,可升级体验【四】
  • Java面试深度剖析:从JVM到云原生的技术演进
  • opencv学习(轮廓检测)
  • OpenCV(05)直方图均衡化,模板匹配,霍夫变换,图像亮度变换,形态学变换
  • UE5 UI自适应 DPI缩放
  • 【Spring WebFlux】 三、响应式流规范与实战
  • android-屏幕-刷新流程
  • 《深入剖析Kafka分布式消息队列架构奥秘》之Kafka基本知识介绍
  • MCU 中的 PWM(脉冲宽度调制)是什么?
  • uniapp 更新apk有缓存点不动,卸载安装apk没有问题。android
  • LeetCode 刷题【18. 四数之和】
  • R 语言科研绘图 --- 其他绘图-汇总1
  • 2025 DevOps工具生态全景解读:本土化服务与智能化演进成关键赛点
  • Centos 7 命令:ip addr