From aa5459ba94fef7e97e34f6904bfdda5f0d4f7c08 Mon Sep 17 00:00:00 2001 From: Andrew Kay Date: Tue, 7 Jul 2020 16:56:32 -0500 Subject: [PATCH] Firmware update... --- interface2/firmware/include/NewCoax.h | 44 +++++ interface2/firmware/src/NewCoax.cpp | 242 ++++++++++++++++++++++++++ interface2/firmware/src/main.cpp | 47 +---- 3 files changed, 293 insertions(+), 40 deletions(-) create mode 100644 interface2/firmware/include/NewCoax.h create mode 100644 interface2/firmware/src/NewCoax.cpp diff --git a/interface2/firmware/include/NewCoax.h b/interface2/firmware/include/NewCoax.h new file mode 100644 index 0000000..11eed7d --- /dev/null +++ b/interface2/firmware/include/NewCoax.h @@ -0,0 +1,44 @@ +#pragma once + +#define ERROR_RX_RECEIVER_ACTIVE -5 +#define ERROR_RX_TIMEOUT -2 +#define ERROR_RX_OVERFLOW -3 + +class NewCoaxDataBus; + +enum NewCoaxReceiverState { Disabled, Idle, Receiving, Received }; + +class NewCoaxReceiver +{ +public: + NewCoaxReceiver(NewCoaxDataBus &dataBus) : _dataBus(dataBus) { }; + + void begin(); + void enable(); + void disable(); + int receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout); + void activeInterrupt(); + void dataAvailableInterrupt(); + void errorInterrupt(); + +private: + NewCoaxDataBus &_dataBus; + volatile NewCoaxReceiverState _state = Disabled; + volatile uint16_t _error; + volatile uint16_t *_buffer; + volatile size_t _bufferSize; + volatile int _bufferCount; + + void reset(); + uint16_t read(); +}; + +class NewCoaxDataBus +{ +public: + void setMode(int mode); + uint16_t read(); + void write(uint16_t word); + uint16_t encode(uint16_t word); + uint16_t decode(uint16_t word); +}; diff --git a/interface2/firmware/src/NewCoax.cpp b/interface2/firmware/src/NewCoax.cpp new file mode 100644 index 0000000..47156bc --- /dev/null +++ b/interface2/firmware/src/NewCoax.cpp @@ -0,0 +1,242 @@ +#include + +#include + +//#define RX_ENABLE_PIN 4 +#define RX_RESET_PIN 4 +#define RX_ACTIVE_PIN 5 +#define RX_ERROR_PIN 6 +#define RX_DATA_AVAILABLE_PIN 7 +#define RX_READ_PIN 8 + +#define DATA_BUS_START_PIN 14 +#define DATA_BUS_END_PIN 23 +#define DATA_BUS_MASK 0x0fcf0000 + +static NewCoaxReceiver *receiver = NULL; + +void rxActiveInterrupt() +{ + if (receiver == NULL) { + return; + } + + receiver->activeInterrupt(); +} + +void rxErrorInterrupt() +{ + if (receiver == NULL) { + return; + } + + receiver->errorInterrupt(); +} + +void rxDataAvailableInterrupt() +{ + if (receiver == NULL) { + return; + } + + receiver->dataAvailableInterrupt(); +} + +void NewCoaxReceiver::begin() +{ + receiver = this; + + //pinMode(RX_ENABLE_PIN, OUTPUT); + pinMode(RX_RESET_PIN, OUTPUT); + pinMode(RX_ACTIVE_PIN, INPUT); + pinMode(RX_ERROR_PIN, INPUT); + pinMode(RX_DATA_AVAILABLE_PIN, INPUT); + pinMode(RX_READ_PIN, OUTPUT); + + attachInterrupt(digitalPinToInterrupt(RX_ACTIVE_PIN), rxActiveInterrupt, RISING); + attachInterrupt(digitalPinToInterrupt(RX_ERROR_PIN), rxErrorInterrupt, RISING); + attachInterrupt(digitalPinToInterrupt(RX_DATA_AVAILABLE_PIN), rxDataAvailableInterrupt, RISING); +} + +void NewCoaxReceiver::enable() +{ + _dataBus.setMode(INPUT); + + _state = Idle; + + //digitalWrite(RX_ENABLE_PIN, HIGH); +} + +void NewCoaxReceiver::disable() +{ + //digitalWrite(RX_ENABLE_PIN, LOW); + + _state = Disabled; +} + +int NewCoaxReceiver::receive(uint16_t *buffer, size_t bufferSize, uint16_t timeout) +{ + if (_state != Disabled) { + return ERROR_RX_RECEIVER_ACTIVE; + } + + _error = 0; + _buffer = buffer; + _bufferSize = bufferSize; + _bufferCount = 0; + + if (digitalRead(RX_DATA_AVAILABLE_PIN) || digitalRead(RX_ERROR_PIN)) { + reset(); + } + + enable(); + + if (timeout > 0) { + unsigned long startTime = millis(); + + while (_state == Idle) { + // https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html#unsigned + if ((millis() - startTime) > timeout) { + disable(); + return ERROR_RX_TIMEOUT; + } + } + } + + while (_state != Received) { + // NOP + } + + // Copy the count and error then disable. + uint16_t count = _bufferCount; + uint16_t error = _error; + + disable(); + + // Detect a receiver error. + if (error > 0) { + return (-1) * (error + 100); + } + + // Detect a buffer overflow. + if (count > bufferSize) { + return ERROR_RX_OVERFLOW; + } + + // Unscramble the data. + for (int index = 0; index < count; index++) { + buffer[index] = _dataBus.decode(buffer[index]); + } + + return count; +} + +void NewCoaxReceiver::activeInterrupt() +{ + if (_state != Idle) { + return; + } + + // Flush any old data. + if (digitalRead(RX_DATA_AVAILABLE_PIN)) { + read(); + } + + _bufferCount = 0; + _state = Receiving; +} + +void NewCoaxReceiver::dataAvailableInterrupt() +{ + if (_state != Receiving) { + return; + } + + uint16_t word = read(); + + if (_bufferCount < _bufferSize) { + _buffer[_bufferCount++] = word; + } else { + _bufferCount = _bufferSize + 1; + } + + // TODO: this is wrong... but it allows things to settle! + delayMicroseconds(1); + + if (!digitalRead(RX_ACTIVE_PIN) && !digitalRead(RX_DATA_AVAILABLE_PIN)) { + _state = Received; + } +} + +void NewCoaxReceiver::errorInterrupt() +{ + _error = _dataBus.decode(read()); + + if (_state == Receiving) { + _state = Received; + } + + reset(); +} + +void NewCoaxReceiver::reset() +{ + digitalWrite(RX_RESET_PIN, HIGH); + delayMicroseconds(1); + digitalWrite(RX_RESET_PIN, LOW); +} + +inline uint16_t NewCoaxReceiver::read() +{ + digitalWrite(RX_READ_PIN, HIGH); + + uint16_t word = _dataBus.read(); + + delayMicroseconds(1); + + digitalWrite(RX_READ_PIN, LOW); + + return word; +} + +void NewCoaxDataBus::setMode(int mode) +{ + for (int pin = DATA_BUS_START_PIN; pin <= DATA_BUS_END_PIN; pin++) { + pinMode(pin, mode); + } +} + +inline uint16_t NewCoaxDataBus::read() +{ + return (GPIO6_DR & DATA_BUS_MASK) >> 16; +} + +inline void NewCoaxDataBus::write(uint16_t word) +{ + uint32_t bus = (word << 16) & DATA_BUS_MASK; + + GPIO6_DR_SET = bus; + GPIO6_DR_CLEAR = ~bus; +} + +inline uint16_t NewCoaxDataBus::encode(uint16_t word) +{ + return ((word & 0x0020) >> 5) + | ((word & 0x0010) >> 3) + | (word & 0x0300) + | ((word & 0x0003) << 2) + | ((word & 0x0008) << 3) + | ((word & 0x00c0) << 4) + | ((word & 0x0004) << 5); +} + +inline uint16_t NewCoaxDataBus::decode(uint16_t word) +{ + return ((word & 0x0080) >> 5) + | ((word & 0x0c00) >> 4) + | ((word & 0x0040) >> 3) + | ((word & 0x000c) >> 2) + | (word & 0x0300) + | ((word & 0x0002) << 3) + | ((word & 0x0001) << 5); +} diff --git a/interface2/firmware/src/main.cpp b/interface2/firmware/src/main.cpp index 5e75b01..ca49ba7 100644 --- a/interface2/firmware/src/main.cpp +++ b/interface2/firmware/src/main.cpp @@ -1,59 +1,26 @@ #include -#define RESET_PIN 2 // FPGA #9 +#include -char buffer[20 + 1]; -int bufferIndex = 0; +NewCoaxDataBus dataBus; +NewCoaxReceiver receiver(dataBus); -void doReset() -{ - Serial.println("RESET"); - - digitalWrite(RESET_PIN, HIGH); - digitalWrite(RESET_PIN, LOW); - - Serial.println("OK"); -} +uint16_t buffer[1024]; void setup() { - pinMode(RESET_PIN, OUTPUT); - - digitalWrite(RESET_PIN, LOW); - Serial.begin(115200); while (Serial.available() > 0) { Serial.read(); } - Serial.println("OK"); + receiver.begin(); } void loop() { - if (Serial.available() > 0) { - uint8_t byte = Serial.read(); + int count = receiver.receive(buffer, 1024, 1000); - if (byte == '\r') { - buffer[bufferIndex] = 0; - - Serial.println(); - - if (strncmp(buffer, "reset", 20) == 0) { - doReset(); - } else { - Serial.println("UNRECOGNIZED COMMAND"); - } - - Serial.flush(); - - bufferIndex = 0; - } else { - buffer[bufferIndex++] = byte; - } - - Serial.write(byte); - Serial.flush(); - } + Serial.println(count); }