STM32U5 – DMA for UART TX and RX
STMicroelectronics last STM32 release was with STM32U5 series, in Q4 2021. Product focus are extreme ultra-low-power features, enhanced security, integration, size and performance.
Its advanced integration and performance options are key driver for new innovative silicon IPs. Product integrates new and most advanced DMA block ever seen in any of STM32 lines.
Key new DMA features
- Linked List : Define next configuration after first has been completed
- Option to work in low-power modes
- Selectable buses for data and peripheral
- Automatic copy-paste of register description
- Dedicated AN5593 application note
With its disruptive structure, I have updated my well known Github post about implementing DMA and UART for RX use case – important when you do not know in advance number of bytes to receive and process.
New example is ready to demonstrate code & application setup and runs on NUCLEO-U575ZI-Q board. Follow the link below to access Github project.
View code on Github
Small code excerpt linked to DMA configuration. Github provides full example ready to build with STM32CubeIDE or CMake (w/ GCC compiler).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
/* * Configure GPDMA CH1 for USART TX operation in normal mode * * - Normal mode - no linked list operation * - Source address increase from memory * - Destination address no-increase to peripheral (USART TDR) * - Length set before channel enabled * - Source address set before TX operation * - Source uses PORT1 - fast port to access RAM through bus matrix * - Destination uses PORT0 - fast port for APB access bypassing bus matrix * * Have a look at AN5593 for GPDMA1 use case. * https://www.st.com/resource/en/application_note/an5593-how-to-use-the-gpdma-for-stm32u575585-microcontrollers-stmicroelectronics.pdf */ DMA_InitStruct.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; DMA_InitStruct.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST; DMA_InitStruct.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD; DMA_InitStruct.SrcBurstLength = 1; DMA_InitStruct.DestBurstLength = 1; DMA_InitStruct.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE; DMA_InitStruct.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE; DMA_InitStruct.SrcIncMode = LL_DMA_SRC_INCREMENT; DMA_InitStruct.DestIncMode = LL_DMA_DEST_FIXED; DMA_InitStruct.Priority = LL_DMA_LOW_PRIORITY_MID_WEIGHT; DMA_InitStruct.TriggerMode = LL_DMA_TRIGM_BLK_TRANSFER; DMA_InitStruct.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED; DMA_InitStruct.TriggerSelection = 0x00000000U; DMA_InitStruct.Request = LL_GPDMA1_REQUEST_USART1_TX; DMA_InitStruct.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER; DMA_InitStruct.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT1; DMA_InitStruct.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT0; DMA_InitStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT1; DMA_InitStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION; DMA_InitStruct.LinkedListBaseAddr = 0x00000000U; DMA_InitStruct.LinkedListAddrOffset = 0x00000000U; DMA_InitStruct.DestAddress = LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT); /* Default settings - updated prior start of transmission */ DMA_InitStruct.SrcAddress = 0x00000000U; DMA_InitStruct.BlkDataLength = 0x00000000U; LL_DMA_Init(GPDMA1, LL_DMA_CHANNEL_1, &DMA_InitStruct); /* Enable TC interrupt */ LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_1); /* GPDMA1 interrupt Init */ NVIC_SetPriority(GPDMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(GPDMA1_Channel1_IRQn); /* * Configure linked list structure for GPDMA CH0 - used for USART RX operation * * - Linked-List mode for circular operation * - Source address fixed (USART RXD) * - Destination address increased after every received byte * - Destination address set to start of raw buffer * - Length set to raw buffer size * - Destination uses PORT1 - fast port to access RAM through bus matrix * - Source uses PORT0 - fast port for APB access bypassing bus matrix * * Have a look at AN5593 for GPDMA1 use case. * https://www.st.com/resource/en/application_note/an5593-how-to-use-the-gpdma-for-stm32u575585-microcontrollers-stmicroelectronics.pdf */ NodeConfig.DestAllocatedPort = LL_DMA_DEST_ALLOCATED_PORT1; NodeConfig.DestHWordExchange = LL_DMA_DEST_HALFWORD_PRESERVE; NodeConfig.DestByteExchange = LL_DMA_DEST_BYTE_PRESERVE; NodeConfig.DestBurstLength = 1; NodeConfig.DestIncMode = LL_DMA_DEST_INCREMENT; NodeConfig.DestDataWidth = LL_DMA_DEST_DATAWIDTH_BYTE; NodeConfig.SrcAllocatedPort = LL_DMA_SRC_ALLOCATED_PORT0; NodeConfig.SrcByteExchange = LL_DMA_SRC_BYTE_PRESERVE; NodeConfig.DataAlignment = LL_DMA_DATA_ALIGN_ZEROPADD; NodeConfig.SrcBurstLength = 1; NodeConfig.SrcIncMode = LL_DMA_SRC_FIXED; NodeConfig.SrcDataWidth = LL_DMA_SRC_DATAWIDTH_BYTE; NodeConfig.TransferEventMode = LL_DMA_TCEM_BLK_TRANSFER; NodeConfig.TriggerPolarity = LL_DMA_TRIG_POLARITY_MASKED; NodeConfig.BlkHWRequest = LL_DMA_HWREQUEST_SINGLEBURST; NodeConfig.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; NodeConfig.Request = LL_GPDMA1_REQUEST_USART1_RX; NodeConfig.UpdateRegisters = (LL_DMA_UPDATE_CTR1 | LL_DMA_UPDATE_CTR2 | LL_DMA_UPDATE_CBR1 | LL_DMA_UPDATE_CSAR | LL_DMA_UPDATE_CDAR | LL_DMA_UPDATE_CTR3 | LL_DMA_UPDATE_CBR2 | LL_DMA_UPDATE_CLLR); NodeConfig.NodeType = LL_DMA_GPDMA_LINEAR_NODE; /* Additional settings */ NodeConfig.SrcAddress = LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_RECEIVE); NodeConfig.DestAddress = (uint32_t)usart_rx_dma_buffer; NodeConfig.BlkDataLength = ARRAY_LEN(usart_rx_dma_buffer); LL_DMA_CreateLinkNode(&NodeConfig, &Node_GPDMA1_Channel0); /* Connect node to next node = to itself to achieve circular mode with one configuration */ LL_DMA_ConnectLinkNode(&Node_GPDMA1_Channel0, LL_DMA_CLLR_OFFSET5, &Node_GPDMA1_Channel0, LL_DMA_CLLR_OFFSET5); /* * Set first linked list address to DMA channel * * Set link update mechanism - DMA fetches first configuration from first node * on the start of DMA operation */ LL_DMA_SetLinkedListBaseAddr(GPDMA1, LL_DMA_CHANNEL_0, (uint32_t)&Node_GPDMA1_Channel0); LL_DMA_ConfigLinkUpdate(GPDMA1, LL_DMA_CHANNEL_0, (LL_DMA_UPDATE_CTR1 | LL_DMA_UPDATE_CTR2 | LL_DMA_UPDATE_CBR1 | LL_DMA_UPDATE_CSAR | LL_DMA_UPDATE_CDAR | LL_DMA_UPDATE_CTR3 | LL_DMA_UPDATE_CBR2 | LL_DMA_UPDATE_CLLR), (uint32_t)&Node_GPDMA1_Channel0); /* Initialize linked list general setup for GPDMA CH0 - the way transfers are done */ DMA_InitLinkedListStruct.Priority = LL_DMA_LOW_PRIORITY_LOW_WEIGHT; DMA_InitLinkedListStruct.LinkStepMode = LL_DMA_LSM_FULL_EXECUTION; DMA_InitLinkedListStruct.LinkAllocatedPort = LL_DMA_LINK_ALLOCATED_PORT0; DMA_InitLinkedListStruct.TransferEventMode = LL_DMA_TCEM_LAST_LLITEM_TRANSFER; LL_DMA_List_Init(GPDMA1, LL_DMA_CHANNEL_0, &DMA_InitLinkedListStruct); /* Enable HT&TC interrupt */ LL_DMA_EnableIT_HT(GPDMA1, LL_DMA_CHANNEL_0); LL_DMA_EnableIT_TC(GPDMA1, LL_DMA_CHANNEL_0); /* Enable DMA interrupts */ NVIC_SetPriority(GPDMA1_Channel0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(GPDMA1_Channel0_IRQn); /* Enable USART interrupts */ NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(USART1_IRQn); |
Recent comments