2020-08-20 12:08:00 -04:00
|
|
|
/*
|
|
|
|
* This file is part of the MicroPython project, http://micropython.org/
|
|
|
|
*
|
|
|
|
* The MIT License (MIT)
|
|
|
|
*
|
|
|
|
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "py/runtime.h"
|
|
|
|
#include "py/mperrno.h"
|
|
|
|
|
|
|
|
#include "peripheral_clk_config.h"
|
|
|
|
|
2020-09-21 17:42:12 -04:00
|
|
|
#include "common-hal/canio/CAN.h"
|
2020-08-20 12:08:00 -04:00
|
|
|
#include "shared-bindings/microcontroller/Pin.h"
|
|
|
|
#include "shared-bindings/util.h"
|
|
|
|
#include "supervisor/port.h"
|
|
|
|
|
|
|
|
#include "component/can.h"
|
|
|
|
|
|
|
|
#include "genhdr/candata.h"
|
|
|
|
|
|
|
|
STATIC Can * const can_insts[] = CAN_INSTS;
|
|
|
|
|
|
|
|
STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)];
|
|
|
|
|
|
|
|
// This must be placed in the first 64kB of RAM
|
|
|
|
STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)];
|
|
|
|
|
2020-09-21 16:51:55 -04:00
|
|
|
void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent)
|
2020-08-20 12:08:00 -04:00
|
|
|
{
|
|
|
|
mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx);
|
2020-09-21 16:51:55 -04:00
|
|
|
int instance = tx_function->instance;
|
2020-08-20 12:08:00 -04:00
|
|
|
|
|
|
|
mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx);
|
|
|
|
|
|
|
|
const uint32_t can_frequency = CONF_CAN0_FREQUENCY;
|
|
|
|
|
|
|
|
#define DIV_ROUND(a, b) (((a) + (b)/2) / (b))
|
|
|
|
#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b))
|
|
|
|
|
|
|
|
uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate);
|
|
|
|
uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8);
|
|
|
|
uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample;
|
|
|
|
uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128));
|
|
|
|
if (divisor > 32) {
|
|
|
|
mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen)
|
|
|
|
}
|
|
|
|
|
2020-09-21 16:51:55 -04:00
|
|
|
gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT);
|
|
|
|
gpio_set_pin_function(tx_function->pin, tx_function->function);
|
|
|
|
common_hal_never_reset_pin(tx_function->obj);
|
2020-08-20 12:08:00 -04:00
|
|
|
|
2020-09-21 16:51:55 -04:00
|
|
|
gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN);
|
|
|
|
gpio_set_pin_function(rx_function->pin, rx_function->function);
|
|
|
|
common_hal_never_reset_pin(rx_function->obj);
|
2020-08-20 12:08:00 -04:00
|
|
|
|
2020-09-18 15:19:05 -04:00
|
|
|
self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN;
|
2020-08-20 12:08:00 -04:00
|
|
|
self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN;
|
|
|
|
self->hw = can_insts[instance];
|
|
|
|
self->state = &can_state[instance];
|
|
|
|
|
|
|
|
self->loopback = loopback;
|
2020-09-18 15:19:05 -04:00
|
|
|
self->silent = silent;
|
2020-08-20 12:08:00 -04:00
|
|
|
|
|
|
|
// Allow configuration change
|
|
|
|
hri_can_set_CCCR_INIT_bit(self->hw);
|
|
|
|
while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) {
|
|
|
|
}
|
|
|
|
hri_can_set_CCCR_CCE_bit(self->hw);
|
|
|
|
|
2020-09-17 11:57:56 -04:00
|
|
|
if (instance == 0) {
|
2020-08-20 12:08:00 -04:00
|
|
|
hri_mclk_set_AHBMASK_CAN0_bit(MCLK);
|
|
|
|
hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos));
|
|
|
|
|
|
|
|
NVIC_DisableIRQ(CAN0_IRQn);
|
|
|
|
NVIC_ClearPendingIRQ(CAN0_IRQn);
|
|
|
|
NVIC_EnableIRQ(CAN0_IRQn);
|
|
|
|
hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0);
|
|
|
|
#ifdef CAN1_GCLK_ID
|
2020-09-17 11:57:56 -04:00
|
|
|
} else if (instance == 1) {
|
2020-08-20 12:08:00 -04:00
|
|
|
hri_mclk_set_AHBMASK_CAN1_bit(MCLK);
|
|
|
|
hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos));
|
|
|
|
|
|
|
|
NVIC_DisableIRQ(CAN1_IRQn);
|
|
|
|
NVIC_ClearPendingIRQ(CAN1_IRQn);
|
|
|
|
NVIC_EnableIRQ(CAN1_IRQn);
|
|
|
|
hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled
|
|
|
|
self->hw->CCCR.bit.BRSE = 0;
|
|
|
|
|
|
|
|
hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation)
|
|
|
|
|
|
|
|
// A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate
|
|
|
|
{
|
|
|
|
CAN_NBTP_Type btp = {
|
|
|
|
// 0 means "1 tq", but 2 is subtracted from NTSEG1 for the
|
|
|
|
// fixed 1 "SYNC" tq
|
|
|
|
.bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2,
|
|
|
|
.bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1,
|
|
|
|
.bit.NBRP = divisor - 1,
|
|
|
|
.bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4),
|
|
|
|
};
|
|
|
|
hri_can_write_NBTP_reg(self->hw, btp.reg);
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:19:05 -04:00
|
|
|
// A "data bit" is a data bit :) with dula rate CAN FD, this is a higher
|
|
|
|
// rate. However, CAN FD is not implemented in CircuitPython, and this is
|
|
|
|
// the same rate as the "nominal rate".
|
2020-08-20 12:08:00 -04:00
|
|
|
{
|
|
|
|
CAN_DBTP_Type btp = {
|
|
|
|
.bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1,
|
|
|
|
.bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1,
|
|
|
|
.bit.DBRP = divisor - 1,
|
|
|
|
.bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4),
|
|
|
|
};
|
|
|
|
hri_can_write_DBTP_reg(self->hw, btp.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_RXF0C_Type rxf = {
|
|
|
|
.bit.F0SA = (uint32_t)self->state->rx0_fifo,
|
|
|
|
.bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE,
|
|
|
|
};
|
|
|
|
hri_can_write_RXF0C_reg(self->hw, rxf.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_RXF1C_Type rxf = {
|
|
|
|
.bit.F1SA = (uint32_t)self->state->rx1_fifo,
|
|
|
|
.bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE,
|
|
|
|
};
|
|
|
|
hri_can_write_RXF1C_reg(self->hw, rxf.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// All RX data has an 8 byte payload (max)
|
|
|
|
{
|
|
|
|
CAN_RXESC_Type esc = {
|
|
|
|
.bit.F0DS = CAN_RXESC_F0DS_DATA8_Val,
|
|
|
|
.bit.F1DS = CAN_RXESC_F1DS_DATA8_Val,
|
|
|
|
.bit.RBDS = CAN_RXESC_RBDS_DATA8_Val,
|
|
|
|
};
|
|
|
|
hri_can_write_RXESC_reg(self->hw, esc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// All TX data has an 8 byte payload (max)
|
|
|
|
{
|
|
|
|
CAN_TXESC_Type esc = {
|
|
|
|
.bit.TBDS = CAN_TXESC_TBDS_DATA8_Val,
|
|
|
|
};
|
|
|
|
hri_can_write_TXESC_reg(self->hw, esc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_TXBC_Type bc = {
|
|
|
|
.bit.TBSA = (uint32_t)self->state->tx_fifo,
|
|
|
|
.bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE,
|
|
|
|
.bit.TFQM = 0, // Messages are transmitted in the order submitted
|
|
|
|
};
|
|
|
|
hri_can_write_TXBC_reg(self->hw, bc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_TXEFC_Type efc = {
|
|
|
|
.bit.EFS = 0,
|
|
|
|
};
|
|
|
|
hri_can_write_TXEFC_reg(self->hw, efc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_GFC_Type gfc = {
|
|
|
|
.bit.RRFE = 1,
|
2020-09-17 11:57:56 -04:00
|
|
|
.bit.ANFS = CAN_GFC_ANFS_REJECT_Val,
|
2020-08-20 12:08:00 -04:00
|
|
|
.bit.ANFE = CAN_GFC_ANFE_REJECT_Val,
|
|
|
|
};
|
|
|
|
hri_can_write_GFC_reg(self->hw, gfc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_SIDFC_Type dfc = {
|
|
|
|
.bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE,
|
2020-09-17 11:57:56 -04:00
|
|
|
.bit.FLSSA = (uint32_t)self->state->standard_rx_filter
|
2020-08-20 12:08:00 -04:00
|
|
|
};
|
|
|
|
hri_can_write_SIDFC_reg(self->hw, dfc.reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CAN_XIDFC_Type dfc = {
|
2020-09-17 11:57:56 -04:00
|
|
|
.bit.LSE = COMMON_HAL_CANIO_RX_FILTER_SIZE,
|
|
|
|
.bit.FLESA = (uint32_t)self->state->extended_rx_filter
|
2020-08-20 12:08:00 -04:00
|
|
|
};
|
|
|
|
hri_can_write_XIDFC_reg(self->hw, dfc.reg);
|
|
|
|
}
|
|
|
|
|
2020-09-16 12:59:01 -04:00
|
|
|
{
|
|
|
|
CAN_IE_Type ie = {
|
|
|
|
.bit.EWE = 1,
|
|
|
|
.bit.EPE = 1,
|
|
|
|
.bit.BOE = 1,
|
|
|
|
};
|
|
|
|
hri_can_write_IE_reg(self->hw, ie.reg);
|
|
|
|
}
|
|
|
|
|
2020-08-20 12:08:00 -04:00
|
|
|
hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE);
|
|
|
|
|
|
|
|
// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused)
|
|
|
|
// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused)
|
|
|
|
// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused)
|
|
|
|
self->hw->CCCR.bit.MON = silent;
|
|
|
|
self->hw->CCCR.bit.TEST = loopback;
|
|
|
|
self->hw->TEST.bit.LBCK = loopback;
|
|
|
|
|
2020-09-17 11:57:56 -04:00
|
|
|
if (instance == 0) {
|
2020-08-20 12:08:00 -04:00
|
|
|
NVIC_DisableIRQ(CAN0_IRQn);
|
|
|
|
NVIC_ClearPendingIRQ(CAN0_IRQn);
|
|
|
|
NVIC_EnableIRQ(CAN0_IRQn);
|
|
|
|
#ifdef CAN1_GCLK_ID
|
2020-09-17 11:57:56 -04:00
|
|
|
} else if (instance == 1) {
|
2020-08-20 12:08:00 -04:00
|
|
|
NVIC_DisableIRQ(CAN1_IRQn);
|
|
|
|
NVIC_ClearPendingIRQ(CAN1_IRQn);
|
|
|
|
NVIC_EnableIRQ(CAN1_IRQn);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0);
|
|
|
|
// Prevent configuration change
|
|
|
|
hri_can_clear_CCCR_CCE_bit(self->hw);
|
|
|
|
hri_can_clear_CCCR_INIT_bit(self->hw);
|
|
|
|
while (hri_can_get_CCCR_INIT_bit(self->hw)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
can_objs[instance] = self;
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:19:05 -04:00
|
|
|
bool common_hal_canio_can_loopback_get(canio_can_obj_t *self)
|
2020-08-20 12:08:00 -04:00
|
|
|
{
|
|
|
|
return self->loopback;
|
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self)
|
|
|
|
{
|
|
|
|
return self->baudrate;
|
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
return self->hw->ECR.bit.TEC;
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
return self->hw->ECR.bit.REC;
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
return self->error_warning_state_count;
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
return self->error_passive_state_count;
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
return self->bus_off_state_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) {
|
|
|
|
CAN_PSR_Type psr = self->hw->PSR;
|
2020-09-17 11:57:56 -04:00
|
|
|
if (psr.bit.BO) {
|
2020-09-16 12:59:01 -04:00
|
|
|
return BUS_STATE_OFF;
|
|
|
|
}
|
2020-09-17 11:57:56 -04:00
|
|
|
if (psr.bit.EP) {
|
2020-09-16 12:59:01 -04:00
|
|
|
return BUS_STATE_ERROR_PASSIVE;
|
|
|
|
}
|
2020-09-17 11:57:56 -04:00
|
|
|
if (psr.bit.EW) {
|
2020-09-16 12:59:01 -04:00
|
|
|
return BUS_STATE_ERROR_WARNING;
|
|
|
|
}
|
|
|
|
return BUS_STATE_ERROR_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_can_restart(canio_can_obj_t *self) {
|
|
|
|
if (!self->hw->PSR.bit.BO) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
hri_can_clear_CCCR_INIT_bit(self->hw);
|
|
|
|
while (hri_can_get_CCCR_INIT_bit(self->hw)) {
|
|
|
|
}
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
2020-09-16 12:59:01 -04:00
|
|
|
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) {
|
|
|
|
return self->auto_restart;
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) {
|
|
|
|
self->auto_restart = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void maybe_auto_restart(canio_can_obj_t *self) {
|
2020-09-17 11:57:56 -04:00
|
|
|
if (self->auto_restart) {
|
2020-09-16 12:59:01 -04:00
|
|
|
common_hal_canio_can_restart(self);
|
|
|
|
}
|
2020-08-20 12:08:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message)
|
|
|
|
{
|
2020-09-16 12:59:01 -04:00
|
|
|
maybe_auto_restart(self);
|
|
|
|
|
2020-08-20 12:08:00 -04:00
|
|
|
// We have just one dedicated TX buffer, use it!
|
|
|
|
canio_can_fifo_t *ent = &self->state->tx_fifo[0];
|
2020-09-17 12:35:34 -04:00
|
|
|
|
2020-08-20 12:08:00 -04:00
|
|
|
ent->txb0.bit.ESI = false;
|
2020-09-17 11:57:56 -04:00
|
|
|
ent->txb0.bit.XTD = message->extended;
|
2020-08-20 12:08:00 -04:00
|
|
|
ent->txb0.bit.RTR = message->rtr;
|
2020-09-17 11:57:56 -04:00
|
|
|
if (message->extended) {
|
|
|
|
ent->txb0.bit.ID = message->id << 18;
|
|
|
|
} else {
|
|
|
|
ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified
|
|
|
|
}
|
2020-08-20 12:08:00 -04:00
|
|
|
|
|
|
|
ent->txb1.bit.MM = 0; // "message marker"
|
|
|
|
ent->txb1.bit.EFC = 0; // don't store fifo events to event queue
|
|
|
|
ent->txb1.bit.FDF = 0; // Classic CAN format
|
|
|
|
ent->txb1.bit.BRS = 0; // No bit rate switching
|
|
|
|
ent->txb1.bit.DLC = message->size;
|
|
|
|
|
|
|
|
if (!message->rtr) {
|
|
|
|
memcpy(ent->data, message->data, message->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TX buffer add request
|
|
|
|
self->hw->TXBAR.reg = 1;
|
|
|
|
|
|
|
|
// wait 8ms (hard coded for now) for TX to occur
|
|
|
|
uint64_t deadline = port_get_raw_ticks(NULL) + 8;
|
|
|
|
while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) {
|
|
|
|
RUN_BACKGROUND_TASKS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:19:05 -04:00
|
|
|
bool common_hal_canio_can_silent_get(canio_can_obj_t *self) {
|
|
|
|
return self->silent;
|
|
|
|
}
|
|
|
|
|
2020-08-20 12:08:00 -04:00
|
|
|
bool common_hal_canio_can_deinited(canio_can_obj_t *self) {
|
|
|
|
return !self->hw;
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) {
|
2020-09-17 11:57:56 -04:00
|
|
|
if (common_hal_canio_can_deinited(self)) {
|
2020-08-20 12:08:00 -04:00
|
|
|
raise_deinited_error();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_can_deinit(canio_can_obj_t *self)
|
|
|
|
{
|
|
|
|
if (self->hw) {
|
|
|
|
hri_can_set_CCCR_INIT_bit(self->hw);
|
|
|
|
self->hw = 0;
|
|
|
|
}
|
|
|
|
if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) {
|
|
|
|
reset_pin_number(self->rx_pin_number);
|
|
|
|
self->rx_pin_number = COMMON_HAL_MCU_NO_PIN;
|
|
|
|
}
|
|
|
|
if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) {
|
|
|
|
reset_pin_number(self->tx_pin_number);
|
|
|
|
self->tx_pin_number = COMMON_HAL_MCU_NO_PIN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void common_hal_canio_reset(void) {
|
|
|
|
memset(can_state, 0, sizeof(can_state));
|
|
|
|
|
|
|
|
for (size_t i=0; i<MP_ARRAY_SIZE(can_insts); i++) {
|
|
|
|
hri_can_set_CCCR_INIT_bit(can_insts[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=0; i<MP_ARRAY_SIZE(can_objs); i++) {
|
|
|
|
if (can_objs[i]) {
|
|
|
|
common_hal_canio_can_deinit(can_objs[i]);
|
|
|
|
can_objs[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STATIC void can_handler(int i) {
|
|
|
|
canio_can_obj_t *self = can_objs[i];
|
|
|
|
(void) self;
|
|
|
|
|
|
|
|
Can *hw = can_insts[i];
|
|
|
|
uint32_t ir = hri_can_read_IR_reg(hw);
|
2020-09-16 12:59:01 -04:00
|
|
|
|
|
|
|
/* Count up errors*/
|
|
|
|
if (ir & CAN_IE_EWE) {
|
|
|
|
self->error_warning_state_count += 1;
|
|
|
|
}
|
|
|
|
if (ir & CAN_IE_EPE) {
|
|
|
|
self->error_passive_state_count += 1;
|
|
|
|
}
|
|
|
|
if (ir & CAN_IE_BOE) {
|
|
|
|
self->bus_off_state_count += 1;
|
|
|
|
}
|
2020-08-20 12:08:00 -04:00
|
|
|
|
|
|
|
/* Acknowledge interrupt */
|
|
|
|
hri_can_write_IR_reg(hw, ir);
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((used))
|
|
|
|
void CAN0_Handler(void) {
|
|
|
|
can_handler(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CAN1_GCLK_ID
|
|
|
|
__attribute__((used))
|
|
|
|
void CAN1_Handler(void) {
|
|
|
|
can_handler(1);
|
|
|
|
}
|
|
|
|
#endif
|