Library 55- Extend USART with TX DMA
Here is a great feature for USART. I’ve made an extension library for USART (and for SPI will come soon) to use DMA for TX data using USART. This can be very handy to use if you have a lot of work and not so many time using your STM32F4 device.
I was thinking first about adding DMA RX functionality for USART too. But then I realize that my USART library by default uses RXNE (RX Not Empty) interrupt and that data is transfered to internal USART’s library buffers. Also, some additional logic and interrupt handlers would be required and this will make library very unefficient.
Library
Features
- Extension library for TM USART library
- Supports DMA TX functionality
- Works with any USART from USART1 to UART8
- Supports changeable stream and channel settings
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx DMA
- TM
- TM USART
- TM DMA
- defines.h
- TM USART
Stream and channel settings
STM32F4xx devices have 2 DMA controllers. Each DMA controller has 8Â DMA streams where each stream has 8 DMA channels for different peripherals available.
To get all available DMA peripherals, you should take a STM32F4xx Reference manual (1700+ pages) and take a look at DMA section. There are all available streams and channels for different peripheral.
This library uses only USART TX DMA. Default DMA streams and channels are in table below:
USART | DMA | DMA Stream | Â DMA Channel |
---|---|---|---|
USART1 | DMA2 | DMA Stream 7 | DMA Channel 4 |
USART2 | DMA1 | DMA Stream 6 | DMA Channel 4 |
USART3 | DMA1 | DMA Stream 3 | DMA Channel 4 |
UART4 | DMA1 | DMA Stream 4 | DMA Channel 4 |
UART5 | DMA1 | DMA Stream 7 | DMA Channel 4 |
USART6 | DMA2 | DMA Stream 6 | DMA Channel 5 |
UART7 | DMA1 | DMA Stream 1 | DMA Channel 5 |
UART8 | DMA1 | DMA Stream 0 | DMA Channel 5 |
Some USARTs allows different streams and channels. This can be handy if you have 2 peripherals on the same stream and DMA and you want to enable DMA for both. You can’t do that because only one channel on specific stream can be used at a time. For that purpose, someking of “remapping” was enabled which allows you to select custom Stream and Channel for specific USART if it is available. Always look for STM32F4xx Reference manual for that settings.
Functions
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 |
/** * @defgroup TM_USART_DMA_Functions * @brief Library Functions * @{ */ /** * @brief Initializes USART DMA TX functionality * @note USART HAVE TO be previously initialized using @ref TM_USART library * @param *USARTx: Pointer to USARTx where you want to enable DMA TX mode * @retval None */ void TM_USART_DMA_Init(USART_TypeDef* USARTx); /** * @brief Initializes USART DMA TX functionality with custom DMA stream and Channel options * @note USART HAVE TO be previously initialized using @ref TM_USART library * * @note Use this function only in case default Stream and Channel settings are not good for you * @param *USARTx: Pointer to USARTx where you want to enable DMA TX mode * @param *DMA_Stream: Pointer to DMAy_Streamx, where y is DMA (1 or 2) and x is Stream (0 to 7) * @param DMA_Channel: Select DMA channel for your USART in specific DMA Stream * @retval None */ void TM_USART_DMA_InitWithStreamAndChannel(USART_TypeDef* USARTx, DMA_Stream_TypeDef* DMA_Stream, uint32_t DMA_Channel); /** * @brief Deinitializes USART DMA TX functionality * @param *USARTx: Pointer to USARTx where you want to disable DMA TX mode * @retval None */ void TM_USART_DMA_Deinit(USART_TypeDef* USARTx); /** * @breif Enables interrupts for DMA for USART streams * @note USART DMA must be initialized first using @ref TM_USART_DMA_Init() or @ref TM_USART_DMA_InitWithStreamAndChannel() functions * @param *USARTx: Pointer to USARTx where DMA interrupts will be enabled * @retval None */ void TM_USART_DMA_EnableInterrupts(USART_TypeDef* USARTx); /** * @breif Disables interrupts for DMA for USART streams * @param *USARTx: Pointer to USARTx where DMA interrupts will be disabled * @retval None */ void TM_USART_DMA_DisableInterrupts(USART_TypeDef* USARTx); /** * @brief Gets poitner to DMA stream for desired USART * @param *USARTx: Pointer to USART where you wanna get its stream pointer * @retval Pointer to DMA stream for desired USART */ DMA_Stream_TypeDef* TM_USART_DMA_GetStream(USART_TypeDef* USARTx); /** * @brief Puts string to USART port with DMA * @note Try not to use local variables pointers for DMA memory as parameter *str * @param *USARTx: Pointer to USARTx peripheral you will use * @param *str: Pointer to string to send over USART with DMA * @retval Sending started status: * - 0: DMA has not started with sending data * - > 0: DMA has started with sending data */ uint8_t TM_USART_DMA_Puts(USART_TypeDef* USARTx, char* str); /** * @brief Sends data over USART with DMA TX functionality * @note Try not to use local variables pointers for DMA memory as parameter *str * @param *USARTx: Pointer to USARTx to use for send * @param *DataArray: Pointer to array of data to be sent over USART * @param count: Number of data bytes to be sent over USART with DMA * @retval Sending started status: * - 0: DMA has not started with sending data * - > 0: DMA has started with sending data */ uint8_t TM_USART_DMA_Send(USART_TypeDef* USARTx, uint8_t* DataArray, uint16_t count); /** * @brief Checks if USART DMA TX is still sending data * @param *USARTx: Pointer to USARTx where you want to check if DMA is still working * @retval Sending status: * - 0: USART does not sending anymore * - > 0: USART DMA is still sending data */ uint8_t TM_USART_DMA_Sending(USART_TypeDef* USARTx); /** * @} */ |
Example
Below example works similar than example for my USART library except it uses DMA to return received string from terminal back to user.
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 |
/** * Keil project for USART DMA TX functionality * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx Keil packs version 2.4.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.5.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_usart.h" #include "tm_stm32f4_usart_dma.h" #include "string.h" /* Create USART working buffer */ char USART_Buffer[100] = "Hello via USART2 with TX DMA\n"; int main(void) { /* Initialize system */ SystemInit(); /* Init USART2 on pins TX = PA2, RX = PA3 */ /* This pins are used on Nucleo boards for USB to UART via ST-Link */ TM_USART_Init(USART2, TM_USART_PinsPack_1, 115200); /* Init TX DMA for USART2 */ TM_USART_DMA_Init(USART2); /* Say string without DMA */ TM_USART_Puts(USART2, "Hello via USART2 without DMA\n"); /* Send data with DMA */ TM_USART_DMA_Send(USART2, (uint8_t *)USART_Buffer, strlen(USART_Buffer)); /* Wait till DMA works */ /* You can do other stuff here instead of waiting for DMA to end */ while (TM_USART_DMA_Sending(USART2)); while (1) { /* If any string arrived over USART */ /* Expecting "\n" at the end of string from USART terminal or any other source */ if (TM_USART_Gets(USART2, USART_Buffer, sizeof(USART_Buffer))) { /* Send it back over DMA */ TM_USART_DMA_Send(USART2, (uint8_t *)USART_Buffer, strlen(USART_Buffer)); /* Wait till DMA works */ /* You can do other stuff here instead of waiting for DMA to end */ while (TM_USART_DMA_Sending(USART2)); } } } |
Project is available on my Github account, download library below.
Recent comments