From 86baf31d9f6eb72d40960bc164480ae77c07729a Mon Sep 17 00:00:00 2001 From: thumptech Date: Tue, 15 Dec 2020 12:43:21 +1100 Subject: [PATCH] First commit --- .gitattributes | 2 + README.md | 2 + mcp2515.c | 847 +++++++++++++++++++++++++++++++++++++++++++++++ mcp2515.h | 98 ++++++ mcp2515_consts.h | 406 +++++++++++++++++++++++ 5 files changed, 1355 insertions(+) create mode 100644 .gitattributes create mode 100644 README.md create mode 100644 mcp2515.c create mode 100644 mcp2515.h create mode 100644 mcp2515_consts.h diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/README.md b/README.md new file mode 100644 index 0000000..398fc25 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# STM32-MCP2515 + C Driver for MCP2515 on STM32 MCU diff --git a/mcp2515.c b/mcp2515.c new file mode 100644 index 0000000..53300c2 --- /dev/null +++ b/mcp2515.c @@ -0,0 +1,847 @@ +/* + * mcp2515.c + * + * Created on: Dec 13, 2020 + * Author: matt + */ + +#include "mcp2515.h" +#include "mcp2515_consts.h" +#include +#include //Todo: this is yucky just for the memset function + +/* Modify below items for your SPI configurations */ +extern SPI_HandleTypeDef hspi4; +#define SPI_CAN &hspi4 +#define SPI_TIMEOUT 10 +//#define MCP2515_CS_HIGH() HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET) +//#define MCP2515_CS_LOW() HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_RESET) + +void startSPI() { + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_RESET); +} + +void endSPI() { + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_4, GPIO_PIN_SET); +} + +uint8_t SPI_transfer(uint8_t txByte){ + uint8_t rxByte; + HAL_SPI_TransmitReceive(SPI_CAN, &txByte, &rxByte, 1, SPI_TIMEOUT); + return rxByte; +} + +void setRegister(uint8_t reg, uint8_t value) +{ + startSPI(); + SPI_transfer(INSTRUCTION_WRITE); + SPI_transfer(reg); + SPI_transfer(value); + endSPI(); +} + +void setRegisters(uint8_t reg, uint8_t values[], uint8_t n) +{ + startSPI(); + SPI_transfer(INSTRUCTION_WRITE); + SPI_transfer(reg); + for (uint8_t i=0; i> 8); + canid = (uint16_t)(id >> 16); + buffer[MCP_SIDL] = (uint8_t) (canid & 0x03); + buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3); + buffer[MCP_SIDL] |= TXB_EXIDE_MASK; + buffer[MCP_SIDH] = (uint8_t) (canid >> 5); + } else { + buffer[MCP_SIDH] = (uint8_t) (canid >> 3); + buffer[MCP_SIDL] = (uint8_t) ((canid & 0x07 ) << 5); + buffer[MCP_EID0] = 0; + buffer[MCP_EID8] = 0; + } +} + +uint8_t getStatus(void) +{ + startSPI(); + SPI_transfer(INSTRUCTION_READ_STATUS); + uint8_t i = SPI_transfer(0x00); + endSPI(); + return i; +} + +CAN_Error MCP_setFilterMask(MASK mask, uint8_t ext, uint32_t ulData) +{ + CAN_Error res = setConfigMode(); + if (res != ERROR_OK) { + return res; + } + + uint8_t tbufdata[4]; + prepareId(tbufdata, ext, ulData); + + REGISTER reg; + switch (mask) { + case MASK0: reg = MCP_RXM0SIDH; break; + case MASK1: reg = MCP_RXM1SIDH; break; + default: + return ERROR_FAIL; + } + + setRegisters(reg, tbufdata, 4); + + return ERROR_OK; +} + +CAN_Error MCP_setFilter(RXF num, uint8_t ext, uint32_t ulData) +{ + CAN_Error res = setConfigMode(); + if (res != ERROR_OK) { + return res; + } + + REGISTER reg; + + switch (num) { + case RXF0: reg = MCP_RXF0SIDH; break; + case RXF1: reg = MCP_RXF1SIDH; break; + case RXF2: reg = MCP_RXF2SIDH; break; + case RXF3: reg = MCP_RXF3SIDH; break; + case RXF4: reg = MCP_RXF4SIDH; break; + case RXF5: reg = MCP_RXF5SIDH; break; + default: + return ERROR_FAIL; + } + + uint8_t tbufdata[4]; + prepareId(tbufdata, ext, ulData); + setRegisters(reg, tbufdata, 4); + + return ERROR_OK; +} + +CAN_Error MCP2515_reset(void) +{ + startSPI(); + SPI_transfer(INSTRUCTION_RESET); + endSPI(); + + + HAL_Delay(10); + + uint8_t zeros[14]; + memset(zeros, 0, sizeof(zeros)); + setRegisters(MCP_TXB0CTRL, zeros, 14); + setRegisters(MCP_TXB1CTRL, zeros, 14); + setRegisters(MCP_TXB2CTRL, zeros, 14); + + setRegister(MCP_RXB0CTRL, 0); + setRegister(MCP_RXB1CTRL, 0); + + setRegister(MCP_CANINTE, CANINTF_RX0IF | CANINTF_RX1IF | CANINTF_ERRIF | CANINTF_MERRF); + + // receives all valid messages using either Standard or Extended Identifiers that + // meet filter criteria. RXF0 is applied for RXB0, RXF1 is applied for RXB1 + modifyRegister(MCP_RXB0CTRL, + RXBnCTRL_RXM_MASK | RXB0CTRL_BUKT | RXB0CTRL_FILHIT_MASK, + RXBnCTRL_RXM_STDEXT | RXB0CTRL_BUKT | RXB0CTRL_FILHIT); + modifyRegister(MCP_RXB1CTRL, + RXBnCTRL_RXM_MASK | RXB1CTRL_FILHIT_MASK, + RXBnCTRL_RXM_STDEXT | RXB1CTRL_FILHIT); + + // clear filters and masks + // do not filter any standard frames for RXF0 used by RXB0 + // do not filter any extended frames for RXF1 used by RXB1 + RXF filters[] = {RXF0, RXF1, RXF2, RXF3, RXF4, RXF5}; + for (uint8_t i=0; i<6; i++) { + uint8_t ext = (i == 1); + CAN_Error result = MCP_setFilter(filters[i], ext, 0); + if (result != ERROR_OK) { + return result; + } + } + + MASK masks[] = {MASK0, MASK1}; + for (int i=0; i<2; i++) { + CAN_Error result = MCP_setFilterMask(masks[i], 1, 0); + if (result != ERROR_OK) { + return result; + } + } + + return ERROR_OK; +} + +CAN_Error MCP_reset(void) +{ + startSPI(); + SPI_transfer(INSTRUCTION_RESET); + endSPI(); + + HAL_Delay(10); + + uint8_t zeros[14]; + memset(zeros, 0, sizeof(zeros)); + setRegisters(MCP_TXB0CTRL, zeros, 14); + setRegisters(MCP_TXB1CTRL, zeros, 14); + setRegisters(MCP_TXB2CTRL, zeros, 14); + + setRegister(MCP_RXB0CTRL, 0); + setRegister(MCP_RXB1CTRL, 0); + + setRegister(MCP_CANINTE, CANINTF_RX0IF | CANINTF_RX1IF | CANINTF_ERRIF | CANINTF_MERRF); + + // receives all valid messages using either Standard or Extended Identifiers that + // meet filter criteria. RXF0 is applied for RXB0, RXF1 is applied for RXB1 + modifyRegister(MCP_RXB0CTRL, + RXBnCTRL_RXM_MASK | RXB0CTRL_BUKT | RXB0CTRL_FILHIT_MASK, + RXBnCTRL_RXM_STDEXT | RXB0CTRL_BUKT | RXB0CTRL_FILHIT); + modifyRegister(MCP_RXB1CTRL, + RXBnCTRL_RXM_MASK | RXB1CTRL_FILHIT_MASK, + RXBnCTRL_RXM_STDEXT | RXB1CTRL_FILHIT); + + // clear filters and masks + // do not filter any standard frames for RXF0 used by RXB0 + // do not filter any extended frames for RXF1 used by RXB1 + RXF filters[] = {RXF0, RXF1, RXF2, RXF3, RXF4, RXF5}; + for (int i=0; i<6; i++) { + uint8_t ext = (i == 1); + CAN_Error result = MCP_setFilter(filters[i], ext, 0); + if (result != ERROR_OK) { + return result; + } + } + + MASK masks[] = {MASK0, MASK1}; + for (int i=0; i<2; i++) { + CAN_Error result = MCP_setFilterMask(masks[i], 1, 0); + if (result != ERROR_OK) { + return result; + } + } + + return ERROR_OK; +} + +CAN_Error MCP_setListenOnlyMode() +{ + return setMode(CANCTRL_REQOP_LISTENONLY); +} + +CAN_Error MCP_setSleepMode() +{ + return setMode(CANCTRL_REQOP_SLEEP); +} + +CAN_Error MCP_setLoopbackMode() +{ + return setMode(CANCTRL_REQOP_LOOPBACK); +} + +CAN_Error MCP_setNormalMode() +{ + return setMode(CANCTRL_REQOP_NORMAL); +} + +CAN_Error MCP_setBitrateClock(CAN_SPEED canSpeed, CAN_CLOCK canClock) +{ + CAN_Error error = setConfigMode(); + if (error != ERROR_OK) { + return error; + } + + uint8_t set, cfg1, cfg2, cfg3; + set = 1; + switch (canClock) + { + case (MCP_8MHZ): + switch (canSpeed) + { + case (CAN_5KBPS): // 5KBPS + cfg1 = MCP_8MHz_5kBPS_CFG1; + cfg2 = MCP_8MHz_5kBPS_CFG2; + cfg3 = MCP_8MHz_5kBPS_CFG3; + break; + + case (CAN_10KBPS): // 10KBPS + cfg1 = MCP_8MHz_10kBPS_CFG1; + cfg2 = MCP_8MHz_10kBPS_CFG2; + cfg3 = MCP_8MHz_10kBPS_CFG3; + break; + + case (CAN_20KBPS): // 20KBPS + cfg1 = MCP_8MHz_20kBPS_CFG1; + cfg2 = MCP_8MHz_20kBPS_CFG2; + cfg3 = MCP_8MHz_20kBPS_CFG3; + break; + + case (CAN_31K25BPS): // 31.25KBPS + cfg1 = MCP_8MHz_31k25BPS_CFG1; + cfg2 = MCP_8MHz_31k25BPS_CFG2; + cfg3 = MCP_8MHz_31k25BPS_CFG3; + break; + + case (CAN_33KBPS): // 33.333KBPS + cfg1 = MCP_8MHz_33k3BPS_CFG1; + cfg2 = MCP_8MHz_33k3BPS_CFG2; + cfg3 = MCP_8MHz_33k3BPS_CFG3; + break; + + case (CAN_40KBPS): // 40Kbps + cfg1 = MCP_8MHz_40kBPS_CFG1; + cfg2 = MCP_8MHz_40kBPS_CFG2; + cfg3 = MCP_8MHz_40kBPS_CFG3; + break; + + case (CAN_50KBPS): // 50Kbps + cfg1 = MCP_8MHz_50kBPS_CFG1; + cfg2 = MCP_8MHz_50kBPS_CFG2; + cfg3 = MCP_8MHz_50kBPS_CFG3; + break; + + case (CAN_80KBPS): // 80Kbps + cfg1 = MCP_8MHz_80kBPS_CFG1; + cfg2 = MCP_8MHz_80kBPS_CFG2; + cfg3 = MCP_8MHz_80kBPS_CFG3; + break; + + case (CAN_100KBPS): // 100Kbps + cfg1 = MCP_8MHz_100kBPS_CFG1; + cfg2 = MCP_8MHz_100kBPS_CFG2; + cfg3 = MCP_8MHz_100kBPS_CFG3; + break; + + case (CAN_125KBPS): // 125Kbps + cfg1 = MCP_8MHz_125kBPS_CFG1; + cfg2 = MCP_8MHz_125kBPS_CFG2; + cfg3 = MCP_8MHz_125kBPS_CFG3; + break; + + case (CAN_200KBPS): // 200Kbps + cfg1 = MCP_8MHz_200kBPS_CFG1; + cfg2 = MCP_8MHz_200kBPS_CFG2; + cfg3 = MCP_8MHz_200kBPS_CFG3; + break; + + case (CAN_250KBPS): // 250Kbps + cfg1 = MCP_8MHz_250kBPS_CFG1; + cfg2 = MCP_8MHz_250kBPS_CFG2; + cfg3 = MCP_8MHz_250kBPS_CFG3; + break; + + case (CAN_500KBPS): // 500Kbps + cfg1 = MCP_8MHz_500kBPS_CFG1; + cfg2 = MCP_8MHz_500kBPS_CFG2; + cfg3 = MCP_8MHz_500kBPS_CFG3; + break; + + case (CAN_1000KBPS): // 1Mbps + cfg1 = MCP_8MHz_1000kBPS_CFG1; + cfg2 = MCP_8MHz_1000kBPS_CFG2; + cfg3 = MCP_8MHz_1000kBPS_CFG3; + break; + + default: + set = 0; + break; + } + break; + + case (MCP_16MHZ): + switch (canSpeed) + { + case (CAN_5KBPS): // 5Kbps + cfg1 = MCP_16MHz_5kBPS_CFG1; + cfg2 = MCP_16MHz_5kBPS_CFG2; + cfg3 = MCP_16MHz_5kBPS_CFG3; + break; + + case (CAN_10KBPS): // 10Kbps + cfg1 = MCP_16MHz_10kBPS_CFG1; + cfg2 = MCP_16MHz_10kBPS_CFG2; + cfg3 = MCP_16MHz_10kBPS_CFG3; + break; + + case (CAN_20KBPS): // 20Kbps + cfg1 = MCP_16MHz_20kBPS_CFG1; + cfg2 = MCP_16MHz_20kBPS_CFG2; + cfg3 = MCP_16MHz_20kBPS_CFG3; + break; + + case (CAN_33KBPS): // 33.333Kbps + cfg1 = MCP_16MHz_33k3BPS_CFG1; + cfg2 = MCP_16MHz_33k3BPS_CFG2; + cfg3 = MCP_16MHz_33k3BPS_CFG3; + break; + + case (CAN_40KBPS): // 40Kbps + cfg1 = MCP_16MHz_40kBPS_CFG1; + cfg2 = MCP_16MHz_40kBPS_CFG2; + cfg3 = MCP_16MHz_40kBPS_CFG3; + break; + + case (CAN_50KBPS): // 50Kbps + cfg1 = MCP_16MHz_50kBPS_CFG1; + cfg2 = MCP_16MHz_50kBPS_CFG2; + cfg3 = MCP_16MHz_50kBPS_CFG3; + break; + + case (CAN_80KBPS): // 80Kbps + cfg1 = MCP_16MHz_80kBPS_CFG1; + cfg2 = MCP_16MHz_80kBPS_CFG2; + cfg3 = MCP_16MHz_80kBPS_CFG3; + break; + + case (CAN_83K3BPS): // 83.333Kbps + cfg1 = MCP_16MHz_83k3BPS_CFG1; + cfg2 = MCP_16MHz_83k3BPS_CFG2; + cfg3 = MCP_16MHz_83k3BPS_CFG3; + break; + + case (CAN_100KBPS): // 100Kbps + cfg1 = MCP_16MHz_100kBPS_CFG1; + cfg2 = MCP_16MHz_100kBPS_CFG2; + cfg3 = MCP_16MHz_100kBPS_CFG3; + break; + + case (CAN_125KBPS): // 125Kbps + cfg1 = MCP_16MHz_125kBPS_CFG1; + cfg2 = MCP_16MHz_125kBPS_CFG2; + cfg3 = MCP_16MHz_125kBPS_CFG3; + break; + + case (CAN_200KBPS): // 200Kbps + cfg1 = MCP_16MHz_200kBPS_CFG1; + cfg2 = MCP_16MHz_200kBPS_CFG2; + cfg3 = MCP_16MHz_200kBPS_CFG3; + break; + + case (CAN_250KBPS): // 250Kbps + cfg1 = MCP_16MHz_250kBPS_CFG1; + cfg2 = MCP_16MHz_250kBPS_CFG2; + cfg3 = MCP_16MHz_250kBPS_CFG3; + break; + + case (CAN_500KBPS): // 500Kbps + cfg1 = MCP_16MHz_500kBPS_CFG1; + cfg2 = MCP_16MHz_500kBPS_CFG2; + cfg3 = MCP_16MHz_500kBPS_CFG3; + break; + + case (CAN_1000KBPS): // 1Mbps + cfg1 = MCP_16MHz_1000kBPS_CFG1; + cfg2 = MCP_16MHz_1000kBPS_CFG2; + cfg3 = MCP_16MHz_1000kBPS_CFG3; + break; + + default: + set = 0; + break; + } + break; + + case (MCP_20MHZ): + switch (canSpeed) + { + case (CAN_33KBPS): // 33.333Kbps + cfg1 = MCP_20MHz_33k3BPS_CFG1; + cfg2 = MCP_20MHz_33k3BPS_CFG2; + cfg3 = MCP_20MHz_33k3BPS_CFG3; + break; + + case (CAN_40KBPS): // 40Kbps + cfg1 = MCP_20MHz_40kBPS_CFG1; + cfg2 = MCP_20MHz_40kBPS_CFG2; + cfg3 = MCP_20MHz_40kBPS_CFG3; + break; + + case (CAN_50KBPS): // 50Kbps + cfg1 = MCP_20MHz_50kBPS_CFG1; + cfg2 = MCP_20MHz_50kBPS_CFG2; + cfg3 = MCP_20MHz_50kBPS_CFG3; + break; + + case (CAN_80KBPS): // 80Kbps + cfg1 = MCP_20MHz_80kBPS_CFG1; + cfg2 = MCP_20MHz_80kBPS_CFG2; + cfg3 = MCP_20MHz_80kBPS_CFG3; + break; + + case (CAN_83K3BPS): // 83.333Kbps + cfg1 = MCP_20MHz_83k3BPS_CFG1; + cfg2 = MCP_20MHz_83k3BPS_CFG2; + cfg3 = MCP_20MHz_83k3BPS_CFG3; + break; + + case (CAN_100KBPS): // 100Kbps + cfg1 = MCP_20MHz_100kBPS_CFG1; + cfg2 = MCP_20MHz_100kBPS_CFG2; + cfg3 = MCP_20MHz_100kBPS_CFG3; + break; + + case (CAN_125KBPS): // 125Kbps + cfg1 = MCP_20MHz_125kBPS_CFG1; + cfg2 = MCP_20MHz_125kBPS_CFG2; + cfg3 = MCP_20MHz_125kBPS_CFG3; + break; + + case (CAN_200KBPS): // 200Kbps + cfg1 = MCP_20MHz_200kBPS_CFG1; + cfg2 = MCP_20MHz_200kBPS_CFG2; + cfg3 = MCP_20MHz_200kBPS_CFG3; + break; + + case (CAN_250KBPS): // 250Kbps + cfg1 = MCP_20MHz_250kBPS_CFG1; + cfg2 = MCP_20MHz_250kBPS_CFG2; + cfg3 = MCP_20MHz_250kBPS_CFG3; + break; + + case (CAN_500KBPS): // 500Kbps + cfg1 = MCP_20MHz_500kBPS_CFG1; + cfg2 = MCP_20MHz_500kBPS_CFG2; + cfg3 = MCP_20MHz_500kBPS_CFG3; + break; + + case (CAN_1000KBPS): // 1Mbps + cfg1 = MCP_20MHz_1000kBPS_CFG1; + cfg2 = MCP_20MHz_1000kBPS_CFG2; + cfg3 = MCP_20MHz_1000kBPS_CFG3; + break; + + default: + set = 0; + break; + } + break; + + default: + set = 0; + break; + } + + if (set) { + setRegister(MCP_CNF1, cfg1); + setRegister(MCP_CNF2, cfg2); + setRegister(MCP_CNF3, cfg3); + return ERROR_OK; + } + else { + return ERROR_FAIL; + } +} + +CAN_Error MCP_setBitrate( CAN_SPEED canSpeed) +{ + return MCP_setBitrateClock(canSpeed, MCP_16MHZ); +} + + +void MCP_RequestToSend(uint8_t instruction) +{ + startSPI(); + SPI_transfer(instruction); + endSPI(); +} + +CAN_Error MCP_sendMessageTo(TXBn txbn, can_frame *frame) +//TXBm is just 0,1,2 for txbox number +{ + if (frame->can_dlc > CAN_MAX_DLEN) { + return ERROR_FAILTX; + } + + //Todo, fix these magic numbers, but not with something as awful as the og arduino library + uint8_t load_addr = (2 * txbn) | 0x40; + + uint8_t rts_addr = (1 << txbn) | 0x80; + + uint8_t data[13]; + + uint8_t ext = !!(frame->can_id & CAN_EFF_FLAG); + uint8_t rtr = !!(frame->can_id & CAN_RTR_FLAG); + uint32_t id = (frame->can_id & (ext ? CAN_EFF_MASK : CAN_SFF_MASK)); + + prepareId(data, ext, id); + + data[MCP_DLC] = rtr ? (frame->can_dlc | RTR_MASK) : frame->can_dlc; + + for(int i = 0; i < frame->can_dlc; i++){ + data[MCP_DATA+i]=frame->data[i]; + } + + // memcpy(&data[MCP_DATA], frame->data, frame->can_dlc); + + loadTx(load_addr, data, 5 + frame->can_dlc); + //setRegisters(load_addr, data, 5 + frame->can_dlc); + + //modifyRegister(txbuf->CTRL, TXB_TXREQ, TXB_TXREQ); + //modifyRegister(rts_addr, TXB_TXREQ, TXB_TXREQ); + MCP_RequestToSend(rts_addr); + //setRegister(rts_addr, TXB_TXREQ); + + uint8_t ctrl = readRegister(rts_addr); + if ((ctrl & (TXB_ABTF | TXB_MLOA | TXB_TXERR)) != 0) { + return ERROR_FAILTX; + } + return ERROR_OK; +} + +CAN_Error MCP_sendMessage(can_frame *frame) +{ + if (frame->can_dlc > CAN_MAX_DLEN) { + return ERROR_FAILTX; + } + + + for (uint8_t i=0; i>5); + + if ( (rxReg.rx_reg_array[MCP_SIDL] & TXB_EXIDE_MASK) == TXB_EXIDE_MASK ) { + id = (id<<2) + (rxReg.rx_reg_array[MCP_SIDL] & 0x03); + id = (id<<8) + rxReg.rx_reg_array[MCP_EID8]; + id = (id<<8) + rxReg.rx_reg_array[MCP_EID0]; + id |= CAN_EFF_FLAG; + } + + uint8_t dlc = (rxReg.rx_reg_array[MCP_DLC] & DLC_MASK); + if (dlc > CAN_MAX_DLEN) { + return ERROR_FAIL; + } + + + //0x60 or 0x70 + uint8_t ctrl = readRegister((rxbn + 6) << 4); + if (ctrl & RXBnCTRL_RTR) { + id |= CAN_RTR_FLAG; + } + + frame->can_id = id; + frame->can_dlc = dlc; + + frame->data[0] = rxReg.RXBnD0; + frame->data[1] = rxReg.RXBnD1; + frame->data[2] = rxReg.RXBnD2; + frame->data[3] = rxReg.RXBnD3; + frame->data[4] = rxReg.RXBnD4; + frame->data[5] = rxReg.RXBnD5; + frame->data[6] = rxReg.RXBnD6; + frame->data[7] = rxReg.RXBnD7; + + + //Clear the inbox interrupt, 0x1 or 0x2 + modifyRegister(MCP_CANINTF, rxbn + 1, 0); + + return ERROR_OK; +} + +CAN_Error MCP_readMessage(can_frame *frame) +{ + CAN_Error rc; + uint8_t stat = getStatus(); + + if ( stat & STAT_RX0IF ) { + rc = MCP_readMessageFrom(RXB0, frame); + } else if ( stat & STAT_RX1IF ) { + rc = MCP_readMessageFrom(RXB1, frame); + } else { + rc = ERROR_NOMSG; + } + + return rc; +} + +uint8_t MCP_checkReceive(void) +{ + uint8_t res = getStatus(); + if ( res & STAT_RXIF_MASK ) { + return 1; + } else { + return 0; + } +} + +uint8_t MCP_getErrorFlags(void) +{ + return readRegister(MCP_EFLG); +} + +uint8_t MCP_checkError(void) +{ + uint8_t eflg = MCP_getErrorFlags(); + + if ( eflg & EFLG_ERRORMASK ) { + return 1; + } else { + return 0; + } +} + + +void MCP_clearRXnOVRFlags(void) +{ + modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0); +} + +uint8_t MCP_getInterrupts(void) +{ + return readRegister(MCP_CANINTF); +} + +void MCP_clearInterrupts(void) +{ + setRegister(MCP_CANINTF, 0); +} + +uint8_t MCP_getInterruptMask(void) +{ + return readRegister(MCP_CANINTE); +} + +void MCP_clearTXInterrupts(void) +{ + modifyRegister(MCP_CANINTF, (CANINTF_TX0IF | CANINTF_TX1IF | CANINTF_TX2IF), 0); +} + +void MCP_clearRXnOVR(void) +{ + uint8_t eflg = MCP_getErrorFlags(); + if (eflg != 0) { + MCP_clearRXnOVRFlags(); + MCP_clearInterrupts(); + //modifyRegister(MCP_CANINTF, CANINTF_ERRIF, 0); + } + +} + +void MCP_clearMERR() +{ + //modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0); + //clearInterrupts(); + modifyRegister(MCP_CANINTF, CANINTF_MERRF, 0); +} + +void MCP_clearERRIF() +{ + //modifyRegister(MCP_EFLG, EFLG_RX0OVR | EFLG_RX1OVR, 0); + //clearInterrupts(); + modifyRegister(MCP_CANINTF, CANINTF_ERRIF, 0); +} + diff --git a/mcp2515.h b/mcp2515.h new file mode 100644 index 0000000..ada128f --- /dev/null +++ b/mcp2515.h @@ -0,0 +1,98 @@ +/* + * mcp2515.h + * + * Created on: Dec 13, 2020 + * Author: matt + */ + +#ifndef APPLICATION_USER_INC_MCP2515_H_ +#define APPLICATION_USER_INC_MCP2515_H_ + +#include +#include "can.h" + +typedef enum { + ERROR_OK = 0, + ERROR_FAIL = 1, + ERROR_ALLTXBUSY = 2, + ERROR_FAILINIT = 3, + ERROR_FAILTX = 4, + ERROR_NOMSG = 5 +} CAN_Error; + +typedef enum { + CLKOUT_DISABLE = -1, + CLKOUT_DIV1 = 0x0, + CLKOUT_DIV2 = 0x1, + CLKOUT_DIV4 = 0x2, + CLKOUT_DIV8 = 0x3, +} CAN_CLKOUT; + +typedef enum { + MCP_20MHZ, MCP_16MHZ, MCP_8MHZ +} CAN_CLOCK; + +typedef enum { + CAN_5KBPS, + CAN_10KBPS, + CAN_20KBPS, + CAN_31K25BPS, + CAN_33KBPS, + CAN_40KBPS, + CAN_50KBPS, + CAN_80KBPS, + CAN_83K3BPS, + CAN_95KBPS, + CAN_100KBPS, + CAN_125KBPS, + CAN_200KBPS, + CAN_250KBPS, + CAN_500KBPS, + CAN_1000KBPS +} CAN_SPEED; + +typedef enum { + MASK0, MASK1 +} MASK; + +typedef enum { + RXF0 = 0, RXF1 = 1, RXF2 = 2, RXF3 = 3, RXF4 = 4, RXF5 = 5 +} RXF; + +typedef enum { + TXB0 = 0, TXB1 = 1, TXB2 = 2 +} TXBn; + +typedef enum { + RXB0 = 0, RXB1 = 1 +} RXBn; + + +CAN_Error MCP_reset(void);// +CAN_Error MCP_setListenOnlyMode();// +CAN_Error MCP_setSleepMode();// +CAN_Error MCP_setLoopbackMode();// +CAN_Error MCP_setNormalMode();// +CAN_Error MCP_setBitrate(CAN_SPEED canSpeed);// +CAN_Error MCP_setBitrateClock(CAN_SPEED canSpeed, CAN_CLOCK canClock); // +CAN_Error MCP_setFilterMask(MASK num, uint8_t ext, uint32_t ulData);// +CAN_Error MCP_setFilter(RXF num, uint8_t ext, uint32_t ulData);// +CAN_Error MCP_sendMessageTo(TXBn txbn, can_frame *frame);// +CAN_Error MCP_sendMessage(can_frame *frame);// +CAN_Error MCP_readMessageFrom(RXBn rxbn, can_frame *frame);// +CAN_Error MCP_readMessage(can_frame *frame);// +uint8_t MCP_checkReceive(void);// +uint8_t MCP_checkError(void);// +uint8_t MCP_getErrorFlags(void);// +void MCP_clearRXnOVRFlags(void);// +uint8_t MCP_getInterrupts(void);// +uint8_t MCP_getInterruptMask(void);// +void MCP_clearInterrupts(void);// +void MCP_clearTXInterrupts(void); +uint8_t MCP_getStatus(void);// +void MCP_clearRXnOVR(void);// +void MCP_clearMERR();// +void MCP_clearERRIF();// + +#endif /* APPLICATION_USER_INC_MCP2515_H_ */ + diff --git a/mcp2515_consts.h b/mcp2515_consts.h new file mode 100644 index 0000000..4185d0f --- /dev/null +++ b/mcp2515_consts.h @@ -0,0 +1,406 @@ +/* + * mcp2515_consts.h + * + * Created on: Dec 13, 2020 + * Author: matt + */ + +#ifndef APPLICATION_USER_INC_MCP2515_CONSTS_H_ +#define APPLICATION_USER_INC_MCP2515_CONSTS_H_ + + +#include + +/* + * Speed 8M + */ +#define MCP_8MHz_1000kBPS_CFG1 (0x00) +#define MCP_8MHz_1000kBPS_CFG2 (0x80) +#define MCP_8MHz_1000kBPS_CFG3 (0x80) + +#define MCP_8MHz_500kBPS_CFG1 (0x00) +#define MCP_8MHz_500kBPS_CFG2 (0x90) +#define MCP_8MHz_500kBPS_CFG3 (0x82) + +#define MCP_8MHz_250kBPS_CFG1 (0x00) +#define MCP_8MHz_250kBPS_CFG2 (0xB1) +#define MCP_8MHz_250kBPS_CFG3 (0x85) + +#define MCP_8MHz_200kBPS_CFG1 (0x00) +#define MCP_8MHz_200kBPS_CFG2 (0xB4) +#define MCP_8MHz_200kBPS_CFG3 (0x86) + +#define MCP_8MHz_125kBPS_CFG1 (0x01) +#define MCP_8MHz_125kBPS_CFG2 (0xB1) +#define MCP_8MHz_125kBPS_CFG3 (0x85) + +#define MCP_8MHz_100kBPS_CFG1 (0x01) +#define MCP_8MHz_100kBPS_CFG2 (0xB4) +#define MCP_8MHz_100kBPS_CFG3 (0x86) + +#define MCP_8MHz_80kBPS_CFG1 (0x01) +#define MCP_8MHz_80kBPS_CFG2 (0xBF) +#define MCP_8MHz_80kBPS_CFG3 (0x87) + +#define MCP_8MHz_50kBPS_CFG1 (0x03) +#define MCP_8MHz_50kBPS_CFG2 (0xB4) +#define MCP_8MHz_50kBPS_CFG3 (0x86) + +#define MCP_8MHz_40kBPS_CFG1 (0x03) +#define MCP_8MHz_40kBPS_CFG2 (0xBF) +#define MCP_8MHz_40kBPS_CFG3 (0x87) + +#define MCP_8MHz_33k3BPS_CFG1 (0x47) +#define MCP_8MHz_33k3BPS_CFG2 (0xE2) +#define MCP_8MHz_33k3BPS_CFG3 (0x85) + +#define MCP_8MHz_31k25BPS_CFG1 (0x07) +#define MCP_8MHz_31k25BPS_CFG2 (0xA4) +#define MCP_8MHz_31k25BPS_CFG3 (0x84) + +#define MCP_8MHz_20kBPS_CFG1 (0x07) +#define MCP_8MHz_20kBPS_CFG2 (0xBF) +#define MCP_8MHz_20kBPS_CFG3 (0x87) + +#define MCP_8MHz_10kBPS_CFG1 (0x0F) +#define MCP_8MHz_10kBPS_CFG2 (0xBF) +#define MCP_8MHz_10kBPS_CFG3 (0x87) + +#define MCP_8MHz_5kBPS_CFG1 (0x1F) +#define MCP_8MHz_5kBPS_CFG2 (0xBF) +#define MCP_8MHz_5kBPS_CFG3 (0x87) + +/* + * speed 16M + */ +#define MCP_16MHz_1000kBPS_CFG1 (0x00) +#define MCP_16MHz_1000kBPS_CFG2 (0xD0) +#define MCP_16MHz_1000kBPS_CFG3 (0x82) + +#define MCP_16MHz_500kBPS_CFG1 (0x00) +#define MCP_16MHz_500kBPS_CFG2 (0xF0) +#define MCP_16MHz_500kBPS_CFG3 (0x86) + +#define MCP_16MHz_250kBPS_CFG1 (0x41) +#define MCP_16MHz_250kBPS_CFG2 (0xF1) +#define MCP_16MHz_250kBPS_CFG3 (0x85) + +#define MCP_16MHz_200kBPS_CFG1 (0x01) +#define MCP_16MHz_200kBPS_CFG2 (0xFA) +#define MCP_16MHz_200kBPS_CFG3 (0x87) + +#define MCP_16MHz_125kBPS_CFG1 (0x03) +#define MCP_16MHz_125kBPS_CFG2 (0xF0) +#define MCP_16MHz_125kBPS_CFG3 (0x86) + +#define MCP_16MHz_100kBPS_CFG1 (0x03) +#define MCP_16MHz_100kBPS_CFG2 (0xFA) +#define MCP_16MHz_100kBPS_CFG3 (0x87) + +#define MCP_16MHz_80kBPS_CFG1 (0x03) +#define MCP_16MHz_80kBPS_CFG2 (0xFF) +#define MCP_16MHz_80kBPS_CFG3 (0x87) + +#define MCP_16MHz_83k3BPS_CFG1 (0x03) +#define MCP_16MHz_83k3BPS_CFG2 (0xBE) +#define MCP_16MHz_83k3BPS_CFG3 (0x07) + +#define MCP_16MHz_50kBPS_CFG1 (0x07) +#define MCP_16MHz_50kBPS_CFG2 (0xFA) +#define MCP_16MHz_50kBPS_CFG3 (0x87) + +#define MCP_16MHz_40kBPS_CFG1 (0x07) +#define MCP_16MHz_40kBPS_CFG2 (0xFF) +#define MCP_16MHz_40kBPS_CFG3 (0x87) + +#define MCP_16MHz_33k3BPS_CFG1 (0x4E) +#define MCP_16MHz_33k3BPS_CFG2 (0xF1) +#define MCP_16MHz_33k3BPS_CFG3 (0x85) + +#define MCP_16MHz_20kBPS_CFG1 (0x0F) +#define MCP_16MHz_20kBPS_CFG2 (0xFF) +#define MCP_16MHz_20kBPS_CFG3 (0x87) + +#define MCP_16MHz_10kBPS_CFG1 (0x1F) +#define MCP_16MHz_10kBPS_CFG2 (0xFF) +#define MCP_16MHz_10kBPS_CFG3 (0x87) + +#define MCP_16MHz_5kBPS_CFG1 (0x3F) +#define MCP_16MHz_5kBPS_CFG2 (0xFF) +#define MCP_16MHz_5kBPS_CFG3 (0x87) + +/* + * speed 20M + */ +#define MCP_20MHz_1000kBPS_CFG1 (0x00) +#define MCP_20MHz_1000kBPS_CFG2 (0xD9) +#define MCP_20MHz_1000kBPS_CFG3 (0x82) + +#define MCP_20MHz_500kBPS_CFG1 (0x00) +#define MCP_20MHz_500kBPS_CFG2 (0xFA) +#define MCP_20MHz_500kBPS_CFG3 (0x87) + +#define MCP_20MHz_250kBPS_CFG1 (0x41) +#define MCP_20MHz_250kBPS_CFG2 (0xFB) +#define MCP_20MHz_250kBPS_CFG3 (0x86) + +#define MCP_20MHz_200kBPS_CFG1 (0x01) +#define MCP_20MHz_200kBPS_CFG2 (0xFF) +#define MCP_20MHz_200kBPS_CFG3 (0x87) + +#define MCP_20MHz_125kBPS_CFG1 (0x03) +#define MCP_20MHz_125kBPS_CFG2 (0xFA) +#define MCP_20MHz_125kBPS_CFG3 (0x87) + +#define MCP_20MHz_100kBPS_CFG1 (0x04) +#define MCP_20MHz_100kBPS_CFG2 (0xFA) +#define MCP_20MHz_100kBPS_CFG3 (0x87) + +#define MCP_20MHz_83k3BPS_CFG1 (0x04) +#define MCP_20MHz_83k3BPS_CFG2 (0xFE) +#define MCP_20MHz_83k3BPS_CFG3 (0x87) + +#define MCP_20MHz_80kBPS_CFG1 (0x04) +#define MCP_20MHz_80kBPS_CFG2 (0xFF) +#define MCP_20MHz_80kBPS_CFG3 (0x87) + +#define MCP_20MHz_50kBPS_CFG1 (0x09) +#define MCP_20MHz_50kBPS_CFG2 (0xFA) +#define MCP_20MHz_50kBPS_CFG3 (0x87) + +#define MCP_20MHz_40kBPS_CFG1 (0x09) +#define MCP_20MHz_40kBPS_CFG2 (0xFF) +#define MCP_20MHz_40kBPS_CFG3 (0x87) + +#define MCP_20MHz_33k3BPS_CFG1 (0x0B) +#define MCP_20MHz_33k3BPS_CFG2 (0xFF) +#define MCP_20MHz_33k3BPS_CFG3 (0x87) + + +typedef enum { + MCP_RXF0SIDH = 0x00, + MCP_RXF0SIDL = 0x01, + MCP_RXF0EID8 = 0x02, + MCP_RXF0EID0 = 0x03, + MCP_RXF1SIDH = 0x04, + MCP_RXF1SIDL = 0x05, + MCP_RXF1EID8 = 0x06, + MCP_RXF1EID0 = 0x07, + MCP_RXF2SIDH = 0x08, + MCP_RXF2SIDL = 0x09, + MCP_RXF2EID8 = 0x0A, + MCP_RXF2EID0 = 0x0B, + MCP_CANSTAT = 0x0E, + MCP_CANCTRL = 0x0F, + MCP_RXF3SIDH = 0x10, + MCP_RXF3SIDL = 0x11, + MCP_RXF3EID8 = 0x12, + MCP_RXF3EID0 = 0x13, + MCP_RXF4SIDH = 0x14, + MCP_RXF4SIDL = 0x15, + MCP_RXF4EID8 = 0x16, + MCP_RXF4EID0 = 0x17, + MCP_RXF5SIDH = 0x18, + MCP_RXF5SIDL = 0x19, + MCP_RXF5EID8 = 0x1A, + MCP_RXF5EID0 = 0x1B, + MCP_TEC = 0x1C, + MCP_REC = 0x1D, + MCP_RXM0SIDH = 0x20, + MCP_RXM0SIDL = 0x21, + MCP_RXM0EID8 = 0x22, + MCP_RXM0EID0 = 0x23, + MCP_RXM1SIDH = 0x24, + MCP_RXM1SIDL = 0x25, + MCP_RXM1EID8 = 0x26, + MCP_RXM1EID0 = 0x27, + MCP_CNF3 = 0x28, + MCP_CNF2 = 0x29, + MCP_CNF1 = 0x2A, + MCP_CANINTE = 0x2B, + MCP_CANINTF = 0x2C, + MCP_EFLG = 0x2D, + MCP_TXB0CTRL = 0x30, + MCP_TXB0SIDH = 0x31, + MCP_TXB0SIDL = 0x32, + MCP_TXB0EID8 = 0x33, + MCP_TXB0EID0 = 0x34, + MCP_TXB0DLC = 0x35, + MCP_TXB0DATA = 0x36, + MCP_TXB1CTRL = 0x40, + MCP_TXB1SIDH = 0x41, + MCP_TXB1SIDL = 0x42, + MCP_TXB1EID8 = 0x43, + MCP_TXB1EID0 = 0x44, + MCP_TXB1DLC = 0x45, + MCP_TXB1DATA = 0x46, + MCP_TXB2CTRL = 0x50, + MCP_TXB2SIDH = 0x51, + MCP_TXB2SIDL = 0x52, + MCP_TXB2EID8 = 0x53, + MCP_TXB2EID0 = 0x54, + MCP_TXB2DLC = 0x55, + MCP_TXB2DATA = 0x56, + MCP_RXB0CTRL = 0x60, + MCP_RXB0SIDH = 0x61, + MCP_RXB0SIDL = 0x62, + MCP_RXB0EID8 = 0x63, + MCP_RXB0EID0 = 0x64, + MCP_RXB0DLC = 0x65, + MCP_RXB0DATA = 0x66, + MCP_RXB1CTRL = 0x70, + MCP_RXB1SIDH = 0x71, + MCP_RXB1SIDL = 0x72, + MCP_RXB1EID8 = 0x73, + MCP_RXB1EID0 = 0x74, + MCP_RXB1DLC = 0x75, + MCP_RXB1DATA = 0x76 + }REGISTER; + + + +typedef enum{ + INSTRUCTION_WRITE = 0x02, + INSTRUCTION_READ = 0x03, + INSTRUCTION_BITMOD = 0x05, + INSTRUCTION_LOAD_TX0 = 0x40, + INSTRUCTION_LOAD_TX1 = 0x42, + INSTRUCTION_LOAD_TX2 = 0x44, + INSTRUCTION_RTS_TX0 = 0x81, + INSTRUCTION_RTS_TX1 = 0x82, + INSTRUCTION_RTS_TX2 = 0x84, + INSTRUCTION_RTS_ALL = 0x87, + INSTRUCTION_READ_RX0 = 0x90, + INSTRUCTION_READ_RX1 = 0x94, + INSTRUCTION_READ_STATUS = 0xA0, + INSTRUCTION_RX_STATUS = 0xB0, + INSTRUCTION_RESET = 0xC0 + }INSTRUCTION; + +typedef enum { + CANINTF_RX0IF = 0x01, + CANINTF_RX1IF = 0x02, + CANINTF_TX0IF = 0x04, + CANINTF_TX1IF = 0x08, + CANINTF_TX2IF = 0x10, + CANINTF_ERRIF = 0x20, + CANINTF_WAKIF = 0x40, + CANINTF_MERRF = 0x80 + }CANINTF; + + +static const uint8_t CANSTAT_OPMOD = 0xE0; +static const uint8_t CANSTAT_ICOD = 0x0E; + +static const uint8_t CNF3_SOF = 0x80; + + static const uint8_t TXB_EXIDE_MASK = 0x08; + static const uint8_t DLC_MASK = 0x0F; + static const uint8_t RTR_MASK = 0x40; + +static const uint8_t RXBnCTRL_RXM_STD = 0x20; +static const uint8_t RXBnCTRL_RXM_EXT = 0x40; +static const uint8_t RXBnCTRL_RXM_STDEXT = 0x00; +static const uint8_t RXBnCTRL_RXM_MASK = 0x60; +static const uint8_t RXBnCTRL_RTR = 0x08; +static const uint8_t RXB0CTRL_BUKT = 0x04; +static const uint8_t RXB0CTRL_FILHIT_MASK = 0x03; +static const uint8_t RXB1CTRL_FILHIT_MASK = 0x07; +static const uint8_t RXB0CTRL_FILHIT = 0x00; +static const uint8_t RXB1CTRL_FILHIT = 0x01; + + +static const uint8_t MCP_SIDH = 0; + static const uint8_t MCP_SIDL = 1; + static const uint8_t MCP_EID8 = 2; + static const uint8_t MCP_EID0 = 3; + static const uint8_t MCP_DLC = 4; + static const uint8_t MCP_DATA = 5; + + +static const uint8_t CANCTRL_REQOP = 0xE0; +static const uint8_t CANCTRL_ABAT = 0x10; +static const uint8_t CANCTRL_OSM = 0x08; +static const uint8_t CANCTRL_CLKEN = 0x04; +static const uint8_t CANCTRL_CLKPRE = 0x03; + +typedef enum { + CANCTRL_REQOP_NORMAL = 0x00, + CANCTRL_REQOP_SLEEP = 0x20, + CANCTRL_REQOP_LOOPBACK = 0x40, + CANCTRL_REQOP_LISTENONLY = 0x60, + CANCTRL_REQOP_CONFIG = 0x80, + CANCTRL_REQOP_POWERUP = 0xE0 + }CANCTRL_REQOP_MODE; + +static const uint8_t N_TXBUFFERS = 3; +static const uint8_t N_RXBUFFERS = 2; + +struct TXBn_REGS { + REGISTER CTRL; + REGISTER SIDH; + REGISTER DATA; +} TXB[3]; //N_TXBUFFERS + +struct RXBn_REGS { + REGISTER CTRL; + REGISTER SIDH; + REGISTER DATA; + CANINTF CANINTF_RXnIF; +} RXB[2]; //N_RXBUFFERS + +typedef enum TXBnCTRL{ + TXB_ABTF = 0x40, + TXB_MLOA = 0x20, + TXB_TXERR = 0x10, + TXB_TXREQ = 0x08, + TXB_TXIE = 0x04, + TXB_TXP = 0x03 +}TXBnCTRL; + +typedef enum{ + STAT_RX0IF = (1<<0), + STAT_RX1IF = (1<<1) +} STAT; + +static const uint8_t STAT_RXIF_MASK = STAT_RX0IF | STAT_RX1IF; + +typedef enum { + EFLG_RX1OVR = (1<<7), + EFLG_RX0OVR = (1<<6), + EFLG_TXBO = (1<<5), + EFLG_TXEP = (1<<4), + EFLG_RXEP = (1<<3), + EFLG_TXWAR = (1<<2), + EFLG_RXWAR = (1<<1), + EFLG_EWARN = (1<<0) +}EFLG; + +static const uint8_t EFLG_ERRORMASK = EFLG_RX1OVR + | EFLG_RX0OVR + | EFLG_TXBO + | EFLG_TXEP + | EFLG_RXEP; + + + +typedef union{ + struct{ + uint8_t RXBnSIDH; + uint8_t RXBnSIDL; + uint8_t RXBnEID8; + uint8_t RXBnEID0; + uint8_t RXBnDLC; + uint8_t RXBnD0; + uint8_t RXBnD1; + uint8_t RXBnD2; + uint8_t RXBnD3; + uint8_t RXBnD4; + uint8_t RXBnD5; + uint8_t RXBnD6; + uint8_t RXBnD7; + }; + uint8_t rx_reg_array[13]; +}rx_reg_t; + +#endif /* APPLICATION_USER_INC_MCP2515_CONSTS_H_ */