synth/arm/uart.cc

176 lines
5.3 KiB
C++
Raw Permalink Normal View History

#include "uart.h"
2022-05-17 17:17:56 +00:00
#include "async.h"
2022-05-17 03:56:25 +00:00
#include "gpio.h"
2022-06-19 07:45:04 +00:00
#include "lock.h"
2022-05-17 03:56:25 +00:00
#include "ring_buffer.h"
#include "trace.h"
2022-06-19 07:45:04 +00:00
#include "uart_async.h"
2022-05-17 17:17:56 +00:00
#include "xuartlite.h"
2022-05-17 03:56:25 +00:00
namespace {
2022-05-17 17:17:56 +00:00
using async::AwaitableType;
constexpr uintptr_t kUart0BaseAddress = 0x40001000;
XUartLite uart0_inst;
XUartLite_Config uart0_config = {
.DeviceId = 0,
.RegBaseAddr = kUart0BaseAddress,
.BaudRate = 115200,
.UseParity = false,
.DataBits = 8,
};
2022-05-17 03:56:25 +00:00
constexpr size_t kUartTxBufferSize = 256;
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
XUartLite* uart0 = &uart0_inst;
2022-05-17 17:17:56 +00:00
} // namespace
void InitUarts() {
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
2022-05-17 17:17:56 +00:00
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
XUartLite_EnableInterrupt(uart0);
}
2022-05-17 03:56:25 +00:00
2022-05-17 17:17:56 +00:00
// xuartlite private header stuff
2022-05-17 03:56:25 +00:00
extern "C" uint8_t XUartLite_GetSR(XUartLite* InstancePtr);
#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
2022-05-17 17:17:56 +00:00
void UartWriteCrash(std::span<const std::byte> data) {
2022-05-17 03:56:25 +00:00
while (data.size() > 0) {
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
}
auto* dat =
reinterpret_cast<uint8_t*>(const_cast<std::byte*>(data.data()));
uint8_t sent = XUartLite_Send(uart0, dat, data.size());
data = data.subspan(sent);
}
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
}
}
2022-05-17 17:17:56 +00:00
async::task<> UartWrite(std::span<const std::byte> data) {
while (!tx_ring_buffer.Store(data)) {
2022-06-19 07:45:04 +00:00
tracing::trace(tracing::TraceEvent::kUartTxBufferFull);
2022-05-17 17:17:56 +00:00
co_await async::await(AwaitableType::kUartTx);
2022-06-19 07:45:04 +00:00
tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull);
2022-05-17 17:17:56 +00:00
}
2022-06-19 07:45:04 +00:00
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
2022-05-17 17:17:56 +00:00
}
}
#define GCC_HAS_BUG_101133 0 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101133
2022-06-19 07:45:04 +00:00
#if !GCC_HAS_BUG_101133
async::task<> UartWriteLoop(async::gimme<std::span<const std::byte>>& data_gen) {
while (1) {
auto data = co_await data_gen;
while (!tx_ring_buffer.Store(data)) {
tracing::trace(tracing::TraceEvent::kUartTxBufferFull);
co_await async::await(AwaitableType::kUartTx);
tracing::trace(tracing::TraceEvent::kUartTxBufferNotFull);
}
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
}
}
}
#endif // !GCC_HAS_BUG_101133
2022-05-17 17:17:56 +00:00
void UartReadBlocking(std::span<std::byte> data) {
size_t bytes_received = 0;
while (bytes_received < data.size()) {
auto* buffer = reinterpret_cast<uint8_t*>(data.data() + bytes_received);
2022-06-19 07:45:04 +00:00
tracing::trace(tracing::TraceEvent::kUartRecv);
2022-05-17 17:17:56 +00:00
bytes_received +=
XUartLite_Recv(uart0, buffer, data.size() - bytes_received);
}
}
void UartWriteBlocking(std::span<const std::byte> data) {
2022-06-19 07:45:04 +00:00
if (__get_PRIMASK() != 0) {
UartWriteCrash("\r\nUartWriteBlocking called with interupts disabled!\r\n");
__builtin_trap();
}
2022-05-17 03:56:25 +00:00
while (!tx_ring_buffer.Store(data)) {
}
2022-06-19 07:45:04 +00:00
{
InterruptLock lock;
if (!XUartLite_IsSending(uart0)) {
tracing::trace(tracing::TraceEvent::kUartSend);
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
}
}
async::task<uint8_t> UartReadLoop() {
uint8_t c;
while (1) {
tracing::trace(tracing::TraceEvent::kUartRecv);
size_t received = XUartLite_Recv(uart0, &c, 1);
// some data may already be in the fifo, but if not, wait:
if (received < 1) {
co_await async::await(AwaitableType::kUartRx);
}
co_yield c;
2022-05-17 03:56:25 +00:00
}
}
2022-05-17 17:17:56 +00:00
async::task<buffer> UartRead(int size) {
auto buff = buffer::make(size);
auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
2022-06-19 07:45:04 +00:00
tracing::trace(tracing::TraceEvent::kUartRecv);
2022-05-17 17:17:56 +00:00
size_t received = XUartLite_Recv(uart0, data, buff.data.size());
2022-06-19 07:45:04 +00:00
// some data may already be in the fifo, but if not, wait:
2022-05-17 17:17:56 +00:00
if (received < buff.data.size()) {
co_await async::await(AwaitableType::kUartRx);
}
co_return buff;
}
2022-05-17 03:56:25 +00:00
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
tx_ring_buffer.Pop(transmitted);
if (tx_ring_buffer.AvailableData() > 0) {
2022-06-19 07:45:04 +00:00
tracing::trace(tracing::TraceEvent::kUartSend);
2022-05-17 03:56:25 +00:00
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
tx_ring_buffer.ContiguousAvailableData());
}
2022-05-17 17:17:56 +00:00
async::resume(AwaitableType::kUartTx);
2022-05-17 03:56:25 +00:00
}
2022-05-17 17:17:56 +00:00
void HandleUartRxFromIsr(void*, unsigned int) {
async::resume(AwaitableType::kUartRx);
}
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }
2022-06-19 07:45:04 +00:00
extern "C" uint8_t XUartLite_GetSR(XUartLite*);
uint8_t UartStatus() { return XUartLite_GetSR(uart0); }
void LogStuff() {
uint8_t data = gpio0->data;
data |= (uart0->ReceiveBuffer.RemainingBytes & 0xf) << 4;
gpio0->data = data;
}