一.系统硬件结构介绍
系统中 CAN 总线主要用来完成 S3C2410 开发板和 CAN 总线分析仪的数据传输。在S3C2410 开发平台上,MCP2515 芯片用作 CAN 控制器,MCP2551 芯片用作 CAN 收发器,S3C2410 微处理器用作节点控制器。如下图1所示。
1.1 S3C2410 的 SPI 接口简介
SPI( Serial Peripheral Interface) 是一个同步串行外围接口,允许 MCU 与各种外围设备以串行方式进行通信。S3C2410 微处理器包括两路 SPI,每一路分别有两个 8 位转移寄存器,用来发送和接收数据。在 SPI 进行传输时,数据同时发送和接收。如果只想发送数据,接收到的数据将是无效的;如果只想接收数据,应当发送全是 1 的数据。
1.2 MCP2551 功能简介
MCP2551 是 CAN 协议控制器和物理总线之间的接口。这个器件向总线提供了差动的发送能力,向 CAN 控制器提供了差动的接收能力。
1.3 MCP2515 功能简介
MCP2515是一款独立CAN控制器,是为简化连接CAN总线的应用而开发的。图2 简要显示了MCP2515的结构框图[3]。该器件主要由三个部分组成:
(1)CAN 协议引擎(处理所有总线上的报文发送和接收) ;
(2)用来为器件及其运行进行配置的控制逻辑和SRAM寄存器;
(3 )SPI协议模块,用来实现SPI通信模式。
二. 驱动程序设计
驱动源码:
/*
* Microchip MCP2515 CAN controller driver.
*
* Copyright (C) 2007 Embedall Technology Co., Ltd.
*
* 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.
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/can/can.h>
#include <linux/delay.h>
#include <linux/can/mcp251x.h>
#include <linux/semaphore.h>
#include <asm/gpio.h>
/* SPI interface instruction set */
#define INSTRUCTION_WRITE 0x02
#define INSTRUCTION_READ 0x03
#define INSTRUCTION_BIT_MODIFY 0x05
#define INSTRUCTION_LOAD_TXB(n) (0x40 + 2 * (n))
#define INSTRUCTION_READ_RXB(n) (0x90 + 4 * (n))
#define INSTRUCTION_RESET 0xc0
#define INSTRUCTION_RTS(n) (0x80 + (1<<n))
#define INSTRUCTION_RX_STATE 0xb0
# define RX_STATE_RTR 0x04
# define RX_STATE_IDE 0x08
#define INSTRUCTION_CAN_STATE 0xa0
# define CAN_STATE_TX2IF 0x01
# define CAN_STATE_TX2REQ 0x02
# define CAN_STATE_TX1IF 0x04
# define CAN_STATE_TX1REQ 0x08
# define CAN_STATE_TX0IF 0x10
# define CAN_STATE_TX0REQ 0x20
# define CAN_STATE_RX1IF 0x40
# define CAN_STATE_RX0IF 0x80
/* MPC251x registers */
#define CANSTAT 0x0e
#define CANCTRL 0x0f
# define CANCTRL_REQOP_MASK 0xe0
# define CANCTRL_REQOP_CONF 0x80
# define CANCTRL_REQOP_LISTEN_ONLY 0x60
# define CANCTRL_REQOP_LOOPBACK 0x40
# define CANCTRL_REQOP_SLEEP 0x20
# define CANCTRL_REQOP_NORMAL 0x00
# define CANCTRL_OSM 0x08
# define CANCTRL_ABAT 0x10
#define TEC 0x1c
#define REC 0x1d
#define CNF1 0x2a
#define CNF2 0x29
# define CNF2_BTLMODE 0x80
#define CNF3 0x28
# define CNF3_SOF 0x08
# define CNF3_WAKFIL 0x04
# define CNF3_PHSEG2_MASK 0x07
#define CANINTE 0x2b
# define CANINTE_MERRE 0x80
# define CANINTE_WAKIE 0x40
# define CANINTE_ERRIE 0x20
# define CANINTE_TX2IE 0x10
# define CANINTE_TX1IE 0x08
# define CANINTE_TX0IE 0x04
# define CANINTE_RX1IE 0x02
# define CANINTE_RX0IE 0x01
#define CANINTF 0x2c
# define CANINTF_MERRF 0x80
# define CANINTF_WAKIF 0x40
# define CANINTF_ERRIF 0x20
# define CANINTF_TX2IF 0x10
# define CANINTF_TX1IF 0x08
# define CANINTF_TX0IF 0x04
# define CANINTF_RX1IF 0x02
# define CANINTF_RX0IF 0x01
#define EFLG 0x2d
# define EFLG_RX1OVR 0x80
# define EFLG_RX0OVR 0x40
#define TXBCTRL(n) ((n * 0x10) + 0x30)
# define TXBCTRL_TXREQ 0x08
# define TXBCTRL_TXPRI(n) (n)
# define TXBCTRL_TXERR (1 << 4)
# define TXBCTRL_MLOA (1 << 5)
# define TXBCTRL_ABTF (1 << 6)
#define RXBCTRL(n) ((n * 0x10) + 0x60)
# define RXBCTRL_MASK 0x60
# define RXBCTRL_RXRTR 0x08
# define RXBCTRL_BULK (1 << 2)
# define RXBCTRL_RXM_MACH_ALL (0 << 6)
# define RXBCTRL_RXM_MACH_STD (1 << 6)
# define RXBCTRL_RXM_MACH_EXT (2 << 6)
# define RXBCTRL_TXM_MACH_OFF (3 << 6)
# define RXBCTRL_FILHIT_MASK 0x07
#define RXM_BASE(n) (0x20 + (n * 4))
#define RXF_BASE(n) ((n>2)?(0x10 + (n-3)*4):(0x00 + (n*4)))
#define SJW1 0x00
#define SJW2 0x40
#define SJW3 0x80
#define SJW4 0xC0
#define BTLMODE_CNF3 0x80
#define SEG1 0x00
#define SEG2 0x01
#define SEG3 0x02
#define SEG4 0x03
#define SEG5 0x04
#define SEG6 0x05
#define SEG7 0x06
#define SEG8 0x07
#define BRP1 0x00
#define BRP2 0x01
#define BRP3 0x02
#define BRP4 0x03
#define BRP5 0x04
#define BRP6 0x05
#define BRP7 0x06
#define BRP8 0x07
//#define CAN_FOSC_12MHZ
#define CAN_FOSC_16MHZ
#if defined(CAN_FOSC_12MHZ)
#define CAN_CNF1_10K (SJW3 | 0x1d)
#define CAN_CNF2_10K (BTLMODE_CNF3|(SEG6<<3)|SEG7)
#define CAN_CNF3_10K (SEG6)
#define CAN_CNF1_20K (SJW2 | 0x0E)
#define CAN_CNF2_20K (BTLMODE_CNF3|(SEG6<<3)|SEG7)
#define CAN_CNF3_20K (SEG6)
#define CAN_CNF1_50K (SJW1 | 0x05)
#define CAN_CNF2_50K (BTLMODE_CNF3|(SEG6<<3)|SEG7)
#define CAN_CNF3_50K (SEG6)
#define CAN_CNF1_100K (SJW1 | BRP3)
#define CAN_CNF2_100K (BTLMODE_CNF3|(SEG6<<3)|SEG7)
#define CAN_CNF3_100K (SEG6)
#define CAN_CNF1_125K (SJW1 | BRP3)
#define CAN_CNF2_125K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_125K (SEG4)
#define CAN_CNF1_250K (SJW1 | BRP2)
#define CAN_CNF2_250K (BTLMODE_CNF3|(SEG3<<3)|SEG5)
#define CAN_CNF3_250K (SEG3)
#define CAN_CNF1_500K (SJW1 | BRP1)
#define CAN_CNF2_500K (BTLMODE_CNF3|(SEG3<<3)|SEG5)
#define CAN_CNF3_500K (SEG3)
#define CAN_CNF1_750K (SJW1 | BRP1)
#define CAN_CNF2_750K (BTLMODE_CNF3|(SEG3<<2)|SEG1)
#define CAN_CNF3_750K (SEG3)
#define CAN_CNF1_1000K (SJW1 | BRP1)
#define CAN_CNF2_1000K (BTLMODE_CNF3|(SEG2<<3)|SEG1)
#define CAN_CNF3_1000K (SEG2)
#elif defined(CAN_FOSC_16MHZ)
#define CAN_CNF1_10K (SJW1 | 0x31)
#define CAN_CNF2_10K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_10K (SEG4)
#define CAN_CNF1_20K (SJW1 | 0x18)
#define CAN_CNF2_20K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_20K (SEG4)
#define CAN_CNF1_50K (SJW1 | 0x09)
#define CAN_CNF2_50K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_50K (SEG4)
#define CAN_CNF1_100K (SJW1 | BRP5)
#define CAN_CNF2_100K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_100K (SEG4)
#define CAN_CNF1_125K (SJW1 | BRP4)
#define CAN_CNF2_125K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_125K (SEG4)
#define CAN_CNF1_250K (SJW1 | BRP2)
#define CAN_CNF2_250K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_250K (SEG4)
#define CAN_CNF1_500K (SJW1 | BRP1)
#define CAN_CNF2_500K (BTLMODE_CNF3|(SEG4<<3)|SEG7)
#define CAN_CNF3_500K (SEG4)
#define CAN_CNF1_750K (SJW1 | BRP1)
#define CAN_CNF2_750K (BTLMODE_CNF3|(SEG3<<3)|SEG4)
#define CAN_CNF3_750K (SEG3)
#define CAN_CNF1_800K (SJW1 | BRP1)
#define CAN_CNF2_800K (BTLMODE_CNF3|(SEG3<<3)|SEG3)
#define CAN_CNF3_800K (SEG3)
#define CAN_CNF1_1000K (SJW1 | BRP1)
#define CAN_CNF2_1000K (BTLMODE_CNF3|(SEG2<<3)|SEG3)
#define CAN_CNF3_1000K (SEG2)
#endif /* end define CAN_FOSC_12MHZ */
/* Buffer size required for the largest SPI transfer (i.e., reading a frame).
*/
#de