From d08ce950e50003d08b185ce1da10855669537fcb Mon Sep 17 00:00:00 2001 From: sundm75 Date: Fri, 9 Feb 2018 07:10:56 +0800 Subject: [BSP][ls1c]Add can driver and lib --- bsp/ls1cdev/drivers/drv_can.c | 542 ++++++++++++++++++++++++++++++++++++++++++ bsp/ls1cdev/drivers/drv_can.h | 30 +++ 2 files changed, 572 insertions(+) create mode 100644 bsp/ls1cdev/drivers/drv_can.c create mode 100644 bsp/ls1cdev/drivers/drv_can.h (limited to 'bsp/ls1cdev/drivers') diff --git a/bsp/ls1cdev/drivers/drv_can.c b/bsp/ls1cdev/drivers/drv_can.c new file mode 100644 index 0000000000..bdcecc0d37 --- /dev/null +++ b/bsp/ls1cdev/drivers/drv_can.c @@ -0,0 +1,542 @@ +/* + * 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 +#include +#include +#include + +#include + + +#include "ls1c.h" +#include "ls1c_public.h" +#include "ls1c_regs.h" +#include "ls1c_clock.h" +#include "ls1c_can.h" +#include "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; idata[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*/ diff --git a/bsp/ls1cdev/drivers/drv_can.h b/bsp/ls1cdev/drivers/drv_can.h new file mode 100644 index 0000000000..0d846dee25 --- /dev/null +++ b/bsp/ls1cdev/drivers/drv_can.h @@ -0,0 +1,30 @@ +/* + * File : bxcan.h + * 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 + */ + +#ifndef LS1C_DRV_CAN_H +#define LS1C_DRV_CAN_H + +extern int ls1c_bxcan_init(void); + +#endif /*DRV_CAN_H_*/ -- cgit v1.3.1