|
@ -10,12 +10,14 @@ struct canbus { |
|
|
|
|
|
|
|
|
uint32_t rcc; |
|
|
uint32_t rcc; |
|
|
|
|
|
|
|
|
int irq0; |
|
|
uint8_t irq; |
|
|
int irq1; |
|
|
|
|
|
|
|
|
uint8_t fifo; |
|
|
|
|
|
|
|
|
void (*setup)(struct canbus *); |
|
|
void (*setup)(struct canbus *); |
|
|
|
|
|
|
|
|
void *user; |
|
|
void *user; |
|
|
void (*callback)(struct canbus *, void *user); |
|
|
void (*callback)(struct canbus *, void *user, struct canrx_msg *msg); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
/* query APB1 clocks */ |
|
|
/* query APB1 clocks */ |
|
@ -122,27 +124,42 @@ int can_set_baudrate(struct canbus *can, unsigned int baudrate) |
|
|
can->conf = conf; |
|
|
can->conf = conf; |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void __canx_init(struct canbus *can) |
|
|
static void __canx_init(struct canbus *can, int baudrate) |
|
|
{ |
|
|
{ |
|
|
/* CAN register init */ |
|
|
/* CAN register init */ |
|
|
CAN_DeInit(can->base); |
|
|
CAN_DeInit(can->base); |
|
|
|
|
|
|
|
|
|
|
|
NVIC_DisableIRQ(can->irq); |
|
|
|
|
|
|
|
|
/* CAN cell init */ |
|
|
/* CAN cell init */ |
|
|
CAN_StructInit(&can->conf); |
|
|
CAN_StructInit(&can->conf); |
|
|
CAN_Init(can->base, &can->conf); |
|
|
CAN_Init(can->base, &can->conf); |
|
|
|
|
|
|
|
|
|
|
|
if (baudrate > 0) { |
|
|
|
|
|
can_set_baudrate(can, baudrate); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* CAN filter init */ |
|
|
/* CAN filter init */ |
|
|
#if 0 |
|
|
can->filter.CAN_FilterNumber = can->base == CAN1 ? 0 : 14; /* can0 use [0, 13], can1 use [14, 27] */ |
|
|
#ifdef USE_CAN1 |
|
|
can->filter.CAN_FilterMode = CAN_FilterMode_IdMask; |
|
|
can->filter.CAN_FilterNumber = 0; |
|
|
can->filter.CAN_FilterScale = CAN_FilterScale_32bit; |
|
|
#else /* USE_CAN2 */ |
|
|
can->filter.CAN_FilterIdHigh = 0x0000; |
|
|
can->filter.CAN_FilterNumber = 14; |
|
|
can->filter.CAN_FilterIdLow = 0x0000; |
|
|
#endif /* USE_CAN1 */ |
|
|
can->filter.CAN_FilterMaskIdHigh = 0x0000; |
|
|
#endif |
|
|
can->filter.CAN_FilterMaskIdLow = 0x0000; |
|
|
|
|
|
|
|
|
|
|
|
if (can->fifo == 0) { |
|
|
|
|
|
can->filter.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; /* fifo 0 */ |
|
|
|
|
|
} else { |
|
|
|
|
|
can->filter.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1; /* fifo 1 */ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
can->filter.CAN_FilterActivation = ENABLE; |
|
|
|
|
|
|
|
|
CAN_FilterInit(&can->filter); |
|
|
CAN_FilterInit(&can->filter); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -154,14 +171,16 @@ void can_setup(struct canbus *can, int baudrate) |
|
|
if (can->setup) |
|
|
if (can->setup) |
|
|
can->setup(can); |
|
|
can->setup(can); |
|
|
|
|
|
|
|
|
__canx_init(can); |
|
|
__canx_init(can, baudrate); |
|
|
|
|
|
|
|
|
if (baudrate > 0) { |
|
|
if (can->fifo == 0) { |
|
|
can_set_baudrate(can, baudrate); |
|
|
CAN_ITConfig(can->base, CAN_IT_FMP0, ENABLE); |
|
|
|
|
|
} else { |
|
|
|
|
|
CAN_ITConfig(can->base, CAN_IT_FMP1, ENABLE); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int do_send_std_data(struct canbus *can, int remote, unsigned char id, const void *data, unsigned char len) |
|
|
static int __do_send_data(struct canbus *can, int is_extend, int remote, unsigned char id, const void *data, unsigned char len) |
|
|
{ |
|
|
{ |
|
|
CanTxMsg tx; |
|
|
CanTxMsg tx; |
|
|
uint8_t tbox; |
|
|
uint8_t tbox; |
|
@ -173,9 +192,14 @@ static int do_send_std_data(struct canbus *can, int remote, unsigned char id, co |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* transmit */ |
|
|
/* transmit */ |
|
|
tx.StdId = id; |
|
|
if (is_extend) { |
|
|
|
|
|
tx.ExtId = id; |
|
|
|
|
|
tx.IDE = CAN_ID_EXT; |
|
|
|
|
|
} else { |
|
|
|
|
|
tx.StdId = id; |
|
|
|
|
|
tx.IDE = CAN_ID_STD; |
|
|
|
|
|
} |
|
|
tx.RTR = remote ? CAN_RTR_REMOTE : CAN_RTR_DATA; |
|
|
tx.RTR = remote ? CAN_RTR_REMOTE : CAN_RTR_DATA; |
|
|
tx.IDE = CAN_ID_STD; |
|
|
|
|
|
tx.DLC = len; |
|
|
tx.DLC = len; |
|
|
memcpy(tx.Data, data, len); |
|
|
memcpy(tx.Data, data, len); |
|
|
|
|
|
|
|
@ -192,29 +216,65 @@ static int do_send_std_data(struct canbus *can, int remote, unsigned char id, co |
|
|
#undef RETRY_MAX |
|
|
#undef RETRY_MAX |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int can_send_std_data(struct canbus *can, unsigned char id, const void *data, unsigned char len) |
|
|
int can_send_std_data(struct canbus *can, int is_extend, unsigned int id, const void *data, unsigned char len) |
|
|
{ |
|
|
{ |
|
|
return do_send_std_data(can, 0, id, data, len); |
|
|
return __do_send_data(can, is_extend, 0, id, data, len); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int can_send_std_remote(struct canbus *can, unsigned char id, const void *data, unsigned char len) |
|
|
int can_send_std_remote(struct canbus *can, int is_extend, unsigned int id, const void *data, unsigned char len) |
|
|
{ |
|
|
{ |
|
|
return do_send_std_data(can, 1, id, data, len); |
|
|
return __do_send_data(can, is_extend, 1, id, data, len); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void can_attach_rx(struct canbus *can, void *user, void (*rx)(struct canbus *can, void *user)) |
|
|
void can_attach_rx(struct canbus *can, void *user, void (*rx)(struct canbus *can, void *user, struct canrx_msg *msg)) |
|
|
{ |
|
|
{ |
|
|
|
|
|
NVIC_DisableIRQ(can->irq); |
|
|
can->user = user; |
|
|
can->user = user; |
|
|
can->callback = rx; |
|
|
can->callback = rx; |
|
|
|
|
|
NVIC_EnableIRQ(can->irq); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void can_close(struct canbus *can) |
|
|
void can_close(struct canbus *can) |
|
|
{ |
|
|
{ |
|
|
RCC_APB1PeriphClockCmd(can->rcc, DISABLE); |
|
|
RCC_APB1PeriphClockCmd(can->rcc, DISABLE); |
|
|
|
|
|
|
|
|
|
|
|
CAN_ITConfig(can->base, CAN_IT_FMP0, DISABLE); |
|
|
|
|
|
CAN_ITConfig(can->base, CAN_IT_FMP1, DISABLE); |
|
|
|
|
|
|
|
|
|
|
|
NVIC_DisableIRQ(can->irq); |
|
|
|
|
|
|
|
|
CAN_DeInit(can->base); |
|
|
CAN_DeInit(can->base); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void __do_rx_isr(struct canbus *can, int fifo) |
|
|
|
|
|
{ |
|
|
|
|
|
CanRxMsg msg; |
|
|
|
|
|
struct canrx_msg rx; |
|
|
|
|
|
|
|
|
|
|
|
while(CAN_MessagePending(can->base, fifo) > 0) { |
|
|
|
|
|
CAN_Receive(can->base, fifo, &msg); |
|
|
|
|
|
if (can->callback) { |
|
|
|
|
|
rx.is_std = msg.IDE == CAN_ID_STD; |
|
|
|
|
|
rx.is_data = msg.RTR == CAN_RTR_Data; |
|
|
|
|
|
rx.data = msg.Data; |
|
|
|
|
|
rx.len = msg.DLC; |
|
|
|
|
|
can->callback(can, can->user, &rx); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
#if (TARGET_HAS_CAN0) |
|
|
#if (TARGET_HAS_CAN0) |
|
|
|
|
|
|
|
|
|
|
|
void CAN1_RX0_IRQHandler() /* CAN1 RX0 */ |
|
|
|
|
|
{ |
|
|
|
|
|
__do_rx_isr(&can0, CAN_FIFO0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CAN1_RX1_IRQHandler() /* CAN1 RX1 */ |
|
|
|
|
|
{ |
|
|
|
|
|
__do_rx_isr(&can0, CAN_FIFO1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void __attribute__((weak)) target_can0_setup() |
|
|
void __attribute__((weak)) target_can0_setup() |
|
|
{ |
|
|
{ |
|
|
GPIO_InitTypeDef gpio_conf; |
|
|
GPIO_InitTypeDef gpio_conf; |
|
@ -236,55 +296,70 @@ void __attribute__((weak)) target_can0_setup() |
|
|
|
|
|
|
|
|
static void __can0_setup(struct canbus *can) |
|
|
static void __can0_setup(struct canbus *can) |
|
|
{ |
|
|
{ |
|
|
|
|
|
if (can->fifo == 0) { |
|
|
|
|
|
can->irq = CAN1_RX0_IRQn; |
|
|
|
|
|
} else { |
|
|
|
|
|
can->irq = CAN1_RX1_IRQn; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
target_can0_setup(); |
|
|
target_can0_setup(); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
struct canbus can0 = { |
|
|
struct canbus can0 = { |
|
|
.base = CAN1, |
|
|
.base = CAN1, |
|
|
.filter = { |
|
|
.fifo = TARGET_CAN0_FIFO, |
|
|
.CAN_FilterNumber = 0, |
|
|
.rcc = RCC_APB1Periph_CAN1, |
|
|
.CAN_FilterMode = CAN_FilterMode_IdMask, |
|
|
|
|
|
.CAN_FilterScale = CAN_FilterScale_32bit, |
|
|
|
|
|
.CAN_FilterIdHigh = 0x0000, |
|
|
|
|
|
.CAN_FilterIdLow = 0x0000, |
|
|
|
|
|
.CAN_FilterMaskIdHigh = 0x0000, |
|
|
|
|
|
.CAN_FilterMaskIdLow = 0x0000, |
|
|
|
|
|
.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0, |
|
|
|
|
|
.CAN_FilterActivation = ENABLE, |
|
|
|
|
|
}, |
|
|
|
|
|
.irq0 = CAN1_RX0_IRQn, |
|
|
|
|
|
.irq1 = CAN1_RX1_IRQn, |
|
|
|
|
|
.rcc = RCC_APB1Periph_CAN1, |
|
|
|
|
|
.setup = __can0_setup, |
|
|
.setup = __can0_setup, |
|
|
}; |
|
|
}; |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#if (TARGET_HAS_CAN1) |
|
|
#if (TARGET_HAS_CAN1) |
|
|
|
|
|
|
|
|
|
|
|
void CAN2_RX0_IRQHandler() /* CAN2 RX0 */ |
|
|
|
|
|
{ |
|
|
|
|
|
__do_rx_isr(&can1, CAN_FIFO0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CAN2_RX1_IRQHandler() /* CAN2 RX1 */ |
|
|
|
|
|
{ |
|
|
|
|
|
__do_rx_isr(&can1, CAN_FIFO1); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void __attribute__((weak)) target_can1_setup() |
|
|
void __attribute__((weak)) target_can1_setup() |
|
|
{ |
|
|
{ |
|
|
|
|
|
GPIO_InitTypeDef gpio_conf; |
|
|
|
|
|
|
|
|
|
|
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); |
|
|
|
|
|
|
|
|
|
|
|
GPIO_StructInit(&gpio_conf); |
|
|
|
|
|
|
|
|
|
|
|
gpio_conf.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13; /* PB 12(CAN2 RX) and PB 13 (CAN2 TX) */ |
|
|
|
|
|
gpio_conf.GPIO_Mode = GPIO_Mode_AF; |
|
|
|
|
|
gpio_conf.GPIO_Speed = GPIO_Speed_100MHz; |
|
|
|
|
|
gpio_conf.GPIO_OType = GPIO_OType_PP; |
|
|
|
|
|
gpio_conf.GPIO_PuPd = GPIO_PuPd_UP; |
|
|
|
|
|
GPIO_Init(GPIOB, &gpio_conf); |
|
|
|
|
|
|
|
|
|
|
|
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_CAN2); |
|
|
|
|
|
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_CAN2); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void __can1_setup(struct canbus *can) |
|
|
static void __can1_setup(struct canbus *can) |
|
|
{ |
|
|
{ |
|
|
|
|
|
if (can->fifo == 0) { |
|
|
|
|
|
can->irq = CAN2_RX0_IRQn; |
|
|
|
|
|
} else { |
|
|
|
|
|
can->irq = CAN2_RX1_IRQn; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
target_can1_setup(); |
|
|
target_can1_setup(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
struct canbus can1 = { |
|
|
struct canbus can1 = { |
|
|
.base = CAN2, |
|
|
.base = CAN2, |
|
|
.filter = { |
|
|
.fifo = TARGET_CAN1_FIFO, |
|
|
.CAN_FilterNumber = 14, |
|
|
.rcc = RCC_APB1Periph_CAN2, |
|
|
.CAN_FilterMode = CAN_FilterMode_IdMask, |
|
|
|
|
|
.CAN_FilterScale = CAN_FilterScale_32bit, |
|
|
|
|
|
.CAN_FilterIdHigh = 0x0000, |
|
|
|
|
|
.CAN_FilterIdLow = 0x0000, |
|
|
|
|
|
.CAN_FilterMaskIdHigh = 0x0000, |
|
|
|
|
|
.CAN_FilterMaskIdLow = 0x0000, |
|
|
|
|
|
.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0, /* fifo 0 or 1 */ |
|
|
|
|
|
.CAN_FilterActivation = ENABLE, |
|
|
|
|
|
}, |
|
|
|
|
|
.irq0 = CAN2_RX0_IRQn, |
|
|
|
|
|
.irq1 = CAN2_RX1_IRQn, |
|
|
|
|
|
.rcc = RCC_APB1Periph_CAN2, |
|
|
|
|
|
.setup = __can1_setup, |
|
|
.setup = __can1_setup, |
|
|
}; |
|
|
}; |
|
|
#endif |
|
|
#endif |
|
|