openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.2 KiB

// ***************************** Interrupt handlers *****************************
void uart_tx_ring(uart_ring *q){
ENTER_CRITICAL();
// Send out next byte of TX buffer
if (q->w_ptr_tx != q->r_ptr_tx) {
// Only send if transmit register is empty (aka last byte has been sent)
if ((q->uart->SR & USART_SR_TXE) != 0) {
q->uart->DR = q->elems_tx[q->r_ptr_tx]; // This clears TXE
q->r_ptr_tx = (q->r_ptr_tx + 1U) % q->tx_fifo_size;
}
// Enable TXE interrupt if there is still data to be sent
if(q->r_ptr_tx != q->w_ptr_tx){
q->uart->CR1 |= USART_CR1_TXEIE;
} else {
q->uart->CR1 &= ~USART_CR1_TXEIE;
}
}
EXIT_CRITICAL();
}
void uart_rx_ring(uart_ring *q){
ENTER_CRITICAL();
// Read out RX buffer
uint8_t c = q->uart->DR; // This read after reading SR clears a bunch of interrupts
uint16_t next_w_ptr = (q->w_ptr_rx + 1U) % q->rx_fifo_size;
if ((next_w_ptr == q->r_ptr_rx) && q->overwrite) {
// overwrite mode: drop oldest byte
q->r_ptr_rx = (q->r_ptr_rx + 1U) % q->rx_fifo_size;
}
// Do not overwrite buffer data
if (next_w_ptr != q->r_ptr_rx) {
q->elems_rx[q->w_ptr_rx] = c;
q->w_ptr_rx = next_w_ptr;
if (q->callback != NULL) {
q->callback(q);
}
}
EXIT_CRITICAL();
}
void uart_send_break(uart_ring *u) {
while ((u->uart->CR1 & USART_CR1_SBK) != 0);
u->uart->CR1 |= USART_CR1_SBK;
}
// This read after reading SR clears all error interrupts. We don't want compiler warnings, nor optimizations
#define UART_READ_DR(uart) volatile uint8_t t = (uart)->DR; UNUSED(t);
void uart_interrupt_handler(uart_ring *q) {
ENTER_CRITICAL();
// Read UART status. This is also the first step necessary in clearing most interrupts
uint32_t status = q->uart->SR;
// If RXNE is set, perform a read. This clears RXNE, ORE, IDLE, NF and FE
if((status & USART_SR_RXNE) != 0U){
uart_rx_ring(q);
}
// Detect errors and clear them
uint32_t err = (status & USART_SR_ORE) | (status & USART_SR_NE) | (status & USART_SR_FE) | (status & USART_SR_PE);
if(err != 0U){
#ifdef DEBUG_UART
print("Encountered UART error: "); puth(err); print("\n");
#endif
UART_READ_DR(q->uart)
}
// Send if necessary
uart_tx_ring(q);
EXIT_CRITICAL();
}
void USART2_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_debug); }
void USART3_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin2); }
void UART5_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin1); }
// ***************************** Hardware setup *****************************
#define __DIV(_PCLK_, _BAUD_) (((_PCLK_) * 25U) / (4U * (_BAUD_)))
#define __DIVMANT(_PCLK_, _BAUD_) (__DIV((_PCLK_), (_BAUD_)) / 100U)
#define __DIVFRAQ(_PCLK_, _BAUD_) ((((__DIV((_PCLK_), (_BAUD_)) - (__DIVMANT((_PCLK_), (_BAUD_)) * 100U)) * 16U) + 50U) / 100U)
#define __USART_BRR(_PCLK_, _BAUD_) ((__DIVMANT((_PCLK_), (_BAUD_)) << 4) | (__DIVFRAQ((_PCLK_), (_BAUD_)) & 0x0FU))
void uart_set_baud(USART_TypeDef *u, unsigned int baud) {
u->BRR = __USART_BRR(APB1_FREQ*1000000U, baud);
}
void uart_init(uart_ring *q, int baud) {
if(q->uart != NULL){
// Register interrupts (max data rate: 115200 baud)
if (q->uart == USART2){
REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2)
} else if (q->uart == USART3){
REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3)
} else if (q->uart == UART5){
REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5)
} else {
// UART not used. Skip registering interrupts
}
// Set baud and enable peripheral with TX and RX mode
uart_set_baud(q->uart, baud);
q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
if ((q->uart == USART2) || (q->uart == USART3) || (q->uart == UART5)) {
q->uart->CR1 |= USART_CR1_RXNEIE;
}
// Enable UART interrupts
if (q->uart == USART2){
NVIC_EnableIRQ(USART2_IRQn);
} else if (q->uart == USART3){
NVIC_EnableIRQ(USART3_IRQn);
} else if (q->uart == UART5){
NVIC_EnableIRQ(UART5_IRQn);
} else {
// UART not used. Skip enabling interrupts
}
}
}