[STM32H5]【NUCLEO- H563ZI 测评】GPDMA的 linked-list 功能

1、STM32H563的GPDMA有个 linked-list功能可以将地址不连续或者长度不一样的的多个数组按照顺序发送出去,同样也可以接收数据到不同地址和大小的数组里面。
和普通的DMA相比, DMA linked-list就是把几个不同的配置的DMA参数像链表一样串联在一起,这样就可以将所有配置的数据发送出去。

 



2、下面的测试使用STM32H563的DMA linked-list 配合USART3发送多个数组到stlink 的VCP ,这样我们就能在PC上验证发送是否成功。因为开发板上USART3和stlink的VCP的传输已经做好了,所有代码里面就不需要这部分处理,只需要注意USART3的波特率和PC上stlink vcp的波特率保持一致。

首先我们定义一个Linked-List Queue 的结构体,将要传输的几个数组通过DMA的配置进行初始化。

复制
DMA_QListTypeDef UART_Tx_Queue;



HAL_StatusTypeDef MX_UART_Tx_Queue_Config(void)

{

  HAL_StatusTypeDef ret = HAL_OK;

  /* DMA node configuration declaration */

  DMA_NodeConfTypeDef pNodeConfig;



  /* Set node configuration ################################################*/

  pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;

  pNodeConfig.Init.Request = GPDMA1_REQUEST_USART3_TX;

  pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;

  pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;

  pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;

  pNodeConfig.Init.DestInc = DMA_DINC_FIXED;

  pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;

  pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;

  pNodeConfig.Init.SrcBurstLength = 1;

  pNodeConfig.Init.DestBurstLength = 1;

  pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;

  pNodeConfig.Init.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;

  pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;

  pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;

  pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;

  pNodeConfig.SrcAddress = 0;

  pNodeConfig.DstAddress = 0;

  pNodeConfig.DataSize = 0;



  /* Build Node1_tx Node */

  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &Node1_tx);



  /* Insert Node1_tx to Queue */

  ret |= HAL_DMAEx_List_InsertNode_Tail(&UART_Tx_Queue, &Node1_tx);



  /* Set node configuration ################################################*/

  pNodeConfig.SrcAddress = (uint32_t) aTxBuffer1;

  pNodeConfig.DstAddress = (uint32_t) &huart3.Instance->TDR;

  pNodeConfig.DataSize = 32;



  /* Build Node2_tx Node */

  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &Node2_tx);



  /* Insert Node2_tx to Queue */

  ret |= HAL_DMAEx_List_InsertNode_Tail(&UART_Tx_Queue, &Node2_tx);



  /* Set node configuration ################################################*/

  pNodeConfig.SrcAddress = (uint32_t) aTxBuffer2;

  pNodeConfig.DataSize = 64;



  /* Build Node3_tx Node */

  ret |= HAL_DMAEx_List_BuildNode(&pNodeConfig, &Node3_tx);



  /* Insert Node3_tx to Queue */

  ret |= HAL_DMAEx_List_InsertNode_Tail(&UART_Tx_Queue, &Node3_tx);



   return ret;

}

上面的这个初始化将各个数组作为一个节点Linked到UART_Tx_Queue上,需要注意,Node1_tx 的发送参数都初始化为了空,Node2_tx和Node3_tx进行了要发送的长度和缓存地址初始化。
至于Node1_tx 的配置会在启动DMA传输的时候进行配置,具体就是HAL_UART_Transmit_DMA(&huart3, (uint8_t*)aTxBuffer0, TXBUFFERSIZE)这个函数,初始化的地方在下面

复制
      /* Check linked list mode */

      if ((huart->hdmatx->Mode & DMA_LINKEDLIST) == DMA_LINKEDLIST)

      {

        if ((huart->hdmatx->LinkedListQueue != NULL) && (huart->hdmatx->LinkedListQueue->Head != NULL))

        {

          /* Set DMA data size */

          huart->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CBR1_DEFAULT_OFFSET] = nbByte;



          /* Set DMA source address */

          huart->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CSAR_DEFAULT_OFFSET] = (uint32_t)huart->pTxBuffPtr;



          /* Set DMA destination address */

          huart->hdmatx->LinkedListQueue->Head->LinkRegisters[NODE_CDAR_DEFAULT_OFFSET] =

            (uint32_t)&huart->Instance->TDR;



          /* Enable the UART transmit DMA channel */

          status = HAL_DMAEx_List_Start_IT(huart->hdmatx);

        }

        else

        {

          /* Update status */

          status = HAL_ERROR;

        }

      }

将初始化好的 UART_Tx_Queue link 到 DMA的通道上,然后再和USART3 的发送DMA相关联

复制
/* Link UART queue to DMA channel */

  HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &UART_Tx_Queue);



  /* Associate the initialized GPDMA handle to the UART handle */

  __HAL_LINKDMA(&huart3, hdmatx, handle_GPDMA1_Channel0);

DMA要发送的是3个数组如下:分别定义的3个独立的数组

复制
ALIGN_32BYTES (uint8_t aTxBuffer0[]) = "0**********UART communication based on DMA Linkedlist*********0\n";

ALIGN_32BYTES (uint8_t aTxBuffer1[]) = "1*****UART communication*******1\n";

ALIGN_32BYTES (uint8_t aTxBuffer2[]) = "2**********UART communication based on DMA Linkedlist*********2\n";

通过这样的配置之后,使用HAL_UART_Transmit_DMA() 就可以触发一次数据发送了。
下面是stlink VCP 收到的一次DMA发送的数据,可以看到3个数组都成功发送了。


 


测试代码如下,需要注意要把代码解压到STM32Cube_FW_H5_V1.1.0\Projects\NUCLEO-H563ZI\Examples\UART路径下面
 

 UART_ComDMAlinkedlist.rar (7.73 MB)。
---------------------
作者:OldestTrick
链接:https://bbs.21ic.com/icview-3322878-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

### 使用 STM32CubeMX 配置 GPDMA #### 初始化项目设置 为了配置GPDMA,在启动STM32CubeMX之后,选择目标设备并创建新工程。确保选择了支持GPDMA特性的MCU型号,比如STM32U5系列。 #### 启用DMA外设 进入Pinout & Configuration界面,找到General-purpose DMA (GPDMA),点击开启此模块。这一步骤激活了DMA控制器以便后续操作[^1]。 #### 设置Burst模式参数 对于希望利用burst传输特性的场景,可以在Advanced Settings选项卡下的对应通道中调整Transfer Request、Data Width以及Burst Size等参数。这些设定允许开发者指定每次传输的数据量大小及其触发条件[^2]。 #### 编程模型的选择 考虑到某些情况下可能面临不兼容问题——例如特定版本的STM32CubeMX或许未能完全适配最新的处理器架构或是第三方中间件库缺失——建议查阅官方文档获取最新指导和支持信息[^3]。 #### 实现PWM波形输出案例 当涉及到更复杂的任务如通过定时器中断驱动DMA完成周期性数据更新时,则可以考虑采用Linked List模式配合二维地址映射技术实现高效能PWM信号生成方案[^4]。 ```c // 示例代码片段展示如何初始化DMA用于PWM输出 void MX_DMA_Init(void) { /* Init with LL driver */ // ...省略其他无关初始化... /* Configure the DMA handler for Transmission process */ hdma_tim->Init.Mode = DMA_NORMAL; hdma_tim->InitPeriphInc = DMA_PINC_DISABLE; hdma_tim->MemInc = DMA_MINC_ENABLE; hdma_tim->PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_tim->MemoryDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_tim->Mode = DMA_CIRCULAR; // 循环模式适合于持续发送相同缓冲区内容的应用场合 hdma_tim->Priority = DMA_PRIORITY_HIGH; if (HAL_DMA_Init(hdma_tim) != HAL_OK) { Error_Handler(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值