This application cries out for prefix bytes to help synchronization and a checksum to verify the data integrity--especially if the data will be controlling anything that can smoke, burn, or explode!
Here is a sample program I wrote that does the data exchange as suggested by the OP.
Code:
// high-speed data exchange sample program
// M. Borgerson 1/14/2023
// Both Teensy boards run this code. To start the exchange of
// packets, you need to connect one of the boards to a terminal
// or the serial monitor. When you send an <s> to one of the boards
// it will start transmitting packets. When the other board receives
// a packet, it will start returning packets.
// The code handles slightly different packet rates and differences
// in the arrival time of the packets.
// Each board transmits on SERIAL6 and receives on SERIAL7.
#define SNDPORT Serial6
#define RCVPORT Serial7
#define BAUDRATE 6000000
#define PKTBYTES 16
#define PKTLONGS 4
#define LONGMARKER 0XEFBEADDE
const char compileTime[] = " Compiled on " __DATE__ " " __TIME__;
typedef union {
uint32_t longs[PKTLONGS];
uint8_t bytes[PKTBYTES];
} longbytes;
volatile longbytes sendpkt, rcvpkt, displaypkt;
volatile uint32_t sendCount, rcvCount, timerCount, errCount, maxAvailable;
IntervalTimer packetTimer;
bool packetReady = false;
bool sendFlag = false;
void setup() {
// initialize the packet to send
sendpkt.longs[0] = 0XEFBEADDE; // DEADBEEF when shown byte by byte
sendpkt.longs[1] = 0x11111111;
sendpkt.longs[2] = 0x22222222;
sendpkt.longs[3] = 0x33333333;
Serial.begin(9600);
delay(1000);
Serial.printf("\n\nSerial Exchange %s \n", compileTime);
SNDPORT.begin(BAUDRATE, SERIAL_8N1);
RCVPORT.begin(BAUDRATE, SERIAL_8N1);
delay(10);
RCVPORT.flush();
delay(5);
packetTimer.begin(packetHandler, 50); // 20,000 interrupts per second
delay(1000);
}
elapsedMillis displayTimer;
void loop() {
// put your main code here, to run repeatedly:
if (displayTimer > 999) {
displayTimer = 0;
if ((sendCount > 0) || (rcvCount > 0)) {
memcpy((void *)&displaypkt, (void *)&rcvpkt, sizeof(displaypkt));
Serial.printf("Send Count:%7lu Rcv Count:%7lu Error Count:%7lu max Available: %lu ", sendCount, rcvCount, errCount, maxAvailable);
maxAvailable = 0;
//for (int i = 0; i < 16; i++) Serial.printf("%02X ", displaypkt.bytes[i]);
Serial.println();
}
}
if (Serial.available()) {
char ch = Serial.read();
if (ch == 's') {
sendFlag = true;
Serial.println("Packet transmission started");
}
if(ch == 'r'){
Serial.println("\nRebooting T4.1 ");
delay(100);
SCB_AIRCR = 0x05FA0004; // software reset
}
}
if(rcvCount > 0)sendFlag = true; // we can start if other end has started
}
// called by timer 20,000 times per second. Send data every other interrupt
// for 10,000 packets per second.
void packetHandler(void) {
uint16_t rcvAvailable;
uint16_t i, bytesLeft, bytesToRead;
static uint16_t rcvIdx = 0;
if ((timerCount++ & 0x01) && sendFlag) { // send on odd timer interrupts when allowed
SendPacket(); // could be inlined for speed
sendCount++;
}
rcvAvailable = RCVPORT.available();
if (rcvAvailable) {
if (rcvAvailable > maxAvailable) maxAvailable = rcvAvailable;
bytesLeft = PKTBYTES - rcvIdx; // Number left to read to fill packet
if (rcvAvailable > bytesLeft) bytesToRead = bytesLeft;
else bytesToRead = rcvAvailable;
for (i = 0; i < bytesToRead; i++) {
rcvpkt.bytes[rcvIdx++] = RCVPORT.read();
}
if (rcvIdx >= PKTBYTES) { // Packet is filled, set ready flag, reset idx, etc.
rcvIdx = 0;
rcvCount++;
packetReady = true;
if (rcvpkt.longs[0] != LONGMARKER) errCount++;
}
}
}
// Real-world code will have to fetch data to fill sendpkt.
// For testing, we just use the pre-defined values and micros()in last long
void SendPacket(void) {
uint8_t i;
//sendpkt.longs[3] = micros(); // use this to check timing
for (i = 0; i < PKTBYTES; i++) SNDPORT.write(sendpkt.bytes[i]);
}
Here are a couple of screenshots showing about 6 million packets exchanged without error---but nothing else was happening except the data exchange and a statistics display once per second.
