mirror of
https://github.com/Seeed-Studio/Seeed_Arduino_CAN.git
synced 2026-07-28 04:06:45 +00:00
3092 lines
82 KiB
C++
3092 lines
82 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: MCP_CAN
|
|
// ** Descriptions: Constructor
|
|
// *********************************************************************************************************/
|
|
// void mcp2518fd::mcp_canbus(uint8_t _CS)
|
|
// {
|
|
// nReservedTx = 0;
|
|
// pSPI = &SPI;
|
|
// init_CS(_CS);
|
|
// }
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: init_CS
|
|
** Descriptions: init CS pin and set UNSELECTED
|
|
*********************************************************************************************************/
|
|
// void mcp2518fd::init_CS(byte _CS)
|
|
// {
|
|
// if (_CS == 0)
|
|
// {
|
|
// return;
|
|
// }
|
|
// SPICS = _CS;
|
|
// pinMode(SPICS, OUTPUT);
|
|
// MCP2518fd_UNSELECT();
|
|
// }
|
|
|
|
/*********************************************************************************************************
|
|
** 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 == MCP2518fd_OK) ? CAN_OK : CAN_FAILINIT);
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: mcp2518fd_reset
|
|
** Descriptions: reset the device
|
|
*********************************************************************************************************/
|
|
int8_t mcp2518fd::mcp2518fd_reset(void)
|
|
{
|
|
uint16_t spiTransferSize = 2;
|
|
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)
|
|
{
|
|
uint16_t spiTransferSize = 3;
|
|
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
|
|
delay(10);
|
|
Serial.printf("DRV_CANFDSPI_ReadByte = %d\n\r", spiReceiveBuffer[2]);
|
|
// Update data
|
|
*rxd = spiReceiveBuffer[2];
|
|
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_WriteByte(uint16_t address, uint8_t txd)
|
|
{
|
|
uint16_t spiTransferSize = 3;
|
|
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
|
|
delay(10);
|
|
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_ReadWord(uint16_t address, uint32_t *rxd)
|
|
{
|
|
uint8_t i;
|
|
uint32_t x;
|
|
uint16_t spiTransferSize = 6;
|
|
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
|
|
delay(10);
|
|
|
|
// 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;
|
|
uint16_t spiTransferSize = 6;
|
|
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
|
|
delay(10);
|
|
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_ReadHalfWord(uint16_t address, uint16_t *rxd)
|
|
{
|
|
uint8_t i;
|
|
uint32_t x;
|
|
uint16_t spiTransferSize = 4;
|
|
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
|
|
delay(10);
|
|
|
|
// 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;
|
|
uint16_t spiTransferSize = 4;
|
|
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
|
|
delay(10);
|
|
|
|
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
|
|
delay(10);
|
|
|
|
// 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
|
|
delay(10);
|
|
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_WriteByteSafe(uint16_t address, uint8_t txd)
|
|
{
|
|
uint16_t crcResult = 0;
|
|
uint16_t spiTransferSize = 5;
|
|
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
|
|
delay(10);
|
|
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_WriteWordSafe(uint16_t address, uint32_t txd)
|
|
{
|
|
uint8_t i;
|
|
uint16_t crcResult = 0;
|
|
uint16_t spiTransferSize = 8;
|
|
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
|
|
delay(10);
|
|
|
|
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
|
|
delay(10);
|
|
|
|
// 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
|
|
delay(10);
|
|
|
|
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
|
|
delay(10);
|
|
// 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
|
|
delay(10);
|
|
|
|
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(CAN_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(CAN_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(CAN_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(CAN_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(CAN_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(CAN_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(
|
|
CAN_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)
|
|
{
|
|
Serial.printf("into DRV_CANFDSPI_TransmitChannelLoad\n\r");
|
|
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;
|
|
}
|
|
}
|
|
|
|
Serial.printf("txBuffer[8] = %d\n\r", txBuffer[8]);
|
|
Serial.printf("txBuffer[9] = %d\n\r", txBuffer[9]);
|
|
Serial.printf("txBuffer[10] = %d\n\r", txBuffer[10]);
|
|
Serial.printf("txBuffer[11] = %d\n\r", txBuffer[11]);
|
|
Serial.printf("txBuffer[12] = %d\n\r", txBuffer[12]);
|
|
Serial.printf("txBuffer[13] = %d\n\r", txBuffer[13]);
|
|
Serial.printf("txBuffer[14] = %d\n\r", txBuffer[14]);
|
|
Serial.printf("txBuffer[15] = %d\n\r", txBuffer[15]);
|
|
|
|
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;
|
|
}
|
|
|
|
Serial.printf("end DRV_CANFDSPI_TransmitChannelLoad\n\r");
|
|
return spiTransferError;
|
|
}
|
|
|
|
int8_t mcp2518fd::mcp2518fd_ReceiveChannelEventGet(CAN_FIFO_CHANNEL channel, CAN_RX_FIFO_EVENT *flags)
|
|
{
|
|
Serial.println("DRV_CANFDSPI_ReceiveChannelEventGet\n\r");
|
|
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);
|
|
|
|
Serial.printf("DRV_CANFDSPI_ReceiveChannelEventGet flags = %x\n\r", (*flags));
|
|
|
|
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;
|
|
}
|
|
|
|
Serial.printf("ciFifoCon.txBF.TxEnable2 = %d\n\r", ciFifoCon.txBF.TxEnable);
|
|
// Check that it is a receive buffer
|
|
ciFifoCon.word = fifoReg[0];
|
|
Serial.printf("ciFifoCon.txBF.TxEnable3 = %d\n\r", 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;
|
|
}
|
|
|
|
Serial.printf("DRV_CANFDSPI_ReceiveMessageGet end\n\r");
|
|
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_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: sendMsgBuf
|
|
** Descriptions: send buf
|
|
*********************************************************************************************************/
|
|
byte mcp2518fd::mcp2518fd_sendMsgBuf(const byte *buf, byte len, unsigned long id, byte ext,bool wait_sent)
|
|
{
|
|
return mcp2518fd_sendMsg(buf, len, id, ext,wait_sent);
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: sendMsg
|
|
** Descriptions: send message
|
|
*********************************************************************************************************/
|
|
byte mcp2518fd::mcp2518fd_sendMsg(const byte *buf, byte len, unsigned long id, byte ext,bool wait_sent)
|
|
{
|
|
uint8_t n;
|
|
int i;
|
|
byte spiTransferError = 0;
|
|
// Configure message data
|
|
txObj.word[0] = 0;
|
|
txObj.word[1] = 0;
|
|
txObj.bF.id.SID = id;
|
|
txObj.bF.ctrl.DLC = len;
|
|
if (ext == 1)
|
|
{
|
|
txObj.bF.ctrl.IDE = 1;
|
|
txObj.bF.ctrl.FDF = 1;
|
|
}
|
|
if (ext == 0)
|
|
{
|
|
txObj.bF.ctrl.IDE = 0;
|
|
txObj.bF.ctrl.FDF = 0;
|
|
}
|
|
txObj.bF.ctrl.BRS = true;
|
|
|
|
//Prepare data
|
|
for (i = 0; i < len; 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((CAN_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(CAN_CLASSIC_MODE);
|
|
|
|
// CAN_OPERATION_MODE abc;
|
|
// abc = DRV_CANFDSPI_OperationModeGet(0);
|
|
// Serial.printf("DRV_CANFDSPI_OperationModeGet = %d\n\r",abc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: enableTxInterrupt
|
|
** Descriptions: enable interrupt for all tx buffers
|
|
*********************************************************************************************************/
|
|
void mcp2518fd::enableTxInterrupt(bool enable) {
|
|
// uint16_t a = 0;
|
|
// int8_t spiTransferError = 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 ;
|
|
// }
|
|
// if (enable == true)
|
|
// {
|
|
// ciFifoCon.byte[0] |= (flags & CAN_RX_FIFO_ALL_EVENTS);
|
|
// }
|
|
// else
|
|
// {
|
|
// ciFifoCon.byte[0] |= (flags & CAN_RX_FIFO_NO_EVENT);
|
|
// }
|
|
|
|
// spiTransferError = mcp2518fd_WriteByte(a, ciFifoCon.byte[0]);
|
|
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* rtrBit,
|
|
volatile byte* len, volatile byte* buf) {
|
|
|
|
return mcp2518fd_readMsgBufID(len, buf);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: readMsgBuf
|
|
** Descriptions: read message buf
|
|
*********************************************************************************************************/
|
|
byte mcp2518fd::readMsgBuf(byte *len, byte buf[])
|
|
{
|
|
return mcp2518fd_readMsgBufID(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;
|
|
// byte res;
|
|
// res = mcp2518_readStatus(); // 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(void) {
|
|
|
|
// CAN_ERROR_STATE* flags;
|
|
// // byte eflg = mcp2515_readRegister(MCP_EFLG);
|
|
// // return ((eflg & MCP_EFLG_ERRORMASK) ? CAN_CTRLERROR : CAN_OK);
|
|
// mcp2518fd_ErrorStateGet(flags);
|
|
// byte eflg = (byte)*flags;
|
|
// return eflg;
|
|
return 1;
|
|
}
|
|
|
|
// /*********************************************************************************************************
|
|
// ** 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 = (unsigned long)rxObj.bF.id.SID;
|
|
Serial.printf("readMsgBufID can_id= %lu\n\r",can_id);
|
|
uint8_t n = DRV_CANFDSPI_DlcToDataBytes((CAN_DLC)rxObj.bF.ctrl.DLC);
|
|
Serial.printf("readMsgBufID n= %d\n\r",n);
|
|
*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 rtrBit, byte len, const byte* buf, byte iTxBuf) {
|
|
|
|
return CAN_OK;
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** 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) {
|
|
// flags &= MCP_TX_INT;
|
|
// if (flags == 0) {
|
|
// return;
|
|
// }
|
|
// mcp2515_modifyRegister(MCP_CANINTF, flags, 0);
|
|
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 rtrBit, byte len, volatile const byte *buf)
|
|
{
|
|
// byte txbuf_n = statusToTxSidh(status);
|
|
|
|
// if (txbuf_n == 0) {
|
|
// return CAN_FAILTX; // Invalid status
|
|
// }
|
|
|
|
// mcp2515_modifyRegister(MCP_CANINTF, status, 0); // Clear interrupt flag
|
|
// mcp2515_write_canMsg(txbuf_n, id, ext, rtrBit, len, buf);
|
|
|
|
// mcp2518fd_sendMsg(buf, len, id, ext);
|
|
|
|
return CAN_OK;
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** Function name: sendMsgBuf
|
|
** Descriptions: send buf
|
|
*********************************************************************************************************/
|
|
byte mcp2518fd::sendMsgBuf(unsigned long id, byte ext, byte rtrBit, byte len, const byte *buf, bool wait_sent)
|
|
{
|
|
return mcp2518fd_sendMsg(buf, len, id, ext,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, wait_sent);
|
|
}
|
|
|
|
/*********************************************************************************************************
|
|
** 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) {
|
|
// // flags &= MCP_TX_INT;
|
|
// // if (flags == 0) {
|
|
// // return;
|
|
// // }
|
|
// // mcp2515_modifyRegister(MCP_CANINTF, flags, 0);
|
|
// }
|
|
|
|
/*********************************************************************************************************
|
|
** 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 = (mcp2515_readStatus() & (MCP_STAT_TXIF_MASK | MCP_STAT_RXIF_MASK));
|
|
// ret = (ret & MCP_STAT_TX0IF ? MCP_TX0IF : 0) |
|
|
// (ret & MCP_STAT_TX1IF ? MCP_TX1IF : 0) |
|
|
// (ret & MCP_STAT_TX2IF ? MCP_TX2IF : 0) |
|
|
// (ret & MCP_STAT_RXIF_MASK); // Rx bits happend to be same on status and MCP_CANINTF
|
|
// return ret;
|
|
// byte ret;
|
|
// CAN_RXCODE rxCode;
|
|
// CAN_TXCODE txCode;
|
|
// mcp2518fd_ModuleEventRxCodeGet(rxCode);
|
|
// mcp2518fd_ModuleEventTxCodeGet(txCode);
|
|
// if (rxCode != CAN_RXCODE_RESERVED)
|
|
// {
|
|
// ret = (byte)rxCode;
|
|
// }
|
|
// if (txCode != CAN_RXCODE_RESERVED)
|
|
// {
|
|
// ret = (byte)txCode;
|
|
// }
|
|
|
|
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) {
|
|
// byte ret;
|
|
|
|
// ret = *status & MCP_RX0IF; *status &= ~MCP_RX0IF;
|
|
|
|
// if (ret == 0) {
|
|
// ret = *status & MCP_RX1IF;
|
|
// *status &= ~MCP_RX1IF;
|
|
// }
|
|
|
|
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) {
|
|
// byte ret;
|
|
|
|
// if (iTxBuf < MCP_N_TXBUFFERS) { // Clear specific buffer flag
|
|
// ret = *status & txIfFlag(iTxBuf); *status &= ~txIfFlag(iTxBuf);
|
|
// } else {
|
|
// ret = 0;
|
|
// for (byte i = 0; i < MCP_N_TXBUFFERS - nReservedTx; i++) {
|
|
// ret = *status & txIfFlag(i);
|
|
// if (ret != 0) {
|
|
// *status &= ~txIfFlag(i);
|
|
// return ret;
|
|
// }
|
|
// };
|
|
// }
|
|
|
|
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;
|
|
}
|