From eb56b832ef2528c9b9dd48c8df98c5311ac42daa Mon Sep 17 00:00:00 2001 From: "Aubr.Cool" Date: Thu, 14 May 2015 15:44:06 +0800 Subject: [PATCH] Add Can Drv --- bsp/stm32f10x/applications/canapp.c | 141 +++ bsp/stm32f10x/drivers/bxcan.c | 1411 ++++++++++++++++++++++ bsp/stm32f10x/drivers/bxcan.h | 16 + components/drivers/can/can.c | 906 ++++++++++++++ components/drivers/include/drivers/can.h | 292 +++++ components/drivers/include/rtdevice.h | 4 + 6 files changed, 2770 insertions(+) create mode 100644 bsp/stm32f10x/applications/canapp.c create mode 100644 bsp/stm32f10x/drivers/bxcan.c create mode 100644 bsp/stm32f10x/drivers/bxcan.h create mode 100644 components/drivers/can/can.c create mode 100644 components/drivers/include/drivers/can.h diff --git a/bsp/stm32f10x/applications/canapp.c b/bsp/stm32f10x/applications/canapp.c new file mode 100644 index 0000000000..7a77df4265 --- /dev/null +++ b/bsp/stm32f10x/applications/canapp.c @@ -0,0 +1,141 @@ +/* + * File : canapp.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + */ +#include +#include +#include +struct can_app_struct +{ + const char* name; + struct rt_event event; + struct rt_can_filter_config * filter; + rt_uint8_t eventopt; +}; +static struct can_app_struct can_data[2]; +static rt_err_t can1ind(rt_device_t dev, void* args, rt_int32_t hdr, rt_size_t size) +{ + rt_event_t pevent = (rt_event_t)args; + rt_event_send(pevent, 1 << (hdr)); + return RT_EOK; +} +static rt_err_t can2ind(rt_device_t dev, void* args, rt_int32_t hdr, rt_size_t size) +{ + rt_event_t pevent = (rt_event_t)args; + rt_event_send(pevent, 1 << (hdr)); + return RT_EOK; +} +struct rt_can_filter_item filter1item[4] = +{ + RT_CAN_FILTER_STD_INIT(1,can1ind,&can_data[0].event), + RT_CAN_FILTER_STD_INIT(2,can1ind,&can_data[0].event), + RT_CAN_STD_RMT_FILTER_INIT(3,can1ind,&can_data[0].event), + RT_CAN_STD_RMT_DATA_FILTER_INIT(4,can1ind,&can_data[0].event), +}; +struct rt_can_filter_item filter2item[4] = +{ + RT_CAN_FILTER_STD_INIT(1,can2ind,&can_data[1].event), + RT_CAN_FILTER_STD_INIT(2,can2ind,&can_data[1].event), + RT_CAN_STD_RMT_FILTER_INIT(3,can2ind,&can_data[1].event), + RT_CAN_STD_RMT_DATA_FILTER_INIT(4,can2ind,&can_data[1].event), +}; +struct rt_can_filter_config filter1 = +{ + .count = 4, + .actived = 1, + .items = filter1item, +}; +struct rt_can_filter_config filter2 = +{ + .count = 4, + .actived = 1, + .items = filter2item, +}; +static struct can_app_struct can_data[2] = { + { + .name = "bxcan1", + .filter = &filter1, + .eventopt = RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, + }, + { + .name = "bxcan2", + .filter = &filter2, + .eventopt = RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, + }, +}; +void rt_can_thread_entry(void* parameter) +{ + struct rt_can_msg msg; + struct can_app_struct* canpara = (struct can_app_struct*) parameter; + rt_device_t candev; + rt_uint32_t e; + + candev = rt_device_find(canpara->name); + RT_ASSERT(candev); + rt_event_init(&canpara->event, canpara->name, RT_IPC_FLAG_FIFO); + rt_device_open(candev, (RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX)); + rt_device_control(candev,RT_CAN_CMD_SET_FILTER,canpara->filter); + while(1) { + if ( + rt_event_recv(&canpara->event, + ((1 << canpara->filter->items[0].hdr) | + (1 << canpara->filter->items[1].hdr) | + (1 << canpara->filter->items[2].hdr) | + (1 << canpara->filter->items[3].hdr)), + canpara->eventopt, + RT_WAITING_FOREVER, &e) != RT_EOK + ) { + continue; + } + if(e & (1 << canpara->filter->items[0].hdr)) { + msg.hdr = canpara->filter->items[0].hdr; + while (rt_device_read(candev, 0, &msg, sizeof(msg)) == sizeof(msg)) { + rt_device_write(candev, 0, &msg, sizeof(msg)); + } + } + if(e & (1 << canpara->filter->items[1].hdr)) { + msg.hdr = canpara->filter->items[1].hdr; + while (rt_device_read(candev, 0, &msg, sizeof(msg)) == sizeof(msg)) { + rt_device_write(candev, 0, &msg, sizeof(msg)); + } + } + if(e & (1 << canpara->filter->items[2].hdr)) { + msg.hdr = canpara->filter->items[2].hdr; + while (rt_device_read(candev, 0, &msg, sizeof(msg)) == sizeof(msg)) { + rt_device_write(candev, 0, &msg, sizeof(msg)); + } + } + if(e & (1 << canpara->filter->items[3].hdr)) { + msg.hdr = canpara->filter->items[3].hdr; + while (rt_device_read(candev, 0, &msg, sizeof(msg)) == sizeof(msg)) { + rt_device_write(candev, 0, &msg, sizeof(msg)); + } + } + } +} +int rt_can_app_init(void) +{ + rt_thread_t tid; + + tid = rt_thread_create("canapp1", + rt_can_thread_entry, &can_data[0], + 512, RT_THREAD_PRIORITY_MAX /3 - 1, 20); + if (tid != RT_NULL) rt_thread_startup(tid); + + tid = rt_thread_create("canapp2", + rt_can_thread_entry, &can_data[1], + 512, RT_THREAD_PRIORITY_MAX /3 - 1, 20); + if (tid != RT_NULL) rt_thread_startup(tid); + + return 0; +} + +INIT_APP_EXPORT(rt_can_app_init); diff --git a/bsp/stm32f10x/drivers/bxcan.c b/bsp/stm32f10x/drivers/bxcan.c new file mode 100644 index 0000000000..0454991708 --- /dev/null +++ b/bsp/stm32f10x/drivers/bxcan.c @@ -0,0 +1,1411 @@ +/* + * File : bxcan.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + */ +#include +#include +#include +#include +#ifdef RT_USING_COMPONENTS_INIT +#include +#endif +#ifdef RT_USING_CAN + +#ifndef STM32F10X_CL +#define BX_CAN_FMRNUMBER 14 +#define BX_CAN2_FMRSTART 7 +#else +#define BX_CAN_FMRNUMBER 28 +#define BX_CAN2_FMRSTART 14 +#endif + +#define BX_CAN_MAX_FILTERS (BX_CAN_FMRNUMBER * 4) +#define BX_CAN_MAX_FILTER_MASKS BX_CAN_MAX_FILTERS +#define BX_CAN_FILTER_MAX_ARRAY_SIZE ((BX_CAN_MAX_FILTERS + 32 - 1) / 32) + +struct stm_bxcanfiltermap { + rt_uint32_t id32mask_cnt; + rt_uint32_t id32bit_cnt; + rt_uint32_t id16mask_cnt; + rt_uint32_t id16bit_cnt; +}; +struct stm_bxcanfilter_masks { + rt_uint32_t id32maskm[BX_CAN_FILTER_MAX_ARRAY_SIZE]; + rt_uint32_t id32bitm[BX_CAN_FILTER_MAX_ARRAY_SIZE]; + rt_uint32_t id16maskm[BX_CAN_FILTER_MAX_ARRAY_SIZE]; + rt_uint32_t id16bitm[BX_CAN_FILTER_MAX_ARRAY_SIZE]; + rt_uint32_t id32maskshift[2]; + rt_uint32_t id32bitshift[2]; + rt_uint32_t id16maskshift[2]; + rt_uint32_t id16bitshift[2]; +}; +struct stm_bxcan +{ + CAN_TypeDef* reg; + void* mfrbase; + IRQn_Type sndirq; + IRQn_Type rcvirq0; + IRQn_Type rcvirq1; + IRQn_Type errirq; + struct stm_bxcanfilter_masks filtermask; + rt_uint32_t alocmask[BX_CAN_FILTER_MAX_ARRAY_SIZE]; + const rt_uint32_t filtercnt; + const rt_uint32_t fifo1filteroff; + const struct stm_bxcanfiltermap filtermap[2]; +}; +static void calcfiltermasks(struct stm_bxcan *pbxcan); +static void bxcan1_filter_init(struct rt_can_device *can) +{ + rt_uint32_t i; + rt_uint32_t mask; + struct stm_bxcan *pbxcan = (struct stm_bxcan *) can->parent.user_data; + for(i = 0; i < BX_CAN2_FMRSTART; i++) { + CAN1->FMR |= FMR_FINIT; + mask = 0x01 << (i + 0); + if(i < pbxcan->fifo1filteroff) { + if(pbxcan->filtermap[0].id32mask_cnt && i < pbxcan->filtermap[0].id32mask_cnt) { + CAN1->FS1R |= mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id32bit_cnt && + i < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2) { + CAN1->FS1R |= mask; + CAN1->FM1R |= mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id16mask_cnt && + i < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2 + + pbxcan->filtermap[0].id16mask_cnt /2) { + CAN1->FS1R &= ~mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id16bit_cnt && + i < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2 + + pbxcan->filtermap[0].id16mask_cnt /2 + pbxcan->filtermap[0].id16bit_cnt / 4 + ) { + CAN1->FS1R &= ~mask; + CAN1->FM1R |= mask; + CAN1->FFA1R &= ~mask; + } + } else { + if(pbxcan->filtermap[1].id32mask_cnt && + i < pbxcan->filtermap[1].id32mask_cnt + pbxcan->fifo1filteroff) { + CAN1->FS1R |= mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id32bit_cnt && + i < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->fifo1filteroff) { + CAN1->FS1R |= mask; + CAN1->FM1R |= mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id16mask_cnt && + i < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->filtermap[1].id16mask_cnt / 2 + pbxcan->fifo1filteroff) { + CAN1->FS1R &= ~mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id16bit_cnt && + i < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->filtermap[1].id16mask_cnt /2 + pbxcan->filtermap[1].id16bit_cnt / 4 + + pbxcan->fifo1filteroff) { + CAN1->FS1R &= ~mask; + CAN1->FM1R |= mask; + CAN1->FFA1R |= mask; + } + } + CAN1->sFilterRegister[i].FR1 = 0xFFFFFFFF; + CAN1->sFilterRegister[i].FR2 = 0xFFFFFFFF; + CAN1->FMR &= ~FMR_FINIT; + } + calcfiltermasks(pbxcan); +} +static void bxcan2_filter_init(struct rt_can_device *can) +{ + rt_uint32_t i; + rt_uint32_t off; + rt_uint32_t mask; + CAN_SlaveStartBank(BX_CAN2_FMRSTART); + struct stm_bxcan *pbxcan = (struct stm_bxcan *) can->parent.user_data; + for(i = BX_CAN2_FMRSTART; i < BX_CAN_FMRNUMBER; i++) { + CAN1->FMR |= FMR_FINIT; + mask = 0x01 << (i + 0); + off = i - BX_CAN2_FMRSTART; + if(i < pbxcan->fifo1filteroff) { + if(pbxcan->filtermap[0].id32mask_cnt && off < pbxcan->filtermap[0].id32mask_cnt) { + CAN1->FS1R |= mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id32bit_cnt && + off < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2) { + CAN1->FS1R |= mask; + CAN1->FM1R |= mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id16mask_cnt && + off < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2 + + pbxcan->filtermap[0].id16mask_cnt /2) { + CAN1->FS1R &= ~mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R &= ~mask; + } else if(pbxcan->filtermap[0].id16bit_cnt && + off < pbxcan->filtermap[0].id32mask_cnt + pbxcan->filtermap[0].id32bit_cnt /2 + + pbxcan->filtermap[0].id16mask_cnt /2 + pbxcan->filtermap[0].id16bit_cnt / 4 + ) { + CAN1->FS1R &= ~mask; + CAN1->FM1R |= mask; + CAN1->FFA1R &= ~mask; + } + } else { + if(pbxcan->filtermap[1].id32mask_cnt && + off < pbxcan->filtermap[1].id32mask_cnt + pbxcan->fifo1filteroff) { + CAN1->FS1R |= mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id32bit_cnt && + off < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->fifo1filteroff) { + CAN1->FS1R |= mask; + CAN1->FM1R |= mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id16mask_cnt && + off < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->filtermap[1].id16mask_cnt / 2 + pbxcan->fifo1filteroff) { + CAN1->FS1R &= ~mask; + CAN1->FM1R &= ~mask; + CAN1->FFA1R |= mask; + } else if(pbxcan->filtermap[1].id16bit_cnt && + off < pbxcan->filtermap[1].id32mask_cnt + pbxcan->filtermap[1].id32bit_cnt /2 + + pbxcan->filtermap[1].id16mask_cnt /2 + pbxcan->filtermap[1].id16bit_cnt / 4 + + pbxcan->fifo1filteroff) { + CAN1->FS1R &= ~mask; + CAN1->FM1R |= mask; + CAN1->FFA1R |= mask; + } + } + CAN1->sFilterRegister[i].FR1 = 0xFFFFFFFF; + CAN1->sFilterRegister[i].FR2 = 0xFFFFFFFF; + CAN1->FMR &= ~FMR_FINIT; + } + calcfiltermasks(pbxcan); +} +#define BS1SHIFT 16 +#define BS2SHIFT 20 +#define RRESCLSHIFT 0 +#define SJWSHIFT 24 +#define BS1MASK ( (0x0F) << BS1SHIFT ) +#define BS2MASK ( (0x07) << BS2SHIFT ) +#define RRESCLMASK ( 0x3FF << RRESCLSHIFT ) +#define SJWMASK ( 0x3 << SJWSHIFT ) + +#define MK_BKCAN_BAUD(SJW,BS1,BS2,PRES) \ + ((SJW << SJWSHIFT) | (BS1 << BS1SHIFT) | (BS2 << BS2SHIFT) | (PRES << RRESCLSHIFT)) + +static const rt_uint32_t bxcan_baud_rate_tab[] = +{ + // 48 M + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,3), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_6tq,CAN_BS2_3tq,6), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,5), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,11), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,23), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,29), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_12tq,CAN_BS2_3tq,59), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_14tq,CAN_BS2_3tq,149), + MK_BKCAN_BAUD(CAN_SJW_2tq,CAN_BS1_16tq,CAN_BS2_8tq,199), +}; + +#define BAUD_DATA(TYPE,NO) \ + ((bxcan_baud_rate_tab[NO] & TYPE##MASK) >> TYPE##SHIFT) + +static void bxcan_init(CAN_TypeDef* pcan, rt_uint32_t baud, rt_uint32_t mode) +{ + CAN_InitTypeDef CAN_InitStructure; + + CAN_InitStructure.CAN_TTCM = DISABLE; + CAN_InitStructure.CAN_ABOM = ENABLE; + CAN_InitStructure.CAN_AWUM = DISABLE; + CAN_InitStructure.CAN_NART = DISABLE; + CAN_InitStructure.CAN_RFLM = DISABLE; + CAN_InitStructure.CAN_TXFP = ENABLE; + switch(mode) + { + case RT_CAN_MODE_NORMAL: + CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; + break; + case RT_CAN_MODE_LISEN: + CAN_InitStructure.CAN_Mode = CAN_Mode_Silent; + break; + case RT_CAN_MODE_LOOPBACK: + CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack; + break; + case RT_CAN_MODE_LOOPBACKANLISEN: + CAN_InitStructure.CAN_Mode = CAN_Mode_Silent_LoopBack; + break; + } + CAN_InitStructure.CAN_SJW = BAUD_DATA(SJW,baud); + CAN_InitStructure.CAN_BS1 = BAUD_DATA(BS1,baud); + CAN_InitStructure.CAN_BS2 = BAUD_DATA(BS2,baud); + CAN_InitStructure.CAN_Prescaler =BAUD_DATA(RRESCL,baud); + + CAN_Init(pcan, &CAN_InitStructure); +} +static void bxcan1_hw_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1 , ENABLE); + + CAN_DeInit(CAN1); + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; + NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; + NVIC_Init(&NVIC_InitStructure); + NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn; + NVIC_Init(&NVIC_InitStructure); + NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_IRQn; + NVIC_Init(&NVIC_InitStructure); +} +static void bxcan2_hw_init(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_Init(GPIOB, &GPIO_InitStructure); + + RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE); + + CAN_DeInit(CAN2); + + NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); + NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; + NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; + NVIC_Init(&NVIC_InitStructure); + NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX1_IRQn; + NVIC_Init(&NVIC_InitStructure); + NVIC_InitStructure.NVIC_IRQChannel = CAN2_TX_IRQn; + NVIC_Init(&NVIC_InitStructure); +} +static inline rt_err_t bxcan_enter_init(CAN_TypeDef* pcan) +{ + uint32_t wait_ack = 0x00000000; + + pcan->MCR |= CAN_MCR_INRQ ; + + while (((pcan->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT)) + { + wait_ack++; + } + if ((pcan->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) + { + return RT_ERROR; + } + return RT_EOK; +} +static inline rt_err_t bxcan_exit_init(CAN_TypeDef* pcan) +{ + uint32_t wait_ack = 0x00000000; + + pcan->MCR &= ~(uint32_t)CAN_MCR_INRQ; + + while (((pcan->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT)) + { + wait_ack++; + } + if ((pcan->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) + { + return RT_ERROR; + } + return RT_EOK; +} +static rt_err_t bxcan_set_mode(CAN_TypeDef* pcan, rt_uint32_t mode) +{ + if(bxcan_enter_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + pcan->BTR &= ~(uint32_t)((uint32_t)0x03 << 30); + switch(mode) + { + case RT_CAN_MODE_NORMAL: + mode = CAN_Mode_Normal; + break; + case RT_CAN_MODE_LISEN: + mode = CAN_Mode_Silent; + break; + case RT_CAN_MODE_LOOPBACK: + mode = CAN_Mode_LoopBack; + break; + case RT_CAN_MODE_LOOPBACKANLISEN: + mode = CAN_Mode_Silent_LoopBack; + break; + } + pcan->BTR |= ~(uint32_t)(mode << 30); + if(bxcan_exit_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + return RT_EOK; +} +static rt_err_t bxcan_set_privmode(CAN_TypeDef* pcan, rt_uint32_t mode) +{ + if(bxcan_enter_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + if (mode == ENABLE) + { + pcan->MCR |= CAN_MCR_TXFP; + } + else + { + pcan->MCR &= ~(uint32_t)CAN_MCR_TXFP; + } + if(bxcan_exit_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + return RT_EOK; +} +static rt_err_t bxcan_set_baud_rate(CAN_TypeDef* pcan, rt_uint32_t baud) +{ + rt_uint32_t mode; + if(bxcan_enter_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + pcan->BTR = 0; + mode = pcan->BTR & ((rt_uint32_t)0x03 << 30); + pcan->BTR = (mode | \ + ((BAUD_DATA(SJW,baud)) << 24) | \ + ((BAUD_DATA(BS1,baud)) << 16) | \ + ((BAUD_DATA(BS2,baud)) << 20) | \ + (BAUD_DATA(RRESCL,baud))); + if(bxcan_exit_init(pcan) != RT_EOK) + { + return RT_ERROR; + } + return RT_EOK; +} +static rt_err_t bxcancalcbaseoff(struct stm_bxcan *pbxcan, rt_int32_t hdr, + rt_int32_t * pbase, rt_int32_t * poff) +{ + rt_uint32_t fifo0start,fifo0end; + rt_uint32_t fifo1start,fifo1end; + rt_uint32_t ptr; + fifo0start = 0; + fifo0end = pbxcan->filtermap[0].id32mask_cnt + + pbxcan->filtermap[0].id32bit_cnt + + pbxcan->filtermap[0].id16mask_cnt + + pbxcan->filtermap[0].id16bit_cnt ; + fifo1start = pbxcan->fifo1filteroff * 4; + fifo1end = pbxcan->filtermap[1].id32mask_cnt + + pbxcan->filtermap[1].id32bit_cnt + + pbxcan->filtermap[1].id16mask_cnt + + pbxcan->filtermap[1].id16bit_cnt ; + if(hdr >= fifo0start && hdr < fifo0end) { + *pbase = 0; + ptr = 0; + } else if(hdr >= fifo1start && hdr < fifo1end) { + *pbase = pbxcan->fifo1filteroff; + ptr = 1; + } else { + return RT_ERROR; + } + ptr = 0; + if(hdr > pbxcan->filtermap[ptr].id32mask_cnt) { + hdr -= pbxcan->filtermap[ptr].id32mask_cnt; + *pbase += pbxcan->filtermap[ptr].id32mask_cnt; + } else { + *pbase += hdr; + *poff = 0; + return RT_EOK; + } + if(hdr > pbxcan->filtermap[ptr].id32bit_cnt) { + hdr -= pbxcan->filtermap[ptr].id32bit_cnt; + *pbase += pbxcan->filtermap[ptr].id32bit_cnt / 2; + } else { + *pbase += hdr / 2; + *poff = hdr % 2; + return RT_EOK; + } + if(hdr > pbxcan->filtermap[ptr].id16mask_cnt) { + hdr -= pbxcan->filtermap[ptr].id16mask_cnt; + *pbase += pbxcan->filtermap[ptr].id16mask_cnt / 2; + } else { + *pbase += hdr / 2; + *poff = hdr % 2; + return RT_EOK; + } + if(hdr > pbxcan->filtermap[ptr].id16bit_cnt) { + return RT_ERROR; + } else { + *pbase += hdr / 4; + *poff = hdr % 4; + return RT_EOK; + } +} +static void calcandormask(rt_uint32_t* pmask,rt_uint32_t shift,rt_int32_t count) +{ + rt_uint32_t tmpmask; + rt_uint32_t tmpmaskarray[BX_CAN_FILTER_MAX_ARRAY_SIZE] = {0,}; + rt_int32_t i; + i = 0; + while(count > 0) { + if(i >= 32) { + tmpmaskarray[i] = 0xFFFFFFFF; + } else { + tmpmaskarray[i] = (0x01 << count) - 1; + } + count -= 32; + i++; + }; + count = i; + for(i = 0; i < count && i < BX_CAN_FILTER_MAX_ARRAY_SIZE; i++) { + tmpmask = tmpmaskarray[i]; + pmask[i] |= (rt_uint32_t)(tmpmask << shift); + if(i < BX_CAN_FILTER_MAX_ARRAY_SIZE - 1) { + pmask[i + 1] |= (rt_uint32_t)(tmpmask >> (32 - shift)); + } + } +} +static void calcfiltermasks(struct stm_bxcan *pbxcan) +{ + rt_memset(&pbxcan->filtermask,0,sizeof(pbxcan->filtermask)); + pbxcan->filtermask.id32maskshift[0] = 0; + if(pbxcan->filtermap[0].id32mask_cnt) { + calcandormask(pbxcan->filtermask.id32maskm,pbxcan->filtermask.id32maskshift[0], + pbxcan->filtermap[0].id32mask_cnt); + } + pbxcan->filtermask.id32maskshift[1] = pbxcan->fifo1filteroff * 4; + if(pbxcan->filtermap[1].id32mask_cnt) { + calcandormask(pbxcan->filtermask.id32maskm,pbxcan->filtermask.id32maskshift[1], + pbxcan->filtermap[1].id32mask_cnt); + } + pbxcan->filtermask.id32bitshift[0] = pbxcan->filtermask.id32maskshift[0] + + pbxcan->filtermap[0].id32mask_cnt; + if(pbxcan->filtermap[0].id32bit_cnt) { + calcandormask(pbxcan->filtermask.id32bitm,pbxcan->filtermask.id32bitshift[0], + pbxcan->filtermap[0].id32bit_cnt); + } + pbxcan->filtermask.id32bitshift[1] = pbxcan->filtermask.id32maskshift[1] + + pbxcan->filtermap[1].id32mask_cnt; + if(pbxcan->filtermap[1].id32bit_cnt) { + calcandormask(pbxcan->filtermask.id32bitm,pbxcan->filtermask.id32bitshift[1], + pbxcan->filtermap[1].id32bit_cnt); + } + pbxcan->filtermask.id16maskshift[0] = pbxcan->filtermask.id32bitshift[0] + + pbxcan->filtermap[0].id32bit_cnt; + if(pbxcan->filtermap[0].id16mask_cnt) { + calcandormask(pbxcan->filtermask.id16maskm,pbxcan->filtermask.id16maskshift[0], + pbxcan->filtermap[0].id16mask_cnt); + } + pbxcan->filtermask.id16maskshift[1] = pbxcan->filtermask.id32bitshift[1] + + pbxcan->filtermap[1].id32bit_cnt; + if(pbxcan->filtermap[1].id16mask_cnt) { + calcandormask(pbxcan->filtermask.id16maskm,pbxcan->filtermask.id16maskshift[1], + pbxcan->filtermap[1].id16mask_cnt); + } + pbxcan->filtermask.id16bitshift[0] = pbxcan->filtermask.id16maskshift[0] + + pbxcan->filtermap[0].id16mask_cnt; + if(pbxcan->filtermap[0].id16bit_cnt) { + calcandormask(pbxcan->filtermask.id16bitm,pbxcan->filtermask.id16bitshift[0], + pbxcan->filtermap[0].id16bit_cnt); + } + pbxcan->filtermask.id16bitshift[1] = pbxcan->filtermask.id16maskshift[1] + + pbxcan->filtermap[1].id16mask_cnt; + if(pbxcan->filtermap[1].id16bit_cnt) { + calcandormask(pbxcan->filtermask.id16bitm,pbxcan->filtermask.id16bitshift[1], + pbxcan->filtermap[1].id16bit_cnt); + } +} +static rt_int32_t bxcanfindfilter(struct stm_bxcan *pbxcan,struct rt_can_filter_item* pitem, + rt_int32_t type,rt_int32_t* base,rt_int32_t* off) +{ + rt_int32_t i; + rt_uint32_t bits,thisid,thismask,shift,found; + CAN_FilterRegister_TypeDef * pfilterreg; + found = 0; + switch(type) { + case 3: + shift = 3; + for(i = 0; i < BX_CAN_MAX_FILTERS; i++) { + bits = 0x01 << (i & 0x1F); + if(bits & (pbxcan->filtermask.id32maskm[i >> 5] & pbxcan->alocmask[i >> 5])) { + bxcancalcbaseoff(pbxcan,i,base,off); + pfilterreg = &((CAN_FilterRegister_TypeDef *)pbxcan->mfrbase)[*base]; + thisid = (rt_uint32_t)pitem->id<mask<ide) { + thisid |= CAN_ID_EXT; + thismask |= CAN_ID_EXT; + } + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE; + thismask |= CAN_RTR_REMOTE; + } + if(pfilterreg->FR1 == thisid && pfilterreg->FR2 == thismask) { + found = 1; + break; + } + } + } + break; + case 2: + shift = 3; + for(i = 0; i < BX_CAN_MAX_FILTERS; i++) { + bits = 0x01 << (i % 32); + if(bits & (pbxcan->filtermask.id32bitm[i >> 5] & pbxcan->alocmask[i >> 5])) { + bxcancalcbaseoff(pbxcan,i,base,off); + pfilterreg = &((CAN_FilterRegister_TypeDef *)pbxcan->mfrbase)[*base]; + thisid = (rt_uint32_t)pitem->id<ide) { + thisid |= CAN_ID_EXT; + } + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE; + } + if((off == 0 && pfilterreg->FR1 == thisid) || + (*off == 1 && pfilterreg->FR2 == thisid) + ) { + found = 1; + break; + } + } + } + break; + case 1: + shift = 5; + for(i = 0; i < BX_CAN_MAX_FILTERS; i++) { + bits = 0x01 << (i % 32); + if(bits & (pbxcan->filtermask.id16maskm[i >> 5] & pbxcan->alocmask[i >> 5])) { + bxcancalcbaseoff(pbxcan,i,base,off); + pfilterreg = &((CAN_FilterRegister_TypeDef *)pbxcan->mfrbase)[*base]; + thisid = pitem->id << shift; + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE << (shift - 2); + } + thismask = pitem->mask << shift; + if(pitem->rtr) { + thismask |= CAN_RTR_REMOTE << (shift - 2); + } + if(*off == 0 && pfilterreg->FR1 == ((thisid & 0x0000FFFF) | ((thismask & 0x0000FFFF) << 16)) || + *off == 1 && pfilterreg->FR2 == ((thisid & 0x0000FFFF) | ((thismask & 0x0000FFFF) << 16)) + ){ + found = 1; + break; + } + } + } + break; + case 0: + shift = 5; + for(i = 0; i < BX_CAN_MAX_FILTERS; i++) { + bits = 0x01 << (i % 32); + if(bits & (pbxcan->filtermask.id16bitm[i >> 5] & pbxcan->alocmask[i >> 5])) { + bxcancalcbaseoff(pbxcan,i,base,off); + pfilterreg = &((CAN_FilterRegister_TypeDef *)pbxcan->mfrbase)[*base]; + thisid = pitem->id << shift; + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE << (shift - 2); + } + if(*off < 2 && ((rt_uint16_t*)&pfilterreg->FR1)[*off & 0x01] == thisid || + *off >= 2 && ((rt_uint16_t*)&pfilterreg->FR2)[*off & 0x01] == thisid) { + found = 1; + break; + } + } + } + break; + } + if(found) { + return i; + } + return -1; +} +extern int __rt_ffs(int value); +static rt_err_t bxcanallocfilter(rt_uint32_t * pmask, rt_uint32_t * palocmask, + rt_uint32_t count, rt_int32_t* hdr) +{ + rt_int32_t i; + for(i = 0; i < count; i++) { + rt_enter_critical(); + if((pmask[i] & ~palocmask[i]) != 0) { + *hdr = __rt_ffs(pmask[i] & ~palocmask[i]) - 1 + i * 32; + palocmask[i] |= 0x01 <<(*hdr % 0x1F); + rt_exit_critical(); + return RT_EOK; + } + rt_exit_critical(); + } + if(i >= count) { + return RT_ENOMEM; + } + return RT_EOK; +} +static rt_err_t bxcanallocnewfilter(struct stm_bxcan *pbxcan, rt_int32_t actived, + rt_int32_t type, rt_int32_t* hdr, rt_int32_t* base, rt_int32_t* off) +{ + rt_err_t res; + *hdr = -1; + switch(type) { + case 0x03: + res = bxcanallocfilter(pbxcan->filtermask.id32maskm,pbxcan->alocmask, + BX_CAN_FILTER_MAX_ARRAY_SIZE,hdr); + break; + case 0x02: + res = bxcanallocfilter(pbxcan->filtermask.id32bitm,pbxcan->alocmask, + BX_CAN_FILTER_MAX_ARRAY_SIZE,hdr); + break; + case 0x01: + res = bxcanallocfilter(pbxcan->filtermask.id16maskm,pbxcan->alocmask, + BX_CAN_FILTER_MAX_ARRAY_SIZE,hdr); + break; + case 0x00: + res = bxcanallocfilter(pbxcan->filtermask.id16bitm,pbxcan->alocmask, + BX_CAN_FILTER_MAX_ARRAY_SIZE,hdr); + break; + } + if(res != RT_EOK || *hdr < 0) { + return RT_ENOMEM; + } + bxcancalcbaseoff(pbxcan,*hdr,base,off); + return RT_EOK; +} +static rt_err_t bxmodifyfilter(struct stm_bxcan *pbxcan, struct rt_can_filter_item* pitem, rt_uint32_t actived) +{ + rt_int32_t fcase; + rt_err_t res; + rt_int32_t hdr,fbase,foff; + + fcase = (pitem->mode | (pitem->ide << 1)); + hdr = bxcanfindfilter(pbxcan,pitem,fcase,&fbase,&foff); + if(hdr < 0) { + if(!actived) { + return RT_EOK; + } else if(pitem->hdr == -1) { + res = bxcanallocnewfilter(pbxcan,actived,fcase,&hdr,&fbase,&foff); + if(res != RT_EOK) { + return res; + } + } else if(pitem->hdr >= 0) { + rt_enter_critical(); + res = bxcancalcbaseoff(pbxcan,pitem->hdr,&fbase,&foff); + if(res != RT_EOK) { + return res; + } + hdr = pitem->hdr; + if(actived) { + pbxcan->alocmask[hdr >> 5] |= 0x01 <<(hdr % 0x1F); + } + rt_exit_critical(); + } + } else { + if(!actived) { + pitem->hdr = hdr; + } else if(hdr >= 0 && (pitem->hdr >= 0 || pitem->hdr == -1)) { + pitem->hdr = hdr; + return RT_EBUSY; + } + } + rt_uint32_t ID[2]; + rt_uint32_t shift; + rt_uint32_t thisid; + rt_uint32_t thismask; + CAN_FilterInitTypeDef CAN_FilterInitStructure; + + pitem->hdr = hdr; + CAN_FilterRegister_TypeDef * pfilterreg = &((CAN_FilterRegister_TypeDef *)pbxcan->mfrbase)[fbase]; + ID[0] = pfilterreg->FR1; + ID[1] = pfilterreg->FR2; + CAN_FilterInitStructure.CAN_FilterNumber = (pfilterreg - &CAN1->sFilterRegister[0]); + if(pitem->mode) { + CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; + } else { + CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdList; + } + if(pitem->ide) { + CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; + } else { + CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; + } + switch(fcase) { + case 0x03: + if(actived) { + shift = 3; + thisid = (rt_uint32_t)pitem->id<mask<ide) { + thisid |= CAN_ID_EXT; + thismask |= CAN_ID_EXT; + } + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE; + thismask |= CAN_RTR_REMOTE; + } + ID[0] = thisid; + ID[1] = thismask; + } else { + ID[0] = 0xFFFFFFFF; + ID[1] = 0xFFFFFFFF; + } + break; + case 0x02: + if(actived) { + shift = 3; + thisid = (rt_uint32_t)pitem->id<ide) { + thisid |= CAN_ID_EXT; + } + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE; + } + ID[foff] = thisid; + } else { + ID[foff] = 0xFFFFFFFF; + } + break; + case 0x01: + if(actived) { + shift = 5; + thisid = pitem->id << shift; + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE << (shift - 2); + } + thismask = pitem->mask << shift; + if(pitem->rtr) { + thismask |= CAN_RTR_REMOTE << (shift - 2); + } + ID[foff] = (thisid & 0x0000FFFF) | ((thismask & 0x0000FFFF) << 16); + } else { + ID[foff] = 0xFFFFFFFF; + } + break; + case 0x00: + if(actived) { + shift = 5; + thisid = pitem->id << shift; + if(pitem->rtr) { + thisid |= CAN_RTR_REMOTE << (shift - 2); + } + ((rt_uint16_t*) ID)[foff] = thisid; + } else { + ((rt_uint16_t*) ID)[foff] = 0xFFFF; + } + break; + } + CAN_FilterInitStructure.CAN_FilterIdHigh = ((ID[1]) & 0x0000FFFF); + CAN_FilterInitStructure.CAN_FilterIdLow = ID[0] & 0x0000FFFF; + CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (ID[1] & 0xFFFF0000) >> 16; + CAN_FilterInitStructure.CAN_FilterMaskIdLow = (ID[0] & 0xFFFF0000) >> 16; + if(fbase >= pbxcan->fifo1filteroff) { + CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 1; + } else { + CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0; + } + if(ID[0] != 0xFFFFFFFF || ID[1] != 0xFFFFFFFF) { + CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; + } else { + CAN_FilterInitStructure.CAN_FilterActivation=DISABLE; + } + if(!actived) { + rt_enter_critical(); + pbxcan->alocmask[hdr >> 5] &= ~(0x01 <<(hdr % 0x1F)); + rt_exit_critical(); + } + CAN_FilterInit(&CAN_FilterInitStructure); + return RT_EOK; +} +static rt_err_t setfilter(struct stm_bxcan *pbxcan,struct rt_can_filter_config *pconfig) +{ + struct rt_can_filter_item* pitem = pconfig->items; + rt_uint32_t count = pconfig->count; + rt_err_t res; + while(count) { + res = bxmodifyfilter(pbxcan,pitem,pconfig->actived); + if(res != RT_EOK) { + return res; + } + pitem++; + count--; + } + return RT_EOK; +} +static rt_err_t configure(struct rt_can_device *can, struct can_configure *cfg) +{ + CAN_TypeDef* pbxcan; + + pbxcan = ((struct stm_bxcan *) can->parent.user_data)->reg; + assert_param(IS_CAN_ALL_PERIPH(pbxcan)); + if(pbxcan == CAN1) + { + bxcan1_hw_init(); + bxcan_init(pbxcan,cfg->baud_rate,can->config.mode); + bxcan1_filter_init(can); + } else { + bxcan2_hw_init(); + bxcan_init(pbxcan,cfg->baud_rate,can->config.mode); + bxcan2_filter_init(can); + } + return RT_EOK; +} +static rt_err_t control(struct rt_can_device *can, int cmd, void *arg) +{ + struct stm_bxcan* pbxcan; + rt_uint32_t argval; + NVIC_InitTypeDef NVIC_InitStructure; + + pbxcan= (struct stm_bxcan *) can->parent.user_data; + assert_param(pbxcan != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_CLR_INT: + argval = (rt_uint32_t) arg; + if(argval == RT_DEVICE_FLAG_INT_RX) + { + NVIC_DisableIRQ(pbxcan->rcvirq0); + NVIC_DisableIRQ(pbxcan->rcvirq1); + CAN_ITConfig(pbxcan->reg,CAN_IT_FMP0 ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FF0 ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FOV0 ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FMP1 ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FF1 ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FOV1 ,DISABLE); + } else if(argval == RT_DEVICE_FLAG_INT_TX) + { + NVIC_DisableIRQ(pbxcan->sndirq); + CAN_ITConfig(pbxcan->reg,CAN_IT_TME,DISABLE); + } else if(argval == RT_DEVICE_CAN_INT_ERR) { + CAN_ITConfig(pbxcan->reg,CAN_IT_BOF ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_LEC ,DISABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_ERR ,DISABLE); + NVIC_DisableIRQ(pbxcan->errirq); + } + break; + case RT_DEVICE_CTRL_SET_INT: + argval = (rt_uint32_t) arg; + if(argval == RT_DEVICE_FLAG_INT_RX) + { + CAN_ITConfig(pbxcan->reg,CAN_IT_FMP0 ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FF0 ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FOV0 ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FMP1 ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FF1 ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_FOV1 ,ENABLE); + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannel = pbxcan->rcvirq0; + NVIC_Init(&NVIC_InitStructure); + NVIC_InitStructure.NVIC_IRQChannel = pbxcan->rcvirq1; + NVIC_Init(&NVIC_InitStructure); + } else if(argval == RT_DEVICE_FLAG_INT_TX) + { + CAN_ITConfig(pbxcan->reg,CAN_IT_TME,ENABLE); + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannel = pbxcan->sndirq; + NVIC_Init(&NVIC_InitStructure); + } else if(argval == RT_DEVICE_CAN_INT_ERR) { + CAN_ITConfig(pbxcan->reg,CAN_IT_BOF ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_LEC ,ENABLE); + CAN_ITConfig(pbxcan->reg,CAN_IT_ERR ,ENABLE); + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x1; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_InitStructure.NVIC_IRQChannel = pbxcan->errirq; + NVIC_Init(&NVIC_InitStructure); + } + break; + case RT_CAN_CMD_SET_FILTER: + return setfilter(pbxcan, (struct rt_can_filter_config*) arg); + break; + case RT_CAN_CMD_SET_MODE: + argval = (rt_uint32_t) arg; + if(argval != RT_CAN_MODE_NORMAL || + argval != RT_CAN_MODE_LISEN || + argval != RT_CAN_MODE_LOOPBACK || + argval != RT_CAN_MODE_LOOPBACKANLISEN ) { + return RT_ERROR; + } + if(argval != can->config.mode) + { + can->config.mode = argval; + return bxcan_set_mode(pbxcan->reg, argval); + } + break; + case RT_CAN_CMD_SET_BAUD: + argval = (rt_uint32_t) arg; + if(argval != CAN1MBaud || + argval != CAN800kBaud || + argval != CAN500kBaud || + argval != CAN250kBaud || + argval != CAN125kBaud || + argval != CAN100kBaud || + argval != CAN50kBaud || + argval != CAN20kBaud || + argval != CAN10kBaud ) { + return RT_ERROR; + } + if(argval != can->config.baud_rate) + { + can->config.baud_rate = argval; + return bxcan_set_baud_rate(pbxcan->reg, argval); + } + break; + case RT_CAN_CMD_SET_PRIV: + argval = (rt_uint32_t) arg; + if(argval != RT_CAN_MODE_PRIV || + argval != RT_CAN_MODE_NOPRIV) { + return RT_ERROR; + } + if(argval != can->config.privmode) + { + can->config.privmode = argval; + return bxcan_set_privmode(pbxcan->reg, argval); + } + break; + case RT_CAN_CMD_GET_STATUS: + { + rt_uint32_t errtype; + errtype = pbxcan->reg->ESR; + can->status.rcverrcnt = errtype >> 24; + can->status.snderrcnt = (errtype >> 16 & 0xFF); + can->status.errcode = errtype & 0x07; + if(arg != &can->status) { + rt_memcpy(arg,&can->status,sizeof(can->status)); + } + } + break; + } + + return RT_EOK; +} +static int sendmsg(struct rt_can_device *can, const void* buf, rt_uint32_t boxno) +{ + CAN_TypeDef* pbxcan; + struct rt_can_msg* pmsg = (struct rt_can_msg*) buf; + + pbxcan= ((struct stm_bxcan *) can->parent.user_data)->reg; + assert_param(IS_CAN_ALL_PERIPH(pbxcan)); + + pbxcan->sTxMailBox[boxno].TIR &= TMIDxR_TXRQ; + if (pmsg->ide == RT_CAN_STDID) + { + assert_param(IS_CAN_STDID(pmsg->id)); + pbxcan->sTxMailBox[boxno].TIR |= ((pmsg->id << 21) | \ + pmsg->rtr); + } + else + { + assert_param(IS_CAN_EXTID(pmsg->id)); + pbxcan->sTxMailBox[boxno].TIR |= ((pmsg->id << 3) | \ + pmsg->ide <<2 | \ + pmsg->rtr); + } + + pmsg->len &= (uint8_t)0x0000000F; + pbxcan->sTxMailBox[boxno].TDTR &= (uint32_t)0xFFFFFFF0; + pbxcan->sTxMailBox[boxno].TDTR |= pmsg->len; + + pbxcan->sTxMailBox[boxno].TDLR = (((uint32_t)pmsg->data[3] << 24) | + ((uint32_t)pmsg->data[2] << 16) | + ((uint32_t)pmsg->data[1] << 8) | + ((uint32_t)pmsg->data[0])); + if(pmsg->len > 4) { + pbxcan->sTxMailBox[boxno].TDHR = (((uint32_t)pmsg->data[7] << 24) | + ((uint32_t)pmsg->data[6] << 16) | + ((uint32_t)pmsg->data[5] << 8) | + ((uint32_t)pmsg->data[4])); + } + pbxcan->sTxMailBox[boxno].TIR |= TMIDxR_TXRQ; + + return RT_EOK; +} +static int recvmsg(struct rt_can_device *can, void* buf, rt_uint32_t boxno) +{ + CAN_TypeDef* pbxcan; + struct rt_can_msg* pmsg = (struct rt_can_msg*) buf; + + pbxcan= ((struct stm_bxcan *) can->parent.user_data)->reg; + assert_param(IS_CAN_ALL_PERIPH(pbxcan)); + assert_param(IS_CAN_FIFO(boxno)); + pmsg->ide = ((uint8_t)0x04 & pbxcan->sFIFOMailBox[boxno].RIR)>>2; + if (pmsg->ide == CAN_Id_Standard) + { + pmsg->id = (uint32_t)0x000007FF & (pbxcan->sFIFOMailBox[boxno].RIR >> 21); + } + else + { + pmsg->id = (uint32_t)0x1FFFFFFF & (pbxcan->sFIFOMailBox[boxno].RIR >> 3); + } + + pmsg->rtr = (uint8_t)0x02 & pbxcan->sFIFOMailBox[boxno].RIR; + pmsg->len = (uint8_t)0x0F & pbxcan->sFIFOMailBox[boxno].RDTR; + pmsg->data[0] = (uint8_t)0xFF & pbxcan->sFIFOMailBox[boxno].RDLR; + pmsg->data[1] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDLR >> 8); + pmsg->data[2] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDLR >> 16); + pmsg->data[3] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDLR >> 24); + if(pmsg->len > 4) { + pmsg->data[4] = (uint8_t)0xFF & pbxcan->sFIFOMailBox[boxno].RDHR; + pmsg->data[5] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDHR >> 8); + pmsg->data[6] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDHR >> 16); + pmsg->data[7] = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDHR >> 24); + } + pmsg->hdr = (uint8_t)0xFF & (pbxcan->sFIFOMailBox[boxno].RDTR >> 8); + if(boxno) pmsg->hdr += ((struct stm_bxcan *) can->parent.user_data)->fifo1filteroff * 4; + return RT_EOK; +} + +static const struct rt_can_ops canops = +{ + configure, + control, + sendmsg, + recvmsg, +}; +#ifdef USING_BXCAN1 +#ifdef RT_CAN_USING_LED +static struct rt_can_led can1rcvled = +{ + CANRT1,PIN_MODE_OUTPUT_OD,1, +}; +static struct rt_can_led can1errled = +{ + CANERR1,PIN_MODE_OUTPUT_OD,1, +}; +#endif +static struct stm_bxcan bxcan1data = +{ + .reg = CAN1, + .mfrbase = (void*)&CAN1->sFilterRegister[0], + .sndirq = CAN1_TX_IRQn, + .rcvirq0 = CAN1_RX0_IRQn, + .rcvirq1 = CAN1_RX1_IRQn, + .errirq = CAN1_SCE_IRQn, + .alocmask = {0,0}, + .filtercnt = BX_CAN2_FMRSTART, + .fifo1filteroff = 7, + .filtermap = { + [0] = { + .id32mask_cnt = 0, + .id32bit_cnt = 0, + .id16mask_cnt = 2, + .id16bit_cnt =24, + }, + [1] = { + .id32mask_cnt = 0, + .id32bit_cnt = 0, + .id16mask_cnt = 2, + .id16bit_cnt =24, + }, + }, +}; +struct rt_can_device bxcan1; +void CAN1_RX0_IRQHandler(void) +{ + while(CAN1->RF0R & 0x11) + { + if ((CAN1->RF0R & CAN_RF0R_FOVR0) != 0) + { + CAN1->RF0R = CAN_RF0R_FOVR0; + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_RXOF_IND | 0<<8); + } else { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_RX_IND | 0<<8); + } + CAN1->RF0R |= CAN_RF0R_RFOM0; + } +} +void CAN1_RX1_IRQHandler(void) +{ + while(CAN1->RF1R & 0x11) + { + if ((CAN1->RF1R & CAN_RF1R_FOVR1) != 0) + { + CAN1->RF1R = CAN_RF1R_FOVR1; + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_RXOF_IND | 1<<8); + } else { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_RX_IND | 1<<8); + } + CAN1->RF1R |= CAN_RF1R_RFOM1; + } +} +void CAN1_TX_IRQHandler(void) +{ + rt_uint32_t state; + if(CAN1->TSR & (CAN_TSR_RQCP0)) + { + state = CAN1->TSR & (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0); + CAN1->TSR |= CAN_TSR_RQCP0; + if(state == (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0)) + { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_DONE | 0<<8); + } else { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_FAIL | 0<<8); + } + } + if(CAN1->TSR & (CAN_TSR_RQCP1)) { + state = CAN1->TSR & (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1); + CAN1->TSR |= CAN_TSR_RQCP1; + if(state == (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1)) + { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_DONE | 1<<8); + } else { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_FAIL | 1<<8); + } + } + if(CAN1->TSR & (CAN_TSR_RQCP2)) { + state = CAN1->TSR & (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2); + CAN1->TSR |= CAN_TSR_RQCP2; + if(state == (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2)) + { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_DONE | 2<<8); + } else { + rt_hw_can_isr(&bxcan1,RT_CAN_EVENT_TX_FAIL | 2<<8); + } + } +} +void CAN1_SCE_IRQHandler(void) +{ + rt_uint32_t errtype; + errtype = CAN1->ESR; + if(errtype & 0x70 && bxcan1.status.lasterrtype == (errtype & 0x70)) { + switch((errtype & 0x70)>>4) { + case RT_CAN_BUS_BIT_PAD_ERR: + bxcan1.status.bitpaderrcnt++; + break; + case RT_CAN_BUS_FORMAT_ERR: + bxcan1.status.formaterrcnt++; + break; + case RT_CAN_BUS_ACK_ERR: + bxcan1.status.ackerrcnt++; + break; + case RT_CAN_BUS_IMPLICIT_BIT_ERR: + case RT_CAN_BUS_EXPLICIT_BIT_ERR: + bxcan1.status.biterrcnt++; + break; + case RT_CAN_BUS_CRC_ERR: + bxcan1.status.crcerrcnt++; + break; + } + bxcan1.status.lasterrtype = errtype & 0x70; + CAN1->ESR &= ~0x70; + } + bxcan1.status.rcverrcnt = errtype >> 24; + bxcan1.status.snderrcnt = (errtype >> 16 & 0xFF); + bxcan1.status.errcode = errtype & 0x07; + CAN1->MSR |= CAN_MSR_ERRI; +} +#endif /*USING_BXCAN1*/ + +#ifdef USING_BXCAN2 +#ifdef RT_CAN_USING_LED +static struct rt_can_led can2rcvled = +{ + CANRT2,PIN_MODE_OUTPUT_OD,1, +}; +static struct rt_can_led can2errled = +{ + CANERR2,PIN_MODE_OUTPUT_OD,1, +}; +#endif +static struct stm_bxcan bxcan2data = +{ + .reg = CAN2, + .mfrbase = (void*)&CAN1->sFilterRegister[BX_CAN2_FMRSTART], + .sndirq = CAN2_TX_IRQn, + .rcvirq0 = CAN2_RX0_IRQn, + .rcvirq1 = CAN2_RX1_IRQn, + .errirq = CAN2_SCE_IRQn, + .alocmask = {0,0}, + .filtercnt = BX_CAN_FMRNUMBER - BX_CAN2_FMRSTART, + .fifo1filteroff = 7, + .filtermap = { + [0] = { + .id32mask_cnt = 0, + .id32bit_cnt = 0, + .id16mask_cnt = 2, + .id16bit_cnt =24, + }, + [1] = { + .id32mask_cnt = 0, + .id32bit_cnt = 0, + .id16mask_cnt = 2, + .id16bit_cnt =24, + }, + }, +}; + +struct rt_can_device bxcan2; +void CAN2_RX0_IRQHandler(void) +{ + while(CAN2->RF0R & 0x11) + { + if ((CAN2->RF0R & CAN_RF0R_FOVR0) != 0) + { + CAN2->RF0R = CAN_RF0R_FOVR0; + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_RXOF_IND | 0<<8); + } else { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_RX_IND | 0<<8); + } + CAN2->RF0R |= CAN_RF0R_RFOM0; + } +} +void CAN2_RX1_IRQHandler(void) +{ + while(CAN2->RF1R & 0x11) + { + if ((CAN2->RF1R & CAN_RF1R_FOVR1) != 0) + { + CAN2->RF1R = CAN_RF1R_FOVR1; + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_RXOF_IND | 1<<8); + } else { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_RX_IND | 1<<8); + } + CAN2->RF1R |= CAN_RF1R_RFOM1; + } +} +void CAN2_TX_IRQHandler(void) +{ + rt_uint32_t state; + if(CAN2->TSR & (CAN_TSR_RQCP0)) + { + state = CAN2->TSR & (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0); + CAN2->TSR |= CAN_TSR_RQCP0; + if(state == (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0)) + { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_DONE | 0<<8); + } else { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_FAIL | 0<<8); + } + } + if(CAN2->TSR & (CAN_TSR_RQCP1)) { + state = CAN2->TSR & (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1); + CAN2->TSR |= CAN_TSR_RQCP1; + if(state == (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1)) + { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_DONE | 1<<8); + } else { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_FAIL | 1<<8); + } + } + if(CAN2->TSR & (CAN_TSR_RQCP2)) { + state = CAN2->TSR & (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2); + CAN2->TSR |= CAN_TSR_RQCP2; + if(state == (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2)) + { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_DONE | 2<<8); + } else { + rt_hw_can_isr(&bxcan2,RT_CAN_EVENT_TX_FAIL | 2<<8); + } + } +} +void CAN2_SCE_IRQHandler(void) +{ + rt_uint32_t errtype; + errtype = CAN2->ESR; + if(errtype & 0x70 && bxcan2.status.lasterrtype == (errtype & 0x70)) { + switch((errtype & 0x70)>>4) { + case RT_CAN_BUS_BIT_PAD_ERR: + bxcan2.status.bitpaderrcnt++; + break; + case RT_CAN_BUS_FORMAT_ERR: + bxcan2.status.formaterrcnt++; + break; + case RT_CAN_BUS_ACK_ERR: + bxcan2.status.ackerrcnt++; + break; + case RT_CAN_BUS_IMPLICIT_BIT_ERR: + case RT_CAN_BUS_EXPLICIT_BIT_ERR: + bxcan2.status.biterrcnt++; + break; + case RT_CAN_BUS_CRC_ERR: + bxcan2.status.crcerrcnt++; + break; + } + bxcan2.status.lasterrtype = errtype & 0x70; + CAN2->ESR &= ~0x70; + } + bxcan2.status.rcverrcnt = errtype >> 24; + bxcan2.status.snderrcnt = (errtype >> 16 & 0xFF); + bxcan2.status.errcode = errtype & 0x07; + CAN2->MSR |= CAN_MSR_ERRI; +} +#endif /*USING_BXCAN2*/ + +int stm32_bxcan_init(void) +{ + +#ifdef USING_BXCAN1 + bxcan1.config.baud_rate=CAN1MBaud; + bxcan1.config.msgboxsz=16; + bxcan1.config.sndboxnumber=3; + bxcan1.config.mode=RT_CAN_MODE_NORMAL; + bxcan1.config.privmode=0; + #ifdef RT_CAN_USING_LED + bxcan1.config.rcvled = &can1rcvled; + bxcan1.config.sndled = RT_NULL; + bxcan1.config.errled = &can1errled; + #endif + bxcan1.config.ticks = 50; +#ifdef RT_CAN_USING_HDR + bxcan1.config.maxhdr = BX_CAN2_FMRSTART * 4; +#endif + rt_hw_can_register(&bxcan1, "bxcan1", &canops, &bxcan1data); +#endif + +#ifdef USING_BXCAN2 + bxcan2.config.baud_rate=CAN1MBaud; + bxcan2.config.msgboxsz=16; + bxcan2.config.sndboxnumber=3; + bxcan2.config.mode=RT_CAN_MODE_NORMAL; + bxcan2.config.privmode=0; + #ifdef RT_CAN_USING_LED + bxcan2.config.rcvled = &can2rcvled; + bxcan2.config.sndled = RT_NULL; + bxcan2.config.errled = &can2errled; + #endif + bxcan2.config.ticks = 50; +#ifdef RT_CAN_USING_HDR + bxcan2.config.maxhdr = (BX_CAN_FMRNUMBER - BX_CAN2_FMRSTART) * 4; +#endif + rt_hw_can_register(&bxcan2, "bxcan2", &canops, &bxcan2data); +#endif + return RT_EOK; +} +INIT_BOARD_EXPORT(stm32_bxcan_init); + +#endif /*RT_USING_CAN2*/ diff --git a/bsp/stm32f10x/drivers/bxcan.h b/bsp/stm32f10x/drivers/bxcan.h new file mode 100644 index 0000000000..60ee996a3c --- /dev/null +++ b/bsp/stm32f10x/drivers/bxcan.h @@ -0,0 +1,16 @@ +/* + * File : bxcan.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + */ + +#ifndef BXCAN_H_ +#define BXCAN_H_ +#endif /*BXCAN_H_*/ diff --git a/components/drivers/can/can.c b/components/drivers/can/can.c new file mode 100644 index 0000000000..3d31409756 --- /dev/null +++ b/components/drivers/can/can.c @@ -0,0 +1,906 @@ +/* + * File : can.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + */ +#include +#include +#include + +static rt_err_t rt_can_init(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* initialize rx/tx */ + can->can_rx = RT_NULL; + can->can_tx = RT_NULL; + + /* apply configuration */ + if (can->ops->configure) + result = can->ops->configure(can, &can->config); + + return result; +} +/* + * can interrupt routines + */ +rt_inline int _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_rx_fifo* rx_fifo; + + RT_ASSERT(can != RT_NULL); + size = msgs; + + rx_fifo = (struct rt_can_rx_fifo*) can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + /* read from software FIFO */ + while (msgs) + { + rt_base_t level; + struct rt_can_msg_list *listmsg=RT_NULL; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); +#ifdef RT_CAN_USING_HDR + rt_int32_t hdr = data->hdr; + if (hdr >=0 && can->hdr && hdr < can->config.maxhdr && !rt_list_isempty(&can->hdr[hdr].list)) + { + listmsg=rt_list_entry(can->hdr[hdr].list.next, struct rt_can_msg_list, hdrlist); + rt_list_remove(&listmsg->list); + rt_list_remove(&listmsg->hdrlist); + if(can->hdr[hdr].msgs) { + can->hdr[hdr].msgs--; + } + listmsg->owner = RT_NULL; + } else +#endif /*RT_CAN_USING_HDR*/ + if (!rt_list_isempty(&rx_fifo->uselist)) + { + listmsg=rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list); + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif + } + else + { + /* no data, enable interrupt and break out */ + rt_hw_interrupt_enable(level); + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + if(listmsg!=RT_NULL) + { + rt_memcpy(data,&listmsg->data,sizeof(struct rt_can_msg)); + level = rt_hw_interrupt_disable(); + rt_list_insert_before(&rx_fifo->freelist,&listmsg->list); + rx_fifo->freenumbers++; + RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz); + rt_hw_interrupt_enable(level); + listmsg = RT_NULL; + } + data ++; msgs -= sizeof(struct rt_can_msg); + } + + return (size - msgs); +} + +rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_tx_fifo *tx_fifo; + + RT_ASSERT(can != RT_NULL); + + size = msgs; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + + while (msgs) + { + rt_base_t level; + rt_uint32_t no; + struct rt_can_sndbxinx_list* tx_tosnd = RT_NULL; + level = rt_hw_interrupt_disable(); + if(!rt_list_isempty(&tx_fifo->freelist)) + { + tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list); + RT_ASSERT(tx_tosnd != RT_NULL); + rt_list_remove(&tx_tosnd->list); + } else { + rt_hw_interrupt_enable(level); + rt_completion_wait(&(tx_fifo->completion), RT_WAITING_FOREVER); + continue; + } + rt_hw_interrupt_enable(level); + no=((rt_uint32_t)tx_tosnd-(rt_uint32_t)tx_fifo->buffer)/sizeof(struct rt_can_sndbxinx_list); + tx_tosnd->result = RT_CAN__SND_RESUTL_WAIT; + if (can->ops->sendmsg(can, data ,no)) + { + level = rt_hw_interrupt_disable(); + rt_list_insert_after(&tx_fifo->freelist,&tx_tosnd->list); + rt_hw_interrupt_enable(level); + continue; + } + can->status.sndchange = 1; + rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER); + level = rt_hw_interrupt_disable(); + rt_uint32_t result = tx_tosnd->result; + if(!rt_list_isempty(&tx_tosnd->list)) { + rt_list_remove(&tx_tosnd->list); + } + rt_list_insert_before(&tx_fifo->freelist,&tx_tosnd->list); + rt_hw_interrupt_enable(level); + + if(result == RT_CAN__SND_RESUTL_OK) + { + level = rt_hw_interrupt_disable(); + can->status.sndpkg++; + rt_hw_interrupt_enable(level); + data ++; msgs -= sizeof(struct rt_can_msg); + if(!msgs) break; + } + else + { + level = rt_hw_interrupt_disable(); + can->status.dropedsndpkg++; + rt_hw_interrupt_enable(level); + break; + } + + level = rt_hw_interrupt_disable(); + if(rt_list_isempty(&tx_fifo->freelist)) + { + rt_hw_interrupt_enable(level); + rt_completion_done(&(tx_fifo->completion)); + } + else + { + rt_hw_interrupt_enable(level); + } + } + + return (size - msgs); +} +rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs) +{ + int size; + struct rt_can_tx_fifo *tx_fifo; + + RT_ASSERT(can != RT_NULL); + + size = msgs; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_base_t level; + rt_uint32_t no; + rt_uint32_t result; + while (msgs) + { + no = data->priv; + if(no >= can->config.sndboxnumber) { + break; + } + level = rt_hw_interrupt_disable(); + if((tx_fifo->buffer[no].result != RT_CAN__SND_RESUTL_OK)) { + rt_hw_interrupt_enable(level); + rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER); + continue; + } + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_WAIT; + rt_hw_interrupt_enable(level); + if (can->ops->sendmsg(can, data ,no) != RT_EOK) + { + continue; + } + can->status.sndchange = 1; + rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER); + result = tx_fifo->buffer[no].result; + if(result == RT_CAN__SND_RESUTL_OK) + { + level = rt_hw_interrupt_disable(); + can->status.sndpkg++; + rt_hw_interrupt_enable(level); + data ++; msgs -= sizeof(struct rt_can_msg); + if(!msgs) break; + } + else + { + level = rt_hw_interrupt_disable(); + can->status.dropedsndpkg++; + rt_hw_interrupt_enable(level); + break; + } + } + + return (size - msgs); +} +static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* get open flags */ + dev->open_flag = oflag & 0xff; + rt_enter_critical(); + if (can->can_rx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_can_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_can_rx_fifo*) rt_malloc (sizeof(struct rt_can_rx_fifo) + + can->config.msgboxsz * sizeof(struct rt_can_msg_list)); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (struct rt_can_msg_list*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, can->config.msgboxsz * sizeof(struct rt_can_msg_list)); + rt_list_init(&rx_fifo->freelist); + rt_list_init(&rx_fifo->uselist); + rx_fifo->freenumbers=can->config.msgboxsz; + int i = 0; + for(i = 0; i< can->config.msgboxsz; i++) + { + rt_list_insert_before(&rx_fifo->freelist,&rx_fifo->buffer[i].list); +#ifdef RT_CAN_USING_HDR + rt_list_init(&rx_fifo->buffer[i].hdrlist); + rx_fifo->buffer[i].owner = RT_NULL; +#endif + } + can->can_rx = rx_fifo; + rt_exit_critical(); + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + else + { + can->can_rx = RT_NULL; + rt_exit_critical(); + } + } else { + rt_exit_critical(); + } + rt_enter_critical(); + if (can->can_tx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_can_tx_fifo *tx_fifo; + + tx_fifo = (struct rt_can_tx_fifo*) rt_malloc(sizeof(struct rt_can_tx_fifo)+ + can->config.sndboxnumber*sizeof(struct rt_can_sndbxinx_list)); + RT_ASSERT(tx_fifo != RT_NULL); + tx_fifo->buffer = (struct rt_can_sndbxinx_list *) (tx_fifo + 1); + rt_memset(tx_fifo->buffer, 0, + can->config.sndboxnumber*sizeof(struct rt_can_sndbxinx_list)); + rt_list_init(&tx_fifo->freelist); + int i = 0; + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_list_insert_before(&tx_fifo->freelist,&tx_fifo->buffer[i].list); + rt_completion_init(&(tx_fifo->buffer[i].completion)); + tx_fifo->buffer[i].result = RT_CAN__SND_RESUTL_OK; + } + rt_completion_init(&(tx_fifo->completion)); + can->can_tx = tx_fifo; + rt_exit_critical(); + dev->open_flag |= RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); + } + else + { + can->can_tx = RT_NULL; + rt_exit_critical(); + } + } else { + rt_exit_critical(); + } + can->ops->control(can, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_CAN_INT_ERR); +#ifdef RT_CAN_USING_HDR + rt_enter_critical(); + if(can->hdr == RT_NULL) { + struct rt_can_hdr * phdr; + phdr = (struct rt_can_hdr *) rt_malloc(can->config.maxhdr*sizeof(struct rt_can_hdr)); + RT_ASSERT(phdr != RT_NULL); + rt_memset(phdr, 0,can->config.maxhdr*sizeof(struct rt_can_hdr)); + int i = 0; + for(i = 0; i< can->config.maxhdr; i++) + { + rt_list_init(&phdr[i].list); + } + can->hdr = phdr; + rt_exit_critical(); + } else { + rt_exit_critical(); + } +#endif + rt_enter_critical(); + if(!can->timerinitflag) { + can->timerinitflag = 1; + rt_exit_critical(); + #ifdef RT_CAN_USING_LED + if(can->config.rcvled != RT_NULL) { + rt_pin_mode(can->config.rcvled->pin,can->config.rcvled->mode); + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + if(can->config.sndled != RT_NULL) { + rt_pin_mode(can->config.sndled->pin,can->config.sndled->mode); + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + if(can->config.errled != RT_NULL) { + rt_pin_mode(can->config.errled->pin,can->config.errled->mode); + rt_pin_write(can->config.errled->pin,can->config.errled->init); + } + #endif + rt_timer_start(&can->timer); + } else { + rt_exit_critical(); + } + return RT_EOK; +} + +static rt_err_t rt_can_close(struct rt_device *dev) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + /* this device has more reference count */ + if (dev->ref_count > 1) return RT_EOK; + rt_enter_critical(); + if(can->timerinitflag) { + can->timerinitflag = 0; + rt_exit_critical(); + rt_timer_stop(&can->timer); + #ifdef RT_CAN_USING_LED + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + rt_pin_write(can->config.rcvled->pin,can->config.sndled->init); + rt_pin_write(can->config.rcvled->pin,can->config.errled->init); + #endif + } else { + rt_exit_critical(); + } + rt_enter_critical(); + can->status_indicate.ind = RT_NULL; + can->status_indicate.args = RT_NULL; + rt_exit_critical(); +#ifdef RT_CAN_USING_HDR + rt_enter_critical(); + if(can->hdr != RT_NULL) { + rt_free(can->hdr); + can->hdr = RT_NULL; + rt_exit_critical(); + } else { + rt_exit_critical(); + } +#endif + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_can_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_can_rx_fifo*)can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + rt_free(rx_fifo); + dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_can_tx_fifo* tx_fifo; + + tx_fifo = (struct rt_can_tx_fifo*)can->can_rx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_free(tx_fifo); + dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + can->ops->control(can, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_CAN_INT_ERR); + return RT_EOK; +} + +static rt_size_t rt_can_read(struct rt_device *dev, + rt_off_t pos, + void *buffer, + rt_size_t size) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + can = (struct rt_can_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + return _can_int_rx(can, buffer, size); + } + return 0; +} + +static rt_size_t rt_can_write(struct rt_device *dev, + rt_off_t pos, + const void *buffer, + rt_size_t size) +{ + struct rt_can_device *can; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + can = (struct rt_can_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + if(can->config.privmode) { + return _can_int_tx_priv(can, buffer, size); + } else { + return _can_int_tx(can, buffer, size); + } + } + return 0; +} + +static rt_err_t rt_can_control(struct rt_device *dev, + rt_uint8_t cmd, + void *args) +{ + struct rt_can_device *can; + rt_err_t res; + + RT_ASSERT(dev != RT_NULL); + can = (struct rt_can_device *)dev; + + switch (cmd) + { + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_CONFIG: + /* configure device */ + can->ops->configure(can, (struct can_configure *)args); + break; + case RT_CAN_CMD_SET_PRIV: + /* configure device */ + if((rt_uint32_t)args != can->config.privmode) { + if(res = can->ops->control(can, cmd, args) != RT_EOK) { + return res; + } + struct rt_can_tx_fifo* tx_fifo; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + int i; + rt_base_t level; + if(can->config.privmode) { + rt_completion_done(&(tx_fifo->completion)); + level = rt_hw_interrupt_disable(); + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_list_remove(&tx_fifo->buffer[i].list); + } + rt_hw_interrupt_enable(level); + } else { + for(i = 0; i< can->config.sndboxnumber; i++) + { + rt_base_t level; + level = rt_hw_interrupt_disable(); + if(tx_fifo->buffer[i].result == RT_CAN__SND_RESUTL_OK) { + rt_list_insert_before(&tx_fifo->freelist,&tx_fifo->buffer[i].list); + } + rt_hw_interrupt_enable(level); + } + } + return RT_EOK; + } + break; + case RT_CAN_CMD_SET_STATUS_IND: + can->status_indicate.ind = ((rt_can_status_ind_type_t)args)->ind; + can->status_indicate.args = ((rt_can_status_ind_type_t)args)->args; + break; +#ifdef RT_CAN_USING_HDR + case RT_CAN_CMD_SET_FILTER: + res = can->ops->control(can, cmd, args); + if(res != RT_EOK || can->hdr == RT_NULL) { + return res; + } + { + struct rt_can_filter_config* pfilter; + struct rt_can_filter_item* pitem; + rt_uint32_t count; + rt_base_t level; + pfilter = (struct rt_can_filter_config*)args; + count = pfilter->count; + pitem = pfilter->items; + if(pfilter->actived) { + while(count) { + if(pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) { + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + if(!can->hdr[pitem->hdr].connected) { + rt_memcpy(&can->hdr[pitem->hdr].filter,pitem, + sizeof(struct rt_can_filter_item)); + can->hdr[pitem->hdr].connected = 1; + can->hdr[pitem->hdr].msgs = 0; + rt_list_init(&can->hdr[pitem->hdr].list); + } + rt_hw_interrupt_enable(level); + count--; + pitem++; + } + } else { + while(count) { + if(pitem->hdr >= can->config.maxhdr || pitem->hdr < 0) { + count--; + pitem++; + continue; + } + level = rt_hw_interrupt_disable(); + if(can->hdr[pitem->hdr].connected) { + rt_memset(&can->hdr[pitem->hdr].filter,0, + sizeof(struct rt_can_filter_item)); + can->hdr[pitem->hdr].connected = 0; + can->hdr[pitem->hdr].msgs = 0; + if(!rt_list_isempty(&can->hdr[pitem->hdr].list)) + { + rt_list_remove(can->hdr[pitem->hdr].list.next); + } + } + rt_hw_interrupt_enable(level); + count--; + pitem++; + } + } + } + break; +#endif /*RT_CAN_USING_HDR*/ + default : + /* control device */ + if(can->ops->control != RT_NULL) + { + can->ops->control(can, cmd, args); + } + break; + } + + return RT_EOK; +} +/* + * can timer + */ +static void cantimeout(void* arg) +{ + rt_uint32_t ledonflag = 0; + rt_can_t can = (rt_can_t)arg; + rt_device_control((rt_device_t)can,RT_CAN_CMD_GET_STATUS,(void* )&can->status); + if(can->timerinitflag == 1) { + ledonflag = 1; + can->timerinitflag = 0xFF; + } + #ifdef RT_CAN_USING_LED + if(can->config.rcvled != RT_NULL && can->config.sndled == RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init?0:1); + } else { + if(can->status.rcvchange == 1 || can->status.sndchange == 1) + { + can->status.rcvchange = 0; + can->status.sndchange = 0; + rt_pin_write(can->config.rcvled->pin,rt_pin_read(can->config.rcvled->pin)?0:1); + } else { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + } + } else if(can->config.rcvled != RT_NULL && can->config.sndled != RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init?0:1); + rt_pin_write(can->config.sndled->pin,can->config.sndled->init?0:1); + } else { + if(can->status.rcvchange == 1) + { + can->status.rcvchange = 0; + rt_pin_write(can->config.rcvled->pin,rt_pin_read(can->config.rcvled->pin)?0:1); + } else { + rt_pin_write(can->config.rcvled->pin,can->config.rcvled->init); + } + if(can->status.sndchange == 1) + { + can->status.sndchange = 0; + rt_pin_write(can->config.sndled->pin,rt_pin_read(can->config.sndled->pin)?0:1); + } else { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + } + } else if(can->config.rcvled == RT_NULL && can->config.sndled != RT_NULL) { + if(ledonflag == 1) { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init?0:1); + } else { + if(can->status.rcvchange == 1 || can->status.sndchange == 1) + { + can->status.rcvchange = 0; + can->status.sndchange = 0; + rt_pin_write(can->config.sndled->pin,rt_pin_read(can->config.sndled->pin)?0:1); + } else { + rt_pin_write(can->config.sndled->pin,can->config.sndled->init); + } + } + } + if(ledonflag == 1) { + rt_pin_write(can->config.errled->pin,can->config.errled->init?0:1); + } else { + if(can->status.errcode) { + rt_pin_write(can->config.errled->pin,can->config.errled->init?0:1); + } else { + rt_pin_write(can->config.errled->pin,can->config.errled->init); + } + } + #endif + if(can->status_indicate.ind != RT_NULL) + { + can->status_indicate.ind(can,can->status_indicate.args); + } +} + +/* + * can register + */ +rt_err_t rt_hw_can_register(struct rt_can_device *can, + const char *name, + const struct rt_can_ops *ops, + void *data) +{ + struct rt_device *device; + RT_ASSERT(can != RT_NULL); + + device = &(can->parent); + + device->type = RT_Device_Class_CAN; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; +#ifdef RT_CAN_USING_HDR + can->hdr = RT_NULL; +#endif + can->can_rx = RT_NULL; + can->can_tx = RT_NULL; + device->init = rt_can_init; + device->open = rt_can_open; + device->close = rt_can_close; + device->read = rt_can_read; + device->write = rt_can_write; + device->control = rt_can_control; + can->ops = ops; + + can->status_indicate.ind = RT_NULL; + can->status_indicate.args = RT_NULL; + rt_memset(&can->status,0,sizeof(can->status)); + + device->user_data = data; + can->timerinitflag = 0; + if(can->config.rcvled != RT_NULL || + can->config.sndled != RT_NULL || + can->config.errled != RT_NULL) + { + rt_timer_init(&can->timer, + name, + cantimeout, + (void*)can, + can->config.ticks, + RT_TIMER_FLAG_PERIODIC); + } + /* register a character device */ + return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR); +} + +/* ISR for can interrupt */ +void rt_hw_can_isr(struct rt_can_device *can, int event) +{ + switch (event & 0xff) + { + case RT_CAN_EVENT_RXOF_IND: + { + rt_base_t level; + level = rt_hw_interrupt_disable(); + can->status.dropedrcvpkg++; + rt_hw_interrupt_enable(level); + } + case RT_CAN_EVENT_RX_IND: + { + struct rt_can_msg tmpmsg; + struct rt_can_rx_fifo* rx_fifo; + struct rt_can_msg_list* listmsg=RT_NULL; +#ifdef RT_CAN_USING_HDR + rt_int32_t hdr; +#endif + int ch = -1; + rt_base_t level; + rx_fifo = (struct rt_can_rx_fifo*)can->can_rx; + RT_ASSERT(rx_fifo != RT_NULL); + /* interrupt mode receive */ + RT_ASSERT(can->parent.open_flag & RT_DEVICE_FLAG_INT_RX); + + rt_uint32_t no; + no = event >> 8; + ch = can->ops->recvmsg(can,&tmpmsg,no); + if (ch == -1) break; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + can->status.rcvpkg++; + can->status.rcvchange = 1; + if(!rt_list_isempty(&rx_fifo->freelist)) + { + listmsg = rt_list_entry(rx_fifo->freelist.next, struct rt_can_msg_list, list); + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif /*RT_CAN_USING_HDR*/ + RT_ASSERT(rx_fifo->freenumbers >0); + rx_fifo->freenumbers--; + } else if(!rt_list_isempty(&rx_fifo->uselist)) { + listmsg = rt_list_entry(rx_fifo->uselist.next, struct rt_can_msg_list, list); + can->status.dropedrcvpkg++; + rt_list_remove(&listmsg->list); +#ifdef RT_CAN_USING_HDR + rt_list_remove(&listmsg->hdrlist); + if(listmsg->owner != RT_NULL && listmsg->owner->msgs) { + listmsg->owner->msgs--; + } + listmsg->owner = RT_NULL; +#endif + } + /* enable interrupt */ + rt_hw_interrupt_enable(level); + if(listmsg != RT_NULL) { + rt_memcpy(&listmsg->data,&tmpmsg,sizeof(struct rt_can_msg)); + level = rt_hw_interrupt_disable(); + rt_list_insert_before(&rx_fifo->uselist,&listmsg->list); +#ifdef RT_CAN_USING_HDR + hdr = tmpmsg.hdr; + if(can->hdr != RT_NULL) { + RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0); + if(can->hdr[hdr].connected) { + rt_list_insert_before(&can->hdr[hdr].list,&listmsg->hdrlist); + listmsg->owner = &can->hdr[hdr]; + can->hdr[hdr].msgs++; + } + + } +#endif + rt_hw_interrupt_enable(level); + } + + /* invoke callback */ +#ifdef RT_CAN_USING_HDR + if(can->hdr != RT_NULL && can->hdr[hdr].connected && can->hdr[hdr].filter.ind) { + RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0); + rt_size_t rx_length; + level = rt_hw_interrupt_disable(); + rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg); + rt_hw_interrupt_enable(level); + can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length); + + } else +#endif + if (can->parent.rx_indicate != RT_NULL) { + rt_size_t rx_length; + /* get rx length */ + level = rt_hw_interrupt_disable(); + rx_length = rx_fifo->freenumbers*sizeof(struct rt_can_msg); + rt_hw_interrupt_enable(level); + + can->parent.rx_indicate(&can->parent, rx_length); + } + break; + } + case RT_CAN_EVENT_TX_DONE: + case RT_CAN_EVENT_TX_FAIL: + { + struct rt_can_tx_fifo* tx_fifo; + rt_uint32_t no; + no = event >> 8; + tx_fifo = (struct rt_can_tx_fifo*) can->can_tx; + RT_ASSERT(tx_fifo != RT_NULL); + if((event & 0xff) == RT_CAN_EVENT_TX_DONE) { + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_OK; + } else { + tx_fifo->buffer[no].result = RT_CAN__SND_RESUTL_ERR; + } + rt_completion_done(&(tx_fifo->buffer[no].completion)); + break; + } + } +} +#ifdef RT_USING_FINSH +#include +int cmd_canstat(int argc,void** argv) +{ + static const char* ErrCode[] = { + "No Error!", + "Warning !", + "Passive !", + "Bus Off !" + }; + if(argc >= 2) { + rt_device_t candev = rt_device_find(argv[1]); + if(!candev) { + rt_kprintf(" Can't find can device %s\n",argv[1]); + return -1; + } + rt_kprintf(" Finded can device: %s...",argv[1]); + struct rt_can_status status; + rt_device_control(candev,RT_CAN_CMD_GET_STATUS,&status); + rt_kprintf("\n Receive...error..count: %010ld. Send.....error....count: %010ld.", + status.rcverrcnt,status.snderrcnt); + rt_kprintf("\n Bit..pad..error..count: %010ld. Format...error....count: %010ld", + status.bitpaderrcnt,status.formaterrcnt); + rt_kprintf("\n Ack.......error..count: %010ld. Bit......error....count: %010ld.", + status.ackerrcnt,status.biterrcnt); + rt_kprintf("\n CRC.......error..count: %010ld. Error.code.[%010ld]: ", + status.crcerrcnt,status.errcode); + switch(status.errcode) { + case 0: + rt_kprintf("%s.",ErrCode[0]); + break; + case 1: + rt_kprintf("%s.",ErrCode[1]); + break; + case 2: + case 3: + rt_kprintf("%s.",ErrCode[2]); + break; + case 4: + case 5: + case 6: + case 7: + rt_kprintf("%s.",ErrCode[3]); + break; + } + rt_kprintf("\n Total.receive.packages: %010ld. Droped.receive.packages: %010ld.", + status.rcvpkg,status.dropedrcvpkg); + rt_kprintf("\n Total..send...packages: %010ld. Droped...send..packages: %010ld.\n", + status.sndpkg + status.dropedsndpkg,status.dropedsndpkg); + } else { + rt_kprintf(" Invalid Call %s\n",argv[0]); + rt_kprintf(" Please using %s cannamex .Here canname is driver name and x is candrive number.\n",argv[0]); + } + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_canstat, __cmd_canstat, Stat Can Device Status.); +#endif diff --git a/components/drivers/include/drivers/can.h b/components/drivers/include/drivers/can.h new file mode 100644 index 0000000000..0bd4106ee0 --- /dev/null +++ b/components/drivers/include/drivers/can.h @@ -0,0 +1,292 @@ +/* + * File : can.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + */ +#ifndef CAN_H_ +#define CAN_H_ + +#ifndef RT_CANMSG_BOX_SZ +#define RT_CANMSG_BOX_SZ 16 +#endif +#ifndef RT_CANSND_BOX_NUM +#define RT_CANSND_BOX_NUM 1 +#endif + +enum CANBAUD +{ + CAN1MBaud=0, // 1 MBit/sec + CAN800kBaud, // 800 kBit/sec + CAN500kBaud, // 500 kBit/sec + CAN250kBaud, // 250 kBit/sec + CAN125kBaud, // 125 kBit/sec + CAN100kBaud, // 100 kBit/sec + CAN50kBaud, // 50 kBit/sec + CAN20kBaud, // 20 kBit/sec + CAN10kBaud // 10 kBit/sec +}; +#define RT_CAN_MODE_NORMAL 0 +#define RT_CAN_MODE_LISEN 1 +#define RT_CAN_MODE_LOOPBACK 2 +#define RT_CAN_MODE_LOOPBACKANLISEN 3 + +#define RT_CAN_MODE_PRIV 0x01 +#define RT_CAN_MODE_NOPRIV 0x00 + +#ifdef RT_CAN_USING_LED +struct rt_can_led +{ + rt_uint32_t pin,mode,init; + struct rt_timer* timer; + const char* timer_name; +}; +#endif /*RT_CAN_USING_LED*/ + +struct rt_can_filter_item +{ + rt_uint32_t id :29; + rt_uint32_t ide :1; + rt_uint32_t rtr :1; + rt_uint32_t mode :1; + rt_uint32_t mask; + rt_int32_t hdr; + rt_err_t (*ind)(rt_device_t dev, void* args ,rt_int32_t hdr, rt_size_t size); + void* args; +}; +#ifdef RT_CAN_USING_HDR +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \ + {\ + id,\ + ide,\ + rtr,\ + mode,\ + mask,\ + -1,\ + ind,\ + args,\ + } +#define RT_CAN_FILTER_STD_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args) +#else +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,args) \ + {\ + id,\ + ide,\ + rtr,\ + mode,\ + mask,\ + -1,\ + args,\ + } +#define RT_CAN_FILTER_STD_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,args) +#define RT_CAN_FILTER_EXT_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,args) +#define RT_CAN_STD_RMT_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,args) +#define RT_CAN_EXT_RMT_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,args) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,args) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,args) +#endif + +struct rt_can_filter_config +{ + rt_uint32_t count; + rt_uint32_t actived; + struct rt_can_filter_item* items; +}; +struct can_configure +{ + rt_uint32_t baud_rate; + rt_uint32_t msgboxsz; + rt_uint32_t sndboxnumber; + rt_uint32_t mode :8; + rt_uint32_t privmode :8; + rt_uint32_t reserved :16; + #ifdef RT_CAN_USING_LED + const struct rt_can_led* rcvled; + const struct rt_can_led* sndled; + const struct rt_can_led* errled; + #endif /*RT_CAN_USING_LED*/ + rt_uint32_t ticks; +#ifdef RT_CAN_USING_HDR + rt_uint32_t maxhdr; +#endif +}; + +#define CANDEFAULTCONFIG \ +{\ + CAN1MBaud,\ + RT_CANMSG_BOX_SZ,\ + RT_CANSND_BOX_NUM,\ + RT_CAN_MODE_NORMAL,\ +}; + +struct rt_can_ops; +#define RT_CAN_CMD_SET_FILTER 0x13 +#define RT_CAN_CMD_SET_BAUD 0x14 +#define RT_CAN_CMD_SET_MODE 0x15 +#define RT_CAN_CMD_SET_PRIV 0x16 +#define RT_CAN_CMD_GET_STATUS 0x17 +#define RT_CAN_CMD_SET_STATUS_IND 0x18 + +#define RT_DEVICE_CAN_INT_ERR 0x1000 + +enum RT_CAN_STATUS_MODE +{ + NORMAL = 0, + ERRWARNING = 1, + ERRPASSIVE = 2, + BUSOFF = 4, +}; +enum RT_CAN_BUS_ERR +{ + RT_CAN_BUS_NO_ERR = 0, + RT_CAN_BUS_BIT_PAD_ERR = 1, + RT_CAN_BUS_FORMAT_ERR = 2, + RT_CAN_BUS_ACK_ERR = 3, + RT_CAN_BUS_IMPLICIT_BIT_ERR = 4, + RT_CAN_BUS_EXPLICIT_BIT_ERR = 5, + RT_CAN_BUS_CRC_ERR = 6, +}; +struct rt_can_status +{ + rt_uint32_t rcverrcnt; + rt_uint32_t snderrcnt; + rt_uint32_t errcode; + rt_uint32_t rcvpkg; + rt_uint32_t dropedrcvpkg; + rt_uint32_t sndpkg; + rt_uint32_t dropedsndpkg; + rt_uint32_t bitpaderrcnt; + rt_uint32_t formaterrcnt; + rt_uint32_t ackerrcnt; + rt_uint32_t biterrcnt; + rt_uint32_t crcerrcnt; + rt_uint32_t rcvchange; + rt_uint32_t sndchange; + rt_uint32_t lasterrtype; +}; +#ifdef RT_CAN_USING_HDR +struct rt_can_hdr { + rt_uint32_t connected; + rt_uint32_t msgs; + struct rt_can_filter_item filter; + struct rt_list_node list; +}; +#endif +struct rt_can_device; +typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device*, void*); +typedef struct rt_can_status_ind_type +{ + rt_canstatus_ind ind; + void* args; +} *rt_can_status_ind_type_t; +struct rt_can_device +{ + struct rt_device parent; + + const struct rt_can_ops *ops; + struct can_configure config; + struct rt_can_status status; + rt_uint32_t timerinitflag; + struct rt_timer timer; + struct rt_can_status_ind_type status_indicate; +#ifdef RT_CAN_USING_HDR + struct rt_can_hdr* hdr; +#endif + void *can_rx; + void *can_tx; +}; +typedef struct rt_can_device *rt_can_t; + +#define RT_CAN_STDID 0 +#define RT_CAN_EXTID 1 +#define RT_CAN_DTR 0 +#define RT_CAN_RTR 1 + +typedef struct rt_can_status * rt_can_status_t; +struct rt_can_msg +{ + rt_uint32_t id :29; + rt_uint32_t ide :1; + rt_uint32_t rtr :1; + rt_uint32_t rsv :1; + rt_uint32_t len :8; + rt_uint32_t priv :8; + rt_uint32_t hdr :8; + rt_uint32_t reserved :8; + rt_uint8_t data[8]; +}; +typedef struct rt_can_msg* rt_can_msg_t; +struct rt_can_msg_list { + struct rt_list_node list; +#ifdef RT_CAN_USING_HDR + struct rt_list_node hdrlist; + struct rt_can_hdr* owner; +#endif + struct rt_can_msg data; +}; +struct rt_can_rx_fifo +{ + /* software fifo */ + struct rt_can_msg_list *buffer; + rt_uint32_t freenumbers; + struct rt_list_node freelist; + struct rt_list_node uselist; +}; + +#define RT_CAN__SND_RESUTL_OK 0 +#define RT_CAN__SND_RESUTL_ERR 1 +#define RT_CAN__SND_RESUTL_WAIT 2 + +#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */ +#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */ +#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */ +#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ +#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ + +struct rt_can_sndbxinx_list { + struct rt_list_node list; + struct rt_completion completion; + rt_uint32_t result; +}; +struct rt_can_tx_fifo +{ + struct rt_can_sndbxinx_list *buffer; + struct rt_completion completion; + struct rt_list_node freelist; +}; +struct rt_can_ops +{ + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + int (*sendmsg)(struct rt_can_device *can, const void* buf, rt_uint32_t boxno); + int (*recvmsg)(struct rt_can_device *can,void* buf, rt_uint32_t boxno); +}; +rt_err_t rt_hw_can_register(struct rt_can_device *can, + const char *name, + const struct rt_can_ops *ops, + void *data); +void rt_hw_can_isr(struct rt_can_device *can, int event); +#endif /*_CAN_H*/ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 5d74ed6199..f4d967831c 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -366,6 +366,10 @@ rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_wo #include "drivers/pin.h" #endif +#ifdef RT_USING_CAN +#include "drivers/can.h" +#endif + #ifdef __cplusplus } #endif