arm: async uart writes & fixes
This commit is contained in:
parent
e9f623e754
commit
e39cdc5709
68
arm/async.h
68
arm/async.h
@ -6,27 +6,32 @@
|
|||||||
|
|
||||||
namespace async {
|
namespace async {
|
||||||
|
|
||||||
template<typename T = void>
|
struct task_final_suspend {
|
||||||
|
bool await_ready() noexcept(true) { return false; }
|
||||||
|
void await_suspend(std::coroutine_handle<> h) noexcept(true) {
|
||||||
|
if (parent) {
|
||||||
|
parent();
|
||||||
|
}
|
||||||
|
h.destroy();
|
||||||
|
}
|
||||||
|
void await_resume() noexcept(true) {}
|
||||||
|
|
||||||
|
std::coroutine_handle<> parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T = void>
|
||||||
struct task {
|
struct task {
|
||||||
struct promise_type;
|
struct promise_type;
|
||||||
using handle_type = std::coroutine_handle<promise_type>;
|
using handle_type = std::coroutine_handle<promise_type>;
|
||||||
|
|
||||||
struct maybe_suspend {
|
|
||||||
bool await_ready() noexcept(true) { return !parent; }
|
|
||||||
void await_suspend(std::coroutine_handle<>) noexcept(true) {
|
|
||||||
if (parent) {
|
|
||||||
parent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void await_resume() noexcept(true) { }
|
|
||||||
|
|
||||||
std::coroutine_handle<> parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct promise_type {
|
struct promise_type {
|
||||||
task get_return_object() { return {.h = handle_type::from_promise(*this)}; }
|
task get_return_object() {
|
||||||
|
return {.h = handle_type::from_promise(*this)};
|
||||||
|
}
|
||||||
std::suspend_always initial_suspend() noexcept { return {}; }
|
std::suspend_always initial_suspend() noexcept { return {}; }
|
||||||
maybe_suspend final_suspend() noexcept { return { .parent = parent }; }
|
task_final_suspend final_suspend() noexcept {
|
||||||
|
return {.parent = parent};
|
||||||
|
}
|
||||||
void return_value(T&& value) { ret_value = std::move(value); }
|
void return_value(T&& value) { ret_value = std::move(value); }
|
||||||
void unhandled_exception() {}
|
void unhandled_exception() {}
|
||||||
|
|
||||||
@ -45,27 +50,19 @@ struct task {
|
|||||||
std::coroutine_handle<promise_type> h;
|
std::coroutine_handle<promise_type> h;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
struct task<void> {
|
struct task<void> {
|
||||||
struct promise_type;
|
struct promise_type;
|
||||||
using handle_type = std::coroutine_handle<promise_type>;
|
using handle_type = std::coroutine_handle<promise_type>;
|
||||||
|
|
||||||
struct maybe_suspend {
|
|
||||||
bool await_ready() noexcept(true) { return !parent; }
|
|
||||||
void await_suspend(std::coroutine_handle<>) noexcept(true) {
|
|
||||||
if (parent) {
|
|
||||||
parent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void await_resume() noexcept(true) { }
|
|
||||||
|
|
||||||
std::coroutine_handle<> parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct promise_type {
|
struct promise_type {
|
||||||
task get_return_object() { return {.h = handle_type::from_promise(*this)}; }
|
task get_return_object() {
|
||||||
|
return {.h = handle_type::from_promise(*this)};
|
||||||
|
}
|
||||||
std::suspend_always initial_suspend() noexcept { return {}; }
|
std::suspend_always initial_suspend() noexcept { return {}; }
|
||||||
maybe_suspend final_suspend() noexcept { return { .parent = parent }; }
|
task_final_suspend final_suspend() noexcept {
|
||||||
|
return {.parent = parent};
|
||||||
|
}
|
||||||
void return_void() {}
|
void return_void() {}
|
||||||
void unhandled_exception() {}
|
void unhandled_exception() {}
|
||||||
|
|
||||||
@ -75,8 +72,8 @@ struct task<void> {
|
|||||||
// awaitable
|
// awaitable
|
||||||
bool await_ready() { return h.done(); }
|
bool await_ready() { return h.done(); }
|
||||||
void await_suspend(std::coroutine_handle<> ha) {
|
void await_suspend(std::coroutine_handle<> ha) {
|
||||||
h();
|
|
||||||
h.promise().parent = ha;
|
h.promise().parent = ha;
|
||||||
|
h();
|
||||||
}
|
}
|
||||||
void await_resume() {}
|
void await_resume() {}
|
||||||
|
|
||||||
@ -86,6 +83,7 @@ struct task<void> {
|
|||||||
enum class AwaitableType {
|
enum class AwaitableType {
|
||||||
kUnknown = 0,
|
kUnknown = 0,
|
||||||
kUartRx = 1,
|
kUartRx = 1,
|
||||||
|
kUartTx = 2,
|
||||||
|
|
||||||
kNumTypes
|
kNumTypes
|
||||||
};
|
};
|
||||||
@ -101,9 +99,7 @@ inline auto await(AwaitableType type) {
|
|||||||
AwaitableType type;
|
AwaitableType type;
|
||||||
|
|
||||||
bool await_ready() { return false; };
|
bool await_ready() { return false; };
|
||||||
void await_suspend(std::coroutine_handle<> h) {
|
void await_suspend(std::coroutine_handle<> h) { enqueue(h, type); }
|
||||||
enqueue(h, type);
|
|
||||||
}
|
|
||||||
void await_resume() {}
|
void await_resume() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,9 +111,7 @@ inline auto delay(int ms) {
|
|||||||
int ms;
|
int ms;
|
||||||
|
|
||||||
bool await_ready() { return false; };
|
bool await_ready() { return false; };
|
||||||
void await_suspend(std::coroutine_handle<> h) {
|
void await_suspend(std::coroutine_handle<> h) { schedule(h, ms); }
|
||||||
schedule(h, ms);
|
|
||||||
}
|
|
||||||
void await_resume() {}
|
void await_resume() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
11
arm/buffer.h
11
arm/buffer.h
@ -17,7 +17,14 @@ struct buffer {
|
|||||||
buffer& operator=(buffer& other) = delete;
|
buffer& operator=(buffer& other) = delete;
|
||||||
|
|
||||||
buffer(buffer&& other) : data(std::exchange(other.data, {})) {}
|
buffer(buffer&& other) : data(std::exchange(other.data, {})) {}
|
||||||
buffer& operator=(buffer&& other) { data = std::exchange(other.data, {}); return *this; }
|
buffer& operator=(buffer&& other) {
|
||||||
|
data = std::exchange(other.data, {});
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
~buffer() { if (data.data()) { delete[] data.data(); }; }
|
~buffer() {
|
||||||
|
if (data.data()) {
|
||||||
|
delete[] data.data();
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
33
arm/crash.cc
33
arm/crash.cc
@ -15,19 +15,19 @@ namespace {
|
|||||||
char addr[] = "00000000: ";
|
char addr[] = "00000000: ";
|
||||||
int i = 0;
|
int i = 0;
|
||||||
itoa(reinterpret_cast<uint32_t>(begin), addr);
|
itoa(reinterpret_cast<uint32_t>(begin), addr);
|
||||||
UartSendCrash(addr);
|
UartWriteCrash(addr);
|
||||||
for (uint32_t* ptr = begin; direction > 0 ? ptr < end : ptr > end;
|
for (uint32_t* ptr = begin; direction > 0 ? ptr < end : ptr > end;
|
||||||
ptr += direction, i++) {
|
ptr += direction, i++) {
|
||||||
itoa(*ptr, number);
|
itoa(*ptr, number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
if (i % 4 == 3) {
|
if (i % 4 == 3) {
|
||||||
UartSendCrash("\r\n");
|
UartWriteCrash("\r\n");
|
||||||
itoa(reinterpret_cast<uint32_t>(ptr + 1), addr);
|
itoa(reinterpret_cast<uint32_t>(ptr + 1), addr);
|
||||||
UartSendCrash(addr);
|
UartWriteCrash(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i % 4 != 3) {
|
if (i % 4 != 3) {
|
||||||
UartSendCrash("\r\n");
|
UartWriteCrash("\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ void StackTrace(uint32_t* sp) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
itoa(*ptr, number);
|
itoa(*ptr, number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,16 +68,16 @@ struct Armv6mRegs {
|
|||||||
void CrashHandler(Armv6mRegs* regs) {
|
void CrashHandler(Armv6mRegs* regs) {
|
||||||
char number[] = "00000000\r\n";
|
char number[] = "00000000\r\n";
|
||||||
|
|
||||||
UartSendCrash("\r\n\r\nCra$h!!\r\n- xpsr: 0x");
|
UartWriteCrash("\r\n\r\nCra$h!!\r\n- xpsr: 0x");
|
||||||
itoa(regs->xpsr, number);
|
itoa(regs->xpsr, number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
UartSendCrash("- pc: 0x");
|
UartWriteCrash("- pc: 0x");
|
||||||
itoa(regs->pc, number);
|
itoa(regs->pc, number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
UartSendCrash("- lr: 0x");
|
UartWriteCrash("- lr: 0x");
|
||||||
itoa(regs->lr, number);
|
itoa(regs->lr, number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
UartSendCrash("- Stack trace:\r\n");
|
UartWriteCrash("- Stack trace:\r\n");
|
||||||
StackTrace(reinterpret_cast<uint32_t*>(regs->sp));
|
StackTrace(reinterpret_cast<uint32_t*>(regs->sp));
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -103,10 +103,13 @@ __attribute__((naked)) void HardFaultHandler() {
|
|||||||
"mrs lr, msp \n"
|
"mrs lr, msp \n"
|
||||||
"push {r0-r3, lr} \n"
|
"push {r0-r3, lr} \n"
|
||||||
"push {r4-r7} \n"
|
"push {r4-r7} \n"
|
||||||
|
:
|
||||||
|
: "r"(gpio0));
|
||||||
|
asm volatile(
|
||||||
"mrs r0, msp \n"
|
"mrs r0, msp \n"
|
||||||
"mov r1, %1 \n"
|
"mov r1, %0 \n"
|
||||||
"blx r1 \n"
|
"blx r1 \n"
|
||||||
:
|
:
|
||||||
: "r"(gpio0), "r"(CrashHandler));
|
: "r"(CrashHandler));
|
||||||
}
|
}
|
||||||
} // namespace crash
|
} // namespace crash
|
||||||
|
@ -6,7 +6,7 @@ struct Gpio {
|
|||||||
volatile uint32_t data;
|
volatile uint32_t data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define gpio0 ((Gpio*) 0x40000000)
|
#define gpio0 ((Gpio*)0x40000000)
|
||||||
|
|
||||||
inline void ToggleLed(int which) {
|
inline void ToggleLed(int which) {
|
||||||
uint8_t data = gpio0->data;
|
uint8_t data = gpio0->data;
|
||||||
|
@ -5,10 +5,7 @@
|
|||||||
struct InterruptLock {
|
struct InterruptLock {
|
||||||
bool was_locked;
|
bool was_locked;
|
||||||
|
|
||||||
InterruptLock()
|
InterruptLock() : was_locked(__get_PRIMASK() != 0) { __disable_irq(); }
|
||||||
: was_locked(__get_PRIMASK() != 0) {
|
|
||||||
__disable_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
~InterruptLock() {
|
~InterruptLock() {
|
||||||
if (!was_locked) {
|
if (!was_locked) {
|
||||||
|
23
arm/main.cc
23
arm/main.cc
@ -10,14 +10,9 @@
|
|||||||
namespace {
|
namespace {
|
||||||
using async::AwaitableType;
|
using async::AwaitableType;
|
||||||
|
|
||||||
void HandleUartRxFromIsr(void*, unsigned int) {
|
|
||||||
tracing::trace(tracing::TraceEvent::kUartRxCb);
|
|
||||||
async::resume(AwaitableType::kUartRx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Uart0Isr() {
|
void Uart0Isr() {
|
||||||
tracing::trace(tracing::TraceEvent::kUartIsr);
|
tracing::trace(tracing::TraceEvent::kUartIsr);
|
||||||
XUartLite_InterruptHandler(uart0);
|
HandleUartIsr();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer0Isr() {
|
void Timer0Isr() {
|
||||||
@ -36,10 +31,6 @@ void SetupUart() {
|
|||||||
vector_table[16 + Timer0_IRQn] = reinterpret_cast<uint32_t>(Timer0Isr);
|
vector_table[16 + Timer0_IRQn] = reinterpret_cast<uint32_t>(Timer0Isr);
|
||||||
NVIC_SetPriority(Uart0_IRQn, 3);
|
NVIC_SetPriority(Uart0_IRQn, 3);
|
||||||
NVIC_EnableIRQ(Uart0_IRQn);
|
NVIC_EnableIRQ(Uart0_IRQn);
|
||||||
|
|
||||||
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
|
||||||
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
|
||||||
XUartLite_EnableInterrupt(uart0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupTimer() {
|
void SetupTimer() {
|
||||||
@ -49,20 +40,10 @@ void SetupTimer() {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
async::task<buffer> UartRead(int size) {
|
|
||||||
auto buff = buffer::make(size);
|
|
||||||
auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
|
|
||||||
size_t received = XUartLite_Recv(uart0, data, buff.data.size());
|
|
||||||
if (received < buff.data.size()) {
|
|
||||||
co_await async::await(AwaitableType::kUartRx);
|
|
||||||
}
|
|
||||||
co_return buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
async::task<> echo() {
|
async::task<> echo() {
|
||||||
while (1) {
|
while (1) {
|
||||||
buffer buff = co_await UartRead(1);
|
buffer buff = co_await UartRead(1);
|
||||||
UartSend(buff.data);
|
co_await UartWrite(buff.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ includes += -Ihal/lib/common
|
|||||||
sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c hal/uart/xuartlite_intr.c
|
sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c hal/uart/xuartlite_intr.c
|
||||||
includes += -Ihal/uart
|
includes += -Ihal/uart
|
||||||
|
|
||||||
bootloader_objects = uart.o bootloader.o vector_table.o $(sources:.c=.o)
|
bootloader_objects = bootloader.o vector_table.o $(sources:.c=.o)
|
||||||
app_objects = app_init.o crash.o main.o uart.o stdlib.o async.o trace.o $(sources:.c=.o)
|
app_objects = app_init.o crash.o main.o uart.o stdlib.o async.o trace.o $(sources:.c=.o)
|
||||||
|
|
||||||
CPPFLAGS += $(includes)
|
CPPFLAGS += $(includes)
|
||||||
|
@ -15,7 +15,8 @@ struct RingBuffer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const size_t to_copy = std::min(buffer.size() - write_ptr, data.size());
|
const size_t to_copy = std::min(buffer.size() - write_ptr, data.size());
|
||||||
std::copy(data.begin(), data.begin() + to_copy, buffer.begin() + write_ptr);
|
std::copy(data.begin(), data.begin() + to_copy,
|
||||||
|
buffer.begin() + write_ptr);
|
||||||
if (to_copy < data.size()) {
|
if (to_copy < data.size()) {
|
||||||
std::copy(data.begin() + to_copy, data.end(), buffer.begin());
|
std::copy(data.begin() + to_copy, data.end(), buffer.begin());
|
||||||
}
|
}
|
||||||
@ -29,9 +30,11 @@ struct RingBuffer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const size_t to_copy = std::min(buffer.size() - read_ptr, out.size());
|
const size_t to_copy = std::min(buffer.size() - read_ptr, out.size());
|
||||||
std::copy(buffer.begin() + read_ptr, buffer.begin() + read_ptr + to_copy, out.begin());
|
std::copy(buffer.begin() + read_ptr,
|
||||||
|
buffer.begin() + read_ptr + to_copy, out.begin());
|
||||||
if (to_copy < out.size()) {
|
if (to_copy < out.size()) {
|
||||||
std::copy(buffer.begin(), buffer.begin() + out.size() - to_copy, out.begin() + to_copy);
|
std::copy(buffer.begin(), buffer.begin() + out.size() - to_copy,
|
||||||
|
out.begin() + to_copy);
|
||||||
}
|
}
|
||||||
Pop(out.size());
|
Pop(out.size());
|
||||||
return true;
|
return true;
|
||||||
@ -59,9 +62,7 @@ struct RingBuffer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FreeSpace() const {
|
size_t FreeSpace() const { return buffer.size() - AvailableData(); }
|
||||||
return buffer.size() - AvailableData();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AvailableData() const {
|
size_t AvailableData() const {
|
||||||
if (read_ptr == write_ptr) {
|
if (read_ptr == write_ptr) {
|
||||||
|
@ -12,9 +12,9 @@ extern unsigned char _heap_begin, _heap_end;
|
|||||||
namespace {
|
namespace {
|
||||||
void LogStats(unsigned char* heap) {
|
void LogStats(unsigned char* heap) {
|
||||||
char number[] = "00000000\r\n";
|
char number[] = "00000000\r\n";
|
||||||
UartSend("Program break now at 0x");
|
UartWriteBlocking("Program break now at 0x");
|
||||||
itoa(reinterpret_cast<int>(heap), number);
|
itoa(reinterpret_cast<int>(heap), number);
|
||||||
UartSend(number);
|
UartWriteBlocking(number);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ extern "C" void* _sbrk(int increment) {
|
|||||||
static unsigned char* heap = &_heap_begin;
|
static unsigned char* heap = &_heap_begin;
|
||||||
unsigned char* prev_heap = heap;
|
unsigned char* prev_heap = heap;
|
||||||
if (heap + increment >= &_heap_end) {
|
if (heap + increment >= &_heap_end) {
|
||||||
UartSend("Heap overflow!\r\n");
|
UartWriteBlocking("Heap overflow!\r\n");
|
||||||
return reinterpret_cast<void*>(-1);
|
return reinterpret_cast<void*>(-1);
|
||||||
}
|
}
|
||||||
heap += increment;
|
heap += increment;
|
||||||
|
@ -38,9 +38,7 @@ struct Timer {
|
|||||||
TCSR1.ENT0 = 1;
|
TCSR1.ENT0 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetT1Ticks() {
|
uint32_t GetT1Ticks() { return TCR1; }
|
||||||
return TCR1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupAsWdt(uint32_t timeout_ticks) {
|
void SetupAsWdt(uint32_t timeout_ticks) {
|
||||||
TLR0 = timeout_ticks;
|
TLR0 = timeout_ticks;
|
||||||
@ -60,4 +58,4 @@ struct Timer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define timer0 ((Timer*) 0x40002000)
|
#define timer0 ((Timer*)0x40002000)
|
||||||
|
@ -32,7 +32,7 @@ void dump() {
|
|||||||
|
|
||||||
for (TraceEvent event : buffer) {
|
for (TraceEvent event : buffer) {
|
||||||
itoa(static_cast<int>(event), number);
|
itoa(static_cast<int>(event), number);
|
||||||
UartSendCrash(number);
|
UartWriteCrash(number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace tracing
|
} // namespace tracing
|
||||||
|
54
arm/uart.cc
54
arm/uart.cc
@ -1,10 +1,13 @@
|
|||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
|
||||||
|
#include "async.h"
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "ring_buffer.h"
|
#include "ring_buffer.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#include "xuartlite.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
using async::AwaitableType;
|
||||||
|
|
||||||
constexpr uintptr_t kUart0BaseAddress = 0x40001000;
|
constexpr uintptr_t kUart0BaseAddress = 0x40001000;
|
||||||
XUartLite uart0_inst;
|
XUartLite uart0_inst;
|
||||||
@ -20,18 +23,22 @@ constexpr size_t kUartTxBufferSize = 256;
|
|||||||
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
||||||
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
XUartLite* uart0 = &uart0_inst;
|
XUartLite* uart0 = &uart0_inst;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void InitUarts() {
|
void InitUarts() {
|
||||||
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
|
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
|
||||||
|
|
||||||
|
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
||||||
|
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
||||||
|
XUartLite_EnableInterrupt(uart0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xuartlite private header stuff
|
||||||
extern "C" uint8_t XUartLite_GetSR(XUartLite* InstancePtr);
|
extern "C" uint8_t XUartLite_GetSR(XUartLite* InstancePtr);
|
||||||
#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
|
#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */
|
||||||
|
|
||||||
void UartSendCrash(std::span<const std::byte> data) {
|
void UartWriteCrash(std::span<const std::byte> data) {
|
||||||
while (data.size() > 0) {
|
while (data.size() > 0) {
|
||||||
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
|
while ((XUartLite_GetSR(uart0) & XUL_SR_TX_FIFO_EMPTY) == 0) {
|
||||||
}
|
}
|
||||||
@ -44,8 +51,27 @@ void UartSendCrash(std::span<const std::byte> data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blocking
|
async::task<> UartWrite(std::span<const std::byte> data) {
|
||||||
void UartSend(std::span<const std::byte> data) {
|
while (!tx_ring_buffer.Store(data)) {
|
||||||
|
co_await async::await(AwaitableType::kUartTx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!XUartLite_IsSending(uart0)) {
|
||||||
|
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||||
|
tx_ring_buffer.ContiguousAvailableData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
bytes_received +=
|
||||||
|
XUartLite_Recv(uart0, buffer, data.size() - bytes_received);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartWriteBlocking(std::span<const std::byte> data) {
|
||||||
while (!tx_ring_buffer.Store(data)) {
|
while (!tx_ring_buffer.Store(data)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +81,16 @@ void UartSend(std::span<const std::byte> data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async::task<buffer> UartRead(int size) {
|
||||||
|
auto buff = buffer::make(size);
|
||||||
|
auto* data = reinterpret_cast<uint8_t*>(buff.data.data());
|
||||||
|
size_t received = XUartLite_Recv(uart0, data, buff.data.size());
|
||||||
|
if (received < buff.data.size()) {
|
||||||
|
co_await async::await(AwaitableType::kUartRx);
|
||||||
|
}
|
||||||
|
co_return buff;
|
||||||
|
}
|
||||||
|
|
||||||
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
||||||
tracing::trace(tracing::TraceEvent::kUartTxCb);
|
tracing::trace(tracing::TraceEvent::kUartTxCb);
|
||||||
tx_ring_buffer.Pop(transmitted);
|
tx_ring_buffer.Pop(transmitted);
|
||||||
@ -62,4 +98,12 @@ void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
|||||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||||
tx_ring_buffer.ContiguousAvailableData());
|
tx_ring_buffer.ContiguousAvailableData());
|
||||||
}
|
}
|
||||||
|
async::resume(AwaitableType::kUartTx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandleUartRxFromIsr(void*, unsigned int) {
|
||||||
|
tracing::trace(tracing::TraceEvent::kUartRxCb);
|
||||||
|
async::resume(AwaitableType::kUartRx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }
|
||||||
|
37
arm/uart.h
37
arm/uart.h
@ -3,20 +3,37 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "xuartlite.h"
|
#include "async.h"
|
||||||
|
#include "buffer.h"
|
||||||
extern XUartLite* uart0;
|
|
||||||
|
|
||||||
void InitUarts();
|
void InitUarts();
|
||||||
|
|
||||||
// blocking
|
async::task<buffer> UartRead(int size);
|
||||||
void UartSend(std::span<const std::byte> data);
|
async::task<> UartWrite(std::span<const std::byte> data);
|
||||||
inline void UartSend(std::string_view s) {
|
inline async::task<> UartWrite(std::string_view s) {
|
||||||
return UartSend(std::as_bytes(std::span{s.data(), s.size()}));
|
co_await UartWrite(std::as_bytes(std::span{s.data(), s.size()}));
|
||||||
}
|
}
|
||||||
void UartSendCrash(std::span<const std::byte> data);
|
|
||||||
inline void UartSendCrash(std::string_view s) {
|
// block until the provided buffer is full
|
||||||
return UartSendCrash(std::as_bytes(std::span{s.data(), s.size()}));
|
void UartReadBlocking(std::span<std::byte> data);
|
||||||
|
inline uint8_t UartReadByteBlocking() {
|
||||||
|
std::byte byte;
|
||||||
|
UartReadBlocking(std::span{&byte, 1});
|
||||||
|
return static_cast<uint8_t>(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send and poll the uart until transmitted
|
||||||
|
void UartWriteCrash(std::span<const std::byte> data);
|
||||||
|
inline void UartWriteCrash(std::string_view s) {
|
||||||
|
return UartWriteCrash(std::as_bytes(std::span{s.data(), s.size()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// block until room is available in tx fifo, then send
|
||||||
|
void UartWriteBlocking(std::span<const std::byte> data);
|
||||||
|
inline void UartWriteBlocking(std::string_view s) {
|
||||||
|
return UartWriteBlocking(std::as_bytes(std::span{s.data(), s.size()}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleUartTxFromIsr(void*, unsigned int transmitted);
|
void HandleUartTxFromIsr(void*, unsigned int transmitted);
|
||||||
|
void HandleUartRxFromIsr(void*, unsigned int);
|
||||||
|
void HandleUartIsr();
|
||||||
|
Loading…
Reference in New Issue
Block a user