blob: 63620ab6c1e0a504c3c7753bedeafac7f2264c8a [file] [log] [blame]
#include "cape/uart.h"
#include "cape/uart_common_private.h"
#include "cape/util.h"
#include "cape/uart_common.h"
// TODO(brians): Add error checking.
static void default_callback(int bytes) {}
void uart_transmit_callback(int bytes_transmitted) ALIAS_WEAK(default_callback);
void uart_receive_callback(int bytes_received) ALIAS_WEAK(default_callback);
static int transmit_bytes, receive_bytes;
// These actually contain 1 less than the indicated number to make the common
// path through the ISR faster.
static int transmitted_bytes, received_bytes;
static uint8_t *transmit_data, *receive_data;
// Enable the transmitter and interrupt when we can write.
static const uint32_t kTransmitBits = USART_CR1_TE | USART_CR1_TXEIE;
// Enable the receive and interrupt when there's data to read.
static const uint32_t kReceiveBits = USART_CR1_RE | USART_CR1_RXNEIE;
void USART1_IRQHandler(void) {
uint32_t status = UART->SR;
if (status & USART_SR_TXE) {
if ((transmitted_bytes + 1) < transmit_bytes) {
UART->DR = transmit_data[++transmitted_bytes];
} else {
// Get another interrupt when it's done writing that last byte.
UART->CR1 = (UART->CR1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE;
}
} else if (status & USART_SR_RXNE) {
receive_data[++received_bytes] = UART->DR;
if ((received_bytes + 1) >= receive_bytes) {
UART->CR1 &= ~kReceiveBits;
uart_receive_callback(receive_bytes);
}
} else if (status & USART_SR_TC) {
UART->CR1 &= ~(USART_CR1_TCIE | USART_CR1_TE);
uart_transmit_callback(transmit_bytes);
}
}
void uart_configure(void) {
NVIC_SetPriority(USART1_IRQn, 3);
NVIC_EnableIRQ(USART1_IRQn);
}
void uart_transmit(int bytes, uint8_t *data) {
transmit_bytes = bytes;
transmitted_bytes = 0;
transmit_data = data;
compiler_memory_barrier();
UART->CR1 |= kTransmitBits;
UART->DR = data[0];
}
void uart_receive(int bytes, uint8_t *data) {
receive_bytes = bytes;
received_bytes = -1;
receive_data = data;
compiler_memory_barrier();
UART->CR1 |= kReceiveBits;
}