aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2025-08-16 12:19:09 -0230
committerSam Anthony <sam@samanthony.xyz>2025-08-16 12:19:09 -0230
commit4a99ede565fa61005f2a6202669adaa87a8ce0ee (patch)
tree472d4e45858d50b4f719591dc3666b5fdc129549
parent31f8d3b1edbe9dd965dba663e40c62c336fe7ca9 (diff)
downloadcan-gauge-interface-4a99ede565fa61005f2a6202669adaa87a8ce0ee.zip
spi and eeprom modules
-rw-r--r--sw/eeprom.c123
-rw-r--r--sw/eeprom.h20
-rw-r--r--sw/main.c26
-rw-r--r--sw/spi.c30
-rw-r--r--sw/spi.h9
-rw-r--r--sw/sys.h5
-rw-r--r--sw/types.c13
-rw-r--r--sw/types.h13
8 files changed, 234 insertions, 5 deletions
diff --git a/sw/eeprom.c b/sw/eeprom.c
new file mode 100644
index 0000000..ce8aed7
--- /dev/null
+++ b/sw/eeprom.c
@@ -0,0 +1,123 @@
+#include <xc.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "sys.h"
+#include "types.h"
+#include "spi.h"
+
+#include "eeprom.h"
+
+// 16-byte page ('C' variant)
+#define PAGE_SIZE 16u
+
+// Commands
+enum {
+ CMD_READ = 0x03,
+ CMD_WRITE = 0x02,
+ CMD_WRITE_DISABLE = 0x04,
+ CMD_WRITE_ENABLE = 0x06,
+ CMD_READ_STATUS = 0x05,
+ CMD_WRITE_STATUS = 0x01,
+};
+
+// Status register masks
+enum {
+ STATUS_WIP = 0x1, // write in progress
+ STATUS_WEL = 0x2, // write enable latch
+ STATUS_BP0 = 0x4, // block protection 0
+ STATUS_BP1 = 0x8, // block protection 1
+};
+
+// Timing
+enum {
+ TIME_WRITE_CYCLE_MS = 5,
+};
+
+void
+eepromInit(void) {
+ EEPROM_CS_TRIS = OUT;
+ EEPROM_CS = 1;
+
+ eepromWriteDisable();
+}
+
+void
+eepromWriteEnable(void) {
+ EEPROM_CS = 0;
+ (void)spiTx(CMD_WRITE_ENABLE);
+ EEPROM_CS = 1;
+}
+
+void
+eepromWriteDisable(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);
+ EEPROM_CS = 1;
+ return status & STATUS_WIP;
+}
+
+static void
+spiTxAddr(U16 addr) {
+ (void)spiTx(addr.hi);
+ (void)spiTx(addr.lo);
+}
+
+static bool
+isPageStart(U16 addr) {
+ return (addr.lo % PAGE_SIZE) == 0;
+}
+
+void
+eepromWrite(U16 addr, U8 *data, U8 size) {
+ while (isWriteInProgress()) {} // wait for previous write to finish
+
+ EEPROM_CS = 0; // pull chip-select low
+
+ (void)spiTx(CMD_WRITE);
+ spiTxAddr(addr);
+ while (size--) {
+ (void)spiTx(*data);
+ data++;
+ incU16(&addr);
+
+ // Check if write crosses page boundary
+ if (isPageStart(addr) && size) {
+ // Write current page to memory
+ EEPROM_CS = 1;
+ while (isWriteInProgress()) {}
+ EEPROM_CS = 0;
+
+ // Start next page
+ (void)spiTx(CMD_WRITE);
+ spiTxAddr(addr);
+ }
+ }
+
+ EEPROM_CS = 1; // release chip-select
+}
+
+void
+eepromRead(U16 addr, U8 *data, U8 size) {
+ EEPROM_CS = 0; // pull chip-select low
+
+ (void)spiTx(CMD_READ);
+ spiTxAddr(addr);
+ while (size--) {
+ *data = spiTx(0x00);
+ data++;
+ }
+
+ EEPROM_CS = 1; // release chip-select
+}
diff --git a/sw/eeprom.h b/sw/eeprom.h
new file mode 100644
index 0000000..4e4dfe2
--- /dev/null
+++ b/sw/eeprom.h
@@ -0,0 +1,20 @@
+/* Microchip 25LC160C 2KiB EEPROM
+ *
+ * Usage:
+ *
+ * #include <xc.h>
+ * #include <stdint.h>
+ * #include "types.h"
+ * #include "spi.h"
+ * #include "eeprom.h"
+ */
+
+// Pin mapping
+#define EEPROM_CS_TRIS TRISAbits.TRISA5
+#define EEPROM_CS LATAbits.LATA5
+
+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);
diff --git a/sw/main.c b/sw/main.c
index c79b6e8..4d9b2be 100644
--- a/sw/main.c
+++ b/sw/main.c
@@ -1,5 +1,11 @@
#include <xc.h>
+#include <stdint.h>
+
+#include "types.h"
+#include "spi.h"
+#include "eeprom.h"
+
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
@@ -23,22 +29,32 @@
#pragma config LVP = ON // Low-Voltage Programming Enable
static void
-clock_init(void) {
+clockInit(void) {
OSCCON = 0xFC; // HFINTOSC @ 16MHz, 3x PLL, PLL enabled
ACTCON = 0x90; // active clock tuning enabled for USB
}
static void
-gpio_init(void) {
-
+pinsInit(void) {
+ // Disable all analog pin functions
+ ANSELA = 0;
+ ANSELB = 0;
+ ANSELC = 0;
}
void
main(void) {
- clock_init();
- gpio_init();
+ clockInit();
+ pinsInit();
+ spiInit();
+ eepromInit();
for (;;) {
}
}
+
+void
+__interrupt() isr(void) {
+
+}
diff --git a/sw/spi.c b/sw/spi.c
new file mode 100644
index 0000000..1793c4d
--- /dev/null
+++ b/sw/spi.c
@@ -0,0 +1,30 @@
+#include <xc.h>
+
+#include <stdint.h>
+
+#include "sys.h"
+#include "types.h"
+
+#include "spi.h"
+
+void
+spiInit(void) {
+ U8 junk;
+
+ TRISBbits.TRISB4 = IN; // SDI
+ TRISCbits.TRISC7 = OUT; // SDO
+ TRISBbits.TRISB6 = OUT; // SCK
+
+ SSPSTAT = 0x00;
+ SSPCON1 = 0x01; // FOSC/16 => 3MHz SPI clock
+ SSPCON1bits.SSPEN = 1; // enable
+ junk = SSPBUF; // dummy read to clear BF
+ (void)junk;
+}
+
+U8
+spiTx(U8 c) {
+ SSPBUF = c;
+ while (!SSPSTATbits.BF) {}
+ return SSPBUF;
+}
diff --git a/sw/spi.h b/sw/spi.h
new file mode 100644
index 0000000..a949155
--- /dev/null
+++ b/sw/spi.h
@@ -0,0 +1,9 @@
+/* Usage:
+ *
+ * #include <stdint.h>
+ * #include "types.h"
+ * #include "spi.h"
+ */
+
+void spiInit(void);
+U8 spiTx(U8 c);
diff --git a/sw/sys.h b/sw/sys.h
new file mode 100644
index 0000000..1d54039
--- /dev/null
+++ b/sw/sys.h
@@ -0,0 +1,5 @@
+// TRIS
+enum {
+ OUT = 0,
+ IN = 1,
+};
diff --git a/sw/types.c b/sw/types.c
new file mode 100644
index 0000000..c18392e
--- /dev/null
+++ b/sw/types.c
@@ -0,0 +1,13 @@
+#include <xc.h>
+
+#include <stdint.h>
+
+#include "types.h"
+
+void
+incU16(U16 *x) {
+ x->lo++;
+ if (x->lo == 0u) {
+ x->hi++;
+ }
+}
diff --git a/sw/types.h b/sw/types.h
new file mode 100644
index 0000000..ba56050
--- /dev/null
+++ b/sw/types.h
@@ -0,0 +1,13 @@
+/* Usage:
+ *
+ * #include <stdint.h>
+ * #include "types.h"
+ */
+
+typedef uint8_t U8;
+
+typedef struct {
+ U8 lo, hi;
+} U16;
+
+void incU16(U16 *x);