/* * 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*/