STM32F411: rework serial-stuff.
Simplify changing the USART for debug or serial output. Implement all 3 USARTs for the stm32f411re.
This commit is contained in:
parent
230572b1d0
commit
dcd67e402a
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
227
serial-stm32.c
227
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__ */
|
||||
Loading…
Reference in New Issue