123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- /*
- * File : drv_can.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date Author Notes
- * 2018-01-06 sundm75 first version
- */
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <board.h>
- #include <rthw.h>
- #include <drv_can.h>
- #include "ls1c.h"
- #include "../libraries/ls1c_public.h"
- #include "../libraries/ls1c_regs.h"
- #include "../libraries/ls1c_clock.h"
- #include "../libraries/ls1c_can.h"
- #include "../libraries/ls1c_pin.h"
- #ifdef RT_USING_CAN
- CanRxMsg RxMessage;
- struct ls1c_bxcan
- {
- CAN_TypeDef *reg;
- void * irq;
- };
- static rt_err_t bxmodifyfilter(struct ls1c_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;
- CAN_TypeDef* CANx;
- CANx = pbxcan->reg;
-
- /*pitem->mode 1-掩码模式; 0- 滤波器模式 SJA1000中使用以下方式*/
- /*SJA1000中AFM 1-单滤波器模式; 0- 双滤波器模式 */
- fcase = pitem->mode;/*1-单滤波器模式; 0- 双滤波器模式*/
- {
- if (!actived)
- {
- return RT_EOK;
- }
- else if (pitem->hdr == -1)
- {
- res = -1;
- if (res != RT_EOK)
- {
- return res;
- }
- }
- else if (pitem->hdr >= 0)
- {
- rt_enter_critical();
- res = RT_EOK;
- if (res != RT_EOK)
- {
- return res;
- }
- hdr = pitem->hdr;
- rt_exit_critical();
- }
- }
- CAN_FilterInitTypeDef CAN_FilterInitStruct;
- unsigned char ide, rtr, id , idmask, mode;
- ide = (unsigned char) pitem->ide;
- rtr = (unsigned char) pitem->rtr;
- id = pitem->id;
- idmask = pitem->mask;
- mode = (unsigned char) pitem->mode;
- CAN_FilterInitStruct.IDE = ide;
- CAN_FilterInitStruct.RTR = rtr;
- CAN_FilterInitStruct.ID = id;
- CAN_FilterInitStruct.IDMASK = idmask;
- CAN_FilterInitStruct.MODE = mode;
- CAN_FilterInit(CANx, &CAN_FilterInitStruct);
-
- return RT_EOK;
- }
- static rt_err_t setfilter(struct ls1c_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 void bxcan0_filter_init(struct rt_can_device *can)
- {
- struct ls1c_bxcan *pbxcan;
- pbxcan = (struct ls1c_bxcan *) can->parent.user_data;
-
- }
- static void bxcan1_filter_init(struct rt_can_device *can)
- {
- struct ls1c_bxcan *pbxcan;
- pbxcan = (struct ls1c_bxcan *) can->parent.user_data;
-
- }
- static void bxcan_init(CAN_TypeDef *pcan, rt_uint32_t baud, rt_uint32_t mode)
- {
- CAN_InitTypeDef CAN_InitStructure;
- Ls1c_CanBPS_t bps ;
- switch(baud)
- {
- case CAN1MBaud:
- bps = LS1C_CAN1MBaud;
- break;
- case CAN800kBaud:
- bps = LS1C_CAN800kBaud;
- break;
- case CAN500kBaud:
- bps = LS1C_CAN500kBaud;
- break;
- case CAN250kBaud:
- bps = LS1C_CAN250kBaud;
- break;
- case CAN125kBaud:
- bps = LS1C_CAN125kBaud;
- break;
- case CAN50kBaud:
- bps = LS1C_CAN40kBaud;
- break;
- default:
- bps = LS1C_CAN250kBaud;
- break;
- }
- switch (mode)
- {
- case RT_CAN_MODE_NORMAL:
- CAN_InitStructure.CAN_Mode = 0x00;
- break;
- case RT_CAN_MODE_LISEN:
- CAN_InitStructure.CAN_Mode = CAN_Mode_LOM;
- break;
- case RT_CAN_MODE_LOOPBACK:
- CAN_InitStructure.CAN_Mode = CAN_Mode_STM;
-
- break;
- case RT_CAN_MODE_LOOPBACKANLISEN:
- CAN_InitStructure.CAN_Mode = CAN_Mode_STM|CAN_Mode_LOM;
- break;
- }
- CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
- switch (bps)
- {
- case LS1C_CAN1MBaud:
- CAN_InitStructure.CAN_Prescaler = 9;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN800kBaud:
- CAN_InitStructure.CAN_Prescaler = 8;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_7tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN500kBaud:
- CAN_InitStructure.CAN_Prescaler = 9;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_11tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN250kBaud:
- CAN_InitStructure.CAN_Prescaler = 36;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN125kBaud:
- CAN_InitStructure.CAN_Prescaler = 36;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_11tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN100kBaud:
- CAN_InitStructure.CAN_Prescaler = 63;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_7tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- case LS1C_CAN50kBaud:
- CAN_InitStructure.CAN_Prescaler = 63;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_16tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
- break;
- default: //250K
- CAN_InitStructure.CAN_Prescaler = 36;
- CAN_InitStructure.CAN_BS1 = CAN_BS1_4tq;
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
- break;
- }
- CAN_Init(pcan, &CAN_InitStructure);
- }
- #ifdef USING_BXCAN0
- static void bxcan0_hw_init(void)
- {
- pin_set_purpose(54, PIN_PURPOSE_OTHER);
- pin_set_purpose(55, PIN_PURPOSE_OTHER);
- pin_set_remap(54, PIN_REMAP_THIRD);
- pin_set_remap(55, PIN_REMAP_THIRD);
- }
- #endif
- #ifdef USING_BXCAN1
- static void bxcan1_hw_init(void)
- {
- pin_set_purpose(56, PIN_PURPOSE_GPIO);
- pin_set_purpose(57, PIN_PURPOSE_GPIO);
- pin_set_remap(56, PIN_REMAP_DEFAULT);
- pin_set_remap(57, PIN_REMAP_DEFAULT);
- }
- #endif
- static rt_err_t configure(struct rt_can_device *can, struct can_configure *cfg)
- {
- CAN_TypeDef *pbxcan;
- pbxcan = ((struct ls1c_bxcan *) can->parent.user_data)->reg;
- if (pbxcan == CAN0)
- {
- #ifdef USING_BXCAN0
- bxcan0_hw_init();
- bxcan_init(pbxcan, cfg->baud_rate, cfg->mode);
- #endif
- }
- else if (pbxcan == CAN1)
- {
- #ifdef USING_BXCAN1
- bxcan1_hw_init();
- bxcan_init(pbxcan, cfg->baud_rate, cfg->mode);
- #endif
- }
- return RT_EOK;
- }
- static rt_err_t control(struct rt_can_device *can, int cmd, void *arg)
- {
- struct ls1c_bxcan *pbxcan;
- rt_uint32_t argval;
- pbxcan = (struct ls1c_bxcan *) can->parent.user_data;
- switch (cmd)
- {
- 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 CAN_SetMode(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 )
- {
- return RT_ERROR;
- }
- if (argval != can->config.baud_rate)
- {
- can->config.baud_rate = argval;
- Ls1c_CanBPS_t bps;
- switch(argval)
- {
- case CAN1MBaud:
- bps = LS1C_CAN1MBaud;
- break;
- case CAN800kBaud:
- bps = LS1C_CAN800kBaud;
- break;
- case CAN500kBaud:
- bps = LS1C_CAN500kBaud;
- break;
- case CAN250kBaud:
- bps = LS1C_CAN250kBaud;
- break;
- case CAN125kBaud:
- bps = LS1C_CAN125kBaud;
- break;
- case CAN50kBaud:
- bps = LS1C_CAN40kBaud;
- break;
- default:
- bps = LS1C_CAN250kBaud;
- break;
- }
- return CAN_SetBps( pbxcan->reg, bps);
- }
- break;
- case RT_CAN_CMD_GET_STATUS:
- {
- rt_uint32_t errtype;
- errtype = pbxcan->reg->RXERR;
- can->status.rcverrcnt = errtype ;
- errtype = pbxcan->reg->TXERR;
- can->status.snderrcnt = errtype ;
- errtype = pbxcan->reg->ECC;
- can->status.errcode = errtype ;
- 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;
- CanTxMsg TxMessage;
- struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
- int i;
- pbxcan = ((struct ls1c_bxcan *) can->parent.user_data)->reg;
- TxMessage.StdId = pmsg->id;
- TxMessage.ExtId = pmsg->id;
- TxMessage.RTR = pmsg->rtr;
- TxMessage.IDE = pmsg->ide;
- TxMessage.DLC = pmsg->len;
- for( i=0; i<TxMessage.DLC ;i++)
- {
- TxMessage.Data[i] = pmsg->data[i];
- }
- CAN_Transmit(pbxcan, &TxMessage);
- 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;
- int i;
- pbxcan = ((struct ls1c_bxcan *) can->parent.user_data)->reg;
- pmsg->ide = (rt_uint32_t) RxMessage.IDE;
- if(RxMessage.IDE == 1)
- pmsg->id = RxMessage.ExtId;
- else
- pmsg->id = RxMessage.StdId;
- pmsg->len = RxMessage.DLC;
- pmsg->rtr = RxMessage.RTR;
- pmsg->hdr = 0;
- for(i= 0;i< RxMessage.DLC; i++)
- {
- pmsg->data[i] = RxMessage.Data[i];
- }
- return RT_EOK;
- }
- static const struct rt_can_ops canops =
- {
- configure,
- control,
- sendmsg,
- recvmsg,
- };
- #ifdef USING_BXCAN0
- struct rt_can_device bxcan0;
- void ls1c_can0_irqhandler(int irq, void *param)
- {
- CAN_TypeDef* CANx;
- unsigned char status;
- CANx = CAN0;
- /*读寄存器清除中断*/
- status = CANx->IR;
-
- /*接收中断*/
- if (( status & CAN_IR_RI) == CAN_IR_RI)
- {
- /*清除RI 中断*/
- CAN_Receive(CANx, &RxMessage);
- CANx->CMR |= CAN_CMR_RRB;
- CANx->CMR |= CAN_CMR_CDO;
- rt_hw_can_isr(&bxcan0, RT_CAN_EVENT_RX_IND);
- rt_kprintf("\r\nCan0 int RX happened!\r\n");
- }
- /*发送中断*/
- else if (( status & CAN_IR_TI) == CAN_IR_TI)
- {
- rt_hw_can_isr(&bxcan0, RT_CAN_EVENT_TX_DONE | 0 << 8);
- rt_kprintf("\r\nCan0 int TX happened!\r\n");
- }
- /*数据溢出中断*/
- else if (( status & CAN_IR_TI) == CAN_IR_DOI)
- {
- rt_hw_can_isr(&bxcan0, RT_CAN_EVENT_RXOF_IND);
- rt_kprintf("\r\nCan0 int RX OF happened!\r\n");
- }
- }
- static struct ls1c_bxcan bxcan0data =
- {
- .reg = CAN0,
- .irq = ls1c_can0_irqhandler,
- };
- #endif /*USING_BXCAN0*/
- #ifdef USING_BXCAN1
- struct rt_can_device bxcan1;
- void ls1c_can1_irqhandler(int irq, void *param)
- {
- CAN_TypeDef* CANx;
- unsigned char status;
- CANx = CAN1;
- /*读寄存器清除中断*/
- status = CANx->IR;
-
- /*接收中断*/
- if (( status & CAN_IR_RI) == CAN_IR_RI)
- {
- /*清除RI 中断*/
- CAN_Receive(CANx, &RxMessage);
- CANx->CMR |= CAN_CMR_RRB;
- CANx->CMR |= CAN_CMR_CDO;
- rt_hw_can_isr(&bxcan1, RT_CAN_EVENT_RX_IND);
- rt_kprintf("\r\nCan1 int RX happened!\r\n");
- }
- /*发送中断*/
- else if (( status & CAN_IR_TI) == CAN_IR_TI)
- {
- rt_hw_can_isr(&bxcan1, RT_CAN_EVENT_TX_DONE | 0 << 8);
- rt_kprintf("\r\nCan1 int TX happened!\r\n");
- }
- /*数据溢出中断*/
- else if (( status & CAN_IR_TI) == CAN_IR_DOI)
- {
- rt_hw_can_isr(&bxcan1, RT_CAN_EVENT_RXOF_IND);
- rt_kprintf("\r\nCan1 int RX OF happened!\r\n");
- }
- }
- static struct ls1c_bxcan bxcan1data =
- {
- .reg = CAN1,
- .irq = ls1c_can1_irqhandler,
- };
- #endif /*USING_BXCAN1*/
- int ls1c_bxcan_init(void)
- {
- #ifdef USING_BXCAN0
- bxcan0.config.baud_rate = CAN250kBaud;
- bxcan0.config.msgboxsz = 1;
- bxcan0.config.sndboxnumber = 1;
- bxcan0.config.mode = RT_CAN_MODE_NORMAL;
- bxcan0.config.privmode = 0;
- bxcan0.config.ticks = 50;
- #ifdef RT_CAN_USING_HDR
- bxcan0.config.maxhdr = 2;
- #endif
- rt_hw_can_register(&bxcan0, "bxcan0", &canops, &bxcan0data);
- rt_kprintf("\r\ncan0 register! \r\n");
-
- rt_hw_interrupt_install(LS1C_CAN0_IRQ,( rt_isr_handler_t)bxcan0data.irq , RT_NULL, "can0");
- rt_hw_interrupt_umask(LS1C_CAN0_IRQ);
- #endif
- #ifdef USING_BXCAN1
- bxcan1.config.baud_rate = CAN250kBaud;
- bxcan1.config.msgboxsz = 1;
- bxcan1.config.sndboxnumber = 1;
- bxcan1.config.mode = RT_CAN_MODE_NORMAL;
- bxcan1.config.privmode = 0;
- bxcan1.config.ticks = 50;
- #ifdef RT_CAN_USING_HDR
- bxcan1.config.maxhdr = 2;
- #endif
- rt_hw_can_register(&bxcan1, "bxcan1", &canops, &bxcan1data);
- rt_kprintf("\r\ncan1 register! \r\n");
-
- rt_hw_interrupt_install(LS1C_CAN1_IRQ,( rt_isr_handler_t)bxcan1data.irq , RT_NULL, "can1");
- rt_hw_interrupt_umask(LS1C_CAN1_IRQ);
- #endif
- return RT_EOK;
- }
- INIT_BOARD_EXPORT(ls1c_bxcan_init);
- #endif /*RT_USING_CAN*/
|