summaryrefslogtreecommitdiff
path: root/bsp/ls1cdev/drivers
diff options
context:
space:
mode:
authorsundm75 <[email protected]>2018-02-09 07:10:56 +0800
committersundm75 <[email protected]>2018-02-09 09:19:32 +0800
commitd08ce950e50003d08b185ce1da10855669537fcb (patch)
tree1082ecb8a34777ce1f835e357356af5c285f4f96 /bsp/ls1cdev/drivers
parentb08ff9eee2461cb6654d52df1d29d6360f05ff97 (diff)
[BSP][ls1c]Add can driver and lib
Diffstat (limited to 'bsp/ls1cdev/drivers')
-rw-r--r--bsp/ls1cdev/drivers/drv_can.c542
-rw-r--r--bsp/ls1cdev/drivers/drv_can.h30
2 files changed, 572 insertions, 0 deletions
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 <rtthread.h>
+#include <rtdevice.h>
+#include <board.h>
+#include <rthw.h>
+
+#include <Drv_can.h>
+
+
+#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; 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*/
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_*/