diff options
Diffstat (limited to 'fw')
| -rw-r--r-- | fw/main.c | 227 |
1 files changed, 161 insertions, 66 deletions
@@ -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 + } } |