打印
[应用方案]

mcp2515驱动移植于新唐的N32926

[复制链接]
1344|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
mintspring|  楼主 | 2016-8-23 09:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

    控制器局域网总线(CAN,Controller Area Network)是一种用于实时应用的串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。CAN协议用于汽车中各种不同元件之间的通信,以此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他自动化和工业应用。CAN协议的特性包括完整性的串行数据通讯、提供实时支持、传输速率高达1Mb/s、同时具有11位的寻址以及检错能力。

         本驱动用到的是Microchip的MCP2515是一款独立控制器局域网络(Controller Area Network, CAN)协议控制器,完全支持CAN V2.0B 技术规范。该器件能发送和接收标准和扩展数据帧以及远程帧。MCP2515自带的两个验收屏蔽寄存器和六个验收滤波寄存器可以过滤掉不想要的报文,因此减少了主单片机(MCU)的开销。MCP2515与MCU的连接是通过业界标准串行外设接口(SearialPeripheral Interface, SPI)来实现的。

         mcp2515驱动移植于新唐的N32926,内核版本是linux-2.6.35.4。开始移植时途中也碰到了很多问题。下面我徒手解答我碰到的一一问题。


沙发
mintspring|  楼主 | 2016-8-23 09:21 | 只看该作者

一,首先我们配置内核选项(Linux-2.6以上的内核都有自带的mcp251x驱动)

cd linux-2.6.35.4/

make menuconfig

1,选择如下配置:

  • Networkingsupport->

          <*>CAN bus subsystemsupport->

              <*>RawCAN Protocal

              <*>BroadcastManage CAN Protocal

              CANDevice Drivers->

                <*>Platform CAN driver withNetlink support

                   

  • CANbit-timing calculation

                <*>Microchip MCP251x SPI CANcontrollers

    2,配置spi驱动

    因为mcp2515是依通过spi通信协议进行数据交流的配置如下

  • SPIsupport --->               

    -*-  Utilitiesfor Bitbanging SPImasters               

    <>  GPIO-based bitbanging SPI Master(NEW)            

    <>  Xilinx SPI controller common module(NEW)         

    <*>  NuvotonW55FA92 seriesSPI                        

    <*>    SPI transfer with PDMA(NEW)                     

            SPI CS0 pin select (enable CS0pin) --->        

            SPI CS1 pin select (disable CS1pin) --->      

          SPI CS0 device select (device for MTDflash)  --->

    <>  DesignWare SPI controller core support(NEW)      

          *** SPI Protocol Masters***                       

    <>  User mode SPI device driver support(NEW)         

    <>   Infineon TLE62X0 (for power switching)(NEW)   

    以上就是驱动方面的配置。


  • 使用特权

    评论回复
    板凳
    mintspring|  楼主 | 2016-8-23 09:26 | 只看该作者

    二,在内核代码增加一个spi的设备

    1,根据硬件我们的mcp2515是挂在在spi0的接口中,不同的板子对应的内核实现都不一样

    N32926  增加一个spi的是设备是在linux-2.6.35.4/arch/arm/mach-w55fa92/dev.c中

    可以其他板子是在 mach-xxx.c中注册一个spi的设备具体可以搜索

    spi_register_board_info(structspi_board_info const *info, unsigned n)

    函数说明

    structspi_board_info 结构体

    structspi_board_info {

             char           modalias[SPI_NAME_SIZE];//定义的spi设备名字

             const void          *platform_data; //平台数据

             void           *controller_data;

             int              irq;  //中断号

             u32            max_speed_hz;


             u16            bus_num;//spi

             u16            chip_select;

             u8              mode;// 模式选择

    };

    在 dev.c中定义了

    staticstruct spi_board_info w55fa92_spi_board_info[] __initdata{  

             ……….

    };



    因此我们把mcp2515所需的数据定义到这个数组中

    staticstruct mcp251x_platform_data mcp251x_info = {

             .oscillator_frequency = 8000000,

    };

    staticstruct spi_board_info w55fa92_spi_board_info[] __initdata = {

            {

                    .modalias ="mcp2515",

                    .bus_num = 0,

                    .chip_select = 0,

                    .platform_data =&mcp251x_info,

                    .irq = W55FA92_IRQ(2),

                    .max_speed_hz = 2*1000*1000,

                    .mode = SPI_MODE_0,

            },


    };

    最终spi注册

    void__init w55fa92_dev_init()

    {

           platform_add_devices(w55fa92_public_dev,ARRAY_SIZE(w55fa92_public_dev));//注册平台设备

           spi_register_board_info(w55fa92_spi_board_info,ARRAY_SIZE(w55fa92_spi_board_info));//注册spi设备

    }

    貌似驱动方面搞定了?看上去好像很简单。那我们编译一下吧!

    编译成功后。

    重新启动板子

    发现can驱动报错:

    mcp251xspi0.0: MCP251x didn't enter in conf mode after reset

    mcp251xspi0.0: Probe failed

    mcp251xspi0.0: probe failed

    这是什么情况?于是我跟了一下代码

    /* Here is OK to not lock the MCP, no oneknows about it yet */

             if(!mcp251x_hw_probe(spi)) {

                       dev_info(&spi->dev,"Probe failed\n");

                       gotoerror_probe;

             }

    static int mcp251x_hw_probe(structspi_device *spi)

    {

             intst1, st2;


             mcp251x_hw_reset(spi);


             st1= mcp251x_read_reg(spi, CANSTAT) & 0xEE;

             st2= mcp251x_read_reg(spi, CANCTRL) & 0x17;


             dev_dbg(&spi->dev,"CANSTAT 0x%02x CANCTRL 0x%02x\n", st1, st2);


             /*Check for power up default values */

             return(st1 == 0x80 && st2 == 0x07) ? 1 : 0;

    }

    static int mcp251x_hw_reset(structspi_device *spi)

    {

             structmcp251x_priv *priv = dev_get_drvdata(&spi->dev);

             intret;

             unsignedlong timeout;


             priv->spi_tx_buf[0]= INSTRUCTION_RESET;//¸´Î»Ö¸Áî

             ret= spi_write(spi, priv->spi_tx_buf, 1);

             if(ret) {

                       dev_err(&spi->dev,"reset failed: ret = %d\n", ret);

                       return-EIO;

             }


             /*Wait for reset to finish */

             timeout= jiffies + HZ;

             mdelay(10);

             while((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)

                    != CANCTRL_REQOP_CONF) {

                       schedule();

                       if(time_after(jiffies, timeout)) {

                                dev_err(&spi->dev,"MCP251x didn't"

                                         "enter in conf mode after reset\n");

                                return-EBUSY;

                       }

             }

             return0;

    }


    使用特权

    评论回复
    地板
    mintspring|  楼主 | 2016-8-23 09:28 | 只看该作者

    原来祸根是这里,mcp251x_read_reg读寄存器出错 ,这里读的目的是判断是不是mcp2515属于配置模式因为probe函数会初始化mcp2515 寄存器。即写寄存器。怎么办继续跟咯

    static u8 mcp251x_read_reg(structspi_device *spi, uint8_t reg)

    {

             structmcp251x_priv *priv = dev_get_drvdata(&spi->dev);

             u8val = 0;


             priv->spi_tx_buf[0]= INSTRUCTION_READ;

             priv->spi_tx_buf[1]= reg;


             mcp251x_spi_trans(spi,3);

             val= priv->spi_rx_buf[2];


             returnval;

    }


    static int mcp251x_spi_trans(structspi_device *spi, int len)

    {

             structmcp251x_priv *priv = dev_get_drvdata(&spi->dev);

             structspi_transfer t = {

                       .tx_buf= priv->spi_tx_buf,

                       .rx_buf= priv->spi_rx_buf,

                       .len= len,

                       .cs_change= 0,

             };

             structspi_message m;

             intret;


             [url=]spi_message_init(&m);[/url]

             spi_message_add_tail(&t,&m);


             ret= spi_sync(spi, &m);

             if(ret)

                       dev_err(&spi->dev,"spi transfer failed: ret = %d\n", ret);


             returnret;

    }


    这下明白了mcp2515  的读写都是调用了mcp251x_spi_trans()函数。而这个函数里实现的是spi协议的 读写。


    使用特权

    评论回复
    发新帖 我要提问
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    294

    主题

    4883

    帖子

    24

    粉丝