drivers: CAN: MCP2515: Add and use Read RX Buffer instruction

Reduces SPI RX buffer read overhead by a byte and further reduces the
SPI use by automatically clearing the associated receive flag RXxIF.

Signed-off-by: Nick Ward <nix.ward@gmail.com>
This commit is contained in:
Nick Ward 2019-07-21 14:59:53 +10:00 committed by Jukka Rissanen
commit 0c5ef3e156
2 changed files with 57 additions and 8 deletions

View file

@ -139,6 +139,43 @@ static int mcp2515_cmd_read_reg(struct device *dev, u8_t reg_addr,
&tx, &rx); &tx, &rx);
} }
/*
* Read RX Buffer instruction
*
* When reading a receive buffer, reduces the overhead of a normal READ
* command by placing the Address Pointer at one of four locations selected by
* parameter nm:
* 0: Receive Buffer 0, Start at RXB0SIDH (0x61)
* 1: Receive Buffer 0, Start at RXB0D0 (0x66)
* 2: Receive Buffer 1, Start at RXB1SIDH (0x71)
* 3: Receive Buffer 1, Start at RXB1D0 (0x76)
*/
static int mcp2515_cmd_read_rx_buffer(struct device *dev, u8_t nm,
u8_t *buf_data, u8_t buf_len)
{
__ASSERT(nm <= 0x03, "nm <= 0x03");
u8_t cmd_buf[] = { MCP2515_OPCODE_READ_RX_BUFFER | (nm << 1) };
struct spi_buf tx_buf[] = {
{ .buf = cmd_buf, .len = sizeof(cmd_buf) },
{ .buf = NULL, .len = buf_len }
};
const struct spi_buf_set tx = {
.buffers = tx_buf, .count = ARRAY_SIZE(tx_buf)
};
struct spi_buf rx_buf[] = {
{ .buf = NULL, .len = sizeof(cmd_buf) },
{ .buf = buf_data, .len = buf_len }
};
const struct spi_buf_set rx = {
.buffers = rx_buf, .count = ARRAY_SIZE(rx_buf)
};
return spi_transceive(DEV_DATA(dev)->spi, &DEV_DATA(dev)->spi_cfg,
&tx, &rx);
}
static u8_t mcp2515_convert_canmode_to_mcp2515mode(enum can_mode mode) static u8_t mcp2515_convert_canmode_to_mcp2515mode(enum can_mode mode)
{ {
switch (mode) { switch (mode) {
@ -499,15 +536,17 @@ static void mcp2515_rx_filter(struct device *dev, struct zcan_frame *msg)
static void mcp2515_rx(struct device *dev, u8_t rx_idx) static void mcp2515_rx(struct device *dev, u8_t rx_idx)
{ {
__ASSERT(rx_idx < MCP2515_RX_CNT, "rx_idx < MCP2515_RX_CNT");
struct zcan_frame msg; struct zcan_frame msg;
u8_t rx_frame[MCP2515_FRAME_LEN]; u8_t rx_frame[MCP2515_FRAME_LEN];
u8_t addr_rx_ctrl = MCP2515_ADDR_RXB0CTRL + u8_t nm;
(rx_idx * MCP2515_ADDR_OFFSET_FRAME2FRAME);
/* Address Pointer selection */
nm = 2 * rx_idx;
/* Fetch rx buffer */ /* Fetch rx buffer */
mcp2515_cmd_read_reg(dev, mcp2515_cmd_read_rx_buffer(dev, nm, rx_frame, sizeof(rx_frame));
addr_rx_ctrl + MCP2515_ADDR_OFFSET_CTRL2FRAME,
rx_frame, sizeof(rx_frame));
mcp2515_convert_mcp2515frame_to_zcanframe(rx_frame, &msg); mcp2515_convert_mcp2515frame_to_zcanframe(rx_frame, &msg);
mcp2515_rx_filter(dev, &msg); mcp2515_rx_filter(dev, &msg);
} }
@ -611,10 +650,16 @@ static void mcp2515_handle_interrupts(struct device *dev)
if (canintf & MCP2515_CANINTF_RX0IF) { if (canintf & MCP2515_CANINTF_RX0IF) {
mcp2515_rx(dev, 0); mcp2515_rx(dev, 0);
/* RX0IF flag cleared automatically during read */
canintf &= ~MCP2515_CANINTF_RX0IF;
} }
if (canintf & MCP2515_CANINTF_RX1IF) { if (canintf & MCP2515_CANINTF_RX1IF) {
mcp2515_rx(dev, 1); mcp2515_rx(dev, 1);
/* RX1IF flag cleared automatically during read */
canintf &= ~MCP2515_CANINTF_RX1IF;
} }
if (canintf & MCP2515_CANINTF_TX0IF) { if (canintf & MCP2515_CANINTF_TX0IF) {
@ -633,9 +678,11 @@ static void mcp2515_handle_interrupts(struct device *dev)
mcp2515_handle_errors(dev); mcp2515_handle_errors(dev);
} }
/* clear the flags we handled */ if (canintf != 0) {
mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_CANINTF, canintf, /* Clear remaining flags */
~canintf); mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_CANINTF,
canintf, ~canintf);
}
/* Break from loop if INT pin is no longer low */ /* Break from loop if INT pin is no longer low */
ret = gpio_pin_read(dev_data->int_gpio, dev_cfg->int_pin, &pin); ret = gpio_pin_read(dev_data->int_gpio, dev_cfg->int_pin, &pin);

View file

@ -10,6 +10,7 @@
#include <drivers/can.h> #include <drivers/can.h>
#define MCP2515_RX_CNT 2
#define MCP2515_TX_CNT 3 #define MCP2515_TX_CNT 3
#define MCP2515_FRAME_LEN 13 #define MCP2515_FRAME_LEN 13
@ -84,6 +85,7 @@ struct mcp2515_config {
#define MCP2515_OPCODE_BIT_MODIFY 0x05 #define MCP2515_OPCODE_BIT_MODIFY 0x05
#define MCP2515_OPCODE_LOAD_TX_BUFFER 0x40 #define MCP2515_OPCODE_LOAD_TX_BUFFER 0x40
#define MCP2515_OPCODE_RTS 0x80 #define MCP2515_OPCODE_RTS 0x80
#define MCP2515_OPCODE_READ_RX_BUFFER 0x90
#define MCP2515_OPCODE_READ_STATUS 0xA0 #define MCP2515_OPCODE_READ_STATUS 0xA0
#define MCP2515_OPCODE_RESET 0xC0 #define MCP2515_OPCODE_RESET 0xC0