linux dma框架【2】-peripheral和dma request id的绑定

dma框架比较简单,网上关于dma框架的文章很多也很详细,这里就不在重复,这里只介绍一个知识点,就是当dma channel的原或目的是peripheral的时候,dma控制器如何知道参加传输的是哪个peripheral,我们基于linux-5.15.73版本介绍。

通过linux dma框架【1】的介绍,我们知道peripheral参与的dma传输需要一组handshaking信号,这其实就需要soc厂家在设计soc时为需要用到dma的peripheral设计一组handshaking信号,并且接入每个channel的一个mux中,每个外设的handshaking信号是否被选通是通过一个id来配置的,这就是dma的request id,每组handshaking对应的request id是多少是在soc设计时就确定好的。

我们以上面的dts节点为例,里面的dmas属性描述的就是这个pepherial使用的是dmac的第78,79号request id。

这个dmac对于的dts节点为

这其实就是通过dts来绑定pepherial和dma request id的方式,我们看看具体如何进行绑定的。

一、通过dts来绑定peripheral和dma request id的方式

1.client侧的channel request接

### STM32 使用 DMA 实现串口通信 #### 配置环境与工具链 为了简化开发流程并提高效率,建议使用STM32CubeMX作为初始配置工具。通过STM32CubeMX可以快速生成初始化代码框架,减少手动编写底层驱动的时间成本[^1]。 #### 初始化设置 在启动任何DMA传输之前,需先完成基本硬件参数设定: - 打开STM32CubeMX软件,创建新工程并选择目标MCU型号(如STM32H750或STM32F103)。 - 进入Pinout & Configuration界面,找到USART外设节点,将其工作模式调整为Asynchronous异步通讯模式。 - 对于UART接口的选择取决于实际应用场景;对于多端口转发需求,则可参照实例分别指定不同UART用于接收发送操作[^2]。 #### 编程要点解析 ##### UART/DMA关联配置 确保所选UART已正确绑定至相应的DMA流/通道上,并开启对应方向上的请求使能位。例如,在`stm32f1xx_hal_msp.c`文件内添加如下回调函数以完成低级资源分配: ```c void HAL_UART_MspInit(UART_HandleTypeDef* huart){ GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN USARTx_MspInit 0 */ if(huart->Instance==USART1 || huart->Instance==USART2){ /* Peripheral clock enable */ __HAL_RCC_USARTx_CLK_ENABLE(); /**USARTx GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX PA2 ------> USART2_TX PA3 ------> USART2_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; // or AF7 for USART2 on pins PA2,PA3 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Enable and configure the DMA channel associated with this UART instance. hdma_usart_rx.Instance = DMACHANNEL_INSTANCE; hdma_usart_rx.Init.Request = DMAREQUEST_SOURCE; hdma_usart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart_rx.Init.Mode = DMA_CIRCULAR; hdma_usart_rx.Init.Priority = DMA_PRIORITY_HIGH; HAL_DMA_Init(&hdma_usart_rx); __HAL_LINKDMA(huart, hdmarx, hdma_usart_rx); /* Configure NVIC for DMA transfer complete interrupt */ HAL_NVIC_SetPriority(DMACHANNEL_IRQN, PREEMPTION_PRIORITY, SUB_PRIORITY); HAL_NVIC_EnableIRQ(DMACHANNEL_IRQN); } } ``` 上述代码片段展示了如何针对特定UART设备初始化其对应的DMA控制器及其相关联的NVIC中断源。注意替换宏定义中的具体数值以便适配不同的芯片平台特性。 ##### 数据缓冲区管理策略 考虑到实时性能的要求以及可能存在的大数据量交换场景,采用循环缓冲结构能够有效提升系统的鲁棒性。当DMA完成一次完整的读取周期后触发ISR服务程序更新指针位置即可维持连续不断的I/O流转过程[^5]。 ```c uint8_t rx_buffer[RX_BUFFER_SIZE]; volatile uint16_t head=0,tail=0; // Inside main loop check available data length without blocking int get_available_data_length(){ int size=(head-tail)&(RX_BUFFER_SIZE-1); return (size<0)?(RX_BUFFER_SIZE+size):size; } // Non-blocking read function to fetch received bytes from circular buffer int non_blocking_read(uint8_t *data,int max_len){ int i,size=get_available_data_length(); if(!size)return 0; size=((max_len<size)?max_len:size); for(i=0;i<size;++i){ *(data+i)=rx_buffer[tail++]; tail&=(RX_BUFFER_SIZE-1); } return size; } ``` 此部分实现了非阻塞式的字符读取逻辑,允许应用程序层灵活控制数据获取时机而不必担心因等待而造成响应延迟问题。 #### 完整示例应用案例分析 结合前述理论知识点来看,下面给出一段综合性的测试脚本用来验证整个架构的有效性。这里假设我们正在构建一个简单的回声服务器——即接收到的信息会立即原样返回给客户端终端模拟器显示出来: ```c #include "main.h" UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; DMA_HandleTypeDef hdma_usart1_rx; DMA_HandleTypeDef hdma_usart2_tx; /* Private function prototypes -----------------------------------------------*/ static void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_USART1_UART_Init(void); static void MX_USART2_UART_Init(void); /** * @brief Main program. * @param None * @retval None */ int main(void){ /* Reset of all peripherals, Initializes the Flash interface and Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); // Set up as receiver only using DMA MX_USART2_UART_Init(); // Set up as transmitter only using DMA while (true) { static uint8_t tempBuffer[1]; // Temporary storage used during echo back operation. // Check whether there is any incoming message waiting inside RX buffer... if(non_blocking_read(tempBuffer,sizeof(tempBuffer))>0){ // Forward it directly through another port via DMA transmission mechanism... HAL_UART_Transmit_DMA(&huart2,tempBuffer,strlen((char*)tempBuffer)); }else{ // Otherwise just keep looping until new input arrives... continue; } } } ``` 这段代码体现了双向桥接的概念,其中一端负责监听外部输入并将捕获到的内容即时反馈回去形成闭环效应。值得注意的是,由于采用了DMA技术,CPU几乎不需要参与具体的搬移动作从而极大地减轻了核心负担。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值