From 7fab1a08e546953f9f601cc108b1bb981316b344 Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Thu, 23 Oct 2025 15:18:11 -0400 Subject: canTx() --- fw/can.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++------------ fw/can.h | 13 +++++++++- fw/main.c | 3 +++ 3 files changed, 87 insertions(+), 18 deletions(-) (limited to 'fw') diff --git a/fw/can.c b/fw/can.c index aef2706..2998631 100644 --- a/fw/can.c +++ b/fw/can.c @@ -91,8 +91,29 @@ typedef enum { REG_RXB1EID0 = 0x74, // extended ID low REG_RXB1DLC = 0x75, // data length code REG_RXB1DM = 0x76, // data byte [76h+0, 76h+7] + + // Transmit buffer 0 + REG_TXB0CTRL = 0x30, // control + REG_TXB0SIDH = 0x31, // standard ID high + REG_TXB0SIDL = 0x32, // standard ID low + REG_TXB0EID8 = 0x33, // extended ID high + REG_TXB0EID0 = 0x34, // extended ID low + REG_TXB0DLC = 0x35, // data length code + REG_TXB0DM = 0x36, // data byte [36h+0, 36h+7] } Reg; +// Masks +enum { + // TXBnCTRL + TXREQ = 0x08, + TXERR = 0x10, + + // TXBnDLC + RTR = 0x40, + + EXIDE = 0x08, // extended identifier enable bit in SIDL registers +}; + // Instructions enum { CMD_RESET = 0xC0, @@ -133,19 +154,6 @@ read(Reg addr) { return data; } -// Read the DATA field of one of the RX buffers. -static void -readRxData(RxBuf bufNum, U8 data[8u]) { - U8 i; - - CAN_CS = 0; - (void)spiTx(CMD_READ_RX | (U8)(bufNum << 2u) | 1u); // start at RXBnD0 - for (i = 0u; i < 8u; i++) { - data[i] = spiTx(0x00); - } - CAN_CS = 1; -} - // Write to a register. static void write(Reg addr, U8 data) { @@ -156,9 +164,8 @@ write(Reg addr, U8 data) { CAN_CS = 1; } -// Read RX status. -static U8 -rxStatus(void) { +U8 +canRxStatus(void) { U8 status; CAN_CS = 0; @@ -227,6 +234,27 @@ canIE(bool enable) { } } +static void +readRxbnData(U8 n, U8 data[8u]) { + CAN_CS = 0; + n &= 0x01; // n in {0,1} + (void)spiTx(CMD_READ_RX | (U8)(n << 2u) | 0x02); // start at RXBnD0 + for (n = 0u; n < 8u; n++) { + data[n] = spiTx(0x00); + } + CAN_CS = 1; +} + +void +canReadRxb0Data(U8 data[8u]) { + readRxbnData(0u, data); +} + +void +canReadRxb1Data(U8 data[8u]) { + readRxbnData(1u, data); +} + static void writeIdToRegs(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) { switch (id->type) { @@ -238,13 +266,40 @@ writeIdToRegs(const CanId *id, Reg sidh, Reg sidl, Reg eid8, Reg eid0) { 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(sidl, (U8)(id->eid[0] << 5u) | EXIDE | (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; } } +Status +canTx(const CanFrame *frame) { + U8 k, ctrl; + + // Set ID, DLC, and RTR + writeIdToRegs(&frame->id, REG_TXB0SIDH, REG_TXB0SIDL, REG_TXB0EID8, REG_TXB0EID0); + write(REG_TXB0DLC, (frame->dlc & 0x0F) | ((frame->rtr) ? RTR : 0)); + + // Copy data to registers + for (k = 0u; k < frame->dlc; k++) { + write(REG_TXB0DM+k, frame->data[k]); + } + + // Send + bitModify(REG_TXB0CTRL, TXREQ, TXREQ); + do { + ctrl = read(REG_TXB0CTRL); + if (ctrl & TXERR) { + // Error + bitModify(REG_TXB0CTRL, TXREQ, 0); // cancel transmission + return FAIL; + } + } while (ctrl & TXREQ); // transmission in progress + + return OK; +} + void canSetMask0(const CanId *mask) { writeIdToRegs(mask, REG_RXM0SIDH, REG_RXM0SIDL, REG_RXM0EID8, REG_RXM0EID0); diff --git a/fw/can.h b/fw/can.h index c7a6c18..8e0cfff 100644 --- a/fw/can.h +++ b/fw/can.h @@ -49,6 +49,14 @@ typedef struct { }; } CanId; +// CAN frame +typedef struct { + CanId id; + U8 dlc; // data length code + U8 data[8]; + bool rtr; // remote transmission request +} CanFrame; + // Initialize the MCP2515. // Initial mode is Config. void canInit(void); @@ -61,7 +69,7 @@ void canSetMode(CanMode mode); // The MCP2515 must be in Config mode. void canSetBitTiming(U8 cnf1, U8 cnf2, U8 cnf3); -// Enable/disable interrupts on the MCP2515's INT pin. +// Enable/disable RX-buffer-full interrupts on the MCP2515's INT pin. void canIE(bool enable); // Read RX status with RX STATUS instruction. @@ -73,6 +81,9 @@ void canReadRxb0Data(U8 data[8u]); // Read the DATA field of RXB1. void canReadRxb1Data(U8 data[8u]); +// Transmit a frame to the CAN bus +Status canTx(const CanFrame *frame); + // Set the message acceptance mask of RXB0. // The MCP2515 must be in Config mode. void canSetMask0(const CanId *mask); diff --git a/fw/main.c b/fw/main.c index 8bf4f80..326f8bf 100644 --- a/fw/main.c +++ b/fw/main.c @@ -1,11 +1,13 @@ #include +#include #include #include "system.h" #include "types.h" #include "spi.h" #include "eeprom.h" +#include "can.h" #include "usb.h" void @@ -13,6 +15,7 @@ main(void) { sysInit(); spiInit(); eepromInit(); + canInit(); usbInit(); for (;;) { -- cgit v1.2.3