Library 04- USART for STM32F4
A lot of times when you work on some project, you want to display data on computer. This can be done with USART peripheral on MCU. With USART you can connect more than just computer, you can connect with GSM modules, GPRS, bluetooth and so much more. Our discovery board supports up to 8 USART channels. In this tutorial we will use USART1 to show principle how to use USART in our project. But first, we have to initialize our pins and peripheral.
Pins pack 1 | Pins pack 2 | Pins pack 3 | |||||
---|---|---|---|---|---|---|---|
U(S)ARTx | TX | RX | TX | RX | TX | RX | APB |
USART1 | PA9 | PA10 | PB6 | PB7 | 2 | ||
USART2 | PA2 | PA3 | PD5 | PD6 | 1 | ||
USART3 | PB10 | PB11 | PC10 | PC11 | PD8 | PD9 | 1 |
UART4 | PA0 | PA1 | PC10 | PC11 | 1 | ||
UART5 | PC12 | PD2 | 1 | ||||
USART6 | PC6 | PC7 | PG14 | PG9 | 2 | ||
UART7 | PE8 | PE7 | PF7 | PF6 | 1 | ||
UART8 | PE1 | PE0 | 1 |
USART1 uses pins
- PA9 for transmitting data
- PA10 for receiving data
so they must have enabled clock, set for alternating function and set them this alternating function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
GPIO_InitTypeDef GPIO_InitStruct; // Enable clock for GPIOA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /** * Tell pins PA9 and PA10 which alternating function you will use * @important Make sure, these lines are before pins configuration! */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); // Initialize pins as alternating function GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); |
Then, when you initialized pins, we have to initialize USART peripheral too
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 |
USART_InitTypeDef USART_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; /** * Enable clock for USART1 peripheral */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /** * Set Baudrate to value you pass to function * Disable Hardware Flow control * Set Mode To TX and RX, so USART will work in full-duplex mode * Disable parity bit * Set 1 stop bit * Set Data bits to 8 * * Initialize USART1 * Activate USART1 */ USART_InitStruct.USART_BaudRate = baudrate; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &USART_InitStruct); USART_Cmd(USART1, ENABLE); /** * Enable RX interrupt */ USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /** * Set Channel to USART1 * Set Channel Cmd to enable. That will enable USART1 channel in NVIC * Set Both priorities to 0. This means high priority * * Initialize NVIC */ NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStruct); |
Because our USART uses interrupt for incoming data, we have to initialize NVIC (Nested Vector Interrupt Controller). Everytime when data will come, our main program will stop executing and our interrupt routine will jump in.
Library
Features
- Operate with up to 8 U(S)ARTs in UART mode
- Selectable pins for USART
- Receive interrupt handler
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx USART
- TM
- defines.h
- attributes.h
- TM GPIO
- defines.h
Functions and enumerations
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
/** * @defgroup TM_USART_Typedefs * @brief USART Typedefs * @{ */ /** * @brief USART PinsPack enumeration to select pins combination for USART */ typedef enum { TM_USART_PinsPack_1, /*!< Select PinsPack1 from Pinout table for specific USART */ TM_USART_PinsPack_2, /*!< Select PinsPack2 from Pinout table for specific USART */ TM_USART_PinsPack_3, /*!< Select PinsPack3 from Pinout table for specific USART */ TM_USART_PinsPack_Custom /*!< Select custom pins for specific USART, callback will be called, look @ref TM_USART_InitCustomPinsCallback */ } TM_USART_PinsPack_t; /** * @brief USART Hardware flow control selection * @note Corresponsing pins must be initialized in case you don't use "None" options */ typedef enum { TM_USART_HardwareFlowControl_None = 0x0000, /*!< No flow control */ TM_USART_HardwareFlowControl_RTS = 0x0100, /*!< RTS flow control */ TM_USART_HardwareFlowControl_CTS = 0x0200, /*!< CTS flow control */ TM_USART_HardwareFlowControl_RTS_CTS = 0x0300 /*!< RTS and CTS flow control */ } TM_USART_HardwareFlowControl_t; /** * @} */ /** * @defgroup TM_USART_Functions * @brief USART Functions * @{ */ /** * @brief Initializes USARTx peripheral and corresponding pins * @param *USARTx: Pointer to USARTx peripheral you will use * @param pinspack: This parameter can be a value of @ref TM_USART_PinsPack_t enumeration * @param baudrate: Baudrate number for USART communication * @retval None */ void TM_USART_Init(USART_TypeDef* USARTx, TM_USART_PinsPack_t pinspack, uint32_t baudrate); /** * @brief Initializes USARTx peripheral and corresponding pins with custom hardware flow control mode * @note Hardware flow control pins are not initialized. Easy solution is to you Custom pinspack option and initialize all USART pins at a time * @param *USARTx: Pointer to USARTx peripheral you will use * @param pinspack: This parameter can be a value of @ref TM_USART_PinsPack_t enumeration * @param baudrate: Baudrate number for USART communication * @param FlowControl: Flow control mode you will use. This parameter can be a value of @ref TM_USART_HardwareFlowControl_t enumeration * @retval None */ void TM_USART_InitWithFlowControl(USART_TypeDef* USARTx, TM_USART_PinsPack_t pinspack, uint32_t baudrate, TM_USART_HardwareFlowControl_t FlowControl); /** * @brief Puts character to USART port * @param *USARTx: Pointer to USARTx peripheral you will use * @param c: character to be send over USART * @retval None */ static __INLINE void TM_USART_Putc(USART_TypeDef* USARTx, volatile char c) { /* Check USART */ if ((USARTx->CR1 & USART_CR1_UE)) { /* Wait to be ready, buffer empty */ USART_WAIT(USARTx); /* Send data */ USARTx->DR = (uint16_t)(c & 0x01FF); /* Wait to be ready, buffer empty */ USART_WAIT(USARTx); } } /** * @brief Puts string to USART port * @param *USARTx: Pointer to USARTx peripheral you will use * @param *str: Pointer to string to send over USART * @retval None */ void TM_USART_Puts(USART_TypeDef* USARTx, char* str); /** * @brief Sends data array to USART port * @param *USARTx: Pointer to USARTx peripheral you will use * @param *DataArray: Pointer to data array to be sent over USART * @param count: Number of elements in data array to be send over USART * @retval None */ void TM_USART_Send(USART_TypeDef* USARTx, uint8_t* DataArray, uint16_t count); /** * @brief Gets character from internal USART buffer * @param *USARTx: Pointer to USARTx peripheral you will use * @retval Character from buffer, or 0 if nothing in buffer */ uint8_t TM_USART_Getc(USART_TypeDef* USARTx); /** * @brief Get string from USART * * This function can create a string from USART received data. * * It generates string until "\n" is not recognized or buffer length is full. * * @note As of version 1.5, this function automatically adds 0x0A (Line feed) at the end of string. * @param *USARTx: Pointer to USARTx peripheral you will use * @param *buffer: Pointer to buffer where data will be stored from buffer * @param bufsize: maximal number of characters we can add to your buffer, including leading zero * @retval Number of characters in buffer */ uint16_t TM_USART_Gets(USART_TypeDef* USARTx, char* buffer, uint16_t bufsize); /** * @brief Check if character c is available in internal buffer * @param *USARTx: Pointer to USARTx peripheral you will use * @param c: character to check if it is in USARTx's buffer * @retval Character status: * - 0: Character was not found * - > 0: Character has been found in buffer */ uint8_t TM_USART_FindCharacter(USART_TypeDef* USARTx, uint8_t c); /** * @brief Checks if internal USARTx buffer is empty * @param *USARTx: Pointer to USARTx peripheral you will use * @retval Buffer empty status: * - 0: Buffer is not empty * - > 0: Buffer is empty */ uint8_t TM_USART_BufferEmpty(USART_TypeDef* USARTx); /** * @brief Checks if internal USARTx buffer is full * @param *USARTx: Pointer to USARTx peripheral you will use * @retval Buffer full status: * - 0: Buffer is not full * - > 0: Buffer is full */ uint8_t TM_USART_BufferFull(USART_TypeDef* USARTx); /** * @brief Clears internal USART buffer * @param *USARTx: Pointer to USARTx peripheral you will use * @retval None */ void TM_USART_ClearBuffer(USART_TypeDef* USARTx); /** * @brief Sets custom character for @ref TM_USART_Gets() function to detect when string ends * @param *USARTx: Pointer to USARTx peripheral you will use * @param Character: Character value to be used as string end * @note Character will also be added at the end for your buffer when calling @ref TM_USART_Gets() function * @retval None */ void TM_USART_SetCustomStringEndCharacter(USART_TypeDef* USARTx, uint8_t Character); /** * @brief Callback for custom pins initialization for USARTx. * When you call TM_USART_Init() function, and if you pass TM_USART_PinsPack_Custom to function, * then this function will be called where you can initialize custom pins for USART peripheral. * @note With __weak parameter to prevent link errors if not defined by user * @param *USARTx: Pointer to USARTx peripheral you will use for initialization * @retval None */ void TM_USART_InitCustomPinsCallback(USART_TypeDef* USARTx); /** * @brief Callback function for receive interrupt on USART1 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_USART1_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on USART2 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_USART2_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on USART3 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_USART3_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on UART4 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_UART4_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on UART5 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_UART5_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on USART6 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_USART6_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on UART7 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_UART7_ReceiveHandler(uint8_t c); /** * @brief Callback function for receive interrupt on UART8 in case you have enabled custom USART handler mode * @note With __weak parameter to prevent link errors if not defined by user * @param c: character received via USART * @retval None */ __weak void TM_UART8_ReceiveHandler(uint8_t c); /** * @} */ |
Hardware
Your computer probably has not RS232 connector, but it has USB for sure. You need USB to serial converter. I prefer FTDI which is very stable and support 3V3 levels. You can buy converter on ebay for about 5$. Connect converter’s TX with board’s RX and converter’s RX with board’s TX. To display data, you need some terminal, I use one from Bray. Open program and set:
- Select your COM port
- baudrate to 9600
- Data bits to 8
- Parity to none
- Stop bits to 1
Example
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 |
/** * Keil project for USART * * 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 * @packs STM32F4xx Keil packs version 2.2.0 or greater required * @stdperiph STM32F4xx Standard peripheral drivers version 1.4.0 or greater required */ /* Include core modules */ #include "stm32f4xx.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32f4_usart.h" int main(void) { uint8_t c; /* Initialize system */ SystemInit(); /* Initialize USART1 at 9600 baud, TX: PB6, RX: PB7 */ TM_USART_Init(USART1, TM_USART_PinsPack_2, 9600); /* Put string to USART */ TM_USART_Puts(USART1, "Hello world\n\r"); while (1) { /* Get character from internal buffer */ c = TM_USART_Getc(USART1); if (c) { /* If anything received, put it back to terminal */ TM_USART_Putc(USART1, c); } } } |
Project available on Github, download library below.
USART library for all USART peripherals
Recent comments