2020-02-19 21:07:58 +01:00
/** library for UART communication
2020-02-11 12:23:10 +01:00
* @ file
2018-02-18 15:18:42 +01:00
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2020-02-11 12:23:10 +01:00
* @ date 2016 - 2020
2018-02-18 15:18:42 +01:00
* @ note peripherals used : USART @ ref uart
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // general utilities
/* STM32 (including CM3) libraries */
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
# include <libopencm3/stm32/usart.h> // universal synchronous asynchronous receiver transmitter library
# include <libopencm3/cm3/nvic.h> // interrupt handler
# include <libopencmsis/core_cm3.h> // Cortex M3 utilities
# include "uart.h" // UART header and definitions
# include "global.h" // common methods
2018-02-18 15:20:01 +01:00
/** @defgroup uart USART peripheral used for UART communication
2018-02-18 15:18:42 +01:00
* @ {
*/
2018-02-18 15:20:01 +01:00
# define UART_ID 1 /**< USART peripheral */
2020-11-27 16:49:59 +01:00
# define UART_TX PA9 /**< pin used for USART TX */
# define UART_RX PA10 /**< pin used for USART RX */
# define UART_AF GPIO_AF7 /**< alternate function for UART pins */
2018-02-18 15:18:42 +01:00
/** @} */
2020-11-27 16:49:59 +01:00
# define UART_BAUDRATE 115200 /**< serial baud rate, in bits per second (with 8N1 8 bits, no parity bit, 1 stop bit settings) */
2018-02-18 15:18:42 +01:00
2018-02-18 15:20:47 +01:00
/* output ring buffer, indexes, and available memory */
2020-06-24 11:47:05 +02:00
static volatile uint8_t tx_buffer [ 128 ] = { 0 } ; /**< ring buffer for data to transmit (size must be a power of 2) */
2020-02-19 21:07:58 +01:00
static volatile uint16_t tx_i = 0 ; /**< current position of transmitted data */
static volatile uint16_t tx_used = 0 ; /**< how much data needs to be transmitted */
2018-02-18 15:18:42 +01:00
void uart_setup ( void )
{
2020-11-27 16:49:59 +01:00
// configure pins
rcc_periph_clock_enable ( GPIO_RCC ( UART_TX ) ) ; // enable clock for USART TX pin port peripheral
gpio_mode_setup ( GPIO_PORT ( UART_TX ) , GPIO_MODE_AF , GPIO_PUPD_NONE , GPIO_PIN ( UART_TX ) ) ; // set TX pin to alternate function
gpio_set_output_options ( GPIO_PORT ( UART_TX ) , GPIO_OTYPE_PP , GPIO_OSPEED_25MHZ , GPIO_PIN ( UART_TX ) ) ; // set TX pin output as push-pull
gpio_set_af ( GPIO_PORT ( UART_TX ) , UART_AF , GPIO_PIN ( UART_TX ) ) ; // set alternate function to USART
rcc_periph_clock_enable ( GPIO_RCC ( UART_RX ) ) ; // enable clock for USART RX pin port peripheral
gpio_mode_setup ( GPIO_PORT ( UART_RX ) , GPIO_MODE_AF , GPIO_PUPD_PULLUP , GPIO_PIN ( UART_RX ) ) ; // set GPIO to alternate function, with pull up to avoid noise in case it is not connected
gpio_set_af ( GPIO_PORT ( UART_RX ) , UART_AF , GPIO_PIN ( UART_RX ) ) ; // set alternate function to USART
2018-02-18 15:18:42 +01:00
2020-11-27 16:49:59 +01:00
// configure USART
rcc_periph_clock_enable ( RCC_USART ( UART_ID ) ) ; // enable clock for USART peripheral
rcc_periph_reset_pulse ( RST_USART ( UART_ID ) ) ; // reset peripheral
2018-02-18 15:18:42 +01:00
usart_set_baudrate ( USART ( UART_ID ) , UART_BAUDRATE ) ;
usart_set_databits ( USART ( UART_ID ) , 8 ) ;
usart_set_stopbits ( USART ( UART_ID ) , USART_STOPBITS_1 ) ;
usart_set_mode ( USART ( UART_ID ) , USART_MODE_TX_RX ) ;
usart_set_parity ( USART ( UART_ID ) , USART_PARITY_NONE ) ;
usart_set_flow_control ( USART ( UART_ID ) , USART_FLOWCONTROL_NONE ) ;
nvic_enable_irq ( USART_IRQ ( UART_ID ) ) ; // enable the UART interrupt
usart_enable_rx_interrupt ( USART ( UART_ID ) ) ; // enable receive interrupt
usart_enable ( USART ( UART_ID ) ) ; // enable UART
2020-11-27 16:49:59 +01:00
// reset buffer states
2018-02-18 15:18:42 +01:00
tx_i = 0 ;
tx_used = 0 ;
}
void uart_putchar_blocking ( char c )
{
2020-06-09 00:59:19 +02:00
usart_send_blocking ( USART ( UART_ID ) , c ) ; // send character (this already wait for the buffer to be empty)
2018-02-18 15:18:42 +01:00
}
void uart_flush ( void )
{
while ( tx_used ) { // idle until buffer is empty
__WFI ( ) ; // sleep until interrupt
}
usart_wait_send_ready ( USART ( UART_ID ) ) ; // wait until transmit register is empty (transmission might not be complete)
2020-06-09 00:59:19 +02:00
while ( ! usart_get_flag ( USART ( UART_ID ) , USART_SR_TC ) ) ; // wait for transmission to be complete
2018-02-18 15:18:42 +01:00
}
void uart_putchar_nonblocking ( char c )
{
2020-02-11 12:23:10 +01:00
while ( tx_used > = LENGTH ( tx_buffer ) ) { // idle until buffer has some space
2018-02-18 15:18:42 +01:00
usart_enable_tx_interrupt ( USART ( UART_ID ) ) ; // enable transmit interrupt
2018-06-14 13:18:51 +02:00
// don't go to sleep since this might prevent an interrupt
2018-02-18 15:18:42 +01:00
}
usart_disable_tx_interrupt ( USART ( UART_ID ) ) ; // disable transmit interrupt to prevent index corruption
2020-06-24 11:47:05 +02:00
tx_buffer [ ( tx_i + tx_used ) & ( LENGTH ( tx_buffer ) - 1 ) ] = c ; // put character in buffer
2018-02-18 15:18:42 +01:00
tx_used + + ; // update used buffer
usart_enable_tx_interrupt ( USART ( UART_ID ) ) ; // enable transmit interrupt
}
/** UART interrupt service routine called when data has been transmitted or received */
void USART_ISR ( UART_ID ) ( void )
{
if ( usart_get_flag ( USART ( UART_ID ) , USART_SR_TXE ) ) { // data has been transmitted
if ( ! tx_used ) { // no data in the buffer to transmit
usart_disable_tx_interrupt ( USART ( UART_ID ) ) ; // disable transmit interrupt
} else {
2020-02-11 12:23:10 +01:00
usart_send ( USART ( UART_ID ) , tx_buffer [ tx_i ] ) ; // put data in transmit register
2020-06-24 11:47:05 +02:00
tx_i = ( tx_i + 1 ) & ( LENGTH ( tx_buffer ) - 1 ) ; // update location on buffer
2018-02-18 15:18:42 +01:00
tx_used - - ; // update used size
}
}
while ( usart_get_flag ( USART ( UART_ID ) , USART_SR_RXNE ) ) { // data has been received (repeat while receiving)
char c = usart_recv ( USART ( UART_ID ) ) ; // save character and free UART buffer
2018-02-18 15:20:47 +01:00
user_input_store ( c ) ; // store data
2018-02-18 15:18:42 +01:00
}
}