Got MCP2521 to work
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
idf_component_register(SRCS
|
||||
"interface_commands.cpp"
|
||||
"interface_commands_complex.cpp"
|
||||
"interface_interrupts.cpp"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES driver
|
||||
REQUIRES mcp2521_hardware_interface
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#define MCP2521_BFPCTRL 0x0C
|
||||
#define MCP2521_BFPCTRL_B1BFS (1 << 5)
|
||||
@@ -110,6 +111,10 @@ struct CANSTAT_Register {
|
||||
#define MCP2521_TXB0CTRL_TXP1 (1 << 1)
|
||||
#define MCP2521_TXB0CTRL_TXP0 (1 << 0)
|
||||
|
||||
#define MCP2521_TXB0DLC 0x35
|
||||
#define MCP2521_TXB1DLC 0x45
|
||||
#define MCP2521_TXB2DLC 0x55
|
||||
|
||||
#define MCP2521_TXB1CTRL 0x40
|
||||
#define MCP2521_TXB1CTRL_ABTF (1 << 6)
|
||||
#define MCP2521_TXB1CTRL_MLOA (1 << 5)
|
||||
@@ -161,4 +166,27 @@ struct TXBnCTRL_Register {
|
||||
#define MCP2521_OP_RTS 0b10000000
|
||||
#define MCP2521_OP_READ_STATUS 0b10100000
|
||||
#define MCP2521_OP_RX_STATUS 0b10110000
|
||||
#define MCP2521_OP_BIT_MODIFY 0b00000101
|
||||
#define MCP2521_OP_BIT_MODIFY 0b00000101
|
||||
|
||||
#define MCP2521_TXB0SIDH 0x31
|
||||
#define MCP2521_TXB1SIDH 0x41
|
||||
#define MCP2521_TXB2SIDH 0x51
|
||||
|
||||
#define MCP2521_TXB0SIDL 0x32
|
||||
#define MCP2521_TXB1SIDL 0x42
|
||||
#define MCP2521_TXB2SIDL 0x52
|
||||
|
||||
#define MCP2521_RXB0SIDH 0x61
|
||||
#define MCP2521_RXB1SIDH 0x71
|
||||
|
||||
#define MCP2521_RXB0SIDL 0x62
|
||||
#define MCP2521_RXB1SIDL 0x72
|
||||
|
||||
#define MCP2521_RXB0EID8 0x63
|
||||
#define MCP2521_RXB1EID8 0x73
|
||||
|
||||
#define MCP2521_RXB0EID0 0x64
|
||||
#define MCP2521_RXB1EID0 0x74
|
||||
|
||||
#define MCP2521_RXB0DLC 0x65
|
||||
#define MCP2521_RXB1DLC 0x75
|
||||
@@ -21,15 +21,55 @@ enum MCP2521_BUFFER_TYPE {
|
||||
DATA = 1
|
||||
};
|
||||
|
||||
enum MCP2521_OPERATION_MODE {
|
||||
NORMAL = 0b000,
|
||||
SLEEP = 0b001,
|
||||
LOOPBACK = 0b010,
|
||||
LISTEN_ONLY = 0b011,
|
||||
CONFIG = 0b100
|
||||
};
|
||||
|
||||
struct rx_info {
|
||||
bool extended;
|
||||
|
||||
uint16_t id;
|
||||
uint32_t extended_id;
|
||||
|
||||
bool rtr;
|
||||
bool extended_rtr;
|
||||
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
class MCP2521_Command_Interface {
|
||||
private:
|
||||
MCP2521_Hardware_Handle * hardware_handle;
|
||||
|
||||
intHandlerFunction_t rx0_handler;
|
||||
intHandlerFunction_t rx1_handler;
|
||||
intHandlerFunction_t tx0_handler;
|
||||
intHandlerFunction_t tx1_handler;
|
||||
intHandlerFunction_t tx2_handler;
|
||||
intHandlerFunction_t error_handler;
|
||||
intHandlerFunction_t wakeup_handler;
|
||||
intHandlerFunction_t message_error_handler;
|
||||
|
||||
void * rx0_handler_arg;
|
||||
void * rx1_handler_arg;
|
||||
void * tx0_handler_arg;
|
||||
void * tx1_handler_arg;
|
||||
void * tx2_handler_arg;
|
||||
void * error_handler_arg;
|
||||
void * wakeup_handler_arg;
|
||||
void * message_error_handler_arg;
|
||||
public:
|
||||
|
||||
MCP2521_Command_Interface(
|
||||
MCP2521_Hardware_Handle * hardware_handle
|
||||
);
|
||||
|
||||
void handleInterrupt();
|
||||
|
||||
void reset();
|
||||
|
||||
void read_reg(uint8_t address, uint8_t *data, size_t length);
|
||||
@@ -49,5 +89,45 @@ public:
|
||||
uint8_t read_rx_status();
|
||||
|
||||
void bit_modify(uint8_t address, uint8_t mask, uint8_t data);
|
||||
|
||||
// More Complex Commands
|
||||
void set_tx_id(MCP2521_TX_BUFFER buffer, uint16_t id, bool extended);
|
||||
|
||||
/**
|
||||
* @brief Loads the Data Length Code register for the specified buffer
|
||||
*
|
||||
* @param buffer What Buffer to load the DLC register for
|
||||
* @param length How many bytes are in the message (0-8)
|
||||
* @param rtr: Remote Transmission Request
|
||||
*/
|
||||
void set_DLC_reg(MCP2521_TX_BUFFER buffer, uint8_t length, bool rtr);
|
||||
|
||||
/**
|
||||
* @brief Loads the data and id into the specified buffer
|
||||
*
|
||||
* @param buffer
|
||||
* @param id
|
||||
* @param data
|
||||
* @param length
|
||||
*/
|
||||
void prepare_tx(MCP2521_TX_BUFFER buffer, uint32_t id, uint8_t *data, size_t length, bool rtr, bool extended);
|
||||
|
||||
void set_mode_of_operation(MCP2521_OPERATION_MODE mode, bool singleshot);
|
||||
void set_singleshot_mode(bool enable);
|
||||
|
||||
void enable_interrupts(bool MessageError, bool ErrorInterrupt, bool WakeUp, bool TXB0, bool TXB1, bool TXB2, bool RXB0, bool RXB1);
|
||||
rx_info get_rx_id(MCP2521_RX_BUFFER buffer);
|
||||
|
||||
|
||||
|
||||
// Registering Handlers for Interrupts
|
||||
void register_rx0_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_rx1_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_tx0_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_tx1_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_tx2_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_error_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_wakeup_handler(intHandlerFunction_t handler, void * arg);
|
||||
void register_message_error_handler(intHandlerFunction_t handler, void * arg);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ class MCP2515 {
|
||||
private:
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
MCP2515();
|
||||
~MCP2515();
|
||||
|
||||
@@ -3,10 +3,34 @@
|
||||
#include "mcp2521.hpp"
|
||||
#include "mcp2521_addresses.hpp"
|
||||
|
||||
void runIntHandler(void *arg) {
|
||||
MCP2521_Command_Interface *command_interface = (MCP2521_Command_Interface *)arg;
|
||||
command_interface->handleInterrupt();
|
||||
}
|
||||
|
||||
MCP2521_Command_Interface::MCP2521_Command_Interface(
|
||||
MCP2521_Hardware_Handle * hardware_handle
|
||||
) {
|
||||
this->hardware_handle = hardware_handle;
|
||||
this->hardware_handle->registerIntHandler(runIntHandler, (void *)this);
|
||||
|
||||
rx0_handler = NULL;
|
||||
rx1_handler = NULL;
|
||||
tx0_handler = NULL;
|
||||
tx1_handler = NULL;
|
||||
tx2_handler = NULL;
|
||||
error_handler = NULL;
|
||||
wakeup_handler = NULL;
|
||||
message_error_handler = NULL;
|
||||
|
||||
rx0_handler_arg = NULL;
|
||||
rx1_handler_arg = NULL;
|
||||
tx0_handler_arg = NULL;
|
||||
tx1_handler_arg = NULL;
|
||||
tx2_handler_arg = NULL;
|
||||
error_handler_arg = NULL;
|
||||
wakeup_handler_arg = NULL;
|
||||
message_error_handler_arg = NULL;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::reset() {
|
||||
@@ -35,7 +59,7 @@ void MCP2521_Command_Interface::write_reg(uint8_t address, uint8_t data) {
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::write_tx_buf(MCP2521_TX_BUFFER buffer, MCP2521_BUFFER_TYPE type, uint8_t *data, size_t length) {
|
||||
uint8_t address = buffer | (type << 2);
|
||||
uint8_t address = (buffer << 1) | (type);
|
||||
hardware_handle->write(MCP2521_OP_LOAD_TX_BUFFER | address, data, length);
|
||||
}
|
||||
|
||||
|
||||
123
can-interface/components/mcp2521/interface_commands_complex.cpp
Normal file
123
can-interface/components/mcp2521/interface_commands_complex.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "mcp2521.hpp"
|
||||
#include "mcp2521_addresses.hpp"
|
||||
|
||||
void MCP2521_Command_Interface::set_tx_id(MCP2521_TX_BUFFER buffer, uint16_t id, bool extended) {
|
||||
uint8_t addr_offset = 0;
|
||||
switch (buffer)
|
||||
{
|
||||
case MCP2521_TX_BUFFER::TXB0:
|
||||
addr_offset = 0x00;
|
||||
break;
|
||||
case MCP2521_TX_BUFFER::TXB1:
|
||||
addr_offset = 0x10;
|
||||
break;
|
||||
case MCP2521_TX_BUFFER::TXB2:
|
||||
addr_offset = 0x20;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t upper_id = (id >> 3) & 0xFF;
|
||||
uint8_t lower_id = ((id & 0b111) << 5);
|
||||
|
||||
if(extended) {
|
||||
lower_id |= 0b1000;
|
||||
lower_id |= (id >> 8) & 0b11;
|
||||
}
|
||||
|
||||
write_reg(MCP2521_TXB0SIDH | addr_offset, upper_id);
|
||||
write_reg(MCP2521_TXB0SIDL | addr_offset, lower_id);
|
||||
}
|
||||
|
||||
// 00110101 0x35
|
||||
// 01000101 0x45
|
||||
// 01010101 0x55
|
||||
|
||||
void MCP2521_Command_Interface::set_DLC_reg(MCP2521_TX_BUFFER buffer, uint8_t length, bool rtr) {
|
||||
uint8_t data = length;
|
||||
|
||||
if (rtr)
|
||||
data |= 0b01000000;
|
||||
|
||||
uint8_t reg_address = 0;
|
||||
|
||||
switch (buffer) {
|
||||
case MCP2521_TX_BUFFER::TXB0:
|
||||
reg_address = MCP2521_TXB0DLC;
|
||||
break;
|
||||
case MCP2521_TX_BUFFER::TXB1:
|
||||
reg_address = MCP2521_TXB1DLC;
|
||||
break;
|
||||
case MCP2521_TX_BUFFER::TXB2:
|
||||
reg_address = MCP2521_TXB2DLC;
|
||||
break;
|
||||
}
|
||||
|
||||
write_reg(reg_address, data);
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::set_mode_of_operation(MCP2521_OPERATION_MODE mode, bool singleshot) {
|
||||
|
||||
uint8_t single = singleshot ? 0b00001000 : 0x0;
|
||||
|
||||
bit_modify(MCP2521_CANCTRL, 0b11101000 , (mode << 5) | single);
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::set_singleshot_mode(bool enable) {
|
||||
uint8_t data = enable ? 0x08 : 0x00;
|
||||
bit_modify(MCP2521_CANCTRL, 0x08, data);
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::enable_interrupts(bool MessageError, bool ErrorInterrupt, bool WakeUp, bool TXB0, bool TXB1, bool TXB2, bool RXB0, bool RXB1) {
|
||||
uint8_t interrupt_flags = 0;
|
||||
|
||||
if (MessageError) interrupt_flags |= 0b10000000;
|
||||
if (WakeUp) interrupt_flags |= 0b01000000;
|
||||
if (ErrorInterrupt) interrupt_flags |= 0b00100000;
|
||||
if (TXB2) interrupt_flags |= 0b00010000;
|
||||
if (TXB1) interrupt_flags |= 0b00001000;
|
||||
if (TXB0) interrupt_flags |= 0b00000100;
|
||||
if (RXB1) interrupt_flags |= 0b00000010;
|
||||
if (RXB0) interrupt_flags |= 0b00000001;
|
||||
|
||||
write_reg(MCP2521_CANINTE, interrupt_flags);
|
||||
}
|
||||
|
||||
rx_info MCP2521_Command_Interface::get_rx_id(MCP2521_RX_BUFFER buffer) {
|
||||
uint8_t data[5];
|
||||
uint8_t addr_offset = MCP2521_RXB0SIDH;
|
||||
|
||||
switch (buffer) {
|
||||
case MCP2521_RX_BUFFER::RXB0:
|
||||
addr_offset |= 0x00;
|
||||
break;
|
||||
case MCP2521_RX_BUFFER::RXB1:
|
||||
addr_offset |= 0x10;
|
||||
break;
|
||||
}
|
||||
|
||||
read_reg(addr_offset, data, 5);
|
||||
|
||||
rx_info res;
|
||||
res.extended = data[1] & 0b1000;
|
||||
res.id = (data[0] << 3) | (data[1] >> 5);
|
||||
res.extended_id = ((data[1] & 0b11) << 16) | (data[2] << 8) | data[3];
|
||||
res.rtr = data[1] & 0b10000;
|
||||
res.extended_rtr = (data[4] & 0b1000000);
|
||||
res.length = (data[4] & 0b1111);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::prepare_tx(
|
||||
MCP2521_TX_BUFFER buffer,
|
||||
uint32_t id,
|
||||
uint8_t *data,
|
||||
size_t length,
|
||||
bool rtr, bool extended) {
|
||||
|
||||
set_tx_id(buffer, id, extended);
|
||||
set_DLC_reg(buffer, length, rtr);
|
||||
write_tx_buf(buffer, MCP2521_BUFFER_TYPE::DATA, data, length);
|
||||
}
|
||||
114
can-interface/components/mcp2521/interface_interrupts.cpp
Normal file
114
can-interface/components/mcp2521/interface_interrupts.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "mcp2521.hpp"
|
||||
#include "mcp2521_addresses.hpp"
|
||||
#include <stdio.h>
|
||||
|
||||
void MCP2521_Command_Interface::register_rx0_handler(intHandlerFunction_t handler, void* args) {
|
||||
rx0_handler = handler;
|
||||
rx0_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_rx1_handler(intHandlerFunction_t handler, void* args) {
|
||||
rx1_handler = handler;
|
||||
rx1_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_tx0_handler(intHandlerFunction_t handler, void* args) {
|
||||
tx0_handler = handler;
|
||||
tx0_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_tx1_handler(intHandlerFunction_t handler, void* args) {
|
||||
tx1_handler = handler;
|
||||
tx1_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_tx2_handler(intHandlerFunction_t handler, void* args) {
|
||||
tx2_handler = handler;
|
||||
tx2_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_error_handler(intHandlerFunction_t handler, void* args) {
|
||||
error_handler = handler;
|
||||
error_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_wakeup_handler(intHandlerFunction_t handler, void* args) {
|
||||
wakeup_handler = handler;
|
||||
wakeup_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::register_message_error_handler(intHandlerFunction_t handler, void* args) {
|
||||
message_error_handler = handler;
|
||||
message_error_handler_arg = args;
|
||||
}
|
||||
|
||||
void MCP2521_Command_Interface::handleInterrupt() {
|
||||
uint8_t flags = read_reg(MCP2521_CANINTF);
|
||||
uint8_t clearBits = 0;
|
||||
|
||||
if (flags & MCP2521_CANINTF_RX0IF) {
|
||||
if (rx0_handler) {
|
||||
rx0_handler(rx0_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_RX0IF;
|
||||
clearBits |= MCP2521_CANINTF_RX0IF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_RX1IF) {
|
||||
if (rx1_handler) {
|
||||
rx1_handler(rx1_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_RX1IF;
|
||||
clearBits |= MCP2521_CANINTF_RX1IF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_TX0IF) {
|
||||
if (tx0_handler) {
|
||||
tx0_handler(tx0_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_TX0IF;
|
||||
clearBits |= MCP2521_CANINTF_TX0IF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_TX1IF) {
|
||||
if (tx1_handler) {
|
||||
tx1_handler(tx1_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_TX1IF;
|
||||
clearBits |= MCP2521_CANINTF_TX1IF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_TX2IF) {
|
||||
if (tx2_handler) {
|
||||
tx2_handler(tx2_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_TX2IF;
|
||||
clearBits |= MCP2521_CANINTF_TX2IF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_ERRIF) {
|
||||
if (error_handler) {
|
||||
error_handler(error_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_ERRIF;
|
||||
clearBits |= MCP2521_CANINTF_ERRIF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_WAKIF) {
|
||||
if (wakeup_handler) {
|
||||
wakeup_handler(wakeup_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_WAKIF;
|
||||
clearBits |= MCP2521_CANINTF_WAKIF;
|
||||
}
|
||||
|
||||
if (flags & MCP2521_CANINTF_MERRF) {
|
||||
if (message_error_handler) {
|
||||
message_error_handler(message_error_handler_arg);
|
||||
}
|
||||
flags &= ~MCP2521_CANINTF_MERRF;
|
||||
clearBits |= MCP2521_CANINTF_MERRF;
|
||||
}
|
||||
|
||||
bit_modify(MCP2521_CANINTF, clearBits, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user