打印
[STM32H5]

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

[复制链接]
375|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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)


使用特权

评论回复
评论
xu@xupt 2023-9-17 08:14 回复TA
学习啦~~~~~~~~~~ 
沙发
香水城| | 2023-9-17 16:30 | 只看该作者

使用特权

评论回复
板凳
Jacquetry| | 2023-9-17 21:24 | 只看该作者
为啥代码还有指定路径才行

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

31

帖子

3

粉丝