From 6c2055af79f8bae9123c18a0ac29a4582eaa90f4 Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Sat, 4 Oct 2025 16:53:10 -0400 Subject: CAN filter- and mask-setting functions --- fw/can.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++------------- fw/can.h | 81 ++++++++++++++++++++++++++++++--- fw/types.h | 3 ++ 3 files changed, 193 insertions(+), 39 deletions(-) diff --git a/fw/can.c b/fw/can.c index b311383..aef2706 100644 --- a/fw/can.c +++ b/fw/can.c @@ -1,5 +1,6 @@ #include +#include #include #include "system.h" @@ -12,21 +13,21 @@ #define STARTUP_TIME 128u // Register addresses -enum { - // Config - REG_BFPCTRL = 0x0C, // pin control and status +typedef enum { + // Config and status REG_CANCTRL = 0x0F, // CAN control REG_CANSTAT = 0x0E, // CAN status + REG_BFPCTRL = 0x0C, // pin control and status + REG_RXB0CTRL = 0x60, // receive buffer 0 control + REG_RXB1CTRL = 0x70, // receive buffer 1 control + REG_CANINTE = 0x2B, // CAN interrupt enable + REG_CANINTF = 0x2C, // CAN interrupt flags // Bit timing REG_CNF1 = 0x2A, REG_CNF2 = 0x29, REG_CNF3 = 0x28, - // Interrupts - REG_CANINTE = 0x2B, // CAN interrupt enable - REG_CANINTF = 0x2C, // CAN interrupt flag - // Filter 0 REG_RXF0SIDH = 0x00, // standard ID high REG_RXF0SIDL = 0x01, // standard ID low @@ -76,7 +77,6 @@ enum { REG_RXM1EID0 = 0x27, // extended ID low // Receive buffer 0 - REG_RXB0CTRL = 0x60, // control REG_RXB0SIDH = 0x61, // standard ID high REG_RXB0SIDL = 0x62, // standard ID low REG_RXB0EID8 = 0x63, // extended ID high @@ -85,23 +85,13 @@ enum { REG_RXB0DM = 0x66, // data byte [66h+0, 66h+7] // Receive buffer 1 - REG_RXB1CTRL = 0x70, // control REG_RXB1SIDH = 0x71, // standard ID high REG_RXB1SIDL = 0x72, // standard ID low REG_RXB1EID8 = 0x73, // extended ID high REG_RXB1EID0 = 0x74, // extended ID low REG_RXB1DLC = 0x75, // data length code REG_RXB1DM = 0x76, // data byte [76h+0, 76h+7] -}; - -// Modes of operation -typedef enum { - MODE_NORMAL = 0x0, - MODE_SLEEP = 0x1, - MODE_LOOPBACK = 0x2, - MODE_LISTEN_ONLY = 0x3, - MODE_CONFIG = 0x4, -} Mode; +} Reg; // Instructions enum { @@ -130,17 +120,17 @@ reset(void) { CAN_CS = 1; } -// Read n registers into data, starting at the specified address. -static void -read(U8 addr, U8 *data, U8 n) { +// Read a register. +static U8 +read(Reg addr) { + U8 data; + CAN_CS = 0; (void)spiTx(CMD_READ); - (void)spiTx(addr); - while (n--) { - *data = spiTx(0x00); - data++; - } + (void)spiTx((U8)addr); + data = spiTx(0x00); CAN_CS = 1; + return data; } // Read the DATA field of one of the RX buffers. @@ -158,10 +148,10 @@ readRxData(RxBuf bufNum, U8 data[8u]) { // Write to a register. static void -write(U8 addr, U8 data) { +write(Reg addr, U8 data) { CAN_CS = 0; (void)spiTx(CMD_WRITE); - (void)spiTx(addr); + (void)spiTx((U8)addr); (void)spiTx(data); CAN_CS = 1; } @@ -180,10 +170,10 @@ rxStatus(void) { // Write individual bits of a register with the BIT MODIFY instruction. static void -bitModify(U8 addr, U8 mask, U8 data) { +bitModify(Reg addr, U8 mask, U8 data) { CAN_CS = 0; (void)spiTx(CMD_BIT_MODIFY); - (void)spiTx(addr); + (void)spiTx((U8)addr); (void)spiTx(mask); (void)spiTx(data); CAN_CS = 1; @@ -191,12 +181,106 @@ bitModify(U8 addr, U8 mask, U8 data) { void canInit(void) { + // Configure chip-select pin CAN_CS_TRIS = OUT; CAN_CS = 1; + // Send RESET command _delay(STARTUP_TIME); // wait for MCP2515 to power on reset(); // send RESET command _delay(STARTUP_TIME); // wait to power on again - // TODO + // Configure registers + canSetMode(CAN_MODE_CONFIG); + bitModify(REG_CANCTRL, 0x1F, 0x00); // disable one-shot mode and CLKOUT pin + write(REG_BFPCTRL, 0x00); // disable RXnBF interrupt pins + write(REG_RXB0CTRL, 0x00); // use filters, disable rollover + write(REG_RXB1CTRL, 0x00); // use filters +} + +void +canSetMode(CanMode mode) { + CanMode currentMode; + + do { + // Set REQOP of CANCTRL to request mode + bitModify(REG_CANCTRL, 0xE0, (U8) (mode << 5u)); + // Read OPMOD of CANSTAT + currentMode = read(REG_CANSTAT) >> 5u; + } while (currentMode != mode); +} + +void +canSetBitTiming(U8 cnf1, U8 cnf2, U8 cnf3) { + write(REG_CNF1, cnf1); + write(REG_CNF2, cnf2); + write(REG_CNF3, cnf3); +} + +void +canIE(bool enable) { + if (enable) { + write(REG_CANINTF, 0x00); // clear interrupt flags + write(REG_CANINTE, 0x03); // enable RX-buffer-full interrupts + } else { + write(REG_CANINTE, 0x00); // disable interrupts + } +} + +static void +writeIdToRegs(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) { + switch (id->type) { + case CAN_ID_STD: // standard ID + write(sidh, (U8)(id->sid.hi << 5u) | (U8)(id->sid.lo >> 3u)); + write(sidl, (U8) (id->sid.lo << 5u)); + write(eid8, 0x00); + write(eid0, 0x00); + break; + case CAN_ID_EXT: // extended ID + write(sidh, (U8)(id->eid[1] << 5u) | (U8)(id->eid[0] >> 3u)); // sid[10:3] + write(sidl, (U8)(id->eid[0] << 5u) | (U8)0x08 | (U8)((id->eid[3] >> 3u) & 0x03)); // sid[2:0], exide, eid[28:27] + write(eid8, (U8)(id->eid[3] << 5u) | (U8)(id->eid[2] >> 3u)); // eid[26:19] + write(eid0, (U8)(id->eid[2] << 5u) | (U8)(id->eid[1] >> 3u)); // eid[18:11] + break; + } +} + +void +canSetMask0(const CanId *mask) { + writeIdToRegs(mask, REG_RXM0SIDH, REG_RXM0SIDL, REG_RXM0EID8, REG_RXM0EID0); +} + +void +canSetMask1(const CanId *mask) { + writeIdToRegs(mask, REG_RXM1SIDH, REG_RXM1SIDL, REG_RXM1EID8, REG_RXM1EID0); +} + +void +canSetFilter0(const CanId *filter) { + writeIdToRegs(filter, REG_RXF0SIDH, REG_RXF0SIDL, REG_RXF0EID8, REG_RXF0EID0); +} + +void +canSetFilter1(const CanId *filter) { + writeIdToRegs(filter, REG_RXF1SIDH, REG_RXF1SIDL, REG_RXF1EID8, REG_RXF1EID0); +} + +void +canSetFilter2(const CanId *filter) { + writeIdToRegs(filter, REG_RXF2SIDH, REG_RXF2SIDL, REG_RXF2EID8, REG_RXF2EID0); +} + +void +canSetFilter3(const CanId *filter) { + writeIdToRegs(filter, REG_RXF3SIDH, REG_RXF3SIDL, REG_RXF3EID8, REG_RXF3EID0); +} + +void +canSetFilter4(const CanId *filter) { + writeIdToRegs(filter, REG_RXF4SIDH, REG_RXF4SIDL, REG_RXF4EID8, REG_RXF4EID0); +} + +void +canSetFilter5(const CanId *filter) { + writeIdToRegs(filter, REG_RXF5SIDH, REG_RXF5SIDL, REG_RXF5EID8, REG_RXF5EID0); } diff --git a/fw/can.h b/fw/can.h index 833a7c4..c9b3d4b 100644 --- a/fw/can.h +++ b/fw/can.h @@ -7,6 +7,7 @@ * * Usage: * + * #include * #include * #include "types.h" * #include "can.h" @@ -17,14 +18,80 @@ #define CAN_CS LATAbits.LATA5 // Bit timings (CNF1, CNF2, CNF3) -#define CAN_TIMINGS_10K 0xDE, 0xAD, 0x06 // BRP=30, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 -#define CAN_TIMINGS_20K 0xCF, 0xAD, 0x06 // BRP=15, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 -#define CAN_TIMINGS_50K 0xC6, 0xAD, 0x06 // BRP=6, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 -#define CAN_TIMINGS_100K 0xC3, 0xAD, 0x06 // BRP=3, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 -#define CAN_TIMINGS_125K 0xC4, 0x9A, 0x03 // BRP=4, PropSeg=3, PS1=4, PS2=4, SP=66.7%, SJW=4 -#define CAN_TIMINGS_250K 0xC2, 0x9A, 0x03 // BRP=2, PropSeg=3, PS1=4, PS2=4, SP=66.7%, SJW=4 -#define CAN_TIMINGS_500K 0xC1, 0x9A, 0x03 // BRP=1, PropSeg=3, PS1=4, PS2=4, SP=66.7, SJW=4 +#define CAN_TIMINGS_10K 0xDD, 0xAD, 0x06 // BRP=30, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 +#define CAN_TIMINGS_20K 0xCE, 0xAD, 0x06 // BRP=15, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 +#define CAN_TIMINGS_50K 0xC5, 0xAD, 0x06 // BRP=6, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 +#define CAN_TIMINGS_100K 0xC2, 0xAD, 0x06 // BRP=3, PropSeg=6, PS1=6, PS2=7, SP=65%, SJW=4 +#define CAN_TIMINGS_125K 0xC3, 0x9A, 0x03 // BRP=4, PropSeg=3, PS1=4, PS2=4, SP=66.7%, SJW=4 +#define CAN_TIMINGS_250K 0xC1, 0x9A, 0x03 // BRP=2, PropSeg=3, PS1=4, PS2=4, SP=66.7%, SJW=4 +#define CAN_TIMINGS_500K 0xC0, 0x9A, 0x03 // BRP=1, PropSeg=3, PS1=4, PS2=4, SP=66.7%, SJW=4 #define CAN_TIMINGS_800K "800kbps unsupported" // not possible with 12MHz clock #define CAN_TIMINGS_1M "1Mbps unsupported" // not possible with 12MHz clock +// MCP2515 modes of operation +typedef enum { + CAN_MODE_NORMAL = 0x0, + CAN_MODE_SLEEP = 0x1, + CAN_MODE_LOOPBACK = 0x2, + CAN_MODE_LISTEN_ONLY = 0x3, + CAN_MODE_CONFIG = 0x4, +} CanMode; + +// CAN identifier +typedef struct { + enum { + CAN_ID_STD, // standard + CAN_ID_EXT, // extended + } type; + union { + U16 sid; // 11-bit standard ID + U32 eid; // 29-bit extended ID + }; +} CanId; + +// Initialize the MCP2515. +// Initial mode is Config. void canInit(void); + +// Set the operating mode of the MCP2515. +void canSetMode(CanMode mode); + +// Set the bit timing parameters (bitrate, etc.). +// Pass one of the CAN_TIMINGS_x macros. +// The MCP2515 must be in Config mode. +void canSetBitTiming(U8 cnf1, U8 cnf2, U8 cnf3); + +// Enable/disable interrupts on the MCP2515's INT pin. +void canIE(bool enable); + +// Set the message acceptance mask of RXB0. +// The MCP2515 must be in Config mode. +void canSetMask0(const CanId *mask); + +// Set the message acceptance mask of RXB1. +// The MCP2515 must be in Config mode. +void canSetMask0(const CanId *mask); + +// Set message acceptance filter 0 (RXB0). +// The MCP2515 must be in Config mode. +void canSetFilter0(const CanId *filter); + +// Set message acceptance filter 1 (RXB0). +// The MCP2515 must be in Config mode. +void canSetFilter1(const CanId *filter); + +// Set message acceptance filter 2 (RXB1). +// The MCP2515 must be in Config mode. +void canSetFilter2(const CanId *filter); + +// Set message acceptance filter 3 (RXB1). +// The MCP2515 must be in Config mode. +void canSetFilter3(const CanId *filter); + +// Set message acceptance filter 4 (RXB1). +// The MCP2515 must be in Config mode. +void canSetFilter4(const CanId *filter); + +// Set message acceptance filter 5 (RXB1). +// The MCP2515 must be in Config mode. +void canSetFilter5(const CanId *filter); diff --git a/fw/types.h b/fw/types.h index 392c7cf..ccdf0ae 100644 --- a/fw/types.h +++ b/fw/types.h @@ -18,6 +18,9 @@ typedef struct { U8 hi, lo; } U16; +// Little-endian 32-bit unsigned integer. +typedef U8 U32[4]; + // *a = *a+b void addU16(U16 *a, U8 b); -- cgit v1.2.3