aboutsummaryrefslogtreecommitdiffstats
path: root/fw/main.c
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-10-25 11:55:53 -0400
committerSam Anthony <sam@samanthony.xyz>2025-10-25 11:55:53 -0400
commit866eca8392991c03386dae1f4c0a3821e4fcfbbb (patch)
treedc9f99dfd05c25277e4ceff3d71fe361e8d0794d /fw/main.c
parentd7e085b5868dc3386eaf96813feaa0f02ee3727f (diff)
downloadcan-gauge-interface-866eca8392991c03386dae1f4c0a3821e4fcfbbb.zip
load CAN IDs from EEPROM
Diffstat (limited to 'fw/main.c')
-rw-r--r--fw/main.c227
1 files changed, 161 insertions, 66 deletions
diff --git a/fw/main.c b/fw/main.c
index 3471d79..1f0308b 100644
--- a/fw/main.c
+++ b/fw/main.c
@@ -5,102 +5,197 @@
#include "system.h"
#include "types.h"
-#include "table.h"
#include "spi.h"
-#include "eeprom.h"
#include "dac.h"
#include "can.h"
+#include "eeprom.h"
+#include "table.h"
-// Parameters:
-// Each parameter has an associated CAN ID and calibration table in the EEPROM.
-enum {
- TACH = 0,
- SPEED = 1,
- AN1 = 2,
- AN2 = 3,
- AN3 = 4,
- AN4 = 5,
-} Parameter;
-
-// CAN ID for writing/reading calibration tables from a host PC.
-// LSB of ID, 'X', indicates table and row number: X[7:5]{table #}, X[4:0]{row #}.
-static const CanId tblCanId = {
+// TODO: auto baud detection
+#define CAN_TIMING CAN_TIMING_10K
+
+// Table Control filter.
+// Used for writing/reading calibration tables.
+static const CanId tblCtrlFilter = {
.type = CAN_ID_EXT,
- .eid = {0x00, 0x2F, 0x27, 0x01}, // 1272F0Xh
+ .eid = {0x00, 0x20, 0x27, 0x01}, // 12720XXh
};
-// CAN ID for writing/reading the CAN ID associated with each parameter
-// from a host PC.
-// LSB of ID, 'X', indicates a particular Parameter enum.
-static const CanId paramCanId = {
+// ID Control filter.
+// Used for writing/reading the CAN ID associated with each parameter.
+// See `doc/datafmt.ps'.
+static const CanId idCtrlFilter = {
.type = CAN_ID_EXT,
- .eid = {0x10, 0x2F, 0x27, 0x01}, // 1272F1Xh
+ .eid = {0x00, 0x21, 0x27, 0x01}, // 127210Xh
};
// Receive buffer 0 mask.
-// RXB0 is used for control messages for reading/writing configuration tables and CAN IDs for each parameter, which are stored in the EEPROM.
-// Mask all but the LSB of the Table and Parameter IDs.
+// RXB0 is used for control messages for reading/writing calibration tables
+// and CAN IDs for each parameter.
+// This mask is the union of the two control message filters.
static const CanId rxb0Mask = {
.type = CAN_ID_EXT,
- .eid = {0x10, 0x2F, 0x27, 0x01}, // 1272F10h
+ .eid = {0x00, 0x21, 0x27, 0x01}, // 1272100h
+};
+
+// Receive buffer 1 mask.
+// RXB1 is used for receiving parameter values.
+// The mask is permissive: all messages are accepted and filtered in software.
+static const CanId rxb1Mask = {
+ .type = CAN_ID_EXT,
+ .eid = {0u, 0u, 0u, 0u}, // accept all messages
};
// Calibration tables in EEPROM:
-static Table tachTbl;
-static Table speedTbl;
-static Table an1Tbl;
-static Table an2Tbl;
-static Table an3Tbl;
-
-// Filter ID addresses in EEPROM:
-// Each one of these addresses holds a CanId struct.
-static U16 id1Addr;
-static U16 id2Addr;
-static U16 id3Addr;
-static U16 id4Addr;
-static U16 id5Addr;
+// Each is 2*sizeof(U32)*TAB_ROWS = 256B -- too big for an 8-bit word.
+// That's why the offsets are hard-coded.
+static const Table tachTbl = {{0x00, 0x00}}; // tachometer
+static const Table speedTbl = {{0x01, 0x00}}; // speedometer
+static const Table an1Tbl = {{0x02, 0x00}}; // analog channels...
+static const Table an2Tbl = {{0x03, 0x00}};
+static const Table an3Tbl = {{0x04, 0x00}};
+static const Table an4Tbl = {{0x05, 0x00}};
+
+// EEPROM address of CAN ID for each parameter.
+// Each of these addresses holds a U32 CAN ID.
+static const EepromAddr tachIdAddr = {0x06, 0x00}; // tachometer
+static const EepromAddr speedIdAddr = {0x06, 0x04}; // speedometer
+static const EepromAddr an1IdAddr = {0x06, 0x08}; // analog channels...
+static const EepromAddr an2IdAddr = {0x06, 0x0C};
+static const EepromAddr an3IdAddr = {0x06, 0x10};
+static const EepromAddr an4IdAddr = {0x06, 0x14};
+
+static volatile CanId tachId; // tachometer
+static volatile CanId speedId; // speedometer
+static volatile CanId an1Id; // analog channels...
+static volatile CanId an2Id;
+static volatile CanId an3Id;
+static volatile CanId an4Id;
+
+// Load parameters' CAN IDs from EEPROM
+static Status
+loadParamIds(void) {
+ U8 oldGie;
+ Status status;
+
+ // Disable interrupts so the volatile address pointers can be passed safely
+ oldGie = INTCONbits.GIE;
+ INTCONbits.GIE = 0;
+
+ status = eepromReadCanId(tachIdAddr, (CanId*)&tachId);
+ if (status != OK) {
+ return FAIL;
+ }
+ status = eepromReadCanId(speedIdAddr, (CanId*)&speedId);
+ if (status != OK) {
+ return FAIL;
+ }
+ status = eepromReadCanId(an1IdAddr, (CanId*)&an1Id);
+ if (status != OK) {
+ return FAIL;
+ }
+ status = eepromReadCanId(an2IdAddr, (CanId*)&an2Id);
+ if (status != OK) {
+ return FAIL;
+ }
+ status = eepromReadCanId(an3IdAddr, (CanId*)&an3Id);
+ if (status != OK) {
+ return FAIL;
+ }
+ status = eepromReadCanId(an4IdAddr, (CanId*)&an4Id);
+ if (status != OK) {
+ return FAIL;
+ }
+
+ // Restore previous interrupt setting
+ INTCONbits.GIE = oldGie;
+
+ return OK;
+}
+
+static void
+reset(void) {
+ _delay(100000);
+ asm("RESET");
+}
void
main(void) {
- U16 offset;
-
- // Initialize calibration table EEPROM addresses
- offset = (U16){0u, 0u};
- tachTbl = (Table){offset};
- offset = addU16U8(offset, TAB_SIZE);
- speedTbl = (Table){offset};
- offset = addU16U8(offset, TAB_SIZE);
- an1Tbl = (Table){offset};
- offset = addU16U8(offset, TAB_SIZE);
- an2Tbl = (Table){offset};
- offset = addU16U8(offset, TAB_SIZE);
- an3Tbl = (Table){offset};
- offset = addU16U8(offset, TAB_SIZE);
-
- // Initialize filter ID EEPROM addresses
- id1Addr = offset;
- offset = addU16U8(offset, sizeof(CanId));
- id2Addr = offset;
- offset = addU16U8(offset, sizeof(CanId));
- id3Addr = offset;
- offset = addU16U8(offset, sizeof(CanId));
- id4Addr = offset;
- offset = addU16U8(offset, sizeof(CanId));
- id5Addr = offset;
- offset = addU16U8(offset, sizeof(CanId));
+ Status status;
sysInit();
spiInit();
- eepromInit();
dacInit();
canInit();
+ eepromInit();
+
+ // Load parameters' CAN IDs from EEPROM
+ status = loadParamIds();
+ if (status != OK) {
+ reset();
+ }
+
+ // Setup MCP2515 CAN controller
+ canSetBitTiming(CAN_TIMING);
+ canSetMask0(&rxb0Mask); // RXB0 receives control messages
+ canSetFilter0(&tblCtrlFilter); // Table Control Frames
+ canSetFilter1(&idCtrlFilter); // ID Control Frames
+ canSetMask1(&rxb1Mask); // RXB1 receives parameter values
+ // Permissive RXB1 mask; filter frames in software
+
+ // Enable interrupts
+ canIE(true); // enable interrupts on MCP2515's INT pin
+ INTCON = 0x00; // clear flags
+ OPTION_REGbits.INTEDG = 0; // interrupt on falling edge of INT pin
+ INTCONbits.INTE = 1; // enable INT pin
+ INTCONbits.PEIE = 1; // enable peripheral interrupts
+ INTCONbits.GIE = 1; // enable global interrupts
for (;;) {
}
}
+// Handle a Table Control Frame.
+// See `doc/datafmt.ps'
+static Status
+handleTblCtrlFrame(const CanFrame *frame) {
+ // TODO
+}
+
+// Handle an ID Control Frame.
+// See `doc/datafmt.ps'
+static Status
+handleIdCtrlFrame(const CanFrame *frame) {
+ // TODO
+}
+
+// Handle a frame potentially holding a parameter value.
+static Status
+handleParamFrame(const CanFrame *frame) {
+ // TODO
+}
+
void
__interrupt() isr(void) {
-
+ U8 rxStatus;
+ CanFrame frame;
+
+ if (INTCONbits.INTF) { // CAN interrupt
+ rxStatus = canRxStatus();
+ switch (rxStatus & 0x7) { // check filter hit
+ case 0u: // RXF0: calibration table control
+ canReadRxb0(&frame);
+ (void)handleTblCtrlFrame(&frame);
+ break;
+ case 1u: // RXF1: parameter ID control
+ canReadRxb0(&frame);
+ (void)handleIdCtrlFrame(&frame);
+ break;
+ default: // message in RXB1
+ canReadRxb1(&frame);
+ (void)handleParamFrame(&frame);
+ }
+ INTCONbits.INTF = 0; // clear flag
+ }
}