diff options
| -rw-r--r-- | fw/eeprom.c | 103 | ||||
| -rw-r--r-- | fw/eeprom.h | 6 | ||||
| -rw-r--r-- | fw/tests/system/eeprom_can_systest.c | 120 | ||||
| -rw-r--r-- | fw/tests/system/eeprom_systest.c | 30 |
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 (;;) { + + } +} |