aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-10-24 09:42:49 -0400
committerSam Anthony <sam@samanthony.xyz>2025-10-24 09:42:49 -0400
commit32dafa1088e2f2428e9b67bf848faf2433216011 (patch)
treed1ee08ceb3e16d80784680fbc6ac2a2df3b580ab
parent94cdc9ec4e75fc5e55deb394eda4820ba672e3e4 (diff)
downloadcan-gauge-interface-32dafa1088e2f2428e9b67bf848faf2433216011.zip
CAN echo systest
-rw-r--r--.gitignore1
-rw-r--r--fw/can.c78
-rw-r--r--fw/can.h10
-rw-r--r--fw/tests/system/can_echo_systest.c85
-rw-r--r--fw/tests/system/can_tx_systest.c4
5 files changed, 151 insertions, 27 deletions
diff --git a/.gitignore b/.gitignore
index 0a7ee41..31b6cd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ _autosave*
*.blg
*.FCBak
*.FCStd1
+*.html
*.lck
*.~lock*
*.log
diff --git a/fw/can.c b/fw/can.c
index 6518f91..b3f41f9 100644
--- a/fw/can.c
+++ b/fw/can.c
@@ -113,7 +113,7 @@ enum {
// TXBnDLC
RTR = 0x40,
- EXIDE = 0x08, // extended identifier enable bit in SIDL registers
+ IDE = 0x08, // extended identifier flag bit of SIDL registers
};
// Instructions
@@ -236,29 +236,65 @@ canIE(bool enable) {
}
}
+// Pack ID register values into a struct.
static void
-readRxbnData(U8 n, U8 data[8u]) {
+packId(CanId *id, U8 sidh, U8 sidl, U8 eid8, U8 eid0) {
+ if (sidl & IDE) { // extended ID
+ id->type = CAN_ID_EXT;
+ id->eid[0] = (U8)(sidh << 3u) | (U8)(sidl >> 5u); // sid[7:0]
+ id->eid[1] = (U8)(eid0 << 3u) | (U8)(sidh >> 5u); //eid[4:0], sid[10:8]
+ id->eid[2] = (U8)(eid8 << 3u) | (U8)(eid0 >> 5u); // eid[12:5]
+ id->eid[3] = (U8)((sidl & 0x3) << 3u) | (U8)(eid8 >> 5u); // eid[17:13]
+ } else { // standard ID
+ id->type = CAN_ID_STD;
+ id->sid.lo = (U8)(sidh << 3u) | (U8)(sidl >> 5u); // sid[7:0]
+ id->sid.hi = sidh >> 5u; // sid[10:8]
+ }
+}
+
+static void
+readRxbn(U8 n, CanFrame *frame) {
+ U8 sidh, sidl, eid8, eid0;
+
CAN_CS = 0;
- n &= 0x01; // n in {0,1}
- (void)spiTx(CMD_READ_RX | (U8)(n << 2u) | 0x02); // start at RXBnD0
- for (n = 0u; n < 8u; n++) {
- data[n] = spiTx(0x00);
+
+ // Start reading at RXBnSIDH
+ (void)spiTx(CMD_READ_RX | (U8)((n & 1u) << 2u));
+
+ // Read ID
+ sidh = spiTx(0u);
+ sidl = spiTx(0u);
+ eid8 = spiTx(0u);
+ eid0 = spiTx(0u);
+ packId(&frame->id, sidh, sidl, eid8, eid0);
+
+ // Read RTR and DLC
+ frame->dlc = spiTx(0u);
+ frame->rtr = frame->dlc & RTR;
+ frame->dlc &= 0xF;
+
+ // Read data
+ for (n = 0u; n < frame->dlc; n++) {
+ frame->data[n] = spiTx(0u);
}
+
CAN_CS = 1;
}
void
-canReadRxb0Data(U8 data[8u]) {
- readRxbnData(0u, data);
+canReadRxb0(CanFrame *frame) {
+ readRxbn(0u, frame);
}
void
-canReadRxb1Data(U8 data[8u]) {
- readRxbnData(1u, data);
+canReadRxb1(CanFrame *frame) {
+ readRxbn(1u, frame);
}
+// Write an ID to a set of {xSIDH, xSIDL, xEID8, xEID0} registers,
+// e.g., RXMnSIDH etc.
static void
-writeIdToRegs(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) {
+writeId(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) {
switch (id->type) {
case CAN_ID_STD: // standard ID
write(sidh, (U8)(id->sid.hi << 5u) | (U8)(id->sid.lo >> 3u));
@@ -268,7 +304,7 @@ writeIdToRegs(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) {
break;
case CAN_ID_EXT: // extended ID
write(sidh, (U8)(id->eid[1] << 5u) | (U8)(id->eid[0] >> 3u)); // sid[10:3]
- write(sidl, (U8)(id->eid[0] << 5u) | EXIDE | (U8)((id->eid[3] >> 3u) & 0x03)); // sid[2:0], exide, eid[28:27]
+ write(sidl, (U8)(id->eid[0] << 5u) | IDE | (U8)((id->eid[3] >> 3u) & 0x03)); // sid[2:0], exide, eid[28:27]
write(eid8, (U8)(id->eid[3] << 5u) | (U8)(id->eid[2] >> 3u)); // eid[26:19]
write(eid0, (U8)(id->eid[2] << 5u) | (U8)(id->eid[1] >> 3u)); // eid[18:11]
break;
@@ -280,7 +316,7 @@ canTx(const CanFrame *frame) {
U8 k, ctrl;
// Set ID, DLC, and RTR
- writeIdToRegs(&frame->id, REG_TXB0SIDH, REG_TXB0SIDL, REG_TXB0EID8, REG_TXB0EID0);
+ writeId(&frame->id, REG_TXB0SIDH, REG_TXB0SIDL, REG_TXB0EID8, REG_TXB0EID0);
write(REG_TXB0DLC, (frame->dlc & 0x0F) | ((frame->rtr) ? RTR : 0));
// Copy data to registers
@@ -305,40 +341,40 @@ canTx(const CanFrame *frame) {
void
canSetMask0(const CanId *mask) {
- writeIdToRegs(mask, REG_RXM0SIDH, REG_RXM0SIDL, REG_RXM0EID8, REG_RXM0EID0);
+ writeId(mask, REG_RXM0SIDH, REG_RXM0SIDL, REG_RXM0EID8, REG_RXM0EID0);
}
void
canSetMask1(const CanId *mask) {
- writeIdToRegs(mask, REG_RXM1SIDH, REG_RXM1SIDL, REG_RXM1EID8, REG_RXM1EID0);
+ writeId(mask, REG_RXM1SIDH, REG_RXM1SIDL, REG_RXM1EID8, REG_RXM1EID0);
}
void
canSetFilter0(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF0SIDH, REG_RXF0SIDL, REG_RXF0EID8, REG_RXF0EID0);
+ writeId(filter, REG_RXF0SIDH, REG_RXF0SIDL, REG_RXF0EID8, REG_RXF0EID0);
}
void
canSetFilter1(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF1SIDH, REG_RXF1SIDL, REG_RXF1EID8, REG_RXF1EID0);
+ writeId(filter, REG_RXF1SIDH, REG_RXF1SIDL, REG_RXF1EID8, REG_RXF1EID0);
}
void
canSetFilter2(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF2SIDH, REG_RXF2SIDL, REG_RXF2EID8, REG_RXF2EID0);
+ writeId(filter, REG_RXF2SIDH, REG_RXF2SIDL, REG_RXF2EID8, REG_RXF2EID0);
}
void
canSetFilter3(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF3SIDH, REG_RXF3SIDL, REG_RXF3EID8, REG_RXF3EID0);
+ writeId(filter, REG_RXF3SIDH, REG_RXF3SIDL, REG_RXF3EID8, REG_RXF3EID0);
}
void
canSetFilter4(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF4SIDH, REG_RXF4SIDL, REG_RXF4EID8, REG_RXF4EID0);
+ writeId(filter, REG_RXF4SIDH, REG_RXF4SIDL, REG_RXF4EID8, REG_RXF4EID0);
}
void
canSetFilter5(const CanId *filter) {
- writeIdToRegs(filter, REG_RXF5SIDH, REG_RXF5SIDL, REG_RXF5EID8, REG_RXF5EID0);
+ writeId(filter, REG_RXF5SIDH, REG_RXF5SIDL, REG_RXF5EID8, REG_RXF5EID0);
}
diff --git a/fw/can.h b/fw/can.h
index 8e0cfff..9ac1cfe 100644
--- a/fw/can.h
+++ b/fw/can.h
@@ -52,9 +52,9 @@ typedef struct {
// CAN frame
typedef struct {
CanId id;
+ bool rtr; // remote transmission request
U8 dlc; // data length code
U8 data[8];
- bool rtr; // remote transmission request
} CanFrame;
// Initialize the MCP2515.
@@ -75,11 +75,11 @@ void canIE(bool enable);
// Read RX status with RX STATUS instruction.
U8 canRxStatus(void);
-// Read the DATA field of RXB0.
-void canReadRxb0Data(U8 data[8u]);
+// Read the frame in RXB0.
+void canReadRxb0(CanFrame *frame);
-// Read the DATA field of RXB1.
-void canReadRxb1Data(U8 data[8u]);
+// Read the frame in RXB1.
+void canReadRxb1(CanFrame *frame);
// Transmit a frame to the CAN bus
Status canTx(const CanFrame *frame);
diff --git a/fw/tests/system/can_echo_systest.c b/fw/tests/system/can_echo_systest.c
new file mode 100644
index 0000000..798e45f
--- /dev/null
+++ b/fw/tests/system/can_echo_systest.c
@@ -0,0 +1,85 @@
+/* Listen for a standard DATA FRAME with ID 123h;
+ * echo it back with each byte of the DATA FIELD incremented by 1.
+ */
+
+#include <xc.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "system.h"
+#include "types.h"
+#include "spi.h"
+#include "can.h"
+
+void
+main(void) {
+ sysInit();
+ spiInit();
+ canInit();
+
+ // Setup MCP2515 CAN controller
+ canSetBitTiming(CAN_TIMING_10K);
+ CanId id = {
+ .type=CAN_ID_STD,
+ .sid = {0xFF, 0xFF},
+ };
+ canSetMask0(&id); // set masks
+ canSetMask1(&id);
+ canSetFilter1(&id); // set unused filters
+ canSetFilter2(&id);
+ canSetFilter3(&id);
+ canSetFilter4(&id);
+ canSetFilter5(&id);
+ id.sid = (U16){0x01, 0x23}; // listen for message on filter 0
+ canSetFilter0(&id);
+ canIE(true); // enable interrupts on INT pin
+ canSetMode(CAN_MODE_NORMAL);
+
+ // Enable interrupts
+ INTCON = 0x00; // clear flags
+ OPTION_REGbits.INTEDG = 0; // interrupt on falling edge
+ INTCONbits.INTE = 1; // enable INT pin
+ INTCONbits.PEIE = 1; // enable peripheral interrupts
+ INTCONbits.GIE = 1; // enable global interrupts
+
+ for (;;) {
+
+ }
+}
+
+// Add 1 to each data byte of a CAN frame and transmit it to the bus.
+static void
+echo(CanFrame *frame) {
+ U8 k;
+
+ for (k = 0u; k < frame->dlc; k++) {
+ frame->data[k]++;
+ }
+
+ canTx(frame);
+}
+
+void
+__interrupt() isr(void) {
+ U8 status;
+ CanFrame frame;
+
+ if (INTCONbits.INTF) {
+ status = canRxStatus();
+ switch (status & 0x7) { // check filter match
+ case 0u: // RXF0
+ canReadRxb0(&frame);
+ echo(&frame);
+ break;
+ case 1u: // RXF1
+ canReadRxb0(&frame); // clear interrupt flag
+ break;
+ default:
+ // Message in RXB1
+ canReadRxb1(&frame); // clear interrupt flag
+ }
+
+ INTCONbits.INTF = 0;
+ }
+}
diff --git a/fw/tests/system/can_tx_systest.c b/fw/tests/system/can_tx_systest.c
index b1dec17..ef1d7b0 100644
--- a/fw/tests/system/can_tx_systest.c
+++ b/fw/tests/system/can_tx_systest.c
@@ -1,3 +1,5 @@
+/* Periodically transmit a frame to the CAN bus. */
+
#include <xc.h>
#include <stdbool.h>
@@ -14,9 +16,9 @@ static const CanFrame frame = {
.type = CAN_ID_STD,
.sid = {0x01, 0x23},
},
+ .rtr = false,
.dlc = 8u,
.data = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77},
- .rtr = false,
};
static U8 ctr = 0u; // timer