Chinaunix首页 | 论坛 | 博客
  • 博客访问: 98974
  • 博文数量: 35
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 147
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-05 22:10
个人简介

不经历风雨,怎能见彩虹!

文章分类

全部博文(35)

文章存档

2013年(35)

我的朋友

分类: LINUX

2013-06-18 09:59:08

       CAN(Controller Area Network)总线,即控制器局域网总线,是一种有效支持分布式控制或实时控制的串行通信网络。由于其高性能、高可靠性、及独特的设计和适宜的价格而广泛应用于工业现场控制、智能楼宇、医疗器械、交通工具以及传感器等领域,并已被公认为几种最有前途的现场总线之一。CAN总线规范已经被国际标准化组织制订为国际标准ISO11898,并得到了众多半导体器件厂商的支持。


移植环境
         linux内核版本: 3.0
         硬件平台 :s3c6410

MCP2515简介

       MCP2515是一种独立的CAN总线通信控制器,是Microchip公司首批独立CAN解决方案的升级器件,其传输能力较Microchip公司原有CAN控制器(MCP2510)高两倍,最高通信速率可达到1Mbps。MCP2515能够接收和发送标准数据帧和扩展数据帧以及远程帧,通过两个接收屏蔽寄存器和六个接收过滤寄存器滤除无关报文,从而减轻CPU负担。

MCP2515主要功能参数及电气特性如下:
      (1)支持CAN技术规范2.0A/B, 最高传输速率达到1Mbps;
      (2)支持标准数据帧、扩展数据帧和远程帧,每帧数据域长度可为0~8个字节;
      (3)内含两个的接收缓冲器和三个发送缓冲器,并且可编程设定优先级;
      (4)内含六个29位(bit)的接收过滤寄存器和两个29位(bit)的接收屏蔽寄存器;
      (5)高速SPI接口,支持SPI 0,0和1,1模式;
      (6)一次性模式可确保报文被一次性传输;
      (7)具有可编程时钟脉冲输出引脚,可作为其他芯片时钟信号源;
      (8) 帧起始(SOF)信号输出功能可被用于在确定的系统中(如时间触发CAN-TTCAN)执行时隙功能,或在CAN总线诊断中决定早期总线出级;
      (9) 采用低功耗CMOS技术,工作电压:2.7V~5.5V, 工作电流:5mA(待机状态1μA);
      (10)工作温度范围:(I)-40℃到+85℃,(E)-40℃到+125℃。

硬件连接方式
     

            模块的CS、SO、SI、SCK分别与s3c6410的SPI(本文用的是SPI0)总线的CS、MISO、MOSI、SCK相连
            模块的INT连接到s3c6410的中断管脚(本文使用的是GPN3)

驱动实现
 
1、修改 arch/arm/mach-s3c64xx/mach-smdk6410.c   
 
增加头文件:
#include
#include  
#include
#include

增加下列函数            

static void  cs_set_level(unsigned line_id, int lvl) {
        gpio_direction_output(line_id, lvl);
};

static struct s3c64xx_spi_csinfo s3c64xx_spi0_csinfo = {
        .fb_delay=0x3,
        .line=S3C64XX_GPC(3),
        .set_level=cs_set_level,
};
static struct mcp251x_platform_data mcp251x_info = {
        .oscillator_frequency = 2 * 8000000,
 };

static struct spi_board_info spi_devs[] = {
        {
                .modalias = "mcp2515",
                .bus_num= 0,
                .chip_select= 0,
                .irq = IRQ_EINT(3),
                .max_speed_hz= 1 * 1000 * 1000,
                .mode=SPI_MODE_0,
                .platform_data = &mcp251x_info,
                .controller_data=&s3c64xx_spi0_csinfo,
        },
};

在smdk6410_devices中增加SPI0总线驱动

static struct platform_device *hwgw6410_devices[] __initdata = {
        &s3c_device_hsmmc0,

        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
        &samsung_asoc_dma,
        &s3c_device_nand,
        &s3c_device_i2c0,
        &s3c64xx_device_spi0,      //新增
        &hwgw6410_leds_device,
        &s3c_device_rtc,
        &s3c_device_wdt,
        /* &s3c_device_hwmon, */
        &hwgw6410_device_eth,
        &key_device,
};

在static void __init hwgw6410_machine_init(void)中增加以下代码
static void __init hwgw6410_machine_init(void)
{
        u32 cs1;

        s3c_nand_set_platdata(&hwgw6410_nand_info);
        s3c_i2c0_set_platdata(NULL);
        s3c_sdhci0_set_platdata(&hwgw6410_hsmmc0_pdata);

        /* configure nCS1 width to 16 bits */

        cs1 = __raw_readl(S3C64XX_SROM_BW) &
                ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
        cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
                (0 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
                (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
                S3C64XX_SROM_BW__NCS1__SHIFT;
        __raw_writel(cs1, S3C64XX_SROM_BW);

        __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
                     (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
                     (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
                     (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
                     (13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
                     (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
                     (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);

        s3c64xx_spi_set_info(0,0,2);                                                    //新增
        spi_register_board_info(spi_devs, ARRAY_SIZE(spi_devs));        //新增
        otg_phy_init();


        platform_add_devices(hwgw6410_devices, ARRAY_SIZE(hwgw6410_devices));
}

 2、在编译内核时增加MCP2515的驱动选项

[*]Networking support->
             <*>CAN bus subsystem support->
             <*>Raw CAN Protocal
             <*>Broadcast Manage CAN Protocal
             CAN Device Drivers->
                       <*>Platform CAN driver with Netlink support
                       [*]CAN bit-timing calculation
                       <*>Microchip MCP251x SPI CAN controllers
         
Device drivers->
             [*]SPI support -> 
             <*> Samsung S3C2416 series type SPI

至此,驱动移植完成,编译好内核后烧写到开发板,启动开发板后使用ifconfig -a 命令就可以看到一个can0 接口           

 

移植过程中遇到的问题及解决办法

1、在内核启动的过程中出现以下警告信息:

 0.080000] ------------[ cut here ]------------
[    0.080000] WARNING: at drivers/gpio/gpiolib.c:101 gpio_ensure_requested+0x4c/0x100()
[    0.080000] autorequest GPIO-20
[    0.080000] Modules linked in:
[    0.080000] [] (unwind_backtrace+0x0/0x134) from [] (warn_slowpath_common+0x4c/0x64)
[    0.080000] [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_fmt+0x30/0x40)
[    0.080000] [] (warn_slowpath_fmt+0x30/0x40) from [] (gpio_ensure_requested+0x4c/0x100)
[    0.080000] [] (gpio_ensure_requested+0x4c/0x100) from [] (gpio_direction_output+0xa0/0x16c)
[    0.080000] [] (gpio_direction_output+0xa0/0x16c) from [] (s3c64xx_spi_setup+0x11c/0x20c)
[    0.080000] [] (s3c64xx_spi_setup+0x11c/0x20c) from [] (spi_setup+0x44/0xf0)
[    0.080000] [] (spi_setup+0x44/0xf0) from [] (spi_add_device+0x98/0x154)
[    0.080000] [] (spi_add_device+0x98/0x154) from [] (spi_new_device+0x74/0xac)
[    0.080000] [] (spi_new_device+0x74/0xac) from [] (spi_match_master_to_boardinfo+0x24/0x44)
[    0.080000] [] (spi_match_master_to_boardinfo+0x24/0x44) from [] (spi_register_master+0x110/0x180)
[    0.080000] [] (spi_register_master+0x110/0x180) from [] (s3c64xx_spi_probe+0x37c/0x4b8)
[    0.080000] [] (s3c64xx_spi_probe+0x37c/0x4b8) from [] (platform_drv_probe+0x18/0x1c)
[    0.080000] [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0xb0/0x278)
[    0.080000] [] (driver_probe_device+0xb0/0x278) from [] (__driver_attach+0x8c/0x90)
[    0.080000] [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x60/0x8c)
[    0.080000] [] (bus_for_each_dev+0x60/0x8c) from [] (bus_add_driver+0x194/0x290)
[    0.080000] [] (bus_add_driver+0x194/0x290) from [] (driver_register+0x78/0x138)
[    0.080000] [] (driver_register+0x78/0x138) from [] (platform_driver_probe+0x18/0x9c)
[    0.080000] [] (platform_driver_probe+0x18/0x9c) from [] (do_one_initcall+0x34/0x178)
[    0.080000] [] (do_one_initcall+0x34/0x178) from [] (kernel_init+0x74/0x118)
[    0.080000] [] (kernel_init+0x74/0x118) from [] (kernel_thread_exit+0x0/0x8)
[    0.080000] ---[ end trace 1b75b31a2719ed1c ]---

这是因为SPI的片选管脚在使用前没有申请造成的,在 arch/arm/mach-s3c64xx/mach-smdk6410.c 中的 static void __init hwgw6410_machine_init(void)中增加以下代码

static void __init hwgw6410_machine_init(void)
{
        u32 cs1;

        s3c_nand_set_platdata(&hwgw6410_nand_info);
        s3c_i2c0_set_platdata(NULL);
        s3c_sdhci0_set_platdata(&hwgw6410_hsmmc0_pdata);

        /* configure nCS1 width to 16 bits */

        cs1 = __raw_readl(S3C64XX_SROM_BW) &
                ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
        cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
                (0 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
                (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
                S3C64XX_SROM_BW__NCS1__SHIFT;
        __raw_writel(cs1, S3C64XX_SROM_BW);

        __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
                     (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
                     (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
                     (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
                     (13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
                     (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
                     (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);

        gpio_request(s3c64xx_spi0_csinfo.line, NULL);      //新增
        s3c64xx_spi_set_info(0,0,2);
        spi_register_board_info(spi_devs, ARRAY_SIZE(spi_devs));
        otg_phy_init();


        platform_add_devices(hwgw6410_devices, ARRAY_SIZE(hwgw6410_devices));
}


2、在使用CAN通信的过程中出现通信一段时间后通信中断的情况
     这是中断触发方式的问题,驱动中默认的是下降沿触发,修改触发方式为低电平触发
      修改 arch/arm/mach-s3c64xx/mach-smdk6410.c 中的
        static struct mcp251x_platform_data mcp251x_info = {
        .oscillator_frequency = 2 * 8000000,
        .irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT   //新增
};

至此CAN总线应该可以正常运行了,如有错误和疑问,欢迎指出!

参考博文:

阅读(5019) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

wanli34562014-02-20 17:06:52

sinc_mark82:楼主,想请教一下,你移植的SPI总线,会再/dev下产生设备节点么?如果不产生,你怎么使用该总线啊?
我在6410下类似操作,在/sys/bus/spi和/sys/platform下可以看到spi的总线了,但该如何使用啊?谢谢!

会产生设备节点,你只要把SPI的线路和MCP2515连接好以后,内核里有SPI的读写节口,你在MCP2515驱动里可以使用这些接口对设备的寄存器进行读写操作。MCP2515的驱动程序会生生一个字符设备或者是网络接口(这个根据你使用的驱动类型决定),在应用层可以对驱动生成的字符设备或网络接口进行操作。

回复 | 举报

sinc_mark822013-12-23 15:07:48

楼主,想请教一下,你移植的SPI总线,会再/dev下产生设备节点么?如果不产生,你怎么使用该总线啊?
我在6410下类似操作,在/sys/bus/spi和/sys/platform下可以看到spi的总线了,但该如何使用啊?谢谢!