STM32F042-Drivers-Pub/usart1.c
Francesco Gritti fe64f5342d initial commit
2024-05-02 12:18:04 +02:00

229 lines
4.9 KiB
C

/*
* USART1.c
*
* Created on: Dec 25, 2023
* Author: Francesco Gritti
*/
#include "main.h"
#ifdef use_usart1
#include "mcu.h"
#include "usart1.h"
// RX Circular Buffer and pointers
#define RX1_BUFFLEN 128 //IMPOSTARE MULTIPLO DI 2 !!!
static volatile u8 rx1_Buffer [RX1_BUFFLEN];
static volatile u8 rx1_Head = 0;
static volatile u8 rx1_Tail = 0;
// TX Circular Buffer and pointers
#define TX1_BUFFLEN 128 //IMPOSTARE MULTIPLO DI 2 !!!
static volatile u8 tx1_Buffer [TX1_BUFFLEN];
static volatile u8 tx1_Head = 0;
static volatile u8 tx1_Tail = 0;
__attribute__((weak)) void USART1_rxCallback (void) {}
static void tx1_BufferOverflow () {
// do something
}
static void rx1_BufferOverflow () {
//while (1);
}
/* configure usart1 with gpio as follows:
* USART1_TX => PB6
* USART1_RX => PB7
*/
void USART1_init (u64 brr) {
RCC_USART1_CLK_ENABLE ();
// disable USART since some registers can be written only
// when the peripheral is disabled
USART_DISABLE (USART1);
USART1->CR1 = 0;
USART1->CR2 = 0;
USART1->CR3 = 0;
// set PRESCALER to 1
USART1->GTPR = 1;
// set BAUDRATE
USART1->BRR = brr;
// CONFIGURE GPIO
GPIO_AF_PP (USART1_TX);
GPIO_AF_PP (USART1_RX);
// SET CORRECT ALTERNATE FUNCTION
GPIO_SET_AFRL (USART1_TX, GPIO_AF0_USART1);
GPIO_SET_AFRL (USART1_RX, GPIO_AF0_USART1);
NVIC_SetPriority (USART1_IRQn, 1<<4);
NVIC_EnableIRQ (USART1_IRQn);
// enable USART peripheral
USART_ENABLE_DATA_RECEIVED_INT (USART1);
USART_START (USART1);
}
void USART1_disable(void) {
__disable_irq();
// disable peripheral, transmitter and receiver
USART_DISABLE_DATA_RECEIVED_INT (USART1);
USART_STOP (USART1);
__enable_irq();
}
void USART1_enable(void) {
__disable_irq();
// enable peripheral, transmitter and receiver
USART_START (USART1);
USART_ENABLE_DATA_RECEIVED_INT (USART1);
__enable_irq();
}
// ISR called when the TX data register is empty. Note that this does NOT mean that the data has been sent and
// disabling the peripheral at this point will result in the data not being correctly send out
void USART1_IRQHandler (void) {
// TX register empty interrupt. Check that TXE interrupt is actually enabled
// since after the last byte of a buffer is transferred this bit remains
// set since data register is empty
if ((USART1->CR1 & USART_CR1_TXEIE) != 0 && (USART1->ISR & USART_ISR_TXE) != 0) {
tx1_Tail = (tx1_Tail+1) & (TX1_BUFFLEN-1);
if (tx1_Tail != tx1_Head) {
// if other data need to be transmitted, write to the TX register. This
// clears TX register empty interrupt
USART_SET_TRANSMIT_DATA (USART1, tx1_Buffer[tx1_Tail]);
}
else {
// if no more data has to be transmitted, disable TX register empty interrupt
USART_DISABLE_TX_DATA_REGISTER_EMPTY_INT (USART1);
}
}
// RX data received interrupt
else if ((USART1->ISR & USART_ISR_RXNE) != 0) {
// read data. This clears interrupt flag
u8 dataByte = USART1->RDR;
// temporary increment
u8 rx1_HeadTemp = (rx1_Head+1) & (RX1_BUFFLEN-1);
if (rx1_HeadTemp != rx1_Tail) {
rx1_Buffer [rx1_Head] = dataByte;
rx1_Head = rx1_HeadTemp;
USART1_rxCallback ();
}
else {
rx1_BufferOverflow ();
}
}
}
void USART1_flush () {
// wait until all data are set into TX register and last data is fully transmitted
while (tx1_Head != tx1_Tail || (USART1->ICR & USART_ISR_TC) == 0)
__asm volatile ("NOP");
}
void USART1_putch (char c) {
// temporarily increment head pointer
u8 tx1_HeadTemp = (tx1_Head+1) & (TX1_BUFFLEN-1);
// if the TX buffer is full, wait until some data is transmitted
if (tx1_HeadTemp == tx1_Tail)
tx1_BufferOverflow();
while (tx1_HeadTemp == tx1_Tail)
__asm volatile ("NOP");
// disable interrupt since it might occur that when in the branch else, the last data is transmitted in between the
// write of the new data to the buffer and the increment of the head pointer. In this case the ISR would disable the
// peripheral and the new data wouldn't be transmitted
// disable data register empty interrupt enable
USART_DISABLE_TX_DATA_REGISTER_EMPTY_INT (USART1);
if (tx1_Head == tx1_Tail) { // empty buffer
tx1_Buffer [tx1_Head] = c;
tx1_Head=(tx1_Head+1) & (TX1_BUFFLEN-1);
USART_SET_TRANSMIT_DATA (USART1, tx1_Buffer[tx1_Tail]);
USART_ENABLE_TX_DATA_REGISTER_EMPTY_INT (USART1);
}
else { // data transmission is already occurring, just add data to the buffer
tx1_Buffer [tx1_Head]=c;
tx1_Head=(tx1_Head+1) & (TX1_BUFFLEN-1);
USART_ENABLE_TX_DATA_REGISTER_EMPTY_INT (USART1);
}
}
void USART1_puts(const char * c) {
while ((*c)>0)
USART1_putch(*c++);
}
void USART1_nputs(const char * c, u16 i) {
while (i-- > 0)
USART1_putch (*c++);
}
u8 USART1_getch (char* c) {
if (rx1_Tail != rx1_Head) {
*c = rx1_Buffer [rx1_Tail];
rx1_Tail = (rx1_Tail+1) & (RX1_BUFFLEN-1);
return 1;
}
return 0;
}
u16 USART1_available (void) {
i32 N = rx1_Head-rx1_Tail;
if (N<0) N += RX1_BUFFLEN;
return (u16) N;
}
#endif