mirror of
https://github.com/halleysfifthinc/AVCLAN-Mockingboard.git
synced 2026-08-11 08:22:52 +00:00
Fix intermittent, early boot short start bit errors
This commit is contained in:
+2
-1
@@ -143,7 +143,8 @@ struct Error {
|
|||||||
BAD_CONTROLLER_PARITY,
|
BAD_CONTROLLER_PARITY,
|
||||||
BAD_CONTROL_PARITY,
|
BAD_CONTROL_PARITY,
|
||||||
BAD_PARITY, // generic bad parity has max severity
|
BAD_PARITY, // generic bad parity has max severity
|
||||||
STARTBIT_TOO_SHORT,
|
STARTBIT_MISSED,
|
||||||
|
STARTBIT_MALFORMED,
|
||||||
STARTBIT_TOO_LONG,
|
STARTBIT_TOO_LONG,
|
||||||
BAD_STARTBIT,
|
BAD_STARTBIT,
|
||||||
POOL_EMPTY, // non-bus error
|
POOL_EMPTY, // non-bus error
|
||||||
|
|||||||
+5
-2
@@ -289,7 +289,10 @@ auto Bus::read(uint16_t address, Frame::Print print)
|
|||||||
switch (err.errno) {
|
switch (err.errno) {
|
||||||
case POOL_EMPTY: puts("failed Frame alloc"); break;
|
case POOL_EMPTY: puts("failed Frame alloc"); break;
|
||||||
case BAD_STARTBIT: fputs("bad start bit (other)", stdout); break;
|
case BAD_STARTBIT: fputs("bad start bit (other)", stdout); break;
|
||||||
case STARTBIT_TOO_SHORT: fputs("bad start bit (short)", stdout); break;
|
case STARTBIT_MISSED: fputs("missed start bit", stdout); break;
|
||||||
|
case STARTBIT_MALFORMED:
|
||||||
|
fputs("malformed start bit (external cause)", stdout);
|
||||||
|
break;
|
||||||
case STARTBIT_TOO_LONG: fputs("bad start bit (long)", stdout); break;
|
case STARTBIT_TOO_LONG: fputs("bad start bit (long)", stdout); break;
|
||||||
case BAD_CONTROLLER_PARITY:
|
case BAD_CONTROLLER_PARITY:
|
||||||
fputs("reading controller addr.", stdout);
|
fputs("reading controller addr.", stdout);
|
||||||
@@ -312,7 +315,7 @@ auto Bus::read(uint16_t address, Frame::Print print)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only print if some data has been correctly received
|
// Only print if some data has been correctly received
|
||||||
if (print.print && (err.errno < STARTBIT_TOO_SHORT)) {
|
if (print.print && (err.errno < STARTBIT_MISSED)) {
|
||||||
if (err.errno > BAD_DATA_PARITY)
|
if (err.errno > BAD_DATA_PARITY)
|
||||||
in->length = 0;
|
in->length = 0;
|
||||||
in->print(print);
|
in->print(print);
|
||||||
|
|||||||
@@ -344,6 +344,14 @@ void phy_init() {
|
|||||||
// error reporting; no printing happens here.
|
// error reporting; no printing happens here.
|
||||||
Read phy_read_startbit() {
|
Read phy_read_startbit() {
|
||||||
uint16_t startbitlen = TCB1.CNT = 0;
|
uint16_t startbitlen = TCB1.CNT = 0;
|
||||||
|
|
||||||
|
// Reset the ~atomic `pulsewidth` variable to detect the post-pulse update
|
||||||
|
// from the TCB0_INT_vect ISR
|
||||||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||||
|
if (!BUS_IS_IDLE) // Only reset if bus is actively driven (i.e. current
|
||||||
|
pulsewidth = 0; // value is stale/already been used)
|
||||||
|
}
|
||||||
|
|
||||||
while (!BUS_IS_IDLE) {
|
while (!BUS_IS_IDLE) {
|
||||||
startbitlen = TCB1.CNT;
|
startbitlen = TCB1.CNT;
|
||||||
if (startbitlen > (uint16_t)AVCLAN_STARTBIT_LOGIC_0 * 1.2) {
|
if (startbitlen > (uint16_t)AVCLAN_STARTBIT_LOGIC_0 * 1.2) {
|
||||||
@@ -367,18 +375,34 @@ Read phy_read_startbit() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `pulsewidth` updates once the TCB0_INT_vect ISR runs for this pulse.
|
||||||
|
TCB1.CNT = 0;
|
||||||
|
do {
|
||||||
|
if (TCB1.CNT > (uint16_t)AVCLAN_BIT0_LOGIC_1) // Wait a max of ~6μs for ISR
|
||||||
|
return BAD_STARTBIT; // ISR/other implementation bug; abort
|
||||||
|
|
||||||
|
// Read ~atomically, to prevent torn reads
|
||||||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { startbitlen = pulsewidth; }
|
||||||
|
} while (startbitlen == 0);
|
||||||
|
|
||||||
if (startbitlen < (uint16_t)(AVCLAN_STARTBIT_LOGIC_0 * 0.8)) {
|
if (startbitlen < (uint16_t)(AVCLAN_STARTBIT_LOGIC_0 * 0.8)) {
|
||||||
// We missed the beginning of this message; wait for it to finish (bus
|
// Not a start bit; wait for the message to finish (bus continuously idle
|
||||||
// continuously idle for >1 bit length) before returning, so we don't have
|
// for >1 bit length) before returning, so we only report one error (instead
|
||||||
// multiple false-starts while the in-progress message keeps sending more
|
// of e.g. repeated "bad (short) start bit" errors)
|
||||||
// bits.
|
|
||||||
TCB1.CNT = 0;
|
TCB1.CNT = 0;
|
||||||
while (TCB1.CNT < (uint16_t)(AVCLAN_BIT_LENGTH_MAX * 1.2)) {
|
while (TCB1.CNT < (uint16_t)(AVCLAN_BIT_LENGTH_MAX * 1.2)) {
|
||||||
if (!BUS_IS_IDLE)
|
if (!BUS_IS_IDLE)
|
||||||
TCB1.CNT = 0;
|
TCB1.CNT = 0; // Reset counter after each bit pulse
|
||||||
}
|
}
|
||||||
return STARTBIT_TOO_SHORT;
|
// A pulse no wider than a normal bit means we merely tuned in mid-frame and
|
||||||
|
// this was a data bit; a wider-but-still-sub-start pulse means some other
|
||||||
|
// device emitted a wonky pulse.
|
||||||
|
return (startbitlen < (uint16_t)AVCLAN_BIT_LENGTH_MAX) ? STARTBIT_MISSED
|
||||||
|
: STARTBIT_MALFORMED;
|
||||||
}
|
}
|
||||||
|
if (startbitlen > (uint16_t)(AVCLAN_STARTBIT_LOGIC_0 * 1.2))
|
||||||
|
return STARTBIT_TOO_LONG;
|
||||||
return (Read)0; // that was a start bit
|
return (Read)0; // that was a start bit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user