Files
Seeed_Arduino_CAN/src/mcp2518fd_can.cpp
T

2837 lines
74 KiB
C++

#include "mcp2518fd_can.h"
uint8_t SPICS = 0;
SPIClass *pSPI;
CAN_CONFIG config;
// Receive objects
CAN_RX_FIFO_CONFIG rxConfig;
REG_CiFLTOBJ fObj;
REG_CiMASK mObj;
CAN_RX_FIFO_EVENT rxFlags;
CAN_RX_MSGOBJ rxObj;
uint8_t rxd[MAX_DATA_BYTES];
// Transmit objects
CAN_TX_FIFO_CONFIG txConfig;
CAN_TX_FIFO_EVENT txFlags;
CAN_TX_MSGOBJ txObj;
uint8_t txd[MAX_DATA_BYTES];
CAN_TX_QUEUE_CONFIG txqueConfig;
// Message IDs
#define TX_REQUEST_ID 0x300
#define TX_RESPONSE_ID 0x301
#define BUTTON_STATUS_ID 0x201
#define LED_STATUS_ID 0x200
#define PAYLOAD_ID 0x101
#define MAX_TXQUEUE_ATTEMPTS 50
// Transmit Channels
#define APP_TX_FIFO CAN_FIFO_CH2
// Receive Channels
#define APP_RX_FIFO CAN_FIFO_CH1
// Maximum number of data bytes in message
#define MAX_DATA_BYTES 64
CAN_BUS_DIAGNOSTIC busDiagnostics;
uint8_t tec;
uint8_t rec;
CAN_ERROR_STATE errorFlags;
// *****************************************************************************
// *****************************************************************************
// Section: Variables
//! SPI Transmit buffer
uint8_t spiTransmitBuffer[SPI_DEFAULT_BUFFER_LENGTH + 2];
//! SPI Receive buffer
uint8_t spiReceiveBuffer[SPI_DEFAULT_BUFFER_LENGTH];
uint16_t DRV_CANFDSPI_CalculateCRC16(uint8_t *data, uint16_t size) {
uint16_t init = CRCBASE;
uint8_t index;
while (size-- != 0) {
index = ((uint8_t *)&init)[CRCUPPER] ^ *data++;
init = (init << 8) ^ crc16_table[index];
}
return init;
}
/*********************************************************************************************************
** Function name: begin
** Descriptions: init can and set speed
*********************************************************************************************************/
byte mcp2518fd::begin(byte speedset, const byte clockset) {
SPI.begin();
byte res = mcp2518fd_init(speedset, clockset);
return res;
}
/*********************************************************************************************************
** Function name: mcp2518fd_reset
** Descriptions: reset the device
*********************************************************************************************************/
int8_t mcp2518fd::mcp2518fd_reset(void) {
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] = (uint8_t)(cINSTRUCTION_RESET << 4);
spiTransmitBuffer[1] = 0;
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
delay(10);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadByte(uint16_t address, uint8_t *rxd) {
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_READ << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
spiTransmitBuffer[2] = 0;
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spiReceiveBuffer[2] = spi_readwrite(0x00);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Update data
*rxd = spiReceiveBuffer[2];
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteByte(uint16_t address, uint8_t txd) {
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
spiTransmitBuffer[2] = txd;
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadWord(uint16_t address, uint32_t *rxd) {
uint8_t i;
uint32_t x;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_READ << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 2; i < 6; i++) {
spiReceiveBuffer[i] = spi_readwrite(0x00);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Update data
*rxd = 0;
for (i = 2; i < 6; i++) {
x = (uint32_t)spiReceiveBuffer[i];
*rxd += x << ((i - 2) * 8);
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteWord(uint16_t address, uint32_t txd) {
uint8_t i;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
// Split word into 4 bytes and add them to buffer
for (i = 0; i < 4; i++) {
spiTransmitBuffer[i + 2] = (uint8_t)((txd >> (i * 8)) & 0xFF);
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
spi_readwrite(spiTransmitBuffer[3]);
spi_readwrite(spiTransmitBuffer[4]);
spi_readwrite(spiTransmitBuffer[5]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadHalfWord(uint16_t address, uint16_t *rxd) {
uint8_t i;
uint32_t x;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_READ << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 2; i < 4; i++) {
spiReceiveBuffer[i] = spi_readwrite(0x00);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Update data
*rxd = 0;
for (i = 2; i < 4; i++) {
x = (uint32_t)spiReceiveBuffer[i];
*rxd += x << ((i - 2) * 8);
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteHalfWord(uint16_t address, uint16_t txd) {
uint8_t i;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
// Split word into 2 bytes and add them to buffer
for (i = 0; i < 2; i++) {
spiTransmitBuffer[i + 2] = (uint8_t)((txd >> (i * 8)) & 0xFF);
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
spi_readwrite(spiTransmitBuffer[3]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadByteArray(uint16_t address, uint8_t *rxd,
uint16_t nBytes) {
uint16_t i;
uint16_t spiTransferSize = nBytes + 2;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_READ << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
// Clear data
for (i = 2; i < spiTransferSize; i++) {
spiTransmitBuffer[i] = 0;
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 0; i < nBytes; i++) {
spiReceiveBuffer[i + 2] = spi_readwrite(0x00);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Update data
for (i = 0; i < nBytes; i++) {
rxd[i] = spiReceiveBuffer[i + 2];
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteByteArray(uint16_t address, uint8_t *txd,
uint16_t nBytes) {
uint16_t i;
uint16_t spiTransferSize = nBytes + 2;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
// Add data
for (i = 2; i < spiTransferSize; i++) {
spiTransmitBuffer[i] = txd[i - 2];
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 2; i < spiTransferSize; i++) {
spi_readwrite(spiTransmitBuffer[i]);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteByteSafe(uint16_t address, uint8_t txd) {
uint16_t crcResult = 0;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE_SAFE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
spiTransmitBuffer[2] = txd;
// Add CRC
crcResult = DRV_CANFDSPI_CalculateCRC16(spiTransmitBuffer, 3);
spiTransmitBuffer[3] = (crcResult >> 8) & 0xFF;
spiTransmitBuffer[4] = crcResult & 0xFF;
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
spi_readwrite(spiTransmitBuffer[3]);
spi_readwrite(spiTransmitBuffer[4]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteWordSafe(uint16_t address, uint32_t txd) {
uint8_t i;
uint16_t crcResult = 0;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE_SAFE << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
// Split word into 4 bytes and add them to buffer
for (i = 0; i < 4; i++) {
spiTransmitBuffer[i + 2] = (uint8_t)((txd >> (i * 8)) & 0xFF);
}
// Add CRC
crcResult = DRV_CANFDSPI_CalculateCRC16(spiTransmitBuffer, 6);
spiTransmitBuffer[6] = (crcResult >> 8) & 0xFF;
spiTransmitBuffer[7] = crcResult & 0xFF;
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
spi_readwrite(spiTransmitBuffer[3]);
spi_readwrite(spiTransmitBuffer[4]);
spi_readwrite(spiTransmitBuffer[5]);
spi_readwrite(spiTransmitBuffer[6]);
spi_readwrite(spiTransmitBuffer[7]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadByteArrayWithCRC(uint16_t address, uint8_t *rxd,
uint16_t nBytes, bool fromRam,
bool *crcIsCorrect) {
uint8_t i;
uint16_t crcFromSpiSlave = 0;
uint16_t crcAtController = 0;
uint16_t spiTransferSize =
nBytes + 5; // first two bytes for sending command & address, third for
// size, last two bytes for CRC
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_READ_CRC << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
if (fromRam) {
spiTransmitBuffer[2] = nBytes >> 2;
} else {
spiTransmitBuffer[2] = nBytes;
}
// Clear data
for (i = 3; i < spiTransferSize; i++) {
spiTransmitBuffer[i] = 0;
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
for (i = 3; i < spiTransferSize; i++) {
spiReceiveBuffer[i] = spi_readwrite(0x00);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Get CRC from controller
crcFromSpiSlave = (uint16_t)(spiReceiveBuffer[spiTransferSize - 2] << 8) +
(uint16_t)(spiReceiveBuffer[spiTransferSize - 1]);
// Use the receive buffer to calculate CRC
// First three bytes need to be command
spiReceiveBuffer[0] = spiTransmitBuffer[0];
spiReceiveBuffer[1] = spiTransmitBuffer[1];
spiReceiveBuffer[2] = spiTransmitBuffer[2];
crcAtController = DRV_CANFDSPI_CalculateCRC16(spiReceiveBuffer, nBytes + 3);
// Compare CRC readings
if (crcFromSpiSlave == crcAtController) {
*crcIsCorrect = true;
} else {
*crcIsCorrect = false;
}
// Update data
for (i = 0; i < nBytes; i++) {
rxd[i] = spiReceiveBuffer[i + 3];
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteByteArrayWithCRC(uint16_t address,
uint8_t *txd, uint16_t nBytes,
bool fromRam) {
uint16_t i;
uint16_t crcResult = 0;
uint16_t spiTransferSize = nBytes + 5;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] =
(uint8_t)((cINSTRUCTION_WRITE_CRC << 4) + ((address >> 8) & 0xF));
spiTransmitBuffer[1] = (uint8_t)(address & 0xFF);
if (fromRam) {
spiTransmitBuffer[2] = nBytes >> 2;
} else {
spiTransmitBuffer[2] = nBytes;
}
// Add data
for (i = 0; i < nBytes; i++) {
spiTransmitBuffer[i + 3] = txd[i];
}
// Add CRC
crcResult =
DRV_CANFDSPI_CalculateCRC16(spiTransmitBuffer, spiTransferSize - 2);
spiTransmitBuffer[spiTransferSize - 2] = (uint8_t)((crcResult >> 8) & 0xFF);
spiTransmitBuffer[spiTransferSize - 1] = (uint8_t)(crcResult & 0xFF);
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
spi_readwrite(spiTransmitBuffer[2]);
for (i = 0; i < nBytes; i++) {
spi_readwrite(spiTransmitBuffer[i + 3]);
}
spi_readwrite(spiTransmitBuffer[spiTransferSize - 2]);
spi_readwrite(spiTransmitBuffer[spiTransferSize - 1]);
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReadWordArray(uint16_t address, uint32_t *rxd,
uint16_t nWords) {
uint16_t i, j, n;
REG_t w;
uint16_t spiTransferSize = nWords * 4 + 2;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] = (cINSTRUCTION_READ << 4) + ((address >> 8) & 0xF);
spiTransmitBuffer[1] = address & 0xFF;
// Clear data
for (i = 2; i < spiTransferSize; i++) {
spiTransmitBuffer[i] = 0;
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 2; i < spiTransferSize; i++) {
// for (i = 2; i < 6; i++) {
spiReceiveBuffer[i] = spi_readwrite(0x00);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
// Convert Byte array to Word array
n = 2;
for (i = 0; i < nWords; i++) {
w.word = 0;
for (j = 0; j < 4; j++, n++) {
w.byte[j] = spiReceiveBuffer[n];
}
rxd[i] = w.word;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_WriteWordArray(uint16_t address, uint32_t *txd,
uint16_t nWords) {
uint16_t i, j, n;
REG_t w;
uint16_t spiTransferSize = nWords * 4 + 2;
int8_t spiTransferError = 0;
// Compose command
spiTransmitBuffer[0] = (cINSTRUCTION_WRITE << 4) + ((address >> 8) & 0xF);
spiTransmitBuffer[1] = address & 0xFF;
// Convert ByteArray to word array
n = 2;
for (i = 0; i < nWords; i++) {
w.word = txd[i];
for (j = 0; j < 4; j++, n++) {
spiTransmitBuffer[n] = w.byte[j];
}
}
#ifdef SPI_HAS_TRANSACTION
SPI_BEGIN();
#endif
MCP2518fd_SELECT();
spi_readwrite(spiTransmitBuffer[0]);
spi_readwrite(spiTransmitBuffer[1]);
for (i = 2; i < spiTransferSize; i++) {
spi_readwrite(spiTransmitBuffer[i]);
}
MCP2518fd_UNSELECT();
#ifdef SPI_HAS_TRANSACTION
SPI_END();
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_EccEnable() {
int8_t spiTransferError = 0;
uint8_t d = 0;
// Read
spiTransferError = mcp2518fd_ReadByte(cREGADDR_ECCCON, &d);
if (spiTransferError) {
return -1;
}
// Modify
d |= 0x01;
// Write
spiTransferError = mcp2518fd_WriteByte(cREGADDR_ECCCON, d);
if (spiTransferError) {
return -2;
}
return 0;
}
int8_t mcp2518fd::mcp2518fd_RamInit(uint8_t d) {
uint8_t txd[SPI_DEFAULT_BUFFER_LENGTH];
uint32_t k;
int8_t spiTransferError = 0;
// Prepare data
for (k = 0; k < SPI_DEFAULT_BUFFER_LENGTH; k++) {
txd[k] = d;
}
uint16_t a = cRAMADDR_START;
for (k = 0; k < (cRAM_SIZE / SPI_DEFAULT_BUFFER_LENGTH); k++) {
spiTransferError =
mcp2518fd_WriteByteArray(a, txd, SPI_DEFAULT_BUFFER_LENGTH);
if (spiTransferError) {
return -1;
}
a += SPI_DEFAULT_BUFFER_LENGTH;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ConfigureObjectReset(CAN_CONFIG *config) {
REG_CiCON ciCon;
ciCon.word = canControlResetValues[cREGADDR_CiCON / 4];
config->DNetFilterCount = ciCon.bF.DNetFilterCount;
config->IsoCrcEnable = ciCon.bF.IsoCrcEnable;
config->ProtocolExpectionEventDisable =
ciCon.bF.ProtocolExceptionEventDisable;
config->WakeUpFilterEnable = ciCon.bF.WakeUpFilterEnable;
config->WakeUpFilterTime = ciCon.bF.WakeUpFilterTime;
config->BitRateSwitchDisable = ciCon.bF.BitRateSwitchDisable;
config->RestrictReTxAttempts = ciCon.bF.RestrictReTxAttempts;
config->EsiInGatewayMode = ciCon.bF.EsiInGatewayMode;
config->SystemErrorToListenOnly = ciCon.bF.SystemErrorToListenOnly;
config->StoreInTEF = ciCon.bF.StoreInTEF;
config->TXQEnable = ciCon.bF.TXQEnable;
config->TxBandWidthSharing = ciCon.bF.TxBandWidthSharing;
return 0;
}
int8_t mcp2518fd::mcp2518fd_Configure(CAN_CONFIG *config) {
REG_CiCON ciCon;
int8_t spiTransferError = 0;
ciCon.word = canControlResetValues[cREGADDR_CiCON / 4];
ciCon.bF.DNetFilterCount = config->DNetFilterCount;
ciCon.bF.IsoCrcEnable = config->IsoCrcEnable;
ciCon.bF.ProtocolExceptionEventDisable =
config->ProtocolExpectionEventDisable;
ciCon.bF.WakeUpFilterEnable = config->WakeUpFilterEnable;
ciCon.bF.WakeUpFilterTime = config->WakeUpFilterTime;
ciCon.bF.BitRateSwitchDisable = config->BitRateSwitchDisable;
ciCon.bF.RestrictReTxAttempts = config->RestrictReTxAttempts;
ciCon.bF.EsiInGatewayMode = config->EsiInGatewayMode;
ciCon.bF.SystemErrorToListenOnly = config->SystemErrorToListenOnly;
ciCon.bF.StoreInTEF = config->StoreInTEF;
ciCon.bF.TXQEnable = config->TXQEnable;
ciCon.bF.TxBandWidthSharing = config->TxBandWidthSharing;
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiCON, ciCon.word);
if (spiTransferError) {
return -1;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_TransmitChannelConfigureObjectReset(
CAN_TX_FIFO_CONFIG *config) {
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = canFifoResetValues[0]; // 10010010100101010000
config->RTREnable = ciFifoCon.txBF.RTREnable;
config->TxPriority = ciFifoCon.txBF.TxPriority;
config->TxAttempts = ciFifoCon.txBF.TxAttempts;
config->FifoSize = ciFifoCon.txBF.FifoSize;
config->PayLoadSize = ciFifoCon.txBF.PayLoadSize;
return 0;
}
int8_t
mcp2518fd::mcp2518fd_TransmitChannelConfigure(CAN_FIFO_CHANNEL channel,
CAN_TX_FIFO_CONFIG *config) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Setup FIFO
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = canFifoResetValues[0];
ciFifoCon.txBF.TxEnable = 1;
ciFifoCon.txBF.FifoSize = config->FifoSize;
ciFifoCon.txBF.PayLoadSize = config->PayLoadSize;
ciFifoCon.txBF.TxAttempts = config->TxAttempts;
ciFifoCon.txBF.TxPriority = config->TxPriority;
ciFifoCon.txBF.RTREnable = config->RTREnable;
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_WriteWord(a, ciFifoCon.word);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReceiveChannelConfigureObjectReset(
CAN_RX_FIFO_CONFIG *config) {
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = canFifoResetValues[0];
config->FifoSize = ciFifoCon.rxBF.FifoSize;
config->PayLoadSize = ciFifoCon.rxBF.PayLoadSize;
config->RxTimeStampEnable = ciFifoCon.rxBF.RxTimeStampEnable;
return 0;
}
int8_t
mcp2518fd::mcp2518fd_ReceiveChannelConfigure(CAN_FIFO_CHANNEL channel,
CAN_RX_FIFO_CONFIG *config) {
int8_t spiTransferError = 0;
uint16_t a = 0;
if (channel == CAN_TXQUEUE_CH0) {
return -100;
}
// Setup FIFO
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = canFifoResetValues[0];
ciFifoCon.rxBF.TxEnable = 0;
ciFifoCon.rxBF.FifoSize = config->FifoSize;
ciFifoCon.rxBF.PayLoadSize = config->PayLoadSize;
ciFifoCon.rxBF.RxTimeStampEnable = config->RxTimeStampEnable;
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_WriteWord(a, ciFifoCon.word);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_FilterObjectConfigure(CAN_FILTER filter,
CAN_FILTEROBJ_ID *id) {
uint16_t a;
REG_CiFLTOBJ fObj;
int8_t spiTransferError = 0;
// Setup
fObj.word = 0;
fObj.bF = *id;
a = cREGADDR_CiFLTOBJ + (filter * CiFILTER_OFFSET);
spiTransferError = mcp2518fd_WriteWord(a, fObj.word);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_FilterMaskConfigure(CAN_FILTER filter,
CAN_MASKOBJ_ID *mask) {
uint16_t a;
REG_CiMASK mObj;
int8_t spiTransferError = 0;
// Setup
mObj.word = 0;
mObj.bF = *mask;
a = cREGADDR_CiMASK + (filter * CiFILTER_OFFSET);
spiTransferError = mcp2518fd_WriteWord(a, mObj.word);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_FilterToFifoLink(CAN_FILTER filter,
CAN_FIFO_CHANNEL channel,
bool enable) {
uint16_t a;
REG_CiFLTCON_BYTE fCtrl;
int8_t spiTransferError = 0;
// Enable
if (enable) {
fCtrl.bF.Enable = 1;
} else {
fCtrl.bF.Enable = 0;
}
// Link
fCtrl.bF.BufferPointer = channel;
a = cREGADDR_CiFLTCON + filter;
spiTransferError = mcp2518fd_WriteByte(a, fCtrl.byte);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_BitTimeConfigureNominal40MHz(
MCP2518FD_BITTIME_SETUP bitTime) {
int8_t spiTransferError = 0;
REG_CiNBTCFG ciNbtcfg;
ciNbtcfg.word = canControlResetValues[cREGADDR_CiNBTCFG / 4];
// Arbitration Bit rate
switch (bitTime) {
// All 500K
case CAN_500K_1M:
case CAN_500K_2M:
case CAN_500K_3M:
case CAN_500K_4M:
case CAN_500K_5M:
case CAN_500K_6M7:
case CAN_500K_8M:
case CAN_500K_10M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 62;
ciNbtcfg.bF.TSEG2 = 15;
ciNbtcfg.bF.SJW = 15;
break;
// All 250K
case CAN_250K_500K:
case CAN_250K_833K:
case CAN_250K_1M:
case CAN_250K_1M5:
case CAN_250K_2M:
case CAN_250K_3M:
case CAN_250K_4M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 126;
ciNbtcfg.bF.TSEG2 = 31;
ciNbtcfg.bF.SJW = 31;
break;
case CAN_1000K_4M:
case CAN_1000K_8M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 30;
ciNbtcfg.bF.TSEG2 = 7;
ciNbtcfg.bF.SJW = 7;
break;
case CAN_125K_500K:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 254;
ciNbtcfg.bF.TSEG2 = 63;
ciNbtcfg.bF.SJW = 63;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiNBTCFG, ciNbtcfg.word);
return spiTransferError;
}
int8_t
mcp2518fd::mcp2518fd_BitTimeConfigureData40MHz(MCP2518FD_BITTIME_SETUP bitTime,
CAN_SSP_MODE sspMode) {
int8_t spiTransferError = 0;
REG_CiDBTCFG ciDbtcfg;
REG_CiTDC ciTdc;
// sspMode;
ciDbtcfg.word = canControlResetValues[cREGADDR_CiDBTCFG / 4];
ciTdc.word = 0;
// Configure Bit time and sample point
ciTdc.bF.TDCMode = CAN_SSP_MODE_AUTO;
uint32_t tdcValue = 0;
// Data Bit rate and SSP
switch (bitTime) {
case CAN_500K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 30;
ciDbtcfg.bF.TSEG2 = 7;
ciDbtcfg.bF.SJW = 7;
// SSP
ciTdc.bF.TDCOffset = 31;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_2M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 14;
ciDbtcfg.bF.TSEG2 = 3;
ciDbtcfg.bF.SJW = 3;
// SSP
ciTdc.bF.TDCOffset = 15;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_3M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 8;
ciDbtcfg.bF.TSEG2 = 2;
ciDbtcfg.bF.SJW = 2;
// SSP
ciTdc.bF.TDCOffset = 9;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_4M:
case CAN_1000K_4M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_5M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 4;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 5;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_6M7:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 3;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 4;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_8M:
case CAN_1000K_8M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 2;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 3;
ciTdc.bF.TDCValue = 1;
break;
case CAN_500K_10M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 1;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 2;
ciTdc.bF.TDCValue = 0;
break;
case CAN_250K_500K:
case CAN_125K_500K:
ciDbtcfg.bF.BRP = 1;
ciDbtcfg.bF.TSEG1 = 30;
ciDbtcfg.bF.TSEG2 = 7;
ciDbtcfg.bF.SJW = 7;
// SSP
ciTdc.bF.TDCOffset = 31;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_833K:
ciDbtcfg.bF.BRP = 1;
ciDbtcfg.bF.TSEG1 = 17;
ciDbtcfg.bF.TSEG2 = 4;
ciDbtcfg.bF.SJW = 4;
// SSP
ciTdc.bF.TDCOffset = 18;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 30;
ciDbtcfg.bF.TSEG2 = 7;
ciDbtcfg.bF.SJW = 7;
// SSP
ciTdc.bF.TDCOffset = 31;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_1M5:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 18;
ciDbtcfg.bF.TSEG2 = 5;
ciDbtcfg.bF.SJW = 5;
// SSP
ciTdc.bF.TDCOffset = 19;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_2M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 14;
ciDbtcfg.bF.TSEG2 = 3;
ciDbtcfg.bF.SJW = 3;
// SSP
ciTdc.bF.TDCOffset = 15;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_3M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 8;
ciDbtcfg.bF.TSEG2 = 2;
ciDbtcfg.bF.SJW = 2;
// SSP
ciTdc.bF.TDCOffset = 9;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_4M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiDBTCFG, ciDbtcfg.word);
if (spiTransferError) {
return -2;
}
// Write Transmitter Delay Compensation
#ifdef REV_A
ciTdc.bF.TDCOffset = 0;
ciTdc.bF.TDCValue = 0;
#endif
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiTDC, ciTdc.word);
if (spiTransferError) {
return -3;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_BitTimeConfigureNominal20MHz(
MCP2518FD_BITTIME_SETUP bitTime) {
int8_t spiTransferError = 0;
REG_CiNBTCFG ciNbtcfg;
ciNbtcfg.word = canControlResetValues[cREGADDR_CiNBTCFG / 4];
// Arbitration Bit rate
switch (bitTime) {
// All 500K
case CAN_500K_1M:
case CAN_500K_2M:
case CAN_500K_4M:
case CAN_500K_5M:
case CAN_500K_6M7:
case CAN_500K_8M:
case CAN_500K_10M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 30;
ciNbtcfg.bF.TSEG2 = 7;
ciNbtcfg.bF.SJW = 7;
break;
// All 250K
case CAN_250K_500K:
case CAN_250K_833K:
case CAN_250K_1M:
case CAN_250K_1M5:
case CAN_250K_2M:
case CAN_250K_3M:
case CAN_250K_4M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 62;
ciNbtcfg.bF.TSEG2 = 15;
ciNbtcfg.bF.SJW = 15;
break;
case CAN_1000K_4M:
case CAN_1000K_8M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 14;
ciNbtcfg.bF.TSEG2 = 3;
ciNbtcfg.bF.SJW = 3;
break;
case CAN_125K_500K:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 126;
ciNbtcfg.bF.TSEG2 = 31;
ciNbtcfg.bF.SJW = 31;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiNBTCFG, ciNbtcfg.word);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t
mcp2518fd::mcp2518fd_BitTimeConfigureData20MHz(MCP2518FD_BITTIME_SETUP bitTime,
CAN_SSP_MODE sspMode) {
int8_t spiTransferError = 0;
REG_CiDBTCFG ciDbtcfg;
REG_CiTDC ciTdc;
// sspMode;
ciDbtcfg.word = canControlResetValues[cREGADDR_CiDBTCFG / 4];
ciTdc.word = 0;
// Configure Bit time and sample point
ciTdc.bF.TDCMode = CAN_SSP_MODE_AUTO;
uint32_t tdcValue = 0;
// Data Bit rate and SSP
switch (bitTime) {
case CAN_500K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 14;
ciDbtcfg.bF.TSEG2 = 3;
ciDbtcfg.bF.SJW = 3;
// SSP
ciTdc.bF.TDCOffset = 15;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_2M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_4M:
case CAN_1000K_4M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 2;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 3;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_5M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 1;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 2;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_6M7:
case CAN_500K_8M:
case CAN_500K_10M:
case CAN_1000K_8M:
// qDebug("Data Bitrate not feasible with this clock!");
return -1;
break;
case CAN_250K_500K:
case CAN_125K_500K:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 30;
ciDbtcfg.bF.TSEG2 = 7;
ciDbtcfg.bF.SJW = 7;
// SSP
ciTdc.bF.TDCOffset = 31;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_833K:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 17;
ciDbtcfg.bF.TSEG2 = 4;
ciDbtcfg.bF.SJW = 4;
// SSP
ciTdc.bF.TDCOffset = 18;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 14;
ciDbtcfg.bF.TSEG2 = 3;
ciDbtcfg.bF.SJW = 3;
// SSP
ciTdc.bF.TDCOffset = 15;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_1M5:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 8;
ciDbtcfg.bF.TSEG2 = 2;
ciDbtcfg.bF.SJW = 2;
// SSP
ciTdc.bF.TDCOffset = 9;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_2M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_3M:
// qDebug("Data Bitrate not feasible with this clock!");
return -1;
break;
case CAN_250K_4M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 2;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 3;
ciTdc.bF.TDCValue = tdcValue;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiDBTCFG, ciDbtcfg.word);
if (spiTransferError) {
return -2;
}
// Write Transmitter Delay Compensation
#ifdef REV_A
ciTdc.bF.TDCOffset = 0;
ciTdc.bF.TDCValue = 0;
#endif
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiTDC, ciTdc.word);
if (spiTransferError) {
return -3;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_BitTimeConfigureNominal10MHz(
MCP2518FD_BITTIME_SETUP bitTime) {
int8_t spiTransferError = 0;
REG_CiNBTCFG ciNbtcfg;
ciNbtcfg.word = canControlResetValues[cREGADDR_CiNBTCFG / 4];
// Arbitration Bit rate
switch (bitTime) {
// All 500K
case CAN_500K_1M:
case CAN_500K_2M:
case CAN_500K_4M:
case CAN_500K_5M:
case CAN_500K_6M7:
case CAN_500K_8M:
case CAN_500K_10M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 14;
ciNbtcfg.bF.TSEG2 = 3;
ciNbtcfg.bF.SJW = 3;
break;
// All 250K
case CAN_250K_500K:
case CAN_250K_833K:
case CAN_250K_1M:
case CAN_250K_1M5:
case CAN_250K_2M:
case CAN_250K_3M:
case CAN_250K_4M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 30;
ciNbtcfg.bF.TSEG2 = 7;
ciNbtcfg.bF.SJW = 7;
break;
case CAN_1000K_4M:
case CAN_1000K_8M:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 7;
ciNbtcfg.bF.TSEG2 = 2;
ciNbtcfg.bF.SJW = 2;
break;
case CAN_125K_500K:
ciNbtcfg.bF.BRP = 0;
ciNbtcfg.bF.TSEG1 = 62;
ciNbtcfg.bF.TSEG2 = 15;
ciNbtcfg.bF.SJW = 15;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiNBTCFG, ciNbtcfg.word);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t
mcp2518fd::mcp2518fd_BitTimeConfigureData10MHz(MCP2518FD_BITTIME_SETUP bitTime,
CAN_SSP_MODE sspMode) {
int8_t spiTransferError = 0;
REG_CiDBTCFG ciDbtcfg;
REG_CiTDC ciTdc;
// sspMode;
ciDbtcfg.word = canControlResetValues[cREGADDR_CiDBTCFG / 4];
ciTdc.word = 0;
// Configure Bit time and sample point
ciTdc.bF.TDCMode = CAN_SSP_MODE_AUTO;
uint32_t tdcValue = 0;
// Data Bit rate and SSP
switch (bitTime) {
case CAN_500K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_2M:
// Data BR
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 2;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 3;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_500K_4M:
case CAN_500K_5M:
case CAN_500K_6M7:
case CAN_500K_8M:
case CAN_500K_10M:
case CAN_1000K_4M:
case CAN_1000K_8M:
// qDebug("Data Bitrate not feasible with this clock!");
return -1;
break;
case CAN_250K_500K:
case CAN_125K_500K:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 14;
ciDbtcfg.bF.TSEG2 = 3;
ciDbtcfg.bF.SJW = 3;
// SSP
ciTdc.bF.TDCOffset = 15;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_833K:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 7;
ciDbtcfg.bF.TSEG2 = 2;
ciDbtcfg.bF.SJW = 2;
// SSP
ciTdc.bF.TDCOffset = 8;
ciTdc.bF.TDCValue = tdcValue;
ciTdc.bF.TDCMode = CAN_SSP_MODE_OFF;
break;
case CAN_250K_1M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 6;
ciDbtcfg.bF.TSEG2 = 1;
ciDbtcfg.bF.SJW = 1;
// SSP
ciTdc.bF.TDCOffset = 7;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_1M5:
// qDebug("Data Bitrate not feasible with this clock!");
return -1;
break;
case CAN_250K_2M:
ciDbtcfg.bF.BRP = 0;
ciDbtcfg.bF.TSEG1 = 2;
ciDbtcfg.bF.TSEG2 = 0;
ciDbtcfg.bF.SJW = 0;
// SSP
ciTdc.bF.TDCOffset = 3;
ciTdc.bF.TDCValue = tdcValue;
break;
case CAN_250K_3M:
case CAN_250K_4M:
// qDebug("Data Bitrate not feasible with this clock!");
return -1;
break;
default:
return -1;
break;
}
// Write Bit time registers
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiDBTCFG, ciDbtcfg.word);
if (spiTransferError) {
return -2;
}
// Write Transmitter Delay Compensation
#ifdef REV_A
ciTdc.bF.TDCOffset = 0;
ciTdc.bF.TDCValue = 0;
#endif
spiTransferError = mcp2518fd_WriteWord(cREGADDR_CiTDC, ciTdc.word);
if (spiTransferError) {
return -3;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_BitTimeConfigure(MCP2518FD_BITTIME_SETUP bitTime,
CAN_SSP_MODE sspMode,
CAN_SYSCLK_SPEED clk) {
int8_t spiTransferError = 0;
// Decode clk
switch (clk) {
case CAN_SYSCLK_40M:
spiTransferError = mcp2518fd_BitTimeConfigureNominal40MHz(bitTime);
if (spiTransferError)
return spiTransferError;
spiTransferError = mcp2518fd_BitTimeConfigureData40MHz(bitTime, sspMode);
break;
case CAN_SYSCLK_20M:
spiTransferError = mcp2518fd_BitTimeConfigureNominal20MHz(bitTime);
if (spiTransferError)
return spiTransferError;
spiTransferError = mcp2518fd_BitTimeConfigureData20MHz(bitTime, sspMode);
break;
case CAN_SYSCLK_10M:
spiTransferError = mcp2518fd_BitTimeConfigureNominal10MHz(bitTime);
if (spiTransferError)
return spiTransferError;
spiTransferError = mcp2518fd_BitTimeConfigureData10MHz(bitTime, sspMode);
break;
default:
spiTransferError = -1;
break;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_GpioModeConfigure(GPIO_PIN_MODE gpio0,
GPIO_PIN_MODE gpio1) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read
a = cREGADDR_IOCON + 3;
REG_IOCON iocon;
iocon.word = 0;
spiTransferError = mcp2518fd_ReadByte(a, &iocon.byte[3]);
if (spiTransferError) {
return -1;
}
// Modify
iocon.bF.PinMode0 = gpio0;
iocon.bF.PinMode1 = gpio1;
// Write
spiTransferError = mcp2518fd_WriteByte(a, iocon.byte[3]);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t
mcp2518fd::mcp2518fd_TransmitChannelEventEnable(CAN_FIFO_CHANNEL channel,
CAN_TX_FIFO_EVENT flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Interrupt Enables
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = 0;
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoCon.byte[0]);
if (spiTransferError) {
return -1;
}
// Modify
ciFifoCon.byte[0] |= (flags & CAN_TX_FIFO_ALL_EVENTS);
// Write
spiTransferError = mcp2518fd_WriteByte(a, ciFifoCon.byte[0]);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReceiveChannelEventEnable(CAN_FIFO_CHANNEL channel,
CAN_RX_FIFO_EVENT flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
if (channel == CAN_TXQUEUE_CH0)
return -100;
// Read Interrupt Enables
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
REG_CiFIFOCON ciFifoCon;
ciFifoCon.word = 0;
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoCon.byte[0]);
if (spiTransferError) {
return -1;
}
// Modify
ciFifoCon.byte[0] |= (flags & CAN_RX_FIFO_ALL_EVENTS);
// Write
spiTransferError = mcp2518fd_WriteByte(a, ciFifoCon.byte[0]);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ModuleEventEnable(CAN_MODULE_EVENT flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Interrupt Enables
a = cREGADDR_CiINTENABLE;
REG_CiINTENABLE intEnables;
intEnables.word = 0;
spiTransferError = mcp2518fd_ReadHalfWord(a, &intEnables.word);
if (spiTransferError) {
return -1;
}
// Modify
intEnables.word |= (flags & CAN_ALL_EVENTS);
// Write
spiTransferError = mcp2518fd_WriteHalfWord(a, intEnables.word);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_OperationModeSelect(CAN_OPERATION_MODE opMode) {
uint8_t d = 0;
int8_t spiTransferError = 0;
// Read
spiTransferError = mcp2518fd_ReadByte(cREGADDR_CiCON + 3, &d);
if (spiTransferError) {
return -1;
}
// Modify
d &= ~0x07;
d |= opMode;
// Write
spiTransferError = mcp2518fd_WriteByte(cREGADDR_CiCON + 3, d);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
CAN_OPERATION_MODE mcp2518fd::mcp2518fd_OperationModeGet() {
uint8_t d = 0;
CAN_OPERATION_MODE mode = CAN_INVALID_MODE;
int8_t spiTransferError = 0;
// Read Opmode
spiTransferError = mcp2518fd_ReadByte(cREGADDR_CiCON + 2, &d);
if (spiTransferError) {
return CAN_INVALID_MODE;
}
// Get Opmode bits
d = (d >> 5) & 0x7;
// Decode Opmode
switch (d) {
case CAN_NORMAL_MODE:
mode = CAN_NORMAL_MODE;
break;
case CAN_SLEEP_MODE:
mode = CAN_SLEEP_MODE;
break;
case CAN_INTERNAL_LOOPBACK_MODE:
mode = CAN_INTERNAL_LOOPBACK_MODE;
break;
case CAN_EXTERNAL_LOOPBACK_MODE:
mode = CAN_EXTERNAL_LOOPBACK_MODE;
break;
case CAN_LISTEN_ONLY_MODE:
mode = CAN_LISTEN_ONLY_MODE;
break;
case CAN_CONFIGURATION_MODE:
mode = CAN_CONFIGURATION_MODE;
break;
case CAN_CLASSIC_MODE:
mode = CAN_CLASSIC_MODE;
break;
case CAN_RESTRICTED_MODE:
mode = CAN_RESTRICTED_MODE;
break;
default:
mode = CAN_INVALID_MODE;
break;
}
return mode;
}
int8_t mcp2518fd::mcp2518fd_TransmitChannelEventGet(CAN_FIFO_CHANNEL channel,
CAN_TX_FIFO_EVENT *flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Interrupt flags
REG_CiFIFOSTA ciFifoSta;
ciFifoSta.word = 0;
a = cREGADDR_CiFIFOSTA + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoSta.byte[0]);
if (spiTransferError) {
return -1;
}
// Update data
*flags = (CAN_TX_FIFO_EVENT)(ciFifoSta.byte[0] & CAN_TX_FIFO_ALL_EVENTS);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ErrorCountStateGet(uint8_t *tec, uint8_t *rec,
CAN_ERROR_STATE *flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Error
a = cREGADDR_CiTREC;
REG_CiTREC ciTrec;
ciTrec.word = 0;
spiTransferError = mcp2518fd_ReadWord(a, &ciTrec.word);
if (spiTransferError) {
return -1;
}
// Update data
*tec = ciTrec.byte[1];
*rec = ciTrec.byte[0];
*flags = (CAN_ERROR_STATE)(ciTrec.byte[2] & CAN_ERROR_ALL);
return spiTransferError;
}
// *****************************************************************************
// *****************************************************************************
// Section: Miscellaneous
uint32_t DRV_CANFDSPI_DlcToDataBytes(CAN_DLC dlc) {
uint32_t dataBytesInObject = 0;
Nop();
Nop();
if (dlc < CAN_DLC_12) {
dataBytesInObject = dlc;
} else {
switch (dlc) {
case CAN_DLC_12:
dataBytesInObject = 12;
break;
case CAN_DLC_16:
dataBytesInObject = 16;
break;
case CAN_DLC_20:
dataBytesInObject = 20;
break;
case CAN_DLC_24:
dataBytesInObject = 24;
break;
case CAN_DLC_32:
dataBytesInObject = 32;
break;
case CAN_DLC_48:
dataBytesInObject = 48;
break;
case CAN_DLC_64:
dataBytesInObject = 64;
break;
default:
break;
}
}
return dataBytesInObject;
}
int8_t mcp2518fd::mcp2518fd_TransmitChannelLoad(CAN_FIFO_CHANNEL channel,
CAN_TX_MSGOBJ *txObj,
uint8_t *txd,
uint32_t txdNumBytes,
bool flush) {
uint16_t a;
uint32_t fifoReg[3];
uint32_t dataBytesInObject;
REG_CiFIFOCON ciFifoCon;
REG_CiFIFOSTA ciFifoSta;
REG_CiFIFOUA ciFifoUa;
int8_t spiTransferError = 0;
// Get FIFO registers
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_ReadWordArray(a, fifoReg, 3);
if (spiTransferError) {
return -1;
}
// Check that it is a transmit buffer
ciFifoCon.word = fifoReg[0];
if (!ciFifoCon.txBF.TxEnable) {
return -2;
}
// Check that DLC is big enough for data
dataBytesInObject = DRV_CANFDSPI_DlcToDataBytes((CAN_DLC)txObj->bF.ctrl.DLC);
if (dataBytesInObject < txdNumBytes) {
return -3;
}
// Get status
ciFifoSta.word = fifoReg[1];
// Get address
ciFifoUa.word = fifoReg[2];
#ifdef USERADDRESS_TIMES_FOUR
a = 4 * ciFifoUa.bF.UserAddress;
#else
a = ciFifoUa.bF.UserAddress;
#endif
a += cRAMADDR_START;
uint8_t txBuffer[MAX_MSG_SIZE];
txBuffer[0] = txObj->byte[0]; // not using 'for' to reduce no of instructions
txBuffer[1] = txObj->byte[1];
txBuffer[2] = txObj->byte[2];
txBuffer[3] = txObj->byte[3];
txBuffer[4] = txObj->byte[4];
txBuffer[5] = txObj->byte[5];
txBuffer[6] = txObj->byte[6];
txBuffer[7] = txObj->byte[7];
uint8_t i;
for (i = 0; i < txdNumBytes; i++) {
txBuffer[i + 8] = txd[i];
}
// Make sure we write a multiple of 4 bytes to RAM
uint16_t n = 0;
uint8_t j = 0;
if (txdNumBytes % 4) {
// Need to add bytes
n = 4 - (txdNumBytes % 4);
i = txdNumBytes + 8;
for (j = 0; j < n; j++) {
txBuffer[i + 8 + j] = 0;
}
}
spiTransferError = mcp2518fd_WriteByteArray(a, txBuffer, txdNumBytes + 8 + n);
if (spiTransferError) {
return -4;
}
// Set UINC and TXREQ
spiTransferError = mcp2518fd_TransmitChannelUpdate(channel, flush);
if (spiTransferError) {
return -5;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReceiveChannelEventGet(CAN_FIFO_CHANNEL channel,
CAN_RX_FIFO_EVENT *flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
if (channel == CAN_TXQUEUE_CH0)
return -100;
// Read Interrupt flags
REG_CiFIFOSTA ciFifoSta;
ciFifoSta.word = 0;
a = cREGADDR_CiFIFOSTA + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoSta.byte[0]);
if (spiTransferError) {
return -1;
}
// Update data
*flags = (CAN_RX_FIFO_EVENT)(ciFifoSta.byte[0] & CAN_RX_FIFO_ALL_EVENTS);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReceiveMessageGet(CAN_FIFO_CHANNEL channel,
CAN_RX_MSGOBJ *rxObj,
uint8_t *rxd, uint8_t nBytes) {
uint8_t n = 0;
uint8_t i = 0;
uint16_t a;
uint32_t fifoReg[3];
REG_CiFIFOCON ciFifoCon;
REG_CiFIFOSTA ciFifoSta;
REG_CiFIFOUA ciFifoUa;
int8_t spiTransferError = 0;
// Get FIFO registers
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_ReadWordArray(a, fifoReg, 3);
if (spiTransferError) {
return -1;
}
// Check that it is a receive buffer
ciFifoCon.word = fifoReg[0];
ciFifoCon.txBF.TxEnable = 0;
if (ciFifoCon.txBF.TxEnable) {
return -2;
}
// Get Status
ciFifoSta.word = fifoReg[1];
// Get address
ciFifoUa.word = fifoReg[2];
#ifdef USERADDRESS_TIMES_FOUR
a = 4 * ciFifoUa.bF.UserAddress;
#else
a = ciFifoUa.bF.UserAddress;
#endif
a += cRAMADDR_START;
// Number of bytes to read
n = nBytes + 8; // Add 8 header bytes
if (ciFifoCon.rxBF.RxTimeStampEnable) {
n += 4; // Add 4 time stamp bytes
}
// Make sure we read a multiple of 4 bytes from RAM
if (n % 4) {
n = n + 4 - (n % 4);
}
// Read rxObj using one access
uint8_t ba[MAX_MSG_SIZE];
if (n > MAX_MSG_SIZE) {
n = MAX_MSG_SIZE;
}
spiTransferError = mcp2518fd_ReadByteArray(a, ba, n);
if (spiTransferError) {
return -3;
}
// Assign message header
REG_t myReg;
myReg.byte[0] = ba[0];
myReg.byte[1] = ba[1];
myReg.byte[2] = ba[2];
myReg.byte[3] = ba[3];
rxObj->word[0] = myReg.word;
myReg.byte[0] = ba[4];
myReg.byte[1] = ba[5];
myReg.byte[2] = ba[6];
myReg.byte[3] = ba[7];
rxObj->word[1] = myReg.word;
if (ciFifoCon.rxBF.RxTimeStampEnable) {
myReg.byte[0] = ba[8];
myReg.byte[1] = ba[9];
myReg.byte[2] = ba[10];
myReg.byte[3] = ba[11];
rxObj->word[2] = myReg.word;
// Assign message data
for (i = 0; i < nBytes; i++) {
rxd[i] = ba[i + 12];
}
} else {
rxObj->word[2] = 0;
// Assign message data
for (i = 0; i < nBytes; i++) {
rxd[i] = ba[i + 8];
}
}
// UINC channel
spiTransferError = mcp2518fd_ReceiveChannelUpdate(channel);
if (spiTransferError) {
return -4;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ReceiveChannelUpdate(CAN_FIFO_CHANNEL channel) {
uint16_t a = 0;
REG_CiFIFOCON ciFifoCon;
int8_t spiTransferError = 0;
ciFifoCon.word = 0;
// Set UINC
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET) +
1; // Byte that contains FRESET
ciFifoCon.rxBF.UINC = 1;
// Write byte
spiTransferError = mcp2518fd_WriteByte(a, ciFifoCon.byte[1]);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_TransmitChannelUpdate(CAN_FIFO_CHANNEL channel,
bool flush) {
uint16_t a;
REG_CiFIFOCON ciFifoCon;
int8_t spiTransferError = 0;
// Set UINC
a = cREGADDR_CiFIFOCON + (channel * CiFIFO_OFFSET) +
1; // Byte that contains FRESET
ciFifoCon.word = 0;
ciFifoCon.txBF.UINC = 1;
// Set TXREQ
if (flush) {
ciFifoCon.txBF.TxRequest = 1;
}
spiTransferError = mcp2518fd_WriteByte(a, ciFifoCon.byte[1]);
if (spiTransferError) {
return -1;
}
return spiTransferError;
}
int8_t
mcp2518fd::mcp2518fd_ReceiveChannelStatusGet(CAN_FIFO_CHANNEL channel,
CAN_RX_FIFO_STATUS *status) {
uint16_t a;
REG_CiFIFOSTA ciFifoSta;
int8_t spiTransferError = 0;
// Read
ciFifoSta.word = 0;
a = cREGADDR_CiFIFOSTA + (channel * CiFIFO_OFFSET);
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoSta.byte[0]);
if (spiTransferError) {
return -1;
}
// Update data
*status = (CAN_RX_FIFO_STATUS)(ciFifoSta.byte[0] & 0x0F);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ErrorStateGet(CAN_ERROR_STATE *flags) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Error state
a = cREGADDR_CiTREC + 2;
uint8_t f = 0;
spiTransferError = mcp2518fd_ReadByte(a, &f);
if (spiTransferError) {
return -1;
}
// Update data
*flags = (CAN_ERROR_STATE)(f & CAN_ERROR_ALL);
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ModuleEventRxCodeGet(CAN_RXCODE *rxCode) {
int8_t spiTransferError = 0;
uint16_t a = 0;
uint8_t rxCodeByte = 0;
// Read
a = cREGADDR_CiVEC + 3;
spiTransferError = mcp2518fd_ReadByte(a, &rxCodeByte);
if (spiTransferError) {
return -1;
}
// Decode data
// 0x40 = "no interrupt" (CAN_FIFO_CIVEC_NOINTERRUPT)
if ((rxCodeByte < CAN_RXCODE_TOTAL_CHANNELS) ||
(rxCodeByte == CAN_RXCODE_NO_INT)) {
*rxCode = (CAN_RXCODE)rxCodeByte;
} else {
*rxCode = CAN_RXCODE_RESERVED; // shouldn't get here
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_ModuleEventTxCodeGet(CAN_TXCODE *txCode) {
int8_t spiTransferError = 0;
uint16_t a = 0;
uint8_t txCodeByte = 0;
// Read
a = cREGADDR_CiVEC + 2;
spiTransferError = mcp2518fd_ReadByte(a, &txCodeByte);
if (spiTransferError) {
return -1;
}
// Decode data
// 0x40 = "no interrupt" (CAN_FIFO_CIVEC_NOINTERRUPT)
if ((txCodeByte < CAN_TXCODE_TOTAL_CHANNELS) ||
(txCodeByte == CAN_TXCODE_NO_INT)) {
*txCode = (CAN_TXCODE)txCodeByte;
} else {
*txCode = CAN_TXCODE_RESERVED; // shouldn't get here
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_TransmitChannelEventAttemptClear(CAN_FIFO_CHANNEL channel)
{
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read Interrupt Enables
a = cREGADDR_CiFIFOSTA + (channel * CiFIFO_OFFSET);
REG_CiFIFOSTA ciFifoSta;
ciFifoSta.word = 0;
spiTransferError = mcp2518fd_ReadByte(a, &ciFifoSta.byte[0]);
if (spiTransferError) {
return -1;
}
// Modify
ciFifoSta.byte[0] &= ~CAN_TX_FIFO_ATTEMPTS_EXHAUSTED_EVENT;
// Write
spiTransferError = mcp2518fd_WriteByte(a, ciFifoSta.byte[0]);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_LowPowerModeEnable() {
int8_t spiTransferError = 0;
uint8_t d = 0;
#ifdef MCP2517FD
// LPM not implemented
spiTransferError = -100;
#else
// Read
spiTransferError = mcp2518fd_ReadByte(cREGADDR_OSC, &d);
if (spiTransferError) {
return -1;
}
// Modify
d |= 0x08;
// Write
spiTransferError = mcp2518fd_WriteByte(cREGADDR_OSC, d);
if (spiTransferError) {
return -2;
}
#endif
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_LowPowerModeDisable() {
int8_t spiTransferError = 0;
uint8_t d = 0;
#ifdef MCP2517FD
// LPM not implemented
spiTransferError = -100;
#else
// Read
spiTransferError = mcp2518fd_ReadByte(cREGADDR_OSC, &d);
if (spiTransferError) {
return -1;
}
// Modify
d &= ~0x08;
// Write
spiTransferError = mcp2518fd_WriteByte(cREGADDR_OSC, d);
if (spiTransferError) {
return -2;
}
#endif
return spiTransferError;
}
void mcp2518fd::mcp2518fd_TransmitMessageQueue(void) {
uint8_t attempts = MAX_TXQUEUE_ATTEMPTS;
// Check if FIFO is not full
do {
mcp2518fd_TransmitChannelEventGet(APP_TX_FIFO, &txFlags);
if (attempts == 0) {
Nop();
Nop();
mcp2518fd_ErrorCountStateGet(&tec, &rec, &errorFlags);
return;
}
attempts--;
} while (!(txFlags & CAN_TX_FIFO_NOT_FULL_EVENT));
// Load message and transmit
uint8_t n = DRV_CANFDSPI_DlcToDataBytes((CAN_DLC)txObj.bF.ctrl.DLC);
mcp2518fd_TransmitChannelLoad(APP_TX_FIFO, &txObj, txd, n, true);
}
/*********************************************************************************************************
** Function name: sendMsg
** Descriptions: send message
*********************************************************************************************************/
byte mcp2518fd::mcp2518fd_sendMsg(const byte *buf, byte len, unsigned long id,
byte ext, byte rtr, bool wait_sent) {
uint8_t n;
int i;
byte spiTransferError = 0;
// Configure message data
txObj.word[0] = 0;
txObj.word[1] = 0;
txObj.bF.ctrl.RTR = !!rtr;
if (rtr && len > CAN_DLC_8) {
len = CAN_DLC_8;
}
txObj.bF.ctrl.DLC = len;
txObj.bF.ctrl.IDE = !!ext;
if (ext) {
txObj.bF.id.SID = (id >> 18) & 0x7FF;
txObj.bF.id.EID = id & 0x3FFFF;
} else {
txObj.bF.id.SID = id;
}
txObj.bF.ctrl.BRS = true;
txObj.bF.ctrl.FDF = (len > 8);
n = DRV_CANFDSPI_DlcToDataBytes((CAN_DLC)txObj.bF.ctrl.DLC);
// Prepare data
for (i = 0; i < n; i++) {
txd[i] = buf[i];
}
mcp2518fd_TransmitMessageQueue();
return spiTransferError;
}
int8_t mcp2518fd::mcp2518fd_receiveMsg() {
mcp2518fd_ReceiveChannelEventGet(APP_RX_FIFO, &rxFlags);
if (rxFlags & CAN_RX_FIFO_NOT_EMPTY_EVENT) {
mcp2518fd_ReceiveMessageGet(APP_RX_FIFO, &rxObj, rxd, 8);
for (int i = 0; i < 8; i++) {
Serial.println(rxd[i]);
Serial.println("\t");
}
Serial.println();
}
return 0;
}
/*********************************************************************************************************
** Function name: mcp2515_init
** Descriptions: init the device
*********************************************************************************************************/
uint8_t mcp2518fd::mcp2518fd_init(byte speedset, const byte clock) {
// Reset device
mcp2518fd_reset();
// Enable ECC and initialize RAM
mcp2518fd_EccEnable();
mcp2518fd_RamInit(0xff);
// Configure device
mcp2518fd_ConfigureObjectReset(&config);
config.IsoCrcEnable = 1;
config.StoreInTEF = 0;
mcp2518fd_Configure(&config);
// Setup TX FIFO
mcp2518fd_TransmitChannelConfigureObjectReset(&txConfig);
txConfig.FifoSize = 7;
txConfig.PayLoadSize = CAN_PLSIZE_64;
txConfig.TxPriority = 1;
mcp2518fd_TransmitChannelConfigure(APP_TX_FIFO, &txConfig);
// Setup RX FIFO
mcp2518fd_ReceiveChannelConfigureObjectReset(&rxConfig);
rxConfig.FifoSize = 15;
rxConfig.PayLoadSize = CAN_PLSIZE_64;
mcp2518fd_ReceiveChannelConfigure(APP_RX_FIFO, &rxConfig);
// Setup RX Filter
fObj.word = 0;
fObj.bF.SID = 0;
fObj.bF.EXIDE = 0;
fObj.bF.EID = 0x00;
mcp2518fd_FilterObjectConfigure(CAN_FILTER0, &fObj.bF);
// Setup RX Mask
mObj.word = 0;
mObj.bF.MSID = 0;
mObj.bF.MIDE = 0; // Only allow standard IDs
mObj.bF.MEID = 0x0;
mcp2518fd_FilterMaskConfigure(CAN_FILTER0, &mObj.bF);
// Link FIFO and Filter
mcp2518fd_FilterToFifoLink(CAN_FILTER0, APP_RX_FIFO, true);
// Setup Bit Time
mcp2518fd_BitTimeConfigure((MCP2518FD_BITTIME_SETUP)speedset,
CAN_SSP_MODE_AUTO, CAN_SYSCLK_40M);
// Setup Transmit and Receive Interrupts
mcp2518fd_GpioModeConfigure(GPIO_MODE_INT, GPIO_MODE_INT);
#ifdef APP_USE_TX_INT
mcp2518fd_TransmitChannelEventEnable(APP_TX_FIFO, CAN_TX_FIFO_NOT_FULL_EVENT);
#endif
mcp2518fd_ReceiveChannelEventEnable(APP_RX_FIFO, CAN_RX_FIFO_NOT_EMPTY_EVENT);
mcp2518fd_ModuleEventEnable((CAN_MODULE_EVENT)(CAN_TX_EVENT | CAN_RX_EVENT));
// Select Normal Mode
// mcp2518fd_OperationModeSelect(CAN_CLASSIC_MODE);
setMode(mcpMode);
return 0;
}
/*********************************************************************************************************
** Function name: enableTxInterrupt
** Descriptions: enable interrupt for all tx buffers
*********************************************************************************************************/
void mcp2518fd::enableTxInterrupt(bool enable) {
if (enable == true)
{
mcp2518fd_ModuleEventEnable(CAN_TX_EVENT);
}
return;
}
byte mcp2518fd::init_Mask(byte num, byte ext, unsigned long ulData) {
int8_t err;
mcp2518fd_OperationModeSelect(CAN_CONFIGURATION_MODE);
// Setup RX Mask
mObj.word = 0;
mObj.bF.MSID = ulData;
mObj.bF.MIDE = ext; // Only allow standard IDs
mObj.bF.MEID = 0x0;
err = mcp2518fd_FilterMaskConfigure((CAN_FILTER)num, &mObj.bF);
mcp2518fd_OperationModeSelect(mcpMode);
return err;
}
/*********************************************************************************************************
** Function name: init_Filt
** Descriptions: init canid filters
*********************************************************************************************************/
byte mcp2518fd::init_Filt(byte num, byte ext, unsigned long ulData) {
int8_t err;
err = mcp2518fd_OperationModeSelect(CAN_CONFIGURATION_MODE);
// Setup RX Filter
fObj.word = 0;
if (ext == 0) {
fObj.bF.SID = ulData;
fObj.bF.EXIDE = 0; // standard identifier
fObj.bF.EID = 0x00;
} else if (ext == 1) {
fObj.bF.SID = 0;
fObj.bF.EXIDE = 1; // extended identifier
fObj.bF.EID = ulData;
}
mcp2518fd_FilterObjectConfigure((CAN_FILTER)num, &fObj.bF);
mcp2518fd_OperationModeSelect(mcpMode);
return err;
}
/*********************************************************************************************************
** Function name: setSleepWakeup
** Descriptions: Enable or disable the wake up interrupt (If disabled
*the MCP2515 will not be woken up by CAN bus activity)
*********************************************************************************************************/
void mcp2518fd::setSleepWakeup(const byte enable) {
if (enable) {
mcp2518fd_LowPowerModeEnable();
} else {
mcp2518fd_LowPowerModeDisable();
}
}
/*********************************************************************************************************
** Function name: sleep
** Descriptions: Put mcp2515 in sleep mode to save power
*********************************************************************************************************/
byte mcp2518fd::sleep() {
if (getMode() != 0x01) {
return mcp2518fd_OperationModeSelect(CAN_SLEEP_MODE);
} else {
return CAN_OK;
}
}
/*********************************************************************************************************
** Function name: wake
** Descriptions: wake MCP2515 manually from sleep. It will come back
*in the mode it was before sleeping.
*********************************************************************************************************/
byte mcp2518fd::wake() {
byte currMode = getMode();
if (currMode != mcpMode) {
return mcp2518fd_OperationModeSelect(mcpMode);
} else {
return CAN_OK;
}
}
/*********************************************************************************************************
** Function name: getMode
** Descriptions: Returns current control mode
*********************************************************************************************************/
byte mcp2518fd::getMode() {
byte ret;
CAN_OPERATION_MODE mode;
mode = mcp2518fd_OperationModeGet();
ret = (byte)mode;
return ret;
}
/*********************************************************************************************************
** Function name: setMode
** Descriptions: Sets control mode
*********************************************************************************************************/
byte mcp2518fd::setMode(const byte opMode) {
if ((CAN_OPERATION_MODE)opMode !=
CAN_SLEEP_MODE) { // if going to sleep, the value stored in opMode is not
// changed so that we can return to it later
mcpMode = (CAN_OPERATION_MODE)opMode;
}
return mcp2518fd_OperationModeSelect(mcpMode);
}
/*********************************************************************************************************
** Function name: getCanId
** Descriptions: when receive something, you can get the can id!!
*********************************************************************************************************/
unsigned long mcp2518fd::getCanId(void) { return can_id; }
/*********************************************************************************************************
** Function name: isRemoteRequest
** Descriptions: when receive something, you can check if it was a
*request
*********************************************************************************************************/
byte mcp2518fd::isRemoteRequest(void) { return rtr; }
/*********************************************************************************************************
** Function name: isExtendedFrame
** Descriptions: did we just receive standard 11bit frame or extended
*29bit? 0 = std, 1 = ext
*********************************************************************************************************/
byte mcp2518fd::isExtendedFrame(void) { return ext_flg; }
/*********************************************************************************************************
** Function name: readMsgBufID
** Descriptions: Read message buf and can bus source ID according to
*status.
** Status has to be read with readRxTxStatus.
*********************************************************************************************************/
byte mcp2518fd::readMsgBufID(byte status, volatile unsigned long *id,
volatile byte *ext, volatile byte *rtr,
volatile byte *len, volatile byte *buf) {
byte r = mcp2518fd_readMsgBufID(len, buf);
if (id)
*id = can_id;
if (ext)
*ext = ext_flg;
if (rtr)
*rtr = this->rtr;
return r;
}
/*********************************************************************************************************
** Function name: readMsgBuf
** Descriptions: read message buf
*********************************************************************************************************/
byte mcp2518fd::readMsgBuf(byte *len, byte buf[]) {
return readMsgBufID(readRxTxStatus(), NULL, &ext_flg, &rtr, len, buf);
}
/*********************************************************************************************************
** Function name: readMsgBufID
** Descriptions: read message buf and can bus source ID
*********************************************************************************************************/
byte mcp2518fd::readMsgBufID(unsigned long *ID, byte *len, byte buf[]) {
return readMsgBufID(readRxTxStatus(), ID, &ext_flg, &rtr, len, buf);
}
/*********************************************************************************************************
** Function name: checkReceive
** Descriptions: check if got something
*********************************************************************************************************/
byte mcp2518fd::checkReceive(void) {
CAN_RX_FIFO_STATUS status; //
// RXnIF in Bit 1 and 0 return ((res & MCP_STAT_RXIF_MASK) ? CAN_MSGAVAIL :
// CAN_NOMSG);
mcp2518fd_ReceiveChannelStatusGet(APP_RX_FIFO, &status);
byte res = (byte)(status & CAN_RX_FIFO_NOT_EMPTY_EVENT) + 2;
return res;
}
/*********************************************************************************************************
** Function name: checkError
** Descriptions: if something error
*********************************************************************************************************/
byte mcp2518fd::checkError(uint8_t* err_ptr) {
CAN_ERROR_STATE flags;
mcp2518fd_ErrorStateGet(&flags);
if (err_ptr) {
*err_ptr = byte(flags);
}
return (byte)flags;
}
// /*********************************************************************************************************
// ** Function name: readMsgBufID
// ** Descriptions: Read message buf and can bus source ID according
// to status.
// ** Status has to be read with readRxTxStatus.
// *********************************************************************************************************/
byte mcp2518fd::mcp2518fd_readMsgBufID(volatile byte *len, volatile byte *buf) {
mcp2518fd_ReceiveMessageGet(APP_RX_FIFO, &rxObj, rxd, MAX_DATA_BYTES);
can_id = rxObj.bF.ctrl.IDE? (rxObj.bF.id.EID | (rxObj.bF.id.SID << 18))
: rxObj.bF.id.SID;
ext_flg = rxObj.bF.ctrl.IDE;
rtr = rxObj.bF.ctrl.RTR;
uint8_t n = DRV_CANFDSPI_DlcToDataBytes((CAN_DLC)rxObj.bF.ctrl.DLC);
*len = n;
for (int i = 0; i < n; i++) {
buf[i] = rxd[i];
}
return 0;
}
/*********************************************************************************************************
** Function name: trySendMsgBuf
** Descriptions: Try to send message. There is no delays for waiting
*free buffer.
*********************************************************************************************************/
byte mcp2518fd::trySendMsgBuf(unsigned long id, byte ext, byte rtr, byte len,
const byte *buf, byte iTxBuf) {
return mcp2518fd_sendMsg(buf, len, id, ext, rtr, false);
}
/*********************************************************************************************************
** Function name: clearBufferTransmitIfFlags
** Descriptions: Clear transmit interrupt flags for specific buffer
*or for all unreserved buffers.
** If interrupt will be used, it is important to clear
*all flags, when there is no
** more data to be sent. Otherwise IRQ will newer
*change state.
*********************************************************************************************************/
void mcp2518fd::clearBufferTransmitIfFlags(byte flags) {
mcp2518fd_TransmitChannelEventAttemptClear(APP_TX_FIFO);
return;
}
/*********************************************************************************************************
** Function name: sendMsgBuf
** Descriptions: Send message by using buffer read as free from
*CANINTF status
** Status has to be read with readRxTxStatus and
*filtered with checkClearTxStatus
*********************************************************************************************************/
byte mcp2518fd::sendMsgBuf(byte status, unsigned long id, byte ext, byte rtr,
byte len, volatile const byte *buf) {
return mcp2518fd_sendMsg((const byte *)buf, len, id, ext, rtr, true);
}
/*********************************************************************************************************
** Function name: sendMsgBuf
** Descriptions: send buf
*********************************************************************************************************/
byte mcp2518fd::sendMsgBuf(unsigned long id, byte ext, byte rtr, byte len,
const byte *buf, bool wait_sent) {
return mcp2518fd_sendMsg(buf, len, id, ext, rtr, wait_sent);
}
/*********************************************************************************************************
** Function name: sendMsgBuf
** Descriptions: send buf
*********************************************************************************************************/
byte mcp2518fd::sendMsgBuf(unsigned long id, byte ext, byte len,
const byte *buf, bool wait_sent) {
return mcp2518fd_sendMsg(buf, len, id, ext, 0, wait_sent);
}
/*********************************************************************************************************
** Function name: readRxTxStatus
** Descriptions: Read RX and TX interrupt bits. Function uses status
*reading, but translates.
** result to MCP_CANINTF. With this you can check
*status e.g. on interrupt sr
** with one single call to save SPI calls. Then use
*checkClearRxStatus and
** checkClearTxStatus for testing.
*********************************************************************************************************/
byte mcp2518fd::readRxTxStatus(void) {
byte ret;
mcp2518fd_ReceiveChannelEventGet(APP_RX_FIFO, &rxFlags);
ret = (byte)rxFlags;
return ret;
}
/*********************************************************************************************************
** Function name: checkClearRxStatus
** Descriptions: Return first found rx CANINTF status and clears it
*from parameter.
** Note that this does not affect to chip CANINTF at
*all. You can use this
** with one single readRxTxStatus call.
*********************************************************************************************************/
byte mcp2518fd::checkClearRxStatus(byte *status) {
return 1;
}
/*********************************************************************************************************
** Function name: checkClearTxStatus
** Descriptions: Return specified buffer of first found tx CANINTF
*status and clears it from parameter.
** Note that this does not affect to chip CANINTF at
*all. You can use this
** with one single readRxTxStatus call.
*********************************************************************************************************/
byte mcp2518fd::checkClearTxStatus(byte *status, byte iTxBuf) {
return 1;
}
/*********************************************************************************************************
** Function name: mcpPinMode
** Descriptions: switch supported pins between HiZ, interrupt, output
*or input
*********************************************************************************************************/
bool mcp2518fd::mcpPinMode(const byte pin, const byte mode) {
int8_t spiTransferError = 1;
uint16_t a = 0;
// Read
a = cREGADDR_IOCON + 3;
REG_IOCON iocon;
iocon.word = 0;
mcp2518fd_ReadByte(a, &iocon.byte[3]);
if (pin == GPIO_PIN_0) {
// Modify
iocon.bF.PinMode0 = (GPIO_PIN_MODE)mode;
}
if (pin == GPIO_PIN_1) {
// Modify
iocon.bF.PinMode1 = (GPIO_PIN_MODE)mode;
}
// Write
mcp2518fd_WriteByte(a, iocon.byte[3]);
return spiTransferError;
}
/*********************************************************************************************************
** Function name: mcpDigitalWrite
** Descriptions: write HIGH or LOW to RX0BF/RX1BF
*********************************************************************************************************/
bool mcp2518fd::mcpDigitalWrite(const byte pin, const byte mode) {
int8_t spiTransferError = 0;
uint16_t a = 0;
// Read
a = cREGADDR_IOCON + 1;
REG_IOCON iocon;
iocon.word = 0;
spiTransferError = mcp2518fd_ReadByte(a, &iocon.byte[1]);
if (spiTransferError) {
return -1;
}
// Modify
switch (pin) {
case GPIO_PIN_0:
iocon.bF.LAT0 = (GPIO_PIN_STATE)mode;
break;
case GPIO_PIN_1:
iocon.bF.LAT1 = (GPIO_PIN_STATE)mode;
break;
default:
return -1;
break;
}
// Write
spiTransferError = mcp2518fd_WriteByte(a, iocon.byte[1]);
if (spiTransferError) {
return -2;
}
return spiTransferError;
}
/*********************************************************************************************************
** Function name: mcpDigitalRead
** Descriptions: read HIGH or LOW from supported pins
*********************************************************************************************************/
byte mcp2518fd::mcpDigitalRead(const byte pin) {
GPIO_PIN_STATE state;
uint16_t a = 0;
// Read
a = cREGADDR_IOCON + 2;
REG_IOCON iocon;
iocon.word = 0;
mcp2518fd_ReadByte(a, &iocon.byte[2]);
// Update data
switch (pin) {
case GPIO_PIN_0:
state = (GPIO_PIN_STATE)iocon.bF.GPIO0;
break;
case GPIO_PIN_1:
state = (GPIO_PIN_STATE)iocon.bF.GPIO1;
break;
default:
return -1;
break;
}
byte ret = (byte)state;
return ret;
}
/* CANFD Auxiliary helper */
byte CANFD::dlc2len(byte dlc) {
if (dlc <= CAN_DLC_8)
return dlc;
switch (dlc) {
case CAN_DLC_12: return 12;
case CAN_DLC_16: return 16;
case CAN_DLC_20: return 20;
case CAN_DLC_24: return 24;
case CAN_DLC_32: return 32;
case CAN_DLC_48: return 48;
default:
case CAN_DLC_64: return 64;
}
}
byte CANFD::len2dlc(byte len) {
if (len <= CAN_DLC_8)
return len;
else if (len <= 12) return CAN_DLC_12;
else if (len <= 16) return CAN_DLC_16;
else if (len <= 20) return CAN_DLC_20;
else if (len <= 24) return CAN_DLC_24;
else if (len <= 32) return CAN_DLC_32;
else if (len <= 48) return CAN_DLC_48;
return CAN_DLC_64;
}