aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-10-24 13:26:25 -0400
committerSam Anthony <sam@samanthony.xyz>2025-10-24 13:26:25 -0400
commita0c6bbb21c5e7d9e0090e66c316cf88ef7f0726b (patch)
treee161e66721a523b11fadf4313dad94a2962c555d
parent32dafa1088e2f2428e9b67bf848faf2433216011 (diff)
downloadcan-gauge-interface-a0c6bbb21c5e7d9e0090e66c316cf88ef7f0726b.zip
eeprom systest
-rw-r--r--fw/eeprom.c103
-rw-r--r--fw/eeprom.h6
-rw-r--r--fw/tests/system/eeprom_can_systest.c120
-rw-r--r--fw/tests/system/eeprom_systest.c30
4 files changed, 226 insertions, 33 deletions
diff --git a/fw/eeprom.c b/fw/eeprom.c
index 567cdc1..e832fa0 100644
--- a/fw/eeprom.c
+++ b/fw/eeprom.c
@@ -12,6 +12,12 @@
// 16-byte page ('C' variant)
#define PAGE_SIZE 16u
+// Write cycle time = 5ms
+// 5ms / (4*Tosc) = 60000
+#define WRITE_DELAY 60000u
+
+#define BAILOUT 10u
+
// Commands
enum {
CMD_READ = 0x03,
@@ -30,42 +36,52 @@ enum {
STATUS_BP1 = 0x8, // block protection 1
};
-// Timing
-enum {
- TIME_WRITE_CYCLE_MS = 5,
-};
+static U8
+readStatus(void) {
+ U8 status;
-void
-eepromInit(void) {
- EEPROM_CS_TRIS = OUT;
+ EEPROM_CS = 0;
+ (void)spiTx(CMD_READ_STATUS);
+ status = spiTx(0x00);
EEPROM_CS = 1;
-
- eepromWriteDisable();
+ return status;
}
-void
-eepromWriteEnable(void) {
+static Status
+writeEnable(void) {
EEPROM_CS = 0;
(void)spiTx(CMD_WRITE_ENABLE);
EEPROM_CS = 1;
+
+ return (readStatus() & STATUS_WEL) ? OK : FAIL;
}
-void
-eepromWriteDisable(void) {
+static void
+writeDisable(void) {
EEPROM_CS = 0;
(void)spiTx(CMD_WRITE_DISABLE);
EEPROM_CS = 1;
}
-static bool
-isWriteInProgress(void) {
- U8 status;
-
- EEPROM_CS = 0;
- (void)spiTx(CMD_READ_STATUS);
- status = spiTx(0x00);
+void
+eepromInit(void) {
+ EEPROM_CS_TRIS = OUT;
EEPROM_CS = 1;
- return status & STATUS_WIP;
+
+ writeDisable();
+}
+
+// Wait for pending write to finish
+static Status
+waitForWrite(void) {
+ U8 status, k;
+
+ status = readStatus();
+ for (k = 0u; (status & STATUS_WIP) && (k < BAILOUT); k++) {
+ _delay(WRITE_DELAY);
+ status = readStatus();
+ }
+ return (k < BAILOUT) ? OK : FAIL;
}
static void
@@ -79,12 +95,24 @@ isPageStart(U16 addr) {
return (addr.lo % PAGE_SIZE) == 0;
}
-void
+Status
eepromWrite(U16 addr, U8 *data, U8 size) {
- while (isWriteInProgress()) {} // wait for previous write to finish
+ Status status;
- EEPROM_CS = 0; // pull chip-select low
+ // Wait for pending write to finish
+ status = waitForWrite();
+ if (status != OK) {
+ return FAIL; // timed out
+ }
+
+ // Set write-enable
+ status = writeEnable();
+ if (status != OK) {
+ return FAIL;
+ }
+ // Write
+ EEPROM_CS = 0;
(void)spiTx(CMD_WRITE);
spiTxAddr(addr);
while (size--) {
@@ -96,7 +124,14 @@ eepromWrite(U16 addr, U8 *data, U8 size) {
if (isPageStart(addr) && size) {
// Write current page to memory
EEPROM_CS = 1;
- while (isWriteInProgress()) {}
+ status = waitForWrite();
+ if (status != OK) {
+ return FAIL; // timed out
+ }
+ status = writeEnable();
+ if (status != OK) {
+ return FAIL;
+ }
EEPROM_CS = 0;
// Start next page
@@ -104,20 +139,30 @@ eepromWrite(U16 addr, U8 *data, U8 size) {
spiTxAddr(addr);
}
}
+ EEPROM_CS = 1;
- EEPROM_CS = 1; // release chip-select
+ return OK;
}
-void
+Status
eepromRead(U16 addr, U8 *data, U8 size) {
- EEPROM_CS = 0; // pull chip-select low
+ Status status;
+
+ // Wait for pending write to finish
+ status = waitForWrite();
+ if (status != OK) {
+ return FAIL; // timed out
+ }
+ // Read
+ EEPROM_CS = 0;
(void)spiTx(CMD_READ);
spiTxAddr(addr);
while (size--) {
*data = spiTx(0x00);
data++;
}
+ EEPROM_CS = 1;
- EEPROM_CS = 1; // release chip-select
+ return OK;
}
diff --git a/fw/eeprom.h b/fw/eeprom.h
index 9ad3cdd..ab701d7 100644
--- a/fw/eeprom.h
+++ b/fw/eeprom.h
@@ -15,7 +15,5 @@
#define EEPROM_CS LATCbits.LATC5
void eepromInit(void);
-void eepromWriteEnable(void);
-void eepromWriteDisable(void);
-void eepromWrite(U16 addr, U8 data[], U8 size);
-void eepromRead(U16 addr, U8 data[], U8 size);
+Status eepromWrite(U16 addr, U8 data[], U8 size);
+Status eepromRead(U16 addr, U8 data[], U8 size);
diff --git a/fw/tests/system/eeprom_can_systest.c b/fw/tests/system/eeprom_can_systest.c
new file mode 100644
index 0000000..29c29e0
--- /dev/null
+++ b/fw/tests/system/eeprom_can_systest.c
@@ -0,0 +1,120 @@
+/* Listen for a standard frame with ID 123h; read or write address Ah of the EEPROM.
+ *
+ * If the frame is a DATA FRAME, D0 is written to address Ah of the EEPROM.
+ *
+ * If the frame is a REMOTE FRAME, address Ah of the EEPROM is read and the value
+ * is sent in the D0 field of a DATA FRAME with the same ID.
+ */
+
+#include <xc.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "system.h"
+#include "types.h"
+#include "spi.h"
+#include "eeprom.h"
+#include "can.h"
+
+static const CanId id = {
+ .type = CAN_ID_STD,
+ .sid = {0x1, 0x23},
+};
+static const U16 addr = {0x00, 0x0A};
+
+void
+main(void) {
+ sysInit();
+ spiInit();
+ eepromInit();
+ canInit();
+
+ // Setup MCP2515 CAN controller
+ canSetBitTiming(CAN_TIMING_10K);
+ CanId mask = {
+ .type=CAN_ID_STD,
+ .sid = {0xFF, 0xFF},
+ };
+ canSetMask0(&mask); // set masks
+ canSetMask1(&mask);
+ canSetFilter1(&mask); // set unused filters
+ canSetFilter2(&mask);
+ canSetFilter3(&mask);
+ canSetFilter4(&mask);
+ canSetFilter5(&mask);
+ canSetFilter0(&id); // listen for message on filter 0
+ 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 (;;) {
+
+ }
+}
+
+// Read the EEPROM and transmit the value in a CAN frame.
+static Status
+readEeprom(const CanFrame *frame) {
+ U8 val;
+ Status status;
+
+ status = eepromRead(addr, &val, 1u);
+ if (status != OK) {
+ return FAIL;
+ }
+
+ CanFrame out = {
+ .id = id,
+ .rtr = false,
+ .dlc = 1u,
+ .data = {val},
+ };
+ return canTx(&out);
+}
+
+// Write a value to the EEPROM.
+static Status
+writeEeprom(const CanFrame *frame) {
+ U8 val;
+
+ if (frame->dlc < 1u) {
+ return FAIL; // malformed frame
+ }
+
+ val = frame->data[0u];
+ return eepromWrite(addr, &val, 1u);
+}
+
+void
+__interrupt() isr(void) {
+ U8 status;
+ CanFrame frame;
+
+ if (INTCONbits.INTF) {
+ status = canRxStatus();
+ switch (status & 0x7) { // check filter match
+ case 0u: // RXF0
+ canReadRxb0(&frame);
+ if (frame.rtr) {
+ (void)readEeprom(&frame);
+ } else {
+ (void)writeEeprom(&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/eeprom_systest.c b/fw/tests/system/eeprom_systest.c
new file mode 100644
index 0000000..8285e5c
--- /dev/null
+++ b/fw/tests/system/eeprom_systest.c
@@ -0,0 +1,30 @@
+#include <xc.h>
+
+#include <stdint.h>
+
+#include "system.h"
+#include "types.h"
+#include "spi.h"
+#include "eeprom.h"
+
+static const U16 addr = {0x00, 0x0A};
+
+void
+main(void) {
+ U8 val;
+
+ sysInit();
+ spiInit();
+ eepromInit();
+
+ val = 0x8A;
+ (void)eepromWrite(addr, &val, 1u); // write 0b1000_1010
+ (void)eepromRead(addr, &val, 1u); // read 0b1000_1010
+ val = 0x8E;
+ (void)eepromWrite(addr, &val, 1u); // write 0b1000_1110
+ (void)eepromRead(addr, &val, 1u); // read 0b1000_1110
+
+ for (;;) {
+
+ }
+}