surenyi
5 years ago
5 changed files with 338 additions and 0 deletions
@ -0,0 +1,291 @@ |
|||||
|
#include <stdint.h> |
||||
|
#include <string.h> |
||||
|
#include "stm32f4xx.h" |
||||
|
#include "can.h" |
||||
|
|
||||
|
struct canbus { |
||||
|
CAN_TypeDef *base; |
||||
|
CAN_InitTypeDef conf; |
||||
|
CAN_FilterInitTypeDef filter; |
||||
|
|
||||
|
uint32_t rcc; |
||||
|
|
||||
|
int irq0; |
||||
|
int irq1; |
||||
|
void (*setup)(struct canbus *); |
||||
|
|
||||
|
void *user; |
||||
|
void (*callback)(struct canbus *, void *user); |
||||
|
}; |
||||
|
|
||||
|
/* query APB1 clocks */ |
||||
|
static uint32_t get_PCLK1_clocks() |
||||
|
{ |
||||
|
RCC_ClocksTypeDef clks; |
||||
|
|
||||
|
RCC_GetClocksFreq(&clks); |
||||
|
|
||||
|
return clks.PCLK1_Frequency; |
||||
|
} |
||||
|
|
||||
|
int can_set_baudrate(struct canbus *can, unsigned int baudrate) |
||||
|
{ |
||||
|
int found = 0; |
||||
|
int calcBaudrate; |
||||
|
uint8_t sjw = 1, bs1 = 1, bs2 = 1; |
||||
|
uint16_t prescaler = 1; |
||||
|
uint32_t frequency; |
||||
|
CAN_InitTypeDef conf = can->conf; |
||||
|
|
||||
|
frequency = get_PCLK1_clocks(); |
||||
|
for (; sjw <= 4 && !found; ) { |
||||
|
for (; bs1 <= 16 && !found; ) { |
||||
|
for (; bs2 <= 8 && !found; ) { |
||||
|
for (; prescaler <= 1024 && !found; ) { |
||||
|
calcBaudrate = (int)(frequency / (prescaler * (sjw + bs1 + bs2))); |
||||
|
if (calcBaudrate == baudrate) { |
||||
|
if (sjw == 1) |
||||
|
conf.CAN_SJW = CAN_SJW_1tq; |
||||
|
else if (sjw == 2) |
||||
|
conf.CAN_SJW = CAN_SJW_2tq; |
||||
|
else if (sjw == 3) |
||||
|
conf.CAN_SJW = CAN_SJW_3tq; |
||||
|
else if (sjw == 4) |
||||
|
conf.CAN_SJW = CAN_SJW_4tq; |
||||
|
|
||||
|
if (bs1 == 1) |
||||
|
conf.CAN_BS1 = CAN_BS1_1tq; |
||||
|
else if (bs1 == 2) |
||||
|
conf.CAN_BS1 = CAN_BS1_2tq; |
||||
|
else if (bs1 == 3) |
||||
|
conf.CAN_BS1 = CAN_BS1_3tq; |
||||
|
else if (bs1 == 4) |
||||
|
conf.CAN_BS1 = CAN_BS1_4tq; |
||||
|
else if (bs1 == 5) |
||||
|
conf.CAN_BS1 = CAN_BS1_5tq; |
||||
|
else if (bs1 == 6) |
||||
|
conf.CAN_BS1 = CAN_BS1_6tq; |
||||
|
else if (bs1 == 7) |
||||
|
conf.CAN_BS1 = CAN_BS1_7tq; |
||||
|
else if (bs1 == 8) |
||||
|
conf.CAN_BS1 = CAN_BS1_8tq; |
||||
|
else if (bs1 == 9) |
||||
|
conf.CAN_BS1 = CAN_BS1_9tq; |
||||
|
else if (bs1 == 10) |
||||
|
conf.CAN_BS1 = CAN_BS1_10tq; |
||||
|
else if (bs1 == 11) |
||||
|
conf.CAN_BS1 = CAN_BS1_11tq; |
||||
|
else if (bs1 == 12) |
||||
|
conf.CAN_BS1 = CAN_BS1_12tq; |
||||
|
else if (bs1 == 13) |
||||
|
conf.CAN_BS1 = CAN_BS1_13tq; |
||||
|
else if (bs1 == 14) |
||||
|
conf.CAN_BS1 = CAN_BS1_14tq; |
||||
|
else if (bs1 == 15) |
||||
|
conf.CAN_BS1 = CAN_BS1_15tq; |
||||
|
else if (bs1 == 16) |
||||
|
conf.CAN_BS1 = CAN_BS1_16tq; |
||||
|
|
||||
|
if (bs2 == 1) |
||||
|
conf.CAN_BS2 = CAN_BS2_1tq; |
||||
|
else if (bs2 == 2) |
||||
|
conf.CAN_BS2 = CAN_BS2_2tq; |
||||
|
else if (bs2 == 3) |
||||
|
conf.CAN_BS2 = CAN_BS2_2tq; |
||||
|
else if (bs2 == 4) |
||||
|
conf.CAN_BS2 = CAN_BS2_2tq; |
||||
|
|
||||
|
conf.CAN_Prescaler = prescaler; |
||||
|
found = 1; |
||||
|
} |
||||
|
|
||||
|
prescaler++; |
||||
|
} |
||||
|
if (!found) { |
||||
|
prescaler = 1; |
||||
|
bs2++; |
||||
|
} |
||||
|
} |
||||
|
if (!found) { |
||||
|
bs2 = 1; |
||||
|
bs1++; |
||||
|
} |
||||
|
} |
||||
|
if (!found) { |
||||
|
bs1 = 1; |
||||
|
sjw++; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (found) { |
||||
|
CAN_Init(can->base, &conf); |
||||
|
can->conf = conf; |
||||
|
return 0; |
||||
|
} |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
static void __canx_init(struct canbus *can) |
||||
|
{ |
||||
|
/* CAN register init */ |
||||
|
CAN_DeInit(can->base); |
||||
|
|
||||
|
|
||||
|
/* CAN cell init */ |
||||
|
CAN_StructInit(&can->conf); |
||||
|
CAN_Init(can->base, &can->conf); |
||||
|
|
||||
|
/* CAN filter init */ |
||||
|
#if 0 |
||||
|
#ifdef USE_CAN1 |
||||
|
can->filter.CAN_FilterNumber = 0; |
||||
|
#else /* USE_CAN2 */ |
||||
|
can->filter.CAN_FilterNumber = 14; |
||||
|
#endif /* USE_CAN1 */ |
||||
|
#endif |
||||
|
CAN_FilterInit(&can->filter); |
||||
|
} |
||||
|
|
||||
|
void can_setup(struct canbus *can, int baudrate) |
||||
|
{ |
||||
|
/* CANx Periph clock enable */ |
||||
|
RCC_APB1PeriphClockCmd(can->rcc, ENABLE); |
||||
|
|
||||
|
if (can->setup) |
||||
|
can->setup(can); |
||||
|
|
||||
|
__canx_init(can); |
||||
|
|
||||
|
if (baudrate > 0) { |
||||
|
can_set_baudrate(can, baudrate); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static int do_send_std_data(struct canbus *can, int remote, unsigned char id, const void *data, unsigned char len) |
||||
|
{ |
||||
|
CanTxMsg tx; |
||||
|
uint8_t tbox; |
||||
|
int i; |
||||
|
#define RETRY_MAX (0xffff) |
||||
|
|
||||
|
if (len > 8) { |
||||
|
len = 8; |
||||
|
} |
||||
|
|
||||
|
/* transmit */ |
||||
|
tx.StdId = id; |
||||
|
tx.RTR = remote ? CAN_RTR_REMOTE : CAN_RTR_DATA; |
||||
|
tx.IDE = CAN_ID_STD; |
||||
|
tx.DLC = len; |
||||
|
memcpy(tx.Data, data, len); |
||||
|
|
||||
|
tbox = CAN_Transmit(can->base, &tx); |
||||
|
|
||||
|
if (tbox == CAN_TxStatus_NoMailBox) { |
||||
|
return -2; |
||||
|
} |
||||
|
i = 0; |
||||
|
while((CAN_TransmitStatus(can->base, tbox) != CANTXOK) && (i != RETRY_MAX)) { |
||||
|
++i; |
||||
|
} |
||||
|
return (i == RETRY_MAX) ? -1 : len; |
||||
|
#undef RETRY_MAX |
||||
|
} |
||||
|
|
||||
|
int can_send_std_data(struct canbus *can, unsigned char id, const void *data, unsigned char len) |
||||
|
{ |
||||
|
return do_send_std_data(can, 0, id, data, len); |
||||
|
} |
||||
|
|
||||
|
int can_send_std_remote(struct canbus *can, unsigned char id, const void *data, unsigned char len) |
||||
|
{ |
||||
|
return do_send_std_data(can, 1, id, data, len); |
||||
|
} |
||||
|
|
||||
|
void can_attach_rx(struct canbus *can, void *user, void (*rx)(struct canbus *can, void *user)) |
||||
|
{ |
||||
|
can->user = user; |
||||
|
can->callback = rx; |
||||
|
} |
||||
|
|
||||
|
void can_close(struct canbus *can) |
||||
|
{ |
||||
|
RCC_APB1PeriphClockCmd(can->rcc, DISABLE); |
||||
|
CAN_DeInit(can->base); |
||||
|
} |
||||
|
|
||||
|
#if (TARGET_HAS_CAN0) |
||||
|
void __attribute__((weak)) target_can0_setup() |
||||
|
{ |
||||
|
GPIO_InitTypeDef gpio_conf; |
||||
|
|
||||
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); |
||||
|
|
||||
|
GPIO_StructInit(&gpio_conf); |
||||
|
|
||||
|
gpio_conf.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; /* PA 11(CAN1 RX) and PA 12 (CAN1 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(GPIOA, &gpio_conf); |
||||
|
|
||||
|
GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1); |
||||
|
GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1); |
||||
|
} |
||||
|
|
||||
|
static void __can0_setup(struct canbus *can) |
||||
|
{ |
||||
|
target_can0_setup(); |
||||
|
} |
||||
|
|
||||
|
struct canbus can0 = { |
||||
|
.base = CAN1, |
||||
|
.filter = { |
||||
|
.CAN_FilterNumber = 0, |
||||
|
.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, |
||||
|
}; |
||||
|
#endif |
||||
|
|
||||
|
#if (TARGET_HAS_CAN1) |
||||
|
void __attribute__((weak)) target_can1_setup() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
static void __can1_setup(struct canbus *can) |
||||
|
{ |
||||
|
target_can1_setup(); |
||||
|
} |
||||
|
|
||||
|
struct canbus can1 = { |
||||
|
.base = CAN2, |
||||
|
.filter = { |
||||
|
.CAN_FilterNumber = 14, |
||||
|
.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, |
||||
|
}; |
||||
|
#endif |
||||
|
|
@ -0,0 +1,36 @@ |
|||||
|
#ifndef __CAN_BUS_H____ |
||||
|
#define __CAN_BUS_H____ |
||||
|
#ifdef __cplusplus |
||||
|
extern "C" { |
||||
|
#endif |
||||
|
#include "config.h" |
||||
|
|
||||
|
struct canbus; |
||||
|
|
||||
|
/* can initialize */ |
||||
|
void can_setup(struct canbus *can, int baudrate); |
||||
|
|
||||
|
int can_set_baudrate(struct canbus *can, unsigned int baudrate); |
||||
|
|
||||
|
/*
|
||||
|
* send standard can frame. |
||||
|
* return > 0 on success. |
||||
|
*/ |
||||
|
int can_send_std_data(struct canbus *can, unsigned char id, const void *data, unsigned char len); |
||||
|
int can_send_std_remote(struct canbus *can, unsigned char id, const void *data, unsigned char len); |
||||
|
|
||||
|
void can_close(struct canbus *can); |
||||
|
|
||||
|
#if (TARGET_HAS_CAN0) |
||||
|
extern struct canbus can0; |
||||
|
#endif |
||||
|
|
||||
|
#if (TARGET_HAS_CAN1) |
||||
|
extern struct canbus can1; |
||||
|
#endif |
||||
|
|
||||
|
#ifdef __cplusplus |
||||
|
} |
||||
|
#endif |
||||
|
#endif |
||||
|
|
Loading…
Reference in new issue