This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

am335x spi设备驱动例程



hi,

最近在搞有关spi的驱动。请问有没有基于am335x具体的外接设备(如oled驱动)的spi驱动例程可借鉴一下呢?

  • 你要的是裸机的还是Linux的?裸机的话可以参考Starterware,Linux的话,我们的SDK中有提供。

  • 我要的是linux的,你说的SDK里面的是指 m25p80.c 这个文件么?这个文件是否有编译进内核?我在/dev 下没有找到该设备节点。

  • 参考这个:http://processors.wiki.ti.com/index.php/AM335x_McSPI_Driver%27s_Guide

    顺带提一下:没有找到该节点的原因,可能是你使用的板子上面并没有SPI的相关设备,或者是profile的设置没挂SPI。如果是TI的EVM板的话,是要通过eeprom和profile的ID鉴别来配置相关的驱动的。如果鉴别出来的结果是没有SPI设备,就不会对其进行配置了。

  • 首先谢谢你的回答。

    我用的是自己做的板子,可能是上面没有相应的设备吧(有关eeprom的代码我已屏蔽掉)。

    你给的链接之前我有看过,我现在要用spi驱动板子上的oled12864,除了在board-am335xevm.c 文件里要进行链接中那样的初始化配置外,

    是不是还要写一个类似于m25p80.c一样的文件,我要通过spi对oled的寄存器进行读写操作,那么write()和read()函数是要自己编写,还是直接在内核中已经封装好,我直接调用就行了?

  • 已解决!

    2.编写spi驱动
    2.1配置板级设备board-am335xevm.c
        配置oled spi1相应引脚(sclk、d0、cs),由于oled只有数据输入引脚,且D/C控制引脚接在d1脚,故d1脚应初始化为普通I/O引脚,这里注释掉mcasp0_axr0.spi1_d1
    static struct pinmux_config spi1_pin_mux[] = {
    {"mcasp0_aclkx.spi1_sclk", OMAP_MUX_MODE3 | AM33XX_PULL_ENBL
    | AM33XX_INPUT_EN},
    //spi's direction seems reverse from the reference. our test confirm that.
    {"mcasp0_fsx.spi1_d0", OMAP_MUX_MODE3 | AM33XX_PULL_ENBL
    | AM33XX_PULL_UP | AM33XX_INPUT_EN},
    #if 0 //this pin is used for gpio in oled.
    {"mcasp0_axr0.spi1_d1", OMAP_MUX_MODE3 | AM33XX_PULL_ENBL
    | AM33XX_INPUT_EN},
    #endif
    {"mcasp0_ahclkr.spi1_cs0", OMAP_MUX_MODE3 | AM33XX_PULL_ENBL
    | AM33XX_PULL_UP | AM33XX_INPUT_EN},
    {NULL, 0},
    };
        配置其他相应I/O引脚:
    static struct pinmux_config gpio_Oled_mux[] = {
    {"mcasp0_aclkr.gpio3_18",OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},//OLED power enable
    {"mcasp0_ahclkx.gpio3_21", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},//OLED RST
    {"mcasp0_axr0.gpio3_16", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT}, //OLED D/C
    {NULL, 0},
    };
      spi_board_info 结构体  设备与驱动的接口
    static struct spi_board_info oled_spi1_slave_info[] = {
    {
    .modalias = "oled",
    .platform_data = (const void *)GPIO_TO_PIN(3, 16),
    .irq = -1,
    .max_speed_hz = 12000000,
    .bus_num = 2,
    .chip_select = 0,
    .mode = SPI_MODE_0,
    },
    };
        引脚初始化与调用spi_register_board_info 函数
    static void spi1_init(int evm_id, int profile)
    {
    setup_pin_mux(spi1_pin_mux);
    spi_register_board_info(oled_spi1_slave_info,
    ARRAY_SIZE(oled_spi1_slave_info));
    return;
    }
        由于mcaspi1与spi1复用引脚,故需把mcaspi1初始化屏蔽掉
    static struct evm_dev_cfg evm_sk_dev_cfg[] = {
    ...
    //{mcasp1_init, DEV_ON_BASEBOARD, PROFILE_ALL},
    {spi1_init, DEV_ON_BASEBOARD, PROFILE_ALL}, //注意这里的第二个参数
    ...
    {NULL, 0, 0},
    };

    驱动就不上了,把我在这过程中遇到的问题说一下下吧:

    3.过程中遇到的问题及解决办法
    a。加载驱动.ko文件时,无法匹配到probe函数,发现板子目录 sys/bus/spi/devices/下没有spi设备,且
    Device Drivers --->
             SPI support --->
                     <*>McSPI driver for OMAP
                     <*>User mode SPI device driver support
    已确定选上。搞了大半天,竟没找出原因,纳闷啊!
    后来把板级文件的设备信息单独写成一个文件,编进内核,结果发现,kuo以了!那这是为什么呢??
    后来不甘心,一步一步加打印信息,发现spi_init函数进不去,调试半天终于找到原因:
    static struct evm_dev_cfg evm_sk_dev_cfg[] = {
    ...
    //{mcasp1_init, DEV_ON_BASEBOARD, PROFILE_ALL},
    {spi1_init, DEV_ON_BASEBOARD, PROFILE_ALL}, //注意这里的第二个参数
    ...
    {NULL, 0, 0},
    };
    {spi1_init, DEV_ON_BASEBOARD, PROFILE_ALL}这里的第二个参数写成了DEV_ON_DGHTR_BRD,改过来就好了.

    b。驱动的设备节点是是挂上去了,但写测试程序没反应啊。好吧,用小行淘宝买的渣渣逻辑分析仪,分析了一下下,发现
    时钟和片选都正确,但数据线测得的波形不行不行的。。。又纠结了很久。。。后来经前辈指点,说画硬件的人把spi的输入输出接口接反了(虽说d0 和 d1 输入或输出是可配的,但内核中的主控代码是d0 :MISO ,d1:MOSI ),好吧,找到主控器的代码spi-omap2-mcspi.c 把 : l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
    l |= OMAP2_MCSPI_CHCONF_DPE0; 改为:l &= (OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE0);
    l |= OMAP2_MCSPI_CHCONF_DPE1; 就解决这个问题了。
    c。解决掉数据输出问题,初始化后发现点亮oled时乱码(这是正常现象,需要清屏),但当我清屏时并没有反应,更不要说在上面显示东东了。调试发现,命令能发送进去(写on/off命令,能正常亮灭),但为什么我清屏(往个像素点写0)会没反应呢?难道是数据写不进去?应该是这个问题了。结果用“逻辑分析仪”测D/C引脚,总感觉怪怪的,然后就从板级文件初始化一直找D/C脚的配置项,最后折腾了半天,在probe函数里,映射完D/C引脚后spi_oled_dc_pin = (int)spi->dev.platform_data; 将它设为输出模式 gpio_request(spi_oled_dc_pin,"o");gpio_direction_output(spi_oled_dc_pin, 1);
    结果就可以了。