SPI子系统之驱动SSD1306 OLED(4)

static struct spi_driver spi_ssd1306_driver = {
    .driver = {
        .name    = "spi_ssd1306",
        .bus    = &spi_bus_type,
        .owner    = THIS_MODULE,
    },
    .probe    = spi_ssd1306_probe,
    .remove    = __devexit_p(spi_ssd1306_remove),
};

static int spi_ssd1306_init(void)
{
    return spi_register_driver(&spi_ssd1306_driver);
}

到这里,基本工作已经完成。怎样驱动ssd1306 OLED呢?

ssd1306 OLED的使用方法,请参考相关的手册。

本例提供的ssd1306 OLED驱动,只需要我们提供一个基本9位spi数据收发的接口即可。

static void ssd1306_write_byte(uint8_t chData, uint8_t chCmd)
{
    struct spi_transfer t;
    struct spi_message m;

uint16_t data = chData;
   
    /* [cgw]: 情况spi_transfer */
    memset(&t,0,sizeof(struct spi_transfer));
   
    /* [cgw]: 第9位表示前8位是命令还是数据,1:数据,0:命令 */   
    if (chCmd) {
        data |= (1 << 8);
    } else {
        data &= ~(1 << 8);
    }

/* [cgw]: 要发送的数据 */
    t.tx_buf = &data;
    /* [cgw]: 长度,2字节 */
    t.len = 2;
    /* [cgw]: 9位spi */
    t.bits_per_word = 9;
    //t.cs_change = 1;
    /* [cgw]: 把数据添加到收发列表,工作队列调度时会从收发队列中取出,并进行收发
    * 注意这里并没有直接收发
    */
    spi_message_init(&m);
    spi_message_add_tail(&t, &m);
    spi_sync(spi_ssd1306_dev, &m);
}

注意,在网上看到一些例子,用8位模式驱动ssd1306 OLED的,需要用DC的状态来表示数据或命令的,他们的做法如下:

void ssd1306_write_cmd(uint8_t cmd)
{
    ssd1306_dc_clr();
    spi_write(cmd);
    ssd1306_dc_set();
}

void ssd1306_write_data(uint8_t data)
{
    ssd1306_dc_set();
    spi_write(data);
    ssd1306_dc_clr();
}

我本人认为是不正确的,至少不符合这个spi框架的逻辑,因为spi数据的收发并不是直接在spi_write()实现,而是在工作队列bitbang_work()中实现。尽管这样仍然能驱动ssd1306 OLED,但理论上不应该这么做。要改的话应该改bitbang_work()中改,添加DC状态的控制。

static void bitbang_work(struct work_struct *work)
{
    struct spi_bitbang    *bitbang =
        container_of(work, struct spi_bitbang, work);
    unsigned long        flags;

spin_lock_irqsave(&bitbang->lock, flags);
    bitbang->busy = 1;
    /* [cgw]: 队列不为空 */
    while (!list_empty(&bitbang->queue)) {
        struct spi_message    *m;
        struct spi_device    *spi;
        unsigned        nsecs;
        struct spi_transfer    *t = NULL;
        unsigned        tmp;
        unsigned        cs_change;
        int            status;
        int            (*setup_transfer)(struct spi_device *,
                        struct spi_transfer *);

/* [cgw]: 取出spi_message */
        m = container_of(bitbang->queue.next, struct spi_message,
                queue);
        /* [cgw]: 删除这个节点 */
        list_del_init(&m->queue);
        /* [cgw]: 进入临界区 */
        spin_unlock_irqrestore(&bitbang->lock, flags);

/* FIXME this is made-up ... the correct value is known to
        * word-at-a-time bitbang code, and presumably chipselect()
        * should enforce these requirements too?
        */
        nsecs = 100;

spi = m->spi;
        tmp = 0;
        cs_change = 1;
        status = 0;
        setup_transfer = NULL;

/* [cgw]: 历遍spi_message中的收发列表 */
        list_for_each_entry (t, &m->transfers, transfer_list) {

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f06f37a19007f6f04167f392c9581460.html