设为首页 加入收藏

TOP

SPI子系统之驱动SSD1306 OLED(四)
2016-12-28 08:16:17 】 浏览:1170
Tags:SPI 子系统 驱动 SSD1306 OLED
ang->lock, flags);


return status;
}


int spi_bitbang_start(struct spi_bitbang *bitbang)
{
int status;


if (!bitbang->master || !bitbang->chipselect)
return -EINVAL;

/* [cgw]: 注册一个工作队列 */
INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue);


/* [cgw]: 配置相关方法 */
if (!bitbang->master->transfer)
bitbang->master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup;
}
} else if (!bitbang->master->setup)
return -EINVAL;


/* [cgw]: 创建一个单线程,用于调度工作队列 */
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
bitbang->workqueue = create_singlethread_workqueue(
bitbang->master->cdev.dev->bus_id);
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
}


/* [cgw]: 注册一个spi主机 */
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
status = spi_register_master(bitbang->master);
if (status < 0)
goto err2;


return status;


err2:
destroy_workqueue(bitbang->workqueue);
err1:
return status;
}


因为在s3c2410_spigpio_probe中注册了spi的设备,因此我们还需为这些设备提供驱动,以被这些设备探测到,探测这些驱动的条件也是设备和驱动的名字同名,即spi_ssd1306。我们这里提供了一个ssd1306 OLED的驱动


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)) {
str

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 4/10/10
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Linux网络驱动--snull 下一篇深入理解 Spring 事务原理

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目