/* * 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