diff --git a/arduino_stm32f411.h b/arduino_stm32f411.h index 994ddf8..5edd7a9 100644 --- a/arduino_stm32f411.h +++ b/arduino_stm32f411.h @@ -22,8 +22,12 @@ /** Pins for UART, the serial port. */ -#define RXD PA_3 -#define TXD PA_2 +#define RX_UART1 PA_10 +#define TX_UART1 PA_9 +#define RX_UART2 PA_3 +#define TX_UART2 PA_2 +#define RX_UART6 PA_12 +#define TX_UART6 PA_11 /** Clock setup for APB1 and APB2 clock. */ diff --git a/serial-stm32.c b/serial-stm32.c index 5422894..6371208 100644 --- a/serial-stm32.c +++ b/serial-stm32.c @@ -21,79 +21,152 @@ See serial-avr.c for inspiration. #endif -void serial_init() -{ - uint32_t tempreg; - // Enable USART2 clock - RCC->APB1ENR |= RCC_APB1ENR_USART2EN; +#define UART_SERIAL USART2 - // Configure the UART pins - // AF 4bits per channel - // Alternate functions from DM00115249.pdf datasheet (page 47; table 9) - SET_AFR(TXD, 0x7); - SET_AFR(RXD, 0x7); +void init_serial1(void) { + // Enable USART1 clock + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; - // Set pins to alternate function mode - SET_MODE(TXD, 0x2); - SET_MODE(RXD, 0x2); + // Configure the UART pins + // AF 4bits per channel + // Alternate functions from DM00115249.pdf datasheet (page 47; table 9) + SET_AFR(TX_UART1, 0x7); + SET_AFR(RX_UART1, 0x7); - SET_OSPEED(TXD, 0x3); - SET_OSPEED(RXD, 0x3); + // Set pins to alternate function mode + SET_MODE(TX_UART1, 0x2); + SET_MODE(RX_UART1, 0x2); - PULL_OFF(TXD); - PULL_OFF(RXD); - - /* Disable the peripheral */ - USART2->CR1 &= ~USART_CR1_UE; - - /* Clear M, PCE, PS, TE and RE bits */ - tempreg = USART2->CR1; - tempreg &= ~(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | \ - USART_CR1_RE | USART_CR1_OVER8); + SET_OSPEED(TX_UART1, 0x3); + SET_OSPEED(RX_UART1, 0x3); - /* Configure the UART Word Length, Parity and mode:*/ - tempreg |= USART_CR1_RE | USART_CR1_TE; - USART2->CR1 = tempreg; + PULL_OFF(TX_UART1); + PULL_OFF(RX_UART1); +} - /* 19.3.4 Fractional baud rate generation => reference manual for STM32F411 - Set BRR for 115,200 Hz - div = 48MHz/(16*BAUD) - Mantisse = int(div) << 8 - Divisor = int((div - int(div))*16) - BRR = Mantisse + Divisor - */ - #if !defined BAUD - #define BAUD 115200 - #endif +void init_serial2(void) { + // Enable USART2 clock + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; - #define SERIAL_APBCLK (__SYSTEM_CLOCK/2) + // Configure the UART pins + // AF 4bits per channel + // Alternate functions from DM00115249.pdf datasheet (page 47; table 9) + SET_AFR(TX_UART2, 0x7); + SET_AFR(RX_UART2, 0x7); - #define INT_DIVIDER ((25 * SERIAL_APBCLK) / (4 * BAUD)) - #define BAUD_H ((INT_DIVIDER / 100) << 4) - #define FRACT_DIVIDER (INT_DIVIDER - (100 * (BAUD_H >> 4))) - #define BAUD_L (((((FRACT_DIVIDER * 16) + 50) / 100)) & 0X0F) + // Set pins to alternate function mode + SET_MODE(TX_UART2, 0x2); + SET_MODE(RX_UART2, 0x2); - USART2->BRR = BAUD_H | BAUD_L; + SET_OSPEED(TX_UART2, 0x3); + SET_OSPEED(RX_UART2, 0x3); - /* Clear STOP[13:12] bits */ - tempreg = USART2->CR2; - tempreg &= ~(USART_CR2_STOP); - - /* In asynchronous mode, the following bits must be kept cleared: - - LINEN and CLKEN bits in the USART_CR2 register, - - SCEN, HDSEL and IREN bits in the USART_CR3 register.*/ - tempreg &= ~(USART_CR2_LINEN | USART_CR2_CLKEN); - USART2->CR2 = tempreg; + PULL_OFF(TX_UART2); + PULL_OFF(RX_UART2); +} - tempreg = USART2->CR3; - tempreg &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); +void init_serial6(void) { + // Enable USART6 clock + RCC->APB2ENR |= RCC_APB2ENR_USART6EN; - /* Clear CTSE and RTSE bits */ - tempreg &= ~(USART_CR3_RTSE | USART_CR3_CTSE); - USART2->CR3 = tempreg; - - /* Enable the peripheral */ - USART2->CR1 |= USART_CR1_UE; + // Configure the UART pins + // AF 4bits per channel + // Alternate functions from DM00115249.pdf datasheet (page 47; table 9) + SET_AFR(TX_UART6, 0x8); + SET_AFR(RX_UART6, 0x8); + + // Set pins to alternate function mode + SET_MODE(TX_UART6, 0x2); + SET_MODE(RX_UART6, 0x2); + + SET_OSPEED(TX_UART6, 0x3); + SET_OSPEED(RX_UART6, 0x3); + + PULL_OFF(TX_UART6); + PULL_OFF(RX_UART6); +} + + +void init_uart(USART_TypeDef *usartx) { + + if (usartx == USART1) + init_serial1(); + else if (usartx == USART2) + init_serial2(); + else if (usartx == USART6) + init_serial6(); + + uint32_t tempreg; + + /* Disable the peripheral */ + usartx->CR1 &= ~USART_CR1_UE; + + /* Clear M, PCE, PS, TE and RE bits */ + tempreg = usartx->CR1; + tempreg &= ~(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | + USART_CR1_RE | USART_CR1_OVER8); + + /* Configure the UART Word Length, Parity and mode:*/ + tempreg |= USART_CR1_RE | USART_CR1_TE; + usartx->CR1 = tempreg; + + /* 19.3.4 Fractional baud rate generation => reference manual for STM32F411 + Set BRR for 115,200 Hz + div = 48MHz/(16*BAUD) + Mantisse = int(div) << 8 + Divisor = int((div - int(div))*16) + BRR = Mantisse + Divisor + */ + #if !defined BAUD + #define BAUD 115200 + #endif + + #define SERIAL_APB1CLK (_APB1_CLOCK) + + #define INT_DIVIDER ((25UL * SERIAL_APB1CLK) / (4 * BAUD)) + #define BAUD_H ((INT_DIVIDER / 100) << 4) + #define FRACT_DIVIDER (INT_DIVIDER - (100 * (BAUD_H >> 4))) + #define BAUD_L ((((FRACT_DIVIDER * 16) + 50) / 100) & 0X0F) + + #define SERIAL_APB2CLK (_APB2_CLOCK) + + #define INT_DIVIDER2 ((25UL * SERIAL_APB2CLK) / (4 * BAUD)) + #define BAUD_H2 ((INT_DIVIDER2 / 100) << 4) + #define FRACT_DIVIDER2 (INT_DIVIDER2 - (100 * (BAUD_H2 >> 4))) + #define BAUD_L2 ((((FRACT_DIVIDER2 * 16) + 50) / 100) & 0X0F) + + // USART2 is on APB1, USART1 and USART6 on APB2 + if (usartx == USART2) + usartx->BRR = BAUD_H | BAUD_L; + else + usartx->BRR = BAUD_H2 | BAUD_L2; + + /* Clear STOP[13:12] bits */ + tempreg = usartx->CR2; + tempreg &= ~(USART_CR2_STOP); + + /* In asynchronous mode, the following bits must be kept cleared: + - LINEN and CLKEN bits in the USART_CR2 register, + - SCEN, HDSEL and IREN bits in the USART_CR3 register.*/ + tempreg &= ~(USART_CR2_LINEN | USART_CR2_CLKEN); + usartx->CR2 = tempreg; + + tempreg = usartx->CR3; + tempreg &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); + + /* Clear CTSE and RTSE bits */ + tempreg &= ~(USART_CR3_RTSE | USART_CR3_CTSE); + usartx->CR3 = tempreg; + + /* Enable the peripheral */ + usartx->CR1 |= USART_CR1_UE; +} + +void serial_init(){ + // Expand this list by adding UARTs + // For example you can add extra USART for debugging. + // In that case expand also the serial_XXcharS() below with new fuctions. + init_uart(UART_SERIAL); } /** Check wether characters can be read. @@ -101,32 +174,44 @@ void serial_init() Other than the AVR implementation this returns not the number of characters in the line, but only wether there is at least one or not. */ -uint8_t serial_rxchars(void) { - return USART2->SR & USART_SR_RXNE; +uint8_t uartx_rxchars(USART_TypeDef* uart) { + return uart->SR & USART_SR_RXNE; } /** Read one character. */ -uint8_t serial_popchar(void) { +uint8_t uartx_popchar(USART_TypeDef* uart) { uint8_t c = 0; - if (serial_rxchars()) - c = (uint8_t)(USART2->DR & 0x1FF); + if (uartx_rxchars(uart)) + c = (uint8_t)(uart->DR & 0x1FF); return c; } /** Check wether characters can be written */ -uint8_t serial_txchars(void) { - return USART2->SR &USART_SR_TXE; +uint8_t uartx_txchars(USART_TypeDef* uart) { + return uart->SR &USART_SR_TXE; } /** Send one character. */ +void uartx_writechar(USART_TypeDef* uart, uint8_t data) { + while ( !uartx_txchars(uart)); // Queue full? + uart->DR = (uint32_t)(data & 0x1FF); +} + +uint8_t serial_rxchars(void) { + return uartx_rxchars(UART_SERIAL); +} +uint8_t serial_popchar(void) { + return uartx_popchar(UART_SERIAL); +} +uint8_t serial_txchars(void) { + return uartx_rxchars(UART_SERIAL); +} void serial_writechar(uint8_t data) { - if ( !serial_txchars()) // Queue full? - delay_us((1000000 / BAUD * 10) + 7); - USART2->DR = (uint32_t)(data & 0x1FF); + uartx_writechar(UART_SERIAL, data); } #endif /* defined TEACUP_C_INCLUDE && defined __ARM_STM32F411__ */ \ No newline at end of file