229 lines
4.9 KiB
C
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
|
||
|
|