mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
mcp2515: add a driver for the mcp2515 SPI CAN controller
This driver implements the candev interface
This commit is contained in:
parent
10592f2bb1
commit
62a9929f9b
121
drivers/include/candev_mcp2515.h
Normal file
121
drivers/include/candev_mcp2515.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_mcp2515 MCP2515
|
||||
* @ingroup drivers_can
|
||||
* @brief Driver for the Microchip MCP2515 can controller.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definition of the implementation of the CAN controller driver.
|
||||
*
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
*/
|
||||
|
||||
#ifndef CANDEV_MCP2515_H
|
||||
#define CANDEV_MCP2515_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "can/candev.h"
|
||||
#include "cpu_conf.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
#include "mutex.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Number of transmit mailboxes
|
||||
*/
|
||||
#define MCP2515_TX_MAILBOXES 3
|
||||
|
||||
/**
|
||||
* @name Receive mailboxes and filters number
|
||||
* @{
|
||||
* for RX buffers: the MCP2515 managed 6 acceptance filters in 2 mailboxes:
|
||||
* - MB0 contains 2 acceptance filters in relation with 1 acceptance mask
|
||||
* - MB1 contains 4 acceptance filters in relation with 1 acceptance mask
|
||||
*
|
||||
* MB0 MB1
|
||||
* +------+ +------+
|
||||
* mask 0 | RXM0 | | RXM1 | mask 1
|
||||
* +======+ +======+
|
||||
* filter 0 | RXF0 | | RXF2 | filter 2
|
||||
* +------+ +------+
|
||||
* filter 1 | RXF1 | | RXF3 | filter 3
|
||||
* +------+ +------+
|
||||
* | RXF4 | filter 4
|
||||
* +------+
|
||||
* | RXF5 | filter 5
|
||||
* +------+
|
||||
*/
|
||||
#define MCP2515_RX_MAILBOXES 2
|
||||
#define MCP2515_FILTERS_MB0 2
|
||||
#define MCP2515_FILTERS_MB1 4
|
||||
#define MCP2515_FILTERS (MCP2515_FILTERS_MB0 + MCP2515_FILTERS_MB1)
|
||||
/** @} */
|
||||
|
||||
/** MCP2515 candev descriptor */
|
||||
typedef struct candev_mcp2515 candev_mcp2515_t;
|
||||
|
||||
/**
|
||||
* @brief MCP2515 configuration descriptor
|
||||
*/
|
||||
typedef struct candev_mcp2515_conf {
|
||||
spi_t spi; /**< SPI bus */
|
||||
spi_mode_t spi_mode; /**< SPI mode */
|
||||
spi_clk_t spi_clk; /**< SPI clock speed */
|
||||
gpio_t cs_pin; /**< Slave select pin */
|
||||
gpio_t rst_pin; /**< Reset pin */
|
||||
gpio_t int_pin; /**< Interrupt pin */
|
||||
uint32_t clk; /**< External clock frequency */
|
||||
} candev_mcp2515_conf_t;
|
||||
|
||||
/**
|
||||
* @brief MCP2515 device descriptor
|
||||
*/
|
||||
struct candev_mcp2515 {
|
||||
/** candev driver */
|
||||
candev_t candev;
|
||||
/** driver configuration */
|
||||
const candev_mcp2515_conf_t *conf;
|
||||
/** tx mailboxes local copy */
|
||||
const struct can_frame *tx_mailbox[MCP2515_TX_MAILBOXES];
|
||||
/** rx mailboxes local copy */
|
||||
struct can_frame rx_buf[MCP2515_RX_MAILBOXES];
|
||||
/** masks list */
|
||||
uint32_t masks[MCP2515_RX_MAILBOXES];
|
||||
/** filters list */
|
||||
canid_t filter_ids[MCP2515_RX_MAILBOXES][MCP2515_FILTERS_MB1];
|
||||
/** wakeup source */
|
||||
int wakeup_src;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize a mcp2515 device by assigning a @p timing and an SPI
|
||||
* configuration @p conf.
|
||||
*
|
||||
* @param[out] dev mcp2515 device descriptor
|
||||
* @param[in] conf mcp2515 configuration
|
||||
*/
|
||||
void candev_mcp2515_init(candev_mcp2515_t *dev, const candev_mcp2515_conf_t *conf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CANDEV_MCP2515_H */
|
||||
/** @} */
|
3
drivers/mcp2515/Makefile
Normal file
3
drivers/mcp2515/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = mcp2515
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
570
drivers/mcp2515/candev_mcp2515.c
Normal file
570
drivers/mcp2515/candev_mcp2515.c
Normal file
@ -0,0 +1,570 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515 Stand-Alone CAN Controller With SPI Interface
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of the CAN controller driver
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <can/common.h>
|
||||
|
||||
#include "candev_mcp2515.h"
|
||||
#include "can/common.h"
|
||||
#include "can/device.h"
|
||||
#include "mcp2515.h"
|
||||
#include "periph_conf.h"
|
||||
#include "thread.h"
|
||||
#include "sched.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define MAILBOX_USED 1
|
||||
#define MAILBOX_EMPTY 0
|
||||
|
||||
#define MAILBOX_TO_INTR(mailbox) (INT_RX0 + (mailbox))
|
||||
|
||||
#ifndef CANDEV_MCP2515_DEFAULT_BITRATE
|
||||
#define CANDEV_MCP2515_DEFAULT_BITRATE 500000
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_MCP2515_DEFAULT_SPT
|
||||
#define CANDEV_MCP2515_DEFAULT_SPT 875
|
||||
#endif
|
||||
|
||||
static int _init(candev_t *candev);
|
||||
static int _send(candev_t *candev, const struct can_frame *frame);
|
||||
static void _isr(candev_t *candev);
|
||||
static int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len);
|
||||
static int _get(candev_t *candev, canopt_t opt, void *value, size_t max_len);
|
||||
static int _abort(candev_t *candev, const struct can_frame *frame);
|
||||
static int _set_filter(candev_t *dev, const struct can_filter * filter);
|
||||
static int _remove_filter(candev_t *dev, const struct can_filter * filter);
|
||||
|
||||
static void _irq_rx(candev_mcp2515_t *dev, int handle);
|
||||
static void _irq_tx(candev_mcp2515_t *dev, int handle);
|
||||
static void _irq_error(candev_mcp2515_t *dev);
|
||||
static void _irq_message_error(candev_mcp2515_t *dev);
|
||||
static void _irq_wakeup(const candev_mcp2515_t *dev);
|
||||
static void _send_event(const candev_mcp2515_t *dev, candev_event_t event, void *arg);
|
||||
|
||||
static const candev_driver_t candev_mcp2515_driver = {
|
||||
.send = _send,
|
||||
.init = _init,
|
||||
.isr = _isr,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
.abort = _abort,
|
||||
.set_filter = _set_filter,
|
||||
.remove_filter = _remove_filter,
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const bittiming_const = {
|
||||
.tseg1_min = 3,
|
||||
.tseg1_max = 16,
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 1,
|
||||
.brp_max = 64,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
static inline int _max_filters(int mailbox)
|
||||
{
|
||||
return mailbox == 0 ? MCP2515_FILTERS_MB0 : MCP2515_FILTERS_MB1;
|
||||
}
|
||||
|
||||
void candev_mcp2515_init(candev_mcp2515_t *dev, const candev_mcp2515_conf_t *conf)
|
||||
{
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->candev.driver = &candev_mcp2515_driver;
|
||||
|
||||
struct can_bittiming timing = { .bitrate = CANDEV_MCP2515_DEFAULT_BITRATE,
|
||||
.sample_point = CANDEV_MCP2515_DEFAULT_SPT };
|
||||
can_device_calc_bittiming(conf->clk / 2, &bittiming_const, &timing);
|
||||
|
||||
memcpy(&dev->candev.bittiming, &timing, sizeof(timing));
|
||||
/* configure filters to be closed */
|
||||
for (int mailbox = 0; mailbox < MCP2515_RX_MAILBOXES; mailbox++) {
|
||||
dev->masks[mailbox] = 0;
|
||||
for (int filter_id = 0; filter_id < MCP2515_FILTERS_MB1; filter_id++) {
|
||||
dev->filter_ids[mailbox][filter_id] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev->conf = conf;
|
||||
}
|
||||
|
||||
static void _mcp2515_irq_handler(void *arg)
|
||||
{
|
||||
candev_mcp2515_t *candev = (candev_mcp2515_t *) arg;
|
||||
_send_event(candev, CANDEV_EVENT_ISR, NULL);
|
||||
}
|
||||
|
||||
static int _init(candev_t *candev)
|
||||
{
|
||||
int res = 0;
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
|
||||
memset(dev->tx_mailbox, 0, sizeof(dev->tx_mailbox));
|
||||
|
||||
mcp2515_init(dev, _mcp2515_irq_handler);
|
||||
mcp2515_reset(dev);
|
||||
mcp2515_set_mode(dev, MODE_CONFIG);
|
||||
mcp2515_configure_bittiming(dev);
|
||||
mcp2515_init_irqs(dev);
|
||||
|
||||
/* configure filters to be closed */
|
||||
for (int mailbox = 0; mailbox < MCP2515_RX_MAILBOXES; mailbox++) {
|
||||
mcp2515_set_mask(dev, mailbox, dev->masks[mailbox]);
|
||||
for (int filter = 0; filter < _max_filters(mailbox); filter++) {
|
||||
mcp2515_set_filter(dev, mailbox * MCP2515_FILTERS_MB0 + filter,
|
||||
dev->filter_ids[mailbox][filter]);
|
||||
}
|
||||
}
|
||||
res = mcp2515_set_mode(dev, MODE_NORMAL);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _send(candev_t *candev, const struct can_frame *frame)
|
||||
{
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
int box;
|
||||
enum mcp2515_mode mode;
|
||||
|
||||
mode = mcp2515_get_mode(dev);
|
||||
if (mode != MODE_NORMAL && mode != MODE_LOOPBACK) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DEBUG("Inside mcp2515 send\n");
|
||||
|
||||
for (box = 0; box < MCP2515_TX_MAILBOXES; box++) {
|
||||
if (dev->tx_mailbox[box] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (box == MCP2515_TX_MAILBOXES) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev->tx_mailbox[box] = frame;
|
||||
|
||||
mcp2515_send(dev, frame, box);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
static int _abort(candev_t *candev, const struct can_frame *frame)
|
||||
{
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
int box;
|
||||
|
||||
DEBUG("Inside mcp2515 abort\n");
|
||||
|
||||
for (box = 0; box < MCP2515_TX_MAILBOXES; box++) {
|
||||
if (dev->tx_mailbox[box] == frame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (box == MCP2515_TX_MAILBOXES) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mcp2515_abort(dev, box);
|
||||
dev->tx_mailbox[box] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _isr(candev_t *candev)
|
||||
{
|
||||
uint8_t flag;
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
|
||||
while((flag = mcp2515_get_irq(dev))) {
|
||||
if (flag & INT_WAKEUP) {
|
||||
if (dev->wakeup_src == MCP2515_WKUP_SRC_INTERNAL) {
|
||||
dev->wakeup_src = 0;
|
||||
}
|
||||
else {
|
||||
_irq_wakeup(dev);
|
||||
}
|
||||
}
|
||||
if (flag & INT_ERROR) {
|
||||
_irq_error(dev);
|
||||
}
|
||||
if (flag & INT_RX0) {
|
||||
_irq_rx(dev, 0);
|
||||
}
|
||||
if (flag & INT_RX1) {
|
||||
_irq_rx(dev, 1);
|
||||
}
|
||||
if (flag & INT_TX0) {
|
||||
_irq_tx(dev, 0);
|
||||
}
|
||||
if (flag & INT_TX1) {
|
||||
_irq_tx(dev, 1);
|
||||
}
|
||||
if (flag & INT_TX2) {
|
||||
_irq_tx(dev, 2);
|
||||
}
|
||||
if (flag & INT_MESSAGE_ERROR) {
|
||||
_irq_message_error(dev);
|
||||
}
|
||||
|
||||
/* clear all flags except for RX flags, which are cleared by receiving */
|
||||
mcp2515_clear_irq(dev, flag & ~INT_RX0 & ~INT_RX1);
|
||||
}
|
||||
}
|
||||
|
||||
static int _set(candev_t *candev, canopt_t opt, void *value, size_t value_len)
|
||||
{
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
int res = 0;
|
||||
|
||||
DEBUG("Inside mcp2515 set opt=%d\n", opt);
|
||||
switch (opt) {
|
||||
case CANOPT_BITTIMING: /**< bit timing parameter */
|
||||
if (value_len < sizeof(candev->bittiming)) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
memcpy(&candev->bittiming, value, sizeof(candev->bittiming));
|
||||
res = _init(candev);
|
||||
if (res == 0) {
|
||||
res = sizeof(candev->bittiming);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case CANOPT_STATE:
|
||||
if (value_len < sizeof(uint8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
switch (*((canopt_state_t *)value)) {
|
||||
case CANOPT_STATE_LISTEN_ONLY:
|
||||
res = mcp2515_set_mode(dev, MODE_LISTEN_ONLY);
|
||||
break;
|
||||
case CANOPT_STATE_OFF:
|
||||
case CANOPT_STATE_SLEEP:
|
||||
res = mcp2515_set_mode(dev, MODE_SLEEP);
|
||||
break;
|
||||
case CANOPT_STATE_ON:
|
||||
res = mcp2515_set_mode(dev, MODE_NORMAL);
|
||||
break;
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _get(candev_t *candev, canopt_t opt, void *value, size_t max_len)
|
||||
{
|
||||
candev_mcp2515_t *dev = (candev_mcp2515_t *)candev;
|
||||
int res = 0;
|
||||
|
||||
DEBUG("Inside mcp2515 get opt=%d\n", opt);
|
||||
switch (opt) {
|
||||
case CANOPT_BITTIMING:
|
||||
if (max_len < sizeof(candev->bittiming)) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
memcpy(value, &candev->bittiming, sizeof(candev->bittiming));
|
||||
res = sizeof(candev->bittiming);
|
||||
}
|
||||
break;
|
||||
case CANOPT_RX_FILTERS: /**< rx filters */
|
||||
if (max_len % sizeof(struct can_filter) != 0) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
res = 1;
|
||||
}
|
||||
break;
|
||||
case CANOPT_BITTIMING_CONST:
|
||||
if (max_len < sizeof(bittiming_const)) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
memcpy(value, &bittiming_const, sizeof(bittiming_const));
|
||||
res = sizeof(bittiming_const);
|
||||
}
|
||||
break;
|
||||
case CANOPT_CLOCK:
|
||||
if (max_len < sizeof(uint32_t)) {
|
||||
res = -EOVERFLOW;
|
||||
}
|
||||
else {
|
||||
*((uint32_t *)value) = (uint32_t)(dev->conf->clk / 2);
|
||||
res = sizeof(uint32_t);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _set_filter(candev_t *dev, const struct can_filter *filter)
|
||||
{
|
||||
DEBUG("inside _set_filter of MCP2515\n");
|
||||
int filter_added = -1;
|
||||
struct can_filter f = *filter;
|
||||
int res = -1;
|
||||
enum mcp2515_mode mode;
|
||||
|
||||
candev_mcp2515_t *dev_mcp = (candev_mcp2515_t *) dev;
|
||||
|
||||
if (f.can_mask == 0) {
|
||||
return -EINVAL; /* invalid mask */
|
||||
}
|
||||
|
||||
mode = mcp2515_get_mode(dev_mcp);
|
||||
res = mcp2515_set_mode(dev_mcp, MODE_CONFIG);
|
||||
if (res != MODE_CONFIG) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((f.can_id & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
||||
f.can_mask &= CAN_EFF_MASK;
|
||||
}
|
||||
else {
|
||||
f.can_mask &= CAN_SFF_MASK;
|
||||
}
|
||||
|
||||
/* Browse on each mailbox to find an empty space */
|
||||
int mailbox_index = 0;
|
||||
while (mailbox_index < MCP2515_RX_MAILBOXES && filter_added == -1) {
|
||||
/* mask unused */
|
||||
if (dev_mcp->masks[mailbox_index] == 0) {
|
||||
/* set mask */
|
||||
mcp2515_set_mask(dev_mcp, mailbox_index, f.can_mask);
|
||||
/* set filter */
|
||||
mcp2515_set_filter(dev_mcp, MCP2515_FILTERS_MB0 * mailbox_index, f.can_id);
|
||||
|
||||
/* save filter */
|
||||
dev_mcp->masks[mailbox_index] = f.can_mask;
|
||||
dev_mcp->filter_ids[mailbox_index][0] = f.can_id;
|
||||
|
||||
/* function succeeded */
|
||||
filter_added = 1;
|
||||
}
|
||||
|
||||
/* mask existed and same mask */
|
||||
else if (dev_mcp->masks[mailbox_index] == f.can_mask) {
|
||||
/* find en empty space if it exist */
|
||||
int filter_pos = 1; /* first one is already filled */
|
||||
/* stop at the end of mailbox or an empty space found */
|
||||
while (filter_pos < _max_filters(mailbox_index) &&
|
||||
dev_mcp->filter_ids[mailbox_index][filter_pos] != 0) {
|
||||
filter_pos++;
|
||||
}
|
||||
|
||||
/* an empty space is found */
|
||||
if (filter_pos < _max_filters(mailbox_index)) {
|
||||
/* set filter on this memory space */
|
||||
mcp2515_set_filter(dev_mcp, MCP2515_FILTERS_MB0 * mailbox_index + filter_pos, f.can_id);
|
||||
|
||||
/* save filter */
|
||||
dev_mcp->filter_ids[mailbox_index][filter_pos] = f.can_id;
|
||||
|
||||
/* function succeeded */
|
||||
filter_added = 1;
|
||||
}
|
||||
}
|
||||
mailbox_index++;
|
||||
}
|
||||
|
||||
mcp2515_set_mode(dev_mcp, mode);
|
||||
|
||||
return filter_added;
|
||||
}
|
||||
|
||||
static int _remove_filter(candev_t *dev, const struct can_filter *filter)
|
||||
{
|
||||
DEBUG("inside _remove_filter of MCP2515\n");
|
||||
int filter_removed = -1;
|
||||
struct can_filter f = *filter;
|
||||
int res = 0;
|
||||
enum mcp2515_mode mode;
|
||||
|
||||
candev_mcp2515_t *dev_mcp = (candev_mcp2515_t *) dev;
|
||||
|
||||
if (f.can_mask == 0) {
|
||||
return -1; /* invalid mask */
|
||||
}
|
||||
|
||||
mode = mcp2515_get_mode(dev_mcp);
|
||||
res = mcp2515_set_mode(dev_mcp, MODE_CONFIG);
|
||||
if(res < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((f.can_id & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
||||
f.can_mask &= CAN_EFF_MASK;
|
||||
}
|
||||
else {
|
||||
f.can_mask &= CAN_SFF_MASK;
|
||||
}
|
||||
|
||||
int mailbox_index = 0;
|
||||
/* Browse on each mailbox to find the right filter id */
|
||||
while (mailbox_index < MCP2515_RX_MAILBOXES && filter_removed == -1) {
|
||||
/* same mask */
|
||||
if (dev_mcp->masks[mailbox_index] == f.can_mask) {
|
||||
int filter_pos = 0;
|
||||
/* stop at the end of mailbox or filter_id found */
|
||||
while (filter_pos < _max_filters(mailbox_index) &&
|
||||
dev_mcp->filter_ids[mailbox_index][filter_pos] != f.can_id) {
|
||||
filter_pos++;
|
||||
}
|
||||
|
||||
/* filter id found */
|
||||
if (filter_pos < _max_filters(mailbox_index)) {
|
||||
/* remove filter */
|
||||
mcp2515_set_filter(dev_mcp, MCP2515_FILTERS_MB0 * mailbox_index + filter_pos, CAN_EFF_MASK);
|
||||
/* save modification */
|
||||
dev_mcp->filter_ids[mailbox_index][filter_pos] = 0;
|
||||
|
||||
/* check mailbox empty */
|
||||
int nb_item = 0;
|
||||
for (int i = 0; i < _max_filters(mailbox_index); i++) {
|
||||
if (dev_mcp->filter_ids[mailbox_index][i] == 0) {
|
||||
nb_item++;
|
||||
}
|
||||
}
|
||||
|
||||
/* mailbox empty */
|
||||
if (nb_item == _max_filters(mailbox_index)) {
|
||||
/* remove mask */
|
||||
mcp2515_set_mask(dev_mcp, mailbox_index, CAN_EFF_MASK);
|
||||
/* save modification */
|
||||
dev_mcp->masks[mailbox_index] = 0;
|
||||
}
|
||||
|
||||
filter_removed = 0;
|
||||
}
|
||||
}
|
||||
mailbox_index++;
|
||||
}
|
||||
mcp2515_set_mode(dev_mcp, mode);
|
||||
|
||||
return filter_removed;
|
||||
}
|
||||
|
||||
static void _irq_rx(candev_mcp2515_t *dev, int box)
|
||||
{
|
||||
DEBUG("Inside mcp2515 rx irq, box=%d\n", box);
|
||||
|
||||
mcp2515_receive(dev, &dev->rx_buf[box], box);
|
||||
|
||||
_send_event(dev, CANDEV_EVENT_RX_INDICATION, &dev->rx_buf[box]);
|
||||
}
|
||||
|
||||
static void _irq_tx(candev_mcp2515_t *dev, int box)
|
||||
{
|
||||
DEBUG("Inside mcp2515 tx irq\n");
|
||||
const struct can_frame *frame = dev->tx_mailbox[box];
|
||||
dev->tx_mailbox[box] = NULL;
|
||||
|
||||
_send_event(dev, CANDEV_EVENT_TX_CONFIRMATION, (void *)frame);
|
||||
}
|
||||
|
||||
static void _irq_error(candev_mcp2515_t *dev)
|
||||
{
|
||||
uint8_t err;
|
||||
DEBUG("Inside mcp2515 error irq\n");
|
||||
|
||||
err = mcp2515_get_errors(dev);
|
||||
|
||||
if(err & (ERR_WARNING | ERR_RX_WARNING | ERR_TX_WARNING)) {
|
||||
DEBUG("Error Warning\n");
|
||||
_send_event(dev, CANDEV_EVENT_ERROR_WARNING, NULL);
|
||||
}
|
||||
else if(err & (ERR_RX_PASSIVE | ERR_TX_PASSIVE)) {
|
||||
DEBUG("Error Passive\n");
|
||||
_send_event(dev, CANDEV_EVENT_ERROR_PASSIVE, NULL);
|
||||
}
|
||||
else if(err & ERR_TX_BUS_OFF) {
|
||||
DEBUG("Buss Off\n");
|
||||
_send_event(dev, CANDEV_EVENT_BUS_OFF, NULL);
|
||||
}
|
||||
else if(err & (ERR_RX_0_OVERFLOW | ERR_RX_1_OVERFLOW)) {
|
||||
DEBUG("RX overflow\n");
|
||||
_send_event(dev, CANDEV_EVENT_RX_ERROR, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void _irq_message_error(candev_mcp2515_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
#if(0)
|
||||
int box;
|
||||
|
||||
DEBUG("Inside mcp2515 message error irq\n");
|
||||
|
||||
for (box = 0; box < MCP2515_TX_MAILBOXES; box++) {
|
||||
if (mcp2515_tx_err_occurred(dev, box)) {
|
||||
DEBUG("Box: %d\n", box);
|
||||
|
||||
mutex_lock(&dev->tx_mutex);
|
||||
mcp2515_abort(dev, box);
|
||||
xtimer_remove(&dev->tx_mailbox[box].timer);
|
||||
mutex_unlock(&dev->tx_mutex);
|
||||
|
||||
_send_event(dev, CANDEV_EVENT_TIMEOUT_TX_CONF, (void *) dev->tx_mailbox[box].pkt);
|
||||
|
||||
mutex_lock(&dev->tx_mutex);
|
||||
dev->tx_mailbox[box].pkt = NULL;
|
||||
mutex_unlock(&dev->tx_mutex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _irq_wakeup(const candev_mcp2515_t *dev)
|
||||
{
|
||||
DEBUG("Inside mcp2515 wakeup irq\n");
|
||||
|
||||
_send_event(dev, CANDEV_EVENT_WAKE_UP, NULL);
|
||||
}
|
||||
|
||||
static void _send_event(const candev_mcp2515_t *dev, candev_event_t event, void *arg)
|
||||
{
|
||||
candev_t *candev = (candev_t *) dev;
|
||||
|
||||
if (candev->event_callback) {
|
||||
candev->event_callback(candev, event, arg);
|
||||
}
|
||||
}
|
66
drivers/mcp2515/include/mcp2515_params.h
Normal file
66
drivers/mcp2515/include/mcp2515_params.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef MCP2515_PARAMS_H
|
||||
#define MCP2515_PARAMS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "can/device.h"
|
||||
#include "candev_mcp2515.h"
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#ifndef MCP2515_PARAM_SPI
|
||||
#define MCP2515_PARAM_SPI SPI_DEV(0)
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_SPI_MODE
|
||||
#define MCP2515_PARAM_SPI_MODE SPI_MODE_0
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_SPI_CLK
|
||||
#define MCP2515_PARAM_SPI_CLK SPI_CLK_10MHZ
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_CS
|
||||
#define MCP2515_PARAM_CS SPI_HWCS(0)
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_RST
|
||||
#define MCP2515_PARAM_RST GPIO_PIN(0, 0)
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_INT
|
||||
#define MCP2515_PARAM_INT GPIO_PIN(0, 1)
|
||||
#endif
|
||||
|
||||
#ifndef MCP2515_PARAM_CLK
|
||||
#define MCP2515_PARAM_CLK (8000000ul)
|
||||
#endif
|
||||
|
||||
#define MCP2515_DEFAULT_CONFIG \
|
||||
{ \
|
||||
.spi = MCP2515_PARAM_SPI, \
|
||||
.spi_mode = MCP2515_PARAM_SPI_MODE, \
|
||||
.spi_clk =MCP2515_PARAM_SPI_CLK, \
|
||||
.cs_pin = MCP2515_PARAM_CS, \
|
||||
.rst_pin = MCP2515_PARAM_RST, \
|
||||
.int_pin = MCP2515_PARAM_INT, \
|
||||
.clk = MCP2515_PARAM_CLK, \
|
||||
}
|
||||
|
||||
const static candev_mcp2515_conf_t candev_mcp2515_conf[] = {
|
||||
MCP2515_DEFAULT_CONFIG
|
||||
};
|
||||
|
||||
const static candev_params_t candev_mcp2515_params[] = {
|
||||
{
|
||||
.name = "can_cmp2515_0",
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MCP2515_PARAMS_H */
|
364
drivers/mcp2515/mcp2515.c
Normal file
364
drivers/mcp2515/mcp2515.c
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief mcp2515 can spi driver
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "xtimer.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "mcp2515.h"
|
||||
#include "mcp2515_spi.h"
|
||||
#include "mcp2515_defines.h"
|
||||
|
||||
#include "can/candev.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* reset delay should be at least 2 microseconds */
|
||||
#define RESET_DELAY 2
|
||||
|
||||
/* size of transmission and reception buffers in mcp2515 */
|
||||
#define BUFFER_SIZE 13
|
||||
|
||||
/* macros for getting the TX and RX control registers */
|
||||
#define TX_CTRL(mailbox) ((MCP2515_TXB0CTRL) + ((mailbox) << 4))
|
||||
#define RX_CTRL(mailbox) ((MCP2515_RXB0CTRL) + ((mailbox) << 4))
|
||||
|
||||
/* oscillator startup time
|
||||
* 128 cycles @ clock freq + some extra */
|
||||
static inline uint32_t ost_delay(candev_mcp2515_t *dev)
|
||||
{
|
||||
return (128 / (dev->conf->clk / 1000000) + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief enable MCP2515 interrupt @p irq
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] irq interrupt to enable
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
static int mcp2515_enable_irq(candev_mcp2515_t *dev, uint8_t irq);
|
||||
|
||||
/**
|
||||
* @brief Fill tx/rx standard buffer instruction from filter identifier @p id
|
||||
*
|
||||
* The Read RX Buffer instruction provides a means to quickly address a receive
|
||||
* buffer for reading. This instruction reduces the SPI overhead by one byte,
|
||||
* the address byte. The command byte actually has four possible values that
|
||||
* determine the address pointer location.
|
||||
*
|
||||
* The Load TX Buffer instruction eliminates the eight-bit address required by
|
||||
* a normal write command. The eight-bit instruction sets the address pointer
|
||||
* to one of six addresses to quickly write to a transmit buffer that points to
|
||||
* the “ID” or “data” address of any of the three transmit buffers.
|
||||
*
|
||||
* @param[in] id filter identifier in the MCP2515 mailbox
|
||||
* @param|out] bytebuf buffer instruction
|
||||
*/
|
||||
static void fill_standard_id(uint32_t id, uint8_t *bytebuf);
|
||||
|
||||
/**
|
||||
* @brief Fill tx/rx extended buffer instruction from filter identifier @p id
|
||||
*
|
||||
* for more details see fill_standard_id.
|
||||
*
|
||||
* @param[in] id filter identifier in the MCP2515 mailbox
|
||||
* @param|out] bytebuf buffer instruction
|
||||
*/
|
||||
static void fill_extended_id(uint32_t id, uint8_t *bytebuf);
|
||||
|
||||
int mcp2515_init(candev_mcp2515_t *dev, void(*irq_handler_cb)(void*))
|
||||
{
|
||||
int res;
|
||||
gpio_init_int(dev->conf->int_pin, GPIO_IN_PU, GPIO_FALLING, (gpio_cb_t)irq_handler_cb, (void *)dev);
|
||||
gpio_init(dev->conf->rst_pin, GPIO_OUT);
|
||||
/*the CS pin should be initialized & set in board.c to avoid conflict with other SPI devices */
|
||||
|
||||
res = mcp2515_spi_init(dev);
|
||||
if (res < 0){
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mcp2515_reset(candev_mcp2515_t *dev)
|
||||
{
|
||||
gpio_clear(dev->conf->rst_pin);
|
||||
xtimer_usleep(RESET_DELAY);
|
||||
gpio_set(dev->conf->rst_pin);
|
||||
xtimer_usleep(ost_delay(dev));
|
||||
}
|
||||
|
||||
static void fill_standard_id(uint32_t id, uint8_t *bytebuf)
|
||||
{
|
||||
bytebuf[0] = (uint8_t) ((id & 0x000007F8UL) >> 3); /* T/RXBnSIDH */
|
||||
bytebuf[1] = (uint8_t) ((id & 0x00000007UL) << 5); /* T/RXBnSIDL */
|
||||
bytebuf[2] = (uint8_t) ((id & 0xFF000000UL) >> 24); /* T/RXBnEID8 */
|
||||
bytebuf[3] = (uint8_t) ((id & 0x00FF0000UL) >> 16); /* T/RXBnEID0 */
|
||||
}
|
||||
|
||||
static void fill_extended_id(uint32_t id, uint8_t *bytebuf)
|
||||
{
|
||||
bytebuf[0] = (uint8_t) ((id & 0x1FE00000UL) >> 21); /* T/RXBnSIDH */
|
||||
bytebuf[1] = (uint8_t) ((id & 0x001C0000UL) >> 12)
|
||||
| (uint8_t) ((id & 0x00030000UL) >> 16) | 0x08; /* T/RXBnSIDL */
|
||||
bytebuf[2] = (uint8_t) ((id & 0x0000FF00UL) >> 8); /* T/RXBnEID8 */
|
||||
bytebuf[3] = (uint8_t) (id & 0x000000FFUL); /* T/RXBnEID0 */
|
||||
}
|
||||
|
||||
int mcp2515_send(candev_mcp2515_t *dev, const struct can_frame *frame, int mailbox)
|
||||
{
|
||||
uint8_t prio = 1; /* TODO: adjust priority */
|
||||
uint8_t outbuf[BUFFER_SIZE];
|
||||
uint8_t ctrl;
|
||||
|
||||
//TODO: for speedup, remove this check
|
||||
mcp2515_spi_read(dev, TX_CTRL(mailbox), &ctrl, 1);
|
||||
if (ctrl & MCP2515_TXBCTRL_TXREQ) {
|
||||
DEBUG("Mailbox in use, TXB%dCTRL: 0x%02x\n", mailbox, ctrl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((frame->can_id & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
||||
fill_extended_id(frame->can_id, outbuf);
|
||||
}
|
||||
else {
|
||||
fill_standard_id(frame->can_id, outbuf);
|
||||
}
|
||||
|
||||
outbuf[4] = frame->can_dlc;
|
||||
memcpy(outbuf+5, frame->data, frame->can_dlc);
|
||||
|
||||
/* set mailbox priority */
|
||||
mcp2515_spi_write(dev, TX_CTRL(mailbox), &prio, 1);
|
||||
|
||||
mcp2515_spi_write_txbuf(dev, mailbox, outbuf, 5 + frame->can_dlc);
|
||||
mcp2515_enable_irq(dev, MCP2515_CANINTE_TX0IE << mailbox);
|
||||
//mcp2515_spi_bitmod(dev, TX_CTRL(mailbox), MCP2515_TXBCTRL_TXREQ, MCP2515_TXBCTRL_TXREQ);
|
||||
mcp2515_spi_rts(dev, mailbox);
|
||||
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
int mcp2515_receive(candev_mcp2515_t *dev, struct can_frame *frame, int mailbox)
|
||||
{
|
||||
uint8_t inbuf[BUFFER_SIZE];
|
||||
|
||||
mcp2515_spi_read_rxbuf(dev, mailbox, inbuf, BUFFER_SIZE);
|
||||
|
||||
/* extended id */
|
||||
if (inbuf[1] & MCP2515_RX_IDE) {
|
||||
frame->can_id = (inbuf[0] << 21) +
|
||||
(((uint32_t)inbuf[1] & 0xE0) << 13) +
|
||||
(((uint32_t)inbuf[1] & 0x03) << 16) +
|
||||
((uint32_t)inbuf[2] << 8) +
|
||||
inbuf[3];
|
||||
frame->can_id |= CAN_EFF_FLAG;
|
||||
}
|
||||
|
||||
/* standard id */
|
||||
else {
|
||||
frame->can_id = ((uint32_t)inbuf[0] << 3) + (((uint32_t)inbuf[1] & 0xE0) >> 5);
|
||||
}
|
||||
|
||||
frame->can_dlc = inbuf[4];
|
||||
memcpy(frame->data, inbuf + 5, frame->can_dlc);
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
int mcp2515_abort(candev_mcp2515_t *dev, int mailbox)
|
||||
{
|
||||
return mcp2515_spi_bitmod(dev, TX_CTRL(mailbox), MCP2515_TXBCTRL_TXREQ, 0);
|
||||
}
|
||||
|
||||
enum mcp2515_mode mcp2515_get_mode(candev_mcp2515_t *dev)
|
||||
{
|
||||
enum mcp2515_mode result = MODE_UNKNOWN;
|
||||
uint8_t mode;
|
||||
|
||||
int res = mcp2515_spi_read(dev, MCP2515_CANSTAT, &mode, 1);
|
||||
if (res == 0) {
|
||||
//TODO: error handling of extra information in mode result
|
||||
result = (enum mcp2515_mode) mode & MCP2515_CANSTAT_OPMOD_MASK;
|
||||
}
|
||||
|
||||
DEBUG("mcp2515_get_mode: mode=%x\n", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum mcp2515_mode mcp2515_set_mode(candev_mcp2515_t *dev, enum mcp2515_mode mode)
|
||||
{
|
||||
DEBUG("mcp2515_set_mode: mode=%x\n", mode);
|
||||
|
||||
if (mode == MODE_UNKNOWN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum mcp2515_mode cur_mode = mcp2515_get_mode(dev);
|
||||
if (cur_mode == mode) {
|
||||
return mode;
|
||||
}
|
||||
if (cur_mode == MODE_SLEEP) {
|
||||
mcp2515_wake_up(dev);
|
||||
}
|
||||
|
||||
mcp2515_spi_bitmod(dev, MCP2515_CANCTRL, MCP2515_CANCTRL_REQOP_MASK, (uint8_t) mode);
|
||||
int cnt = 0;
|
||||
while (cur_mode != mode && cnt++ < 2) {
|
||||
cur_mode = mcp2515_get_mode(dev);
|
||||
}
|
||||
return cur_mode;
|
||||
}
|
||||
|
||||
void mcp2515_wake_up(candev_mcp2515_t *dev)
|
||||
{
|
||||
dev->wakeup_src = MCP2515_WKUP_SRC_INTERNAL;
|
||||
mcp2515_spi_bitmod(dev, MCP2515_CANINTF, MCP2515_CANINTF_WAKIF, MCP2515_CANINTF_WAKIF);
|
||||
xtimer_usleep(ost_delay(dev));
|
||||
|
||||
uint8_t flag = mcp2515_get_irq(dev);
|
||||
if (flag & INT_WAKEUP) {
|
||||
DEBUG("wakeup, irq raised\n");
|
||||
dev->wakeup_src = 0;
|
||||
mcp2515_clear_irq(dev, INT_WAKEUP);
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp2515_enable_irq(candev_mcp2515_t *dev, uint8_t irq)
|
||||
{
|
||||
return mcp2515_spi_bitmod(dev, MCP2515_CANINTE, irq, irq);
|
||||
}
|
||||
|
||||
int mcp2515_configure_bittiming(candev_mcp2515_t *dev)
|
||||
{
|
||||
struct can_bittiming *tim = &(dev->candev.bittiming);
|
||||
int res = 0;
|
||||
uint8_t c;
|
||||
enum mcp2515_mode mode;
|
||||
|
||||
DEBUG("mcp2515_configure_bittiming: brp=%" PRIu32 ", prop_seg=%" PRIu32
|
||||
", phase_seg1=%" PRIu32 ", phase_seg2=%" PRIu32 "\n", tim->brp, tim->prop_seg,
|
||||
tim->phase_seg1, tim->phase_seg2);
|
||||
|
||||
mode = mcp2515_get_mode(dev);
|
||||
if (mode != MODE_CONFIG) {
|
||||
if (mcp2515_set_mode(dev, MODE_CONFIG) != MODE_CONFIG) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
c = ((tim->brp - 1) & 0x3F) | ((tim->sjw - 1) << 6);
|
||||
mcp2515_spi_write(dev, MCP2515_CNF1, &c, 1);
|
||||
|
||||
|
||||
mcp2515_spi_bitmod(dev, MCP2515_CNF2, MCP2515_CNF2_PRSEG_MASK |
|
||||
MCP2515_CNF2_PHSEG_MASK | MCP2515_CNF2_BTLMODE,
|
||||
MCP2515_CNF2_BTLMODE | (tim->prop_seg - 1) | ((tim->phase_seg1 - 1) << 3));
|
||||
mcp2515_spi_bitmod(dev, MCP2515_CNF3, MCP2515_CNF3_PHSEG_MASK | MCP2515_CNF3_WAKFIL,
|
||||
(tim->phase_seg2 - 1) | MCP2515_CNF3_WAKFIL);
|
||||
|
||||
if (mode != MODE_CONFIG) {
|
||||
mcp2515_set_mode(dev, mode);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int mcp2515_init_irqs(candev_mcp2515_t *dev)
|
||||
{
|
||||
return mcp2515_enable_irq(dev,
|
||||
MCP2515_CANINTE_RX0IE |
|
||||
MCP2515_CANINTE_RX1IE |
|
||||
//MCP2515_CANINTE_TX0IE |
|
||||
//MCP2515_CANINTE_TX1IE |
|
||||
//MCP2515_CANINTE_TX2IE |
|
||||
MCP2515_CANINTE_ERRIE |
|
||||
//MCP2515_CANINTE_MERRE |
|
||||
MCP2515_CANINTE_WAKIE);
|
||||
}
|
||||
|
||||
enum mcp2515_interrupt mcp2515_get_irq(candev_mcp2515_t *dev)
|
||||
{
|
||||
uint8_t flag;
|
||||
mcp2515_spi_read(dev, MCP2515_CANINTF, &flag, 1);
|
||||
return (enum mcp2515_interrupt) flag;
|
||||
}
|
||||
|
||||
int mcp2515_clear_irq(candev_mcp2515_t *dev, enum mcp2515_interrupt irq)
|
||||
{
|
||||
if(!irq) { /* no irq's to be cleared */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return mcp2515_spi_bitmod(dev, MCP2515_CANINTF, irq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int mcp2515_tx_err_occurred(candev_mcp2515_t *dev, int mailbox)
|
||||
{
|
||||
uint8_t ctrl_reg;
|
||||
mcp2515_spi_read(dev, TX_CTRL(mailbox), &ctrl_reg, 1);
|
||||
if (ctrl_reg & MCP2515_TXBCTRL_TXERR) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t mcp2515_get_errors(candev_mcp2515_t *dev)
|
||||
{
|
||||
uint8_t eflg;
|
||||
mcp2515_spi_read(dev, MCP2515_EFLG, &eflg, 1);
|
||||
return eflg;
|
||||
}
|
||||
|
||||
int mcp2515_set_filter(candev_mcp2515_t *dev, int filter_id, uint32_t filter)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
uint8_t reg;
|
||||
if ((filter & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
||||
fill_extended_id(filter, buf);
|
||||
}
|
||||
else {
|
||||
fill_standard_id(filter, buf);
|
||||
}
|
||||
if(filter_id < 3) {
|
||||
reg = MCP2515_RXF0SIDH + (filter_id << 2);
|
||||
}
|
||||
else {
|
||||
reg = MCP2515_RXF3SIDH + ((filter_id - 3) << 2);
|
||||
}
|
||||
return mcp2515_spi_write(dev, reg, buf, 4);
|
||||
}
|
||||
|
||||
int mcp2515_set_mask(candev_mcp2515_t *dev, int mailbox, uint32_t mask)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if ((mask & CAN_EFF_FLAG) == CAN_EFF_FLAG) {
|
||||
fill_extended_id(mask, buf);
|
||||
}
|
||||
else {
|
||||
fill_standard_id(mask, buf);
|
||||
}
|
||||
return mcp2515_spi_write(dev, MCP2515_RXM0SIDH + (mailbox << 2), buf, 4);
|
||||
}
|
291
drivers/mcp2515/mcp2515.h
Normal file
291
drivers/mcp2515/mcp2515.h
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515
|
||||
* @brief Driver for the Microchip MCP2515 can controller.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definition of the MCP2515 CAN controller driver.
|
||||
*
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
*/
|
||||
#ifndef MCP2515_H
|
||||
#define MCP2515_H
|
||||
|
||||
#include "mcp2515_defines.h"
|
||||
#include "candev_mcp2515.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MCP2515 mode
|
||||
*/
|
||||
enum mcp2515_mode {
|
||||
MODE_NORMAL = MCP2515_CANSTAT_OPMOD_NORMAL,
|
||||
MODE_SLEEP = MCP2515_CANSTAT_OPMOD_SLEEP,
|
||||
MODE_LOOPBACK = MCP2515_CANSTAT_OPMOD_LOOPBACK,
|
||||
MODE_LISTEN_ONLY = MCP2515_CANSTAT_OPMOD_LISTEN_ONLY,
|
||||
MODE_CONFIG = MCP2515_CANSTAT_OPMOD_CONFIGURATION,
|
||||
MODE_UNKNOWN = -1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief MCP2515 interrupt
|
||||
*/
|
||||
enum mcp2515_interrupt {
|
||||
INT_RX0 = MCP2515_CANINTF_RX0IF,
|
||||
INT_RX1 = MCP2515_CANINTF_RX1IF,
|
||||
INT_TX0 = MCP2515_CANINTF_TX0IF,
|
||||
INT_TX1 = MCP2515_CANINTF_TX1IF,
|
||||
INT_TX2 = MCP2515_CANINTF_TX2IF,
|
||||
INT_ERROR = MCP2515_CANINTF_ERRIF,
|
||||
INT_WAKEUP = MCP2515_CANINTF_WAKIF,
|
||||
INT_MESSAGE_ERROR = MCP2515_CANINTF_MERRF,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief MCP2515 error
|
||||
*/
|
||||
enum mcp2515_error {
|
||||
ERR_WARNING = MCP2515_EFLG_EWARN,
|
||||
ERR_RX_WARNING = MCP2515_EFLG_RXWAR,
|
||||
ERR_TX_WARNING = MCP2515_EFLG_TXWAR,
|
||||
ERR_RX_PASSIVE = MCP2515_EFLG_RXEP,
|
||||
ERR_TX_PASSIVE = MCP2515_EFLG_TXEP,
|
||||
ERR_TX_BUS_OFF = MCP2515_EFLG_TXBO,
|
||||
ERR_RX_0_OVERFLOW = MCP2515_EFLG_RX0OVR,
|
||||
ERR_RX_1_OVERFLOW = MCP2515_EFLG_RX1OVR,
|
||||
};
|
||||
|
||||
/** Wake up source */
|
||||
#define MCP2515_WKUP_SRC_INTERNAL 1
|
||||
|
||||
/**
|
||||
* @brief Initialize pins and SPI interface
|
||||
*
|
||||
* The device descriptor contains all informations related to pins and SPI
|
||||
* interface. This function initialize all corresponding fields and relies
|
||||
* the @p irq_cb callback function to the pin interruption. The pin
|
||||
* interruption should be configured in the device descriptor.
|
||||
*
|
||||
* @param[out] dev device descriptor
|
||||
* @param[in] irq_cb callback function called when an interrupt is raised
|
||||
* from the MCP2515. The MCP2515 makes the interruption
|
||||
* through the interruption pin.
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_init(candev_mcp2515_t *dev, void(*irq_cb)(void*));
|
||||
|
||||
/**
|
||||
* @brief Reset MCP2515 device with dedicated pin
|
||||
*
|
||||
* The MCP2515 device is reset by toggling the rst pin.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*/
|
||||
void mcp2515_reset(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initialize MCP2515 interrupts
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_init_irqs(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Send frame through the corresponding tx @p mailbox.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] frame the frame to send
|
||||
* @param[in] mailbox tx mailbox
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_send(candev_mcp2515_t *dev, const struct can_frame *frame, int mailbox);
|
||||
|
||||
/**
|
||||
* @brief Receive frame from the corresponding rx @p mailbox.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[out] frame the receive frame
|
||||
* @param[in] mailbox rx mailbox
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_receive(candev_mcp2515_t *dev, struct can_frame *frame, int mailbox);
|
||||
|
||||
/**
|
||||
* @brief Abort communication.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox mailbox
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_abort(candev_mcp2515_t *dev, int mailbox);
|
||||
|
||||
/**
|
||||
* @brief Get MCP2515 mode of operation.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return mcp2515_mode enum
|
||||
*/
|
||||
enum mcp2515_mode mcp2515_get_mode(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set MCP2515 mode of operation.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mode mode of operation to set
|
||||
*
|
||||
* @return The mode actually set
|
||||
*/
|
||||
enum mcp2515_mode mcp2515_set_mode(candev_mcp2515_t *dev, enum mcp2515_mode mode);
|
||||
|
||||
/**
|
||||
* @brief Wake up MCP2515
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*/
|
||||
void mcp2515_wake_up(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Get MCP2515 interrupt type.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return mcp2515_interrupt enum
|
||||
*/
|
||||
enum mcp2515_interrupt mcp2515_get_irq(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Clear MCP2515 interrupt.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] irq interrupt to clear
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_clear_irq(candev_mcp2515_t *dev, enum mcp2515_interrupt irq);
|
||||
|
||||
/**
|
||||
* @brief Get if an tx error occurred on MCP2515.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox tx mailbox
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_tx_err_occurred(candev_mcp2515_t *dev, int mailbox);
|
||||
|
||||
/**
|
||||
* @brief Configure the bit timing of the MCP2515.
|
||||
*
|
||||
* The informations about the bit timing should be contained in dev descriptor.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_configure_bittiming(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Get the error flags.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return EFLG error flags
|
||||
*/
|
||||
uint8_t mcp2515_get_errors(candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the @ filter_id to the position in the mailbox.
|
||||
*
|
||||
* @p filter_id corresponds to the position in the MCP2515 mailbox as follow:
|
||||
* - [0; 1]: mailbox RXB0
|
||||
* - [2; 5]: mailbox RXB1
|
||||
*
|
||||
* The MCP2515 managed 6 acceptance filters in 2 rx mailboxes:
|
||||
* - MB0 contains 2 acceptance filters in relation with 1 acceptance mask
|
||||
* - MB1 contains 4 acceptance filters in relation with 1 acceptance mask
|
||||
*
|
||||
* MB0 MB1
|
||||
* +------+ +------+
|
||||
* mask 0 | RXM0 | | RXM1 | mask 1
|
||||
* +======+ +======+
|
||||
* filter 0 | RXF0 | | RXF2 | filter 2
|
||||
* +------+ +------+
|
||||
* filter 1 | RXF1 | | RXF3 | filter 3
|
||||
* +------+ +------+
|
||||
* | RXF4 | filter 4
|
||||
* +------+
|
||||
* | RXF5 | filter 5
|
||||
* +------+
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] filter_id filter identifier in the MCP2515 mailbox
|
||||
* @param[in] filter acceptance filter can identifier
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_set_filter(candev_mcp2515_t *dev, int filter_id, uint32_t filter);
|
||||
|
||||
/**
|
||||
* @brief Set the @ mask to the mailbox.
|
||||
*
|
||||
* The MCP2515 managed 6 acceptance filters in 2 rx mailboxes:
|
||||
* - MB0 contains 2 acceptance filters in relation with 1 acceptance mask
|
||||
* - MB1 contains 4 acceptance filters in relation with 1 acceptance mask
|
||||
*
|
||||
* MB0 MB1
|
||||
* +------+ +------+
|
||||
* mask 0 | RXM0 | | RXM1 | mask 1
|
||||
* +======+ +======+
|
||||
* filter 0 | RXF0 | | RXF2 | filter 2
|
||||
* +------+ +------+
|
||||
* filter 1 | RXF1 | | RXF3 | filter 3
|
||||
* +------+ +------+
|
||||
* | RXF4 | filter 4
|
||||
* +------+
|
||||
* | RXF5 | filter 5
|
||||
* +------+
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox rx mailbox
|
||||
* @param[in] mask acceptance mask
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_set_mask(candev_mcp2515_t *dev, int mailbox, uint32_t mask);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MCP2515_H */
|
||||
/** @} */
|
419
drivers/mcp2515/mcp2515_defines.h
Normal file
419
drivers/mcp2515/mcp2515_defines.h
Normal file
@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515
|
||||
* @brief Driver for the Microchip MCP2515 can controller.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Defines for the MCP2515 can controller driver.
|
||||
*
|
||||
* MCP2515 SPI CAN Controller Register & Configuration Constant
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
*/
|
||||
#ifndef MCP2515_DEFINES_H
|
||||
#define MCP2515_DEFINES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* User configuration
|
||||
* @{
|
||||
*/
|
||||
#define CAN_SPI_CS_PORTBIT BIT4
|
||||
#define CAN_SPI_CS_PORTOUT P2OUT
|
||||
#define CAN_SPI_CS_PORTDIR P2DIR
|
||||
|
||||
#define CAN_IRQ_PORTBIT BIT3
|
||||
#define CAN_IRQ_PORTOUT P1OUT
|
||||
#define CAN_IRQ_PORTDIR P1DIR
|
||||
#define CAN_IRQ_PORTREN P1REN
|
||||
#define CAN_IRQ_PORTIES P1IES
|
||||
#define CAN_IRQ_PORTIE P1IE
|
||||
#define CAN_IRQ_PORTIFG P1IFG
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* BoosterPack contains 8MHz crystal w/ 22pF load caps
|
||||
*/
|
||||
#define CAN_OSC_FREQUENCY 8000000
|
||||
|
||||
/**
|
||||
* @name MCP2515 Register Memory Map
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_RXF0SIDH 0x00
|
||||
#define MCP2515_RXF0SIDL 0x01
|
||||
#define MCP2515_RXF0EID8 0x02
|
||||
#define MCP2515_RXF0EID0 0x03
|
||||
|
||||
#define MCP2515_RXF1SIDH 0x04
|
||||
#define MCP2515_RXF1SIDL 0x05
|
||||
#define MCP2515_RXF1EID8 0x06
|
||||
#define MCP2515_RXF1EID0 0x07
|
||||
|
||||
#define MCP2515_RXF2SIDH 0x08
|
||||
#define MCP2515_RXF2SIDL 0x09
|
||||
#define MCP2515_RXF2EID8 0x0A
|
||||
#define MCP2515_RXF2EID0 0x0B
|
||||
|
||||
#define MCP2515_BFPCTRL 0x0C
|
||||
#define MCP2515_TXRTSCTRL 0x0D
|
||||
#define MCP2515_CANSTAT 0x0E
|
||||
#define MCP2515_CANCTRL 0x0F
|
||||
|
||||
#define MCP2515_RXF3SIDH 0x10
|
||||
#define MCP2515_RXF3SIDL 0x11
|
||||
#define MCP2515_RXF3EID8 0x12
|
||||
#define MCP2515_RXF3EID0 0x13
|
||||
|
||||
#define MCP2515_RXF4SIDH 0x14
|
||||
#define MCP2515_RXF4SIDL 0x15
|
||||
#define MCP2515_RXF4EID8 0x16
|
||||
#define MCP2515_RXF4EID0 0x17
|
||||
|
||||
#define MCP2515_RXF5SIDH 0x18
|
||||
#define MCP2515_RXF5SIDL 0x19
|
||||
#define MCP2515_RXF5EID8 0x1A
|
||||
#define MCP2515_RXF5EID0 0x1B
|
||||
|
||||
#define MCP2515_TEC 0x1C
|
||||
#define MCP2515_REC 0x1D
|
||||
|
||||
#define MCP2515_RXM0SIDH 0x20
|
||||
#define MCP2515_RXM0SIDL 0x21
|
||||
#define MCP2515_RXM0EID8 0x22
|
||||
#define MCP2515_RXM0EID0 0x23
|
||||
|
||||
#define MCP2515_RXM1SIDH 0x24
|
||||
#define MCP2515_RXM1SIDL 0x25
|
||||
#define MCP2515_RXM1EID8 0x26
|
||||
#define MCP2515_RXM1EID0 0x27
|
||||
|
||||
#define MCP2515_CNF3 0x28
|
||||
#define MCP2515_CNF2 0x29
|
||||
#define MCP2515_CNF1 0x2A
|
||||
#define MCP2515_CANINTE 0x2B
|
||||
|
||||
#define MCP2515_CANINTF 0x2C
|
||||
#define MCP2515_EFLG 0x2D
|
||||
|
||||
#define MCP2515_TXB0CTRL 0x30
|
||||
#define MCP2515_TXB0SIDH 0x31
|
||||
#define MCP2515_TXB0SIDL 0x32
|
||||
#define MCP2515_TXB0EID8 0x33
|
||||
#define MCP2515_TXB0EID0 0x34
|
||||
#define MCP2515_TXB0DLC 0x35
|
||||
#define MCP2515_TXB0D0 0x36
|
||||
#define MCP2515_TXB0D1 0x37
|
||||
#define MCP2515_TXB0D2 0x38
|
||||
#define MCP2515_TXB0D3 0x39
|
||||
#define MCP2515_TXB0D4 0x3A
|
||||
#define MCP2515_TXB0D5 0x3B
|
||||
#define MCP2515_TXB0D6 0x3C
|
||||
#define MCP2515_TXB0D7 0x3D
|
||||
|
||||
#define MCP2515_TXB1CTRL 0x40
|
||||
#define MCP2515_TXB1SIDH 0x41
|
||||
#define MCP2515_TXB1SIDL 0x42
|
||||
#define MCP2515_TXB1EID8 0x43
|
||||
#define MCP2515_TXB1EID0 0x44
|
||||
#define MCP2515_TXB1DLC 0x45
|
||||
#define MCP2515_TXB1D0 0x46
|
||||
#define MCP2515_TXB1D1 0x47
|
||||
#define MCP2515_TXB1D2 0x48
|
||||
#define MCP2515_TXB1D3 0x49
|
||||
#define MCP2515_TXB1D4 0x4A
|
||||
#define MCP2515_TXB1D5 0x4B
|
||||
#define MCP2515_TXB1D6 0x4C
|
||||
#define MCP2515_TXB1D7 0x4D
|
||||
|
||||
#define MCP2515_TXB2CTRL 0x50
|
||||
#define MCP2515_TXB2SIDH 0x51
|
||||
#define MCP2515_TXB2SIDL 0x52
|
||||
#define MCP2515_TXB2EID8 0x53
|
||||
#define MCP2515_TXB2EID0 0x54
|
||||
#define MCP2515_TXB2DLC 0x55
|
||||
#define MCP2515_TXB2D0 0x56
|
||||
#define MCP2515_TXB2D1 0x57
|
||||
#define MCP2515_TXB2D2 0x58
|
||||
#define MCP2515_TXB2D3 0x59
|
||||
#define MCP2515_TXB2D4 0x5A
|
||||
#define MCP2515_TXB2D5 0x5B
|
||||
#define MCP2515_TXB2D6 0x5C
|
||||
#define MCP2515_TXB2D7 0x5D
|
||||
|
||||
#define MCP2515_RXB0CTRL 0x60
|
||||
#define MCP2515_RXB0SIDH 0x61
|
||||
#define MCP2515_RXB0SIDL 0x62
|
||||
#define MCP2515_RXB0EID8 0x63
|
||||
#define MCP2515_RXB0EID0 0x64
|
||||
#define MCP2515_RXB0DLC 0x65
|
||||
#define MCP2515_RXB0D0 0x66
|
||||
#define MCP2515_RXB0D1 0x67
|
||||
#define MCP2515_RXB0D2 0x68
|
||||
#define MCP2515_RXB0D3 0x69
|
||||
#define MCP2515_RXB0D4 0x6A
|
||||
#define MCP2515_RXB0D5 0x6B
|
||||
#define MCP2515_RXB0D6 0x6C
|
||||
#define MCP2515_RXB0D7 0x6D
|
||||
|
||||
#define MCP2515_RXB1CTRL 0x70
|
||||
#define MCP2515_RXB1SIDH 0x71
|
||||
#define MCP2515_RXB1SIDL 0x72
|
||||
#define MCP2515_RXB1EID8 0x73
|
||||
#define MCP2515_RXB1EID0 0x74
|
||||
#define MCP2515_RXB1DLC 0x75
|
||||
#define MCP2515_RXB1D0 0x76
|
||||
#define MCP2515_RXB1D1 0x77
|
||||
#define MCP2515_RXB1D2 0x78
|
||||
#define MCP2515_RXB1D3 0x79
|
||||
#define MCP2515_RXB1D4 0x7A
|
||||
#define MCP2515_RXB1D5 0x7B
|
||||
#define MCP2515_RXB1D6 0x7C
|
||||
#define MCP2515_RXB1D7 0x7D
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 Control Register bits
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_BFPCTRL_B0BFM 0x01
|
||||
#define MCP2515_BFPCTRL_B1BFM 0x02
|
||||
#define MCP2515_BFPCTRL_B0BFE 0x04
|
||||
#define MCP2515_BFPCTRL_B1BFE 0x08
|
||||
|
||||
#define MCP2515_BFPCTRL_B0BFS 0x10
|
||||
#define MCP2515_BFPCTRL_B1BFS 0x20
|
||||
|
||||
#define MCP2515_TXRTSCTRL_B0RTSM 0x01
|
||||
#define MCP2515_TXRTSCTRL_B1RTSM 0x02
|
||||
#define MCP2515_TXRTSCTRL_B2RTSM 0x04
|
||||
#define MCP2515_TXRTSCTRL_B0RTS 0x08
|
||||
#define MCP2515_TXRTSCTRL_B1RTS 0x10
|
||||
#define MCP2515_TXRTSCTRL_B2RTS 0x20
|
||||
|
||||
#define MCP2515_CANSTAT_ICOD0 0x02
|
||||
#define MCP2515_CANSTAT_ICOD1 0x04
|
||||
#define MCP2515_CANSTAT_ICOD2 0x08
|
||||
#define MCP2515_CANSTAT_OPMOD0 0x20
|
||||
#define MCP2515_CANSTAT_OPMOD1 0x40
|
||||
#define MCP2515_CANSTAT_OPMOD2 0x80
|
||||
|
||||
#define MCP2515_CANSTAT_ICOD_MASK 0x0E
|
||||
|
||||
#define MCP2515_CANSTAT_OPMOD_MASK 0xE0
|
||||
#define MCP2515_CANSTAT_OPMOD_CONFIGURATION MCP2515_CANSTAT_OPMOD2
|
||||
#define MCP2515_CANSTAT_OPMOD_NORMAL 0x00
|
||||
#define MCP2515_CANSTAT_OPMOD_SLEEP MCP2515_CANSTAT_OPMOD0
|
||||
#define MCP2515_CANSTAT_OPMOD_LOOPBACK MCP2515_CANSTAT_OPMOD1
|
||||
#define MCP2515_CANSTAT_OPMOD_LISTEN_ONLY (MCP2515_CANSTAT_OPMOD1 | MCP2515_CANSTAT_OPMOD0)
|
||||
|
||||
#define MCP2515_CANCTRL_CLKPRE0 0x01
|
||||
#define MCP2515_CANCTRL_CLKPRE1 0x02
|
||||
#define MCP2515_CANCTRL_CLKEN 0x04
|
||||
#define MCP2515_CANCTRL_OSM 0x08
|
||||
#define MCP2515_CANCTRL_ABAT 0x10
|
||||
#define MCP2515_CANCTRL_REQOP0 0x20
|
||||
#define MCP2515_CANCTRL_REQOP1 0x40
|
||||
#define MCP2515_CANCTRL_REQOP2 0x80
|
||||
|
||||
#define MCP2515_CANCTRL_CLKPRE_MASK (MCP2515_CANCTRL_CLKPRE1 | MCP2515_CANCTRL_CLKPRE0)
|
||||
|
||||
#define MCP2515_CANCTRL_REQOP_MASK 0xE0
|
||||
#define MCP2515_CANCTRL_REQOP_CONFIGURATION MCP2515_CANCTRL_REQOP2
|
||||
#define MCP2515_CANCTRL_REQOP_NORMAL 0x00
|
||||
#define MCP2515_CANCTRL_REQOP_SLEEP MCP2515_CANCTRL_REQOP0
|
||||
#define MCP2515_CANCTRL_REQOP_LOOPBACK MCP2515_CANCTRL_REQOP1
|
||||
#define MCP2515_CANCTRL_REQOP_LISTEN_ONLY (MCP2515_CANCTRL_REQOP1 | MCP2515_CANCTRL_REQOP0)
|
||||
|
||||
#define MCP2515_CNF3_PHSEG20 0x01
|
||||
#define MCP2515_CNF3_PHSEG21 0x02
|
||||
#define MCP2515_CNF3_PHSEG22 0x04
|
||||
#define MCP2515_CNF3_WAKFIL 0x40
|
||||
#define MCP2515_CNF3_SOF 0x80
|
||||
|
||||
#define MCP2515_CNF3_PHSEG_MASK 0x07
|
||||
|
||||
#define MCP2515_CNF2_PRSEG0 0x01
|
||||
#define MCP2515_CNF2_PRSEG1 0x02
|
||||
#define MCP2515_CNF2_PRSEG2 0x04
|
||||
#define MCP2515_CNF2_PHSEG10 0x08
|
||||
#define MCP2515_CNF2_PHSEG11 0x10
|
||||
#define MCP2515_CNF2_PHSEG12 0x20
|
||||
#define MCP2515_CNF2_SAM 0x40
|
||||
#define MCP2515_CNF2_BTLMODE 0x80
|
||||
|
||||
#define MCP2515_CNF2_PRSEG_MASK 0x07
|
||||
#define MCP2515_CNF2_PHSEG_MASK 0x38
|
||||
|
||||
#define MCP2515_CNF1_BRP0 0x01
|
||||
#define MCP2515_CNF1_BRP1 0x02
|
||||
#define MCP2515_CNF1_BRP2 0x04
|
||||
#define MCP2515_CNF1_BRP3 0x08
|
||||
#define MCP2515_CNF1_BRP4 0x10
|
||||
#define MCP2515_CNF1_BRP5 0x20
|
||||
#define MCP2515_CNF1_SJW0 0x40
|
||||
#define MCP2515_CNF1_SJW1 0x80
|
||||
|
||||
#define MCP2515_CNF1_BRP_MASK 0x3F
|
||||
#define MCP2515_CNF1_SJW_MASK 0xC0
|
||||
|
||||
#define MCP2515_CANINTE_RX0IE 0x01
|
||||
#define MCP2515_CANINTE_RX1IE 0x02
|
||||
#define MCP2515_CANINTE_TX0IE 0x04
|
||||
#define MCP2515_CANINTE_TX1IE 0x08
|
||||
#define MCP2515_CANINTE_TX2IE 0x10
|
||||
#define MCP2515_CANINTE_ERRIE 0x20
|
||||
#define MCP2515_CANINTE_WAKIE 0x40
|
||||
#define MCP2515_CANINTE_MERRE 0x80
|
||||
|
||||
#define MCP2515_CANINTF_RX0IF 0x01
|
||||
#define MCP2515_CANINTF_RX1IF 0x02
|
||||
#define MCP2515_CANINTF_TX0IF 0x04
|
||||
#define MCP2515_CANINTF_TX1IF 0x08
|
||||
#define MCP2515_CANINTF_TX2IF 0x10
|
||||
#define MCP2515_CANINTF_ERRIF 0x20
|
||||
#define MCP2515_CANINTF_WAKIF 0x40
|
||||
#define MCP2515_CANINTF_MERRF 0x80
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 error flags
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_EFLG_EWARN 0x01
|
||||
#define MCP2515_EFLG_RXWAR 0x02
|
||||
#define MCP2515_EFLG_TXWAR 0x04
|
||||
#define MCP2515_EFLG_RXEP 0x08
|
||||
#define MCP2515_EFLG_TXEP 0x10
|
||||
#define MCP2515_EFLG_TXBO 0x20
|
||||
#define MCP2515_EFLG_RX0OVR 0x40
|
||||
#define MCP2515_EFLG_RX1OVR 0x80
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 Transmit and receive flags
|
||||
* @{
|
||||
*/
|
||||
#define MCP2515_TXBCTRL_TXP0 0x01
|
||||
#define MCP2515_TXBCTRL_TXP1 0x02
|
||||
#define MCP2515_TXBCTRL_TXREQ 0x08
|
||||
#define MCP2515_TXBCTRL_TXERR 0x10
|
||||
#define MCP2515_TXBCTRL_MLOA 0x20
|
||||
#define MCP2515_TXBCTRL_ABTF 0x40
|
||||
|
||||
#define MCP2515_RXB0CTRL_FILHIT0 0x01
|
||||
#define MCP2515_RXB0CTRL_BUKT1 0x02
|
||||
#define MCP2515_RXB0CTRL_BUKT 0x04
|
||||
#define MCP2515_RXB0CTRL_RXRTR 0x08
|
||||
#define MCP2515_RXB0CTRL_RXM0 0x20
|
||||
#define MCP2515_RXB0CTRL_RXM1 0x40
|
||||
#define MCP2515_RXB0CTRL_MODE_RECV_STD_OR_EXT 0x00
|
||||
#define MCP2515_RXB0CTRL_MODE_RECV_STD MCP2515_RXB0CTRL_RXM0
|
||||
#define MCP2515_RXB0CTRL_MODE_RECV_EXT MCP2515_RXB0CTRL_RXM1
|
||||
#define MCP2515_RXB0CTRL_MODE_RECV_ALL (MCP2515_RXB0CTRL_RXM1 | MCP2515_RXB0CTRL_RXM0)
|
||||
|
||||
#define MCP2515_RXB1CTRL_FILHIT0 0x01
|
||||
#define MCP2515_RXB1CTRL_FILHIT1 0x02
|
||||
#define MCP2515_RXB1CTRL_FILHIT2 0x04
|
||||
#define MCP2515_RXB1CTRL_RXRTR 0x08
|
||||
#define MCP2515_RXB1CTRL_RXM0 0x20
|
||||
#define MCP2515_RXB1CTRL_RXM1 0x40
|
||||
#define MCP2515_RXB1CTRL_MODE_RECV_STD_OR_EXT 0x00
|
||||
#define MCP2515_RXB1CTRL_MODE_RECV_STD MCP2515_RXB1CTRL_RXM0
|
||||
#define MCP2515_RXB1CTRL_MODE_RECV_EXT MCP2515_RXB1CTRL_RXM1
|
||||
#define MCP2515_RXB1CTRL_MODE_RECV_ALL (MCP2515_RXB1CTRL_RXM1 | MCP2515_RXB1CTRL_RXM0)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 SPI commands
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_SPI_RESET 0xC0
|
||||
#define MCP2515_SPI_READ 0x03
|
||||
#define MCP2515_SPI_READ_RXBUF 0x90
|
||||
#define MCP2515_SPI_WRITE 0x02
|
||||
#define MCP2515_SPI_LOAD_TXBUF 0x40
|
||||
#define MCP2515_SPI_RTS 0x80
|
||||
#define MCP2515_SPI_READ_STATUS 0xA0
|
||||
#define MCP2515_SPI_RX_STATUS 0xB0
|
||||
#define MCP2515_SPI_BITMOD 0x05
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 RX buffer id
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_RXBUF_RXB0SIDH 0x00
|
||||
#define MCP2515_RXBUF_RXB0D0 0x02
|
||||
#define MCP2515_RXBUF_RXB1SIDH 0x04
|
||||
#define MCP2515_RXBUF_RXB1D0 0x06
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 TX buffer id
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_TXBUF_TXB0SIDH 0x00
|
||||
#define MCP2515_TXBUF_TXB0D0 0x01
|
||||
#define MCP2515_TXBUF_TXB1SIDH 0x02
|
||||
#define MCP2515_TXBUF_TXB1D0 0x03
|
||||
#define MCP2515_TXBUF_TXB2SIDH 0x04
|
||||
#define MCP2515_TXBUF_TXB2D0 0x05
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 option ID for ioctl function
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_OPTION_ROLLOVER 1
|
||||
#define MCP2515_OPTION_ONESHOT 2
|
||||
#define MCP2515_OPTION_ABORT 3
|
||||
#define MCP2515_OPTION_CLOCKOUT 4
|
||||
#define MCP2515_OPTION_LOOPBACK 5
|
||||
#define MCP2515_OPTION_LISTEN_ONLY 6
|
||||
#define MCP2515_OPTION_SLEEP 7
|
||||
#define MCP2515_OPTION_MULTISAMPLE 8
|
||||
#define MCP2515_OPTION_SOFOUT 9
|
||||
#define MCP2515_OPTION_WAKE_GLITCH_FILTER 10
|
||||
#define MCP2515_OPTION_WAKE 11
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 IRQ handling
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_IRQ_FLAGGED 0x80
|
||||
#define MCP2515_IRQ_HANDLED 0x40
|
||||
#define MCP2515_IRQ_RX 0x01
|
||||
#define MCP2515_IRQ_TX 0x02
|
||||
#define MCP2515_IRQ_ERROR 0x04
|
||||
#define MCP2515_IRQ_WAKEUP 0x08
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name MCP2515 Extended ID bit
|
||||
* {
|
||||
*/
|
||||
#define MCP2515_RX_IDE 0x08
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MCP2515_DEFINES_H */
|
||||
/** @} */
|
138
drivers/mcp2515/mcp2515_spi.c
Normal file
138
drivers/mcp2515/mcp2515_spi.c
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief MCP2515 can spi driver
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mcp2515_spi.h"
|
||||
#include "mcp2515_defines.h"
|
||||
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#include "xtimer.h"
|
||||
#include "irq.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
int mcp2515_spi_init(const candev_mcp2515_t *dev)
|
||||
{
|
||||
int res;
|
||||
/* Configure SPI */
|
||||
res = spi_init_cs(dev->conf->spi, dev->conf->cs_pin);
|
||||
if (res != SPI_OK) {
|
||||
DEBUG("spi_init_master: error initializing SPI_%i device (code %i)\n",
|
||||
dev->conf->spi, res);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_reset(const candev_mcp2515_t *dev)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, false, MCP2515_SPI_RESET);
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_read(const candev_mcp2515_t *dev, uint8_t addr, uint8_t *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_READ);
|
||||
spi_transfer_regs(dev->conf->spi, dev->conf->cs_pin, addr, NULL, (void *)buf, len);
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_read_rxbuf(const candev_mcp2515_t *dev, uint8_t mailbox,
|
||||
void *buf, uint8_t len)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_READ_RXBUF | (mailbox << 2));
|
||||
spi_transfer_bytes(dev->conf->spi, dev->conf->cs_pin, false, NULL, (void *)buf, len);
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_write(const candev_mcp2515_t *dev, uint8_t addr, uint8_t *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_WRITE);
|
||||
spi_transfer_regs(dev->conf->spi, dev->conf->cs_pin, addr, (void *)buf, NULL, len);
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_write_txbuf(const candev_mcp2515_t *dev, uint8_t mailbox,
|
||||
void *buf, uint8_t len)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_LOAD_TXBUF | (mailbox << 1));
|
||||
spi_transfer_bytes(dev->conf->spi, dev->conf->cs_pin, false, (void *)buf, NULL, len);
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcp2515_spi_rts(const candev_mcp2515_t *dev, uint8_t mailbox)
|
||||
{
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, false, MCP2515_SPI_RTS | (1 << mailbox));
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t mcp2515_spi_read_status(const candev_mcp2515_t *dev)
|
||||
{
|
||||
uint8_t status;
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_READ_STATUS);
|
||||
status = spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, false, 0);
|
||||
spi_release(dev->conf->spi);
|
||||
return status;
|
||||
}
|
||||
|
||||
int mcp2515_spi_rx_status(const candev_mcp2515_t *dev)
|
||||
{
|
||||
uint8_t status;
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_RX_STATUS);
|
||||
status = spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, false, 0);
|
||||
spi_release(dev->conf->spi);
|
||||
return status;
|
||||
}
|
||||
|
||||
int mcp2515_spi_bitmod(const candev_mcp2515_t *dev, uint8_t addr, uint8_t mask,
|
||||
uint8_t buf)
|
||||
{
|
||||
uint8_t msg[2];
|
||||
|
||||
spi_acquire(dev->conf->spi, dev->conf->cs_pin, dev->conf->spi_mode, dev->conf->spi_clk);
|
||||
spi_transfer_byte(dev->conf->spi, dev->conf->cs_pin, true, MCP2515_SPI_BITMOD);
|
||||
|
||||
msg[0] = mask;
|
||||
msg[1] = buf;
|
||||
|
||||
spi_transfer_regs(dev->conf->spi, dev->conf->cs_pin, addr, (const void*)msg, NULL, sizeof(msg));
|
||||
spi_release(dev->conf->spi);
|
||||
return 0;
|
||||
}
|
169
drivers/mcp2515/mcp2515_spi.h
Normal file
169
drivers/mcp2515/mcp2515_spi.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mcp2515
|
||||
* @brief Driver for the Microchip MCP2515 can controller.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definition of the MCP2515 SPI driver.
|
||||
*
|
||||
*
|
||||
* @author Toon Stegen <toon.stegen@altran.com>
|
||||
*/
|
||||
#ifndef MCP2515_SPI_H
|
||||
#define MCP2515_SPI_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "candev_mcp2515.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize SPI interface
|
||||
*
|
||||
* The device descriptor contains all informations related to the SPI interface.
|
||||
*
|
||||
* @param[out] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_init(const candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Reset MCP2515 device though SPI interface
|
||||
*
|
||||
* The MCP2515 device is reset by sending the right message over SPI interface.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_reset(const candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Read the register value corresponding to @p addr
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] addr register addr
|
||||
* @param[out] buf buffer to receive register value
|
||||
* @param[in] len length of register value
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_read(const candev_mcp2515_t *dev, uint8_t addr, uint8_t *buf,
|
||||
unsigned int len);
|
||||
|
||||
/**
|
||||
* @brief Read the can data received in the rx @p mailbox
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox rx mailbox
|
||||
* @param[out] buf buffer to receive can data
|
||||
* @param[in] len length of can data
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_read_rxbuf(const candev_mcp2515_t *dev, uint8_t mailbox,
|
||||
void *buf, uint8_t len);
|
||||
|
||||
/**
|
||||
* @brief Send the register value corresponding to @p addr
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] addr address to write
|
||||
* @param[in] buf buffer containing register data
|
||||
* @param[in] len buffer length
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_write(const candev_mcp2515_t *dev, uint8_t addr, uint8_t *buf,
|
||||
unsigned int len);
|
||||
|
||||
/**
|
||||
* @brief Send the can data to the tx @p mailbox
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox tx mailbox
|
||||
* @param[in] buf buffer containing can data
|
||||
* @param[in] len buffer length
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_write_txbuf(const candev_mcp2515_t *dev, uint8_t mailbox,
|
||||
void *buf, uint8_t len);
|
||||
|
||||
/**
|
||||
* @brief Initiate message transmission.
|
||||
*
|
||||
* The RTS command can be used to initiate message transmission for one or more
|
||||
* of the transmit buffers.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] mailbox mailbox to enable transmission
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_rts(const candev_mcp2515_t *dev, uint8_t mailbox);
|
||||
|
||||
/**
|
||||
* @brief Read MCP2515 status over SPI interface.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
uint8_t mcp2515_spi_read_status(const candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Read MCP2515 receive status over SPI interface.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_rx_status(const candev_mcp2515_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Bit modify instruction.
|
||||
*
|
||||
* The Bit Modify instruction provides a means for setting or clearing
|
||||
* individual bits in specific status and control registers.
|
||||
* This command is not available for all registers. Executing this command on
|
||||
* registers that are not bit-modifiable will force the mask to FFh.
|
||||
*
|
||||
* @param[in] dev device descriptor
|
||||
* @param[in] addr register address
|
||||
* @param[in] mask mask to modify individual bit
|
||||
* @param[in] buf regsiter value
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int mcp2515_spi_bitmod(const candev_mcp2515_t *dev, uint8_t addr, uint8_t mask,
|
||||
uint8_t buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MCP2515_SPI_H */
|
||||
/** @} */
|
57
sys/auto_init/can/auto_init_mcp2515.c
Normal file
57
sys/auto_init/can/auto_init_mcp2515.c
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2017 OTA keys S.A.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup auto_init
|
||||
* @{
|
||||
* @file
|
||||
* @brief initializes mcp2515 can device
|
||||
*
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef MODULE_MCP2515
|
||||
#include "can/device.h"
|
||||
#include "mcp2515_params.h"
|
||||
|
||||
#define CANDEV_MCP2515_NUMOF ((sizeof(candev_mcp2515_params) / sizeof(candev_params_t)))
|
||||
|
||||
#ifndef CANDEV_MCP2515_STACKSIZE
|
||||
#define CANDEV_MCP2515_STACKSIZE (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
|
||||
#endif
|
||||
|
||||
#ifndef CANDEV_MCP2515_BASE_PRIORITY
|
||||
#define CANDEV_MCP2515_BASE_PRIORITY (THREAD_PRIORITY_MAIN - CANDEV_MCP2515_NUMOF - 2)
|
||||
#endif
|
||||
|
||||
static candev_dev_t candev_dev_mcp2515[CANDEV_MCP2515_NUMOF];
|
||||
static char _can_mcp2515_stacks[CANDEV_MCP2515_NUMOF][CANDEV_MCP2515_STACKSIZE];
|
||||
static candev_mcp2515_t candev_mcp2515[CANDEV_MCP2515_NUMOF];
|
||||
|
||||
void auto_init_can_mcp2515(void) {
|
||||
|
||||
for (size_t i = 0; i < CANDEV_MCP2515_NUMOF; i++) {
|
||||
candev_mcp2515_init(&candev_mcp2515[i], &candev_mcp2515_conf[i]);
|
||||
candev_dev_mcp2515[i].dev = (candev_t *)&candev_mcp2515[i];
|
||||
candev_dev_mcp2515[i].name = candev_mcp2515_params[i].name;
|
||||
#ifdef MODULE_TRX
|
||||
candev_dev_mcp2515[i].trx = candev_mcp2515_params[i].trx;
|
||||
#endif
|
||||
#ifdef MODULE_CAN_PM
|
||||
candev_dev_mcp2515[i].rx_inactivity_timeout = candev_mcp2515_params[i].rx_inactivity_timeout;
|
||||
candev_dev_mcp2515[i].tx_wakeup_timeout = candev_mcp2515_params[i].tx_wakeup_timeout;
|
||||
#endif
|
||||
|
||||
can_device_init(_can_mcp2515_stacks[i], CANDEV_MCP2515_STACKSIZE, CANDEV_MCP2515_BASE_PRIORITY + i,
|
||||
candev_mcp2515_params[i].name, &candev_dev_mcp2515[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
typedef int dont_be_pedantic;
|
||||
#endif
|
@ -53,4 +53,9 @@ void auto_init_candev(void)
|
||||
extern void auto_init_periph_can(void);
|
||||
auto_init_periph_can();
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_MCP2515
|
||||
extern void auto_init_can_mcp2515(void);
|
||||
auto_init_can_mcp2515();
|
||||
#endif
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user