Got MCP2521 to work

This commit is contained in:
AlexanderHD27
2024-11-06 22:01:28 +01:00
parent 4bfb1f533e
commit e7a0035041
17 changed files with 525 additions and 70 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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);
};

View File

@@ -9,8 +9,6 @@ class MCP2515 {
private:
public:
MCP2515();
~MCP2515();

View File

@@ -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);
}

View 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);
}

View 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);
}