mbv: debugging the async app
This commit is contained in:
parent
e4936abb53
commit
e7b38fb560
@ -63,9 +63,6 @@ async::task<> echo() {
|
||||
|
||||
} // namespace
|
||||
|
||||
#define XUL_SR_RX_FIFO_FULL 0x02 /* receive FIFO full */
|
||||
#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */
|
||||
|
||||
int main() {
|
||||
SetupUart();
|
||||
UartWriteCrash("uart setup done\r\n");
|
||||
@ -99,10 +96,6 @@ int main() {
|
||||
#include "itoa.h"
|
||||
#include "lock.h"
|
||||
|
||||
#ifndef SBRK_STATS
|
||||
#define SBRK_STATS 0
|
||||
#endif
|
||||
|
||||
extern unsigned char _heap_begin, _heap_end;
|
||||
|
||||
extern "C" void* _sbrk(int increment) {
|
||||
|
108
mbv/apps/async/main2.cc
Normal file
108
mbv/apps/async/main2.cc
Normal file
@ -0,0 +1,108 @@
|
||||
#include "buffer.h"
|
||||
#include "gpio.h"
|
||||
#include "intc.h"
|
||||
#include "interrupts.h"
|
||||
#include "pol0.h"
|
||||
#include "timer.h"
|
||||
#include "trace.h"
|
||||
#include "uart2.h"
|
||||
|
||||
namespace {
|
||||
|
||||
Timer* timer0;
|
||||
|
||||
void Uart0Isr() {
|
||||
// ToggleLed(7);
|
||||
HandleUartIsr();
|
||||
}
|
||||
|
||||
void Timer0Isr() {
|
||||
SetLed(6);
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
void SetupUart() {
|
||||
InitUarts();
|
||||
|
||||
intc::SetIsr(UART0_IRQN, Uart0Isr);
|
||||
intc::SetIrqEnabled(UART0_IRQN, true);
|
||||
}
|
||||
|
||||
void SetupTimer() {
|
||||
timer0 = Timer::Instance(TIMER0_BASE);
|
||||
// timer0->SetupAsWdt(100'000 * 1000);
|
||||
timer0->EnableT1();
|
||||
|
||||
intc::SetIsr(TIMER0_IRQN, Timer0Isr);
|
||||
intc::SetIrqEnabled(TIMER0_IRQN, true);
|
||||
}
|
||||
|
||||
void SetupInterrupts() {
|
||||
intc::EnableInterrupts();
|
||||
SetExternalInterruptHandler(intc::InterruptHandler);
|
||||
EnableExternalInterrupts();
|
||||
EnableInterrupts(true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
SetupUart();
|
||||
UartWriteCrash("uart setup done\r\n");
|
||||
SetupTimer();
|
||||
UartWriteCrash("timer setup done\r\n");
|
||||
|
||||
SetupInterrupts();
|
||||
|
||||
UartWriteCrash("init done. starting main loop\r\n");
|
||||
|
||||
UartEcho();
|
||||
|
||||
// should never get here
|
||||
}
|
||||
|
||||
/// stdlib stuff
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "itoa.h"
|
||||
#include "lock.h"
|
||||
|
||||
extern unsigned char _heap_begin, _heap_end;
|
||||
|
||||
extern "C" void* _sbrk(int increment) {
|
||||
static unsigned char* heap = &_heap_begin;
|
||||
unsigned char* prev_heap = heap;
|
||||
if (heap + increment >= &_heap_end) {
|
||||
UartWriteCrash("Heap overflow!\r\n");
|
||||
return reinterpret_cast<void*>(-1);
|
||||
}
|
||||
heap += increment;
|
||||
return prev_heap;
|
||||
}
|
||||
|
||||
extern "C" int _gettimeofday(struct timeval* tv, void* tzvp) {
|
||||
(void)tzvp;
|
||||
uint32_t ticks = timer0->GetT1Ticks();
|
||||
tv->tv_sec = ticks / 100000000;
|
||||
tv->tv_usec = (ticks % 100000000) / 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" uint8_t __atomic_exchange_1(volatile void* ptr, uint8_t val,
|
||||
int memorder) {
|
||||
(void)memorder;
|
||||
auto* dest = reinterpret_cast<volatile uint8_t*>(ptr);
|
||||
bool ret;
|
||||
|
||||
{
|
||||
InterruptLock lock;
|
||||
ret = *dest;
|
||||
*dest = val;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <span>
|
||||
|
||||
#include "lock.h"
|
||||
@ -8,9 +7,9 @@
|
||||
struct RingBuffer {
|
||||
std::span<std::byte> buffer;
|
||||
|
||||
std::atomic<size_t> read_ptr = 0;
|
||||
std::atomic<size_t> write_ptr = 0;
|
||||
std::atomic<bool> full = 0;
|
||||
size_t read_ptr = 0;
|
||||
size_t write_ptr = 0;
|
||||
size_t used = 0;
|
||||
|
||||
bool Store(std::span<const std::byte> data) {
|
||||
InterruptLock lock;
|
||||
@ -53,9 +52,7 @@ struct RingBuffer {
|
||||
return false;
|
||||
}
|
||||
write_ptr = (write_ptr + amount) % buffer.size();
|
||||
if (read_ptr == write_ptr) {
|
||||
full = true;
|
||||
}
|
||||
used = used + amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -66,25 +63,20 @@ struct RingBuffer {
|
||||
return false;
|
||||
}
|
||||
read_ptr = (read_ptr + amount) % buffer.size();
|
||||
if (amount > 0) {
|
||||
full = false;
|
||||
}
|
||||
used = used - amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FreeSpace() const {
|
||||
InterruptLock lock;
|
||||
|
||||
return buffer.size() - AvailableData();
|
||||
return buffer.size() - used;
|
||||
}
|
||||
|
||||
size_t AvailableData() const {
|
||||
InterruptLock lock;
|
||||
|
||||
if (read_ptr == write_ptr) {
|
||||
return full ? buffer.size() : 0;
|
||||
}
|
||||
return (buffer.size() + write_ptr - read_ptr) % buffer.size();
|
||||
return used;
|
||||
}
|
||||
|
||||
uint8_t* RawReadPointer() const {
|
||||
@ -93,16 +85,21 @@ struct RingBuffer {
|
||||
return reinterpret_cast<uint8_t*>(buffer.data() + read_ptr);
|
||||
}
|
||||
|
||||
uint8_t* RawWritePointer() const {
|
||||
InterruptLock lock;
|
||||
|
||||
return reinterpret_cast<uint8_t*>(buffer.data() + write_ptr);
|
||||
}
|
||||
|
||||
size_t ContiguousFreeSpace() const {
|
||||
InterruptLock lock;
|
||||
|
||||
return std::min(FreeSpace(), buffer.size() - write_ptr);
|
||||
}
|
||||
|
||||
size_t ContiguousAvailableData() const {
|
||||
InterruptLock lock;
|
||||
|
||||
if (read_ptr < write_ptr) {
|
||||
return AvailableData();
|
||||
}
|
||||
if (full) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buffer.size() - read_ptr;
|
||||
return std::min(AvailableData(), buffer.size() - read_ptr);
|
||||
}
|
||||
};
|
||||
|
@ -27,6 +27,8 @@ std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
||||
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
||||
|
||||
XUartLite* uart0 = &uart0_inst;
|
||||
|
||||
bool sending;
|
||||
} // namespace
|
||||
|
||||
void InitUarts() {
|
||||
@ -35,9 +37,12 @@ void InitUarts() {
|
||||
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
||||
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
|
||||
sending = false;
|
||||
}
|
||||
|
||||
void UartWriteCrash(std::span<const std::byte> data) {
|
||||
XUartLite_DisableInterrupt(uart0);
|
||||
while (data.size() > 0) {
|
||||
while (XUartLite_IsSending(uart0)) {
|
||||
}
|
||||
@ -48,6 +53,7 @@ void UartWriteCrash(std::span<const std::byte> data) {
|
||||
}
|
||||
while (XUartLite_IsSending(uart0)) {
|
||||
}
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
}
|
||||
|
||||
async::task<> UartWrite(std::span<const std::byte> data) {
|
||||
@ -79,10 +85,11 @@ async::task<> UartWriteLoop(
|
||||
|
||||
{
|
||||
InterruptLock lock;
|
||||
if (!XUartLite_IsSending(uart0)) {
|
||||
if (!sending) {
|
||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||
tx_ring_buffer.ContiguousAvailableData());
|
||||
sending = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,11 +146,13 @@ async::task<buffer> UartRead(int size) {
|
||||
}
|
||||
|
||||
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
||||
sending = false;
|
||||
tx_ring_buffer.Pop(transmitted);
|
||||
if (tx_ring_buffer.AvailableData() > 0) {
|
||||
tracing::trace(tracing::TraceEvent::kUartSend);
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(),
|
||||
tx_ring_buffer.ContiguousAvailableData());
|
||||
sending = true;
|
||||
}
|
||||
async::resume(AwaitableType::kUartTx);
|
||||
}
|
||||
|
119
mbv/apps/async/uart2.cc
Normal file
119
mbv/apps/async/uart2.cc
Normal file
@ -0,0 +1,119 @@
|
||||
#include "uart2.h"
|
||||
|
||||
#include "gpio.h"
|
||||
#include "lock.h"
|
||||
#include "pol0.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "xuartlite.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uintptr_t kUart0BaseAddress = UART0_BASE;
|
||||
XUartLite uart0_inst;
|
||||
XUartLite_Config uart0_config = {
|
||||
.DeviceId = 0,
|
||||
.RegBaseAddr = kUart0BaseAddress,
|
||||
.BaudRate = 115200,
|
||||
.UseParity = false,
|
||||
.DataBits = 8,
|
||||
};
|
||||
|
||||
constexpr size_t kUartRxBufferSize = 256;
|
||||
std::array<std::byte, kUartRxBufferSize> rx_buffer = {};
|
||||
RingBuffer rx_ring_buffer{.buffer = rx_buffer};
|
||||
|
||||
constexpr size_t kUartTxBufferSize = 256;
|
||||
std::array<std::byte, kUartTxBufferSize> tx_buffer = {};
|
||||
RingBuffer tx_ring_buffer{.buffer = tx_buffer};
|
||||
|
||||
XUartLite* uart0 = &uart0_inst;
|
||||
|
||||
volatile int sending = 0;
|
||||
|
||||
void StartReceiving() {
|
||||
while (1) {
|
||||
if (rx_ring_buffer.FreeSpace() < 1) {
|
||||
// woops, full. discard some data
|
||||
// TODO: keep track of overrun stats
|
||||
rx_ring_buffer.Pop(1);
|
||||
}
|
||||
if (XUartLite_Recv(uart0, rx_ring_buffer.RawWritePointer(), 1) < 1) {
|
||||
break;
|
||||
}
|
||||
rx_ring_buffer.Push(1);
|
||||
}
|
||||
}
|
||||
|
||||
void StartSending() {
|
||||
if (tx_ring_buffer.AvailableData() > 0 && sending < 1) {
|
||||
sending += 1;
|
||||
XUartLite_Send(uart0, tx_ring_buffer.RawReadPointer(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::byte UartReadByte() {
|
||||
std::byte c;
|
||||
while (!rx_ring_buffer.Load(std::span{&c, 1})) {
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void UartWriteByte(std::byte c) {
|
||||
while (!tx_ring_buffer.Store(std::span{&c, 1})) {
|
||||
}
|
||||
{
|
||||
InterruptLock lock;
|
||||
StartSending();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void InitUarts() {
|
||||
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
|
||||
|
||||
XUartLite_SetSendHandler(uart0, HandleUartTxFromIsr, nullptr);
|
||||
XUartLite_SetRecvHandler(uart0, HandleUartRxFromIsr, nullptr);
|
||||
StartReceiving();
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
}
|
||||
|
||||
void UartWriteCrash(std::span<const std::byte> data) {
|
||||
XUartLite_DisableInterrupt(uart0);
|
||||
while (data.size() > 0) {
|
||||
while (XUartLite_IsSending(uart0)) {
|
||||
}
|
||||
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_IsSending(uart0)) {
|
||||
}
|
||||
XUartLite_EnableInterrupt(uart0);
|
||||
}
|
||||
|
||||
void UartEcho() {
|
||||
while (1) {
|
||||
gpio0->data = tx_ring_buffer.AvailableData();
|
||||
|
||||
std::byte c = UartReadByte();
|
||||
UartWriteByte(c);
|
||||
|
||||
//gpio0->data = uart0->Stats.ReceiveOverrunErrors;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleUartTxFromIsr(void*, unsigned int transmitted) {
|
||||
sending -= 1;
|
||||
tx_ring_buffer.Pop(transmitted);
|
||||
StartSending();
|
||||
}
|
||||
|
||||
void HandleUartRxFromIsr(void*, unsigned int transmitted) {
|
||||
rx_ring_buffer.Push(transmitted);
|
||||
StartReceiving();
|
||||
}
|
||||
|
||||
void HandleUartIsr() { XUartLite_InterruptHandler(uart0); }
|
18
mbv/apps/async/uart2.h
Normal file
18
mbv/apps/async/uart2.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
void InitUarts();
|
||||
|
||||
// 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()}));
|
||||
}
|
||||
|
||||
void UartEcho();
|
||||
|
||||
void HandleUartTxFromIsr(void*, unsigned int transmitted);
|
||||
void HandleUartRxFromIsr(void*, unsigned int);
|
||||
void HandleUartIsr();
|
4
mbv/configure
vendored
4
mbv/configure
vendored
@ -304,9 +304,9 @@ all = [
|
||||
app_image("async", sources=[
|
||||
"apps/async/async.cc",
|
||||
"apps/async/lock.cc",
|
||||
"apps/async/main.cc",
|
||||
"apps/async/main2.cc",
|
||||
"apps/async/trace.cc",
|
||||
"apps/async/uart.cc",
|
||||
"apps/async/uart2.cc",
|
||||
]),
|
||||
]
|
||||
|
||||
|
62
mbv/testecho.py
Normal file
62
mbv/testecho.py
Normal file
@ -0,0 +1,62 @@
|
||||
import argparse
|
||||
import random
|
||||
import serial
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
tty = "/dev/ttyUSB1"
|
||||
baud = 115200
|
||||
|
||||
|
||||
def sendrecv(s, size, timeout=5):
|
||||
"""Send some data and recv until the same data was received back."""
|
||||
data = random.randbytes(size)
|
||||
return sendcheck(s, data, timeout)
|
||||
|
||||
|
||||
def sendcheck(s, data, timeout=5):
|
||||
s.write(data)
|
||||
received = 0
|
||||
start = time.time()
|
||||
got = bytearray()
|
||||
while received < len(data):
|
||||
r = s.read()
|
||||
got += r
|
||||
try:
|
||||
assert(r == data[received: received + len(r)])
|
||||
assert(time.time() < start + timeout)
|
||||
except:
|
||||
fr = received - 10
|
||||
to = received + len(r) + 1
|
||||
sdat = data[fr: to]
|
||||
rdat = bytes(got[fr: to])
|
||||
print(f"failed after receiving {received} correct bytes")
|
||||
print(f"expected {sdat}")
|
||||
print(f" got {rdat}")
|
||||
sys.exit(-1)
|
||||
|
||||
received += len(r)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
s = serial.Serial(tty, baud, timeout=1)
|
||||
for i in range(12):
|
||||
size = 2**i
|
||||
print(f"Trying with {size} bytes")
|
||||
sendrecv(s, size)
|
||||
data = b'ze%s\x96:M#\xd8\x98\x9d\x96\xf5?\x80c\xc6\xa7\x03\xe0i\x04V\xcb\xa3\x95#GC\xabf\x98'
|
||||
#sendcheck(s, data)
|
||||
|
||||
print("All sizes passed.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user