体験!マイコンボードで組込みLinux

第14回 組込みLinuxでLCDを制御してみよう

この記事を読むのに必要な時間:およそ 3.5 分

LCDデバイスドライバ

ソフトウェアとハードウェアの分担

マイクロコンピュータと周辺コントローラの間でのバスインターフェース接続では,図8のように負論理であるチップセレクト端子がロー(有効)のときのみデータが有効になり,データのアクセスが行われます。

図8 標準的なインターフェース

図8 標準的なインターフェース

図8のような標準インターフェースでは,そのようなアクセス処理はマイクロコンピュータのハードウェアが自動的に行うので,特にデバイスドライバのほうで処理を行う必要はありません。

しかし,HD44780は非常に古風なインターフェースであり,図9のようにE端子(チップセレクト)がハイからローに変化するときにデータが有効になるような独特なバスインターフェースのため,SH7706プロセッサのバスコントローラでHD44780を扱うことができません。そのため,通常はハードウェアが行うようなバスインターフェースの処理もデバイスドライバで面倒を見なければいけません。

図9 HD44780のインターフェース

図9 HD44780のインターフェース

LCDに文字を出力する概要

HD44780の詳細な使い方については液晶購入時に同時に添付されるデータシートを参照してください。図7の接続回路に対応したLCDデバイスドライバのソースコードはリスト1の通りとなります。

リスト1 LCDデバイスドライバのプログラム


  1    #include <linux/module.h>
  2    #include <linux/init.h>
  3    #include <linux/device.h>
  4    #include <linux/ctype.h>
  5    #include <linux/poll.h>
  6    #include <linux/delay.h>
  7    #include <asm/io.h>
  8    
  9    #define PFC_PDCR        0xa4000106UL
 10    #define PFC_PECR        0xa4000108UL
 11    #define PORT_PDDR       0xa4000126UL
 12    #define PORT_PEDR       0xa4000128UL
 13    #define TMU_TOCR        0xfffffe90UL
 14    
 15    static int      lcd_major;
 16    
 17    // PTD6
 18    static void lcd_enable(int enable) {
 19            if(enable) {
 20                    ctrl_outb(ctrl_inb(PORT_PDDR) | 0x40, PORT_PDDR);
 21            } else {
 22                    ctrl_outb(ctrl_inb(PORT_PDDR) & ~0x40, PORT_PDDR);
 23            }
 24    }
 25    
 26    // PTD7
 27    static void lcd_rs(int rs) {
 28            if(rs) {
 29                    ctrl_outb(ctrl_inb(PORT_PDDR) | 0x80, PORT_PDDR);
 30            } else {
 31                    ctrl_outb(ctrl_inb(PORT_PDDR) & ~0x80, PORT_PDDR);
 32            }
 33    }
 34    
 35    // D4=PTE1 D5=PTE3 D6=PTD5 D7=PTD1
 36    static void lcd_data(int data) {
 37            if(data & 0x10) {
 38                    ctrl_outb(ctrl_inb(PORT_PEDR) | 0x02, PORT_PEDR);
 39            } else {
 40                    ctrl_outb(ctrl_inb(PORT_PEDR) & ~0x02, PORT_PEDR);
 41            }
 42            if(data & 0x20) {
 43                    ctrl_outb(ctrl_inb(PORT_PEDR) | 0x08, PORT_PEDR);
 44            } else {
 45                    ctrl_outb(ctrl_inb(PORT_PEDR) & ~0x08, PORT_PEDR);
 46            }
 47            if(data & 0x40) {
 48                    ctrl_outb(ctrl_inb(PORT_PDDR) | 0x20, PORT_PDDR);
 49            } else {
 50                    ctrl_outb(ctrl_inb(PORT_PDDR) & ~0x20, PORT_PDDR);
 51            }
 52            if(data & 0x80) {
 53                    ctrl_outb(ctrl_inb(PORT_PDDR) | 0x02, PORT_PDDR);
 54            } else {
 55                    ctrl_outb(ctrl_inb(PORT_PDDR) & ~0x02, PORT_PDDR);
 56            }
 57    }
 58    
 59    static void lcd_out8(int data) {
 60            lcd_enable(1);
 61            lcd_rs(0);
 62            lcd_data(data);
 63            udelay(83);
 64            lcd_enable(0);
 65            udelay(4000);
 66    }
 67    
 68    static void lcd_out4(int rs, int data) {
 69            lcd_enable(1);
 70            lcd_rs(rs);
 71            lcd_data(data);
 72            udelay(83);
 73            lcd_enable(0);
 74            udelay(83);
 75            lcd_enable(1);
 76            lcd_data(data << 4);
 77            udelay(83);
 78            lcd_enable(0);
 79            if(rs == 0) {
 80                    udelay(4000);
 81            } else {
 82                    udelay(83);
 83            }
 84    }
 85    
 86    static ssize_t lcd_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) {
 87            ssize_t n, d;
 88            unsigned char   c;
 89    
 90            lcd_out4(0, 0x01);
 91            d = 0;
 92            for(n = 0;n < count;n++) {
 93                    copy_from_user(&c, buf + n, 1);
 94                    if(c >= ' ') {
 95                            if(d == 16) lcd_out4(0, 0x80 + 0x40);
 96                            if(d < 32) lcd_out4(1, (int)c & 0xff);
 97                            d++;
 98                    }
 99            }
100            return count;
101    }
102    
103    static const struct file_operations lcd_fops = {
104            .owner  = THIS_MODULE,
105            .write  = lcd_write,
106    };
107    
108    #define CHRDEV "lcd"
109    static int __init lcd_init (void) {
110            lcd_major = register_chrdev(0, CHRDEV, &lcd_fops);
111            ctrl_outw(0x5404, PFC_PDCR);
112            ctrl_outw(0x0044, PFC_PECR);
113            ctrl_outb(0x01, TMU_TOCR);
114            lcd_rs(0);
115            lcd_enable(0);
116            lcd_data(0);
117            udelay(4000);
118            lcd_out8(0x30);
119            udelay(4000);
120            lcd_out8(0x30);
121            udelay(4000);
122            lcd_out8(0x30);
123            udelay(4000);
124            lcd_out8(0x20);
125            lcd_out4(0, 0x28);      // Function set
126            lcd_out4(0, 0x0c);      // Display on
127            lcd_out4(0, 0x06);      // Entry mode
128            lcd_out4(0, 0x01);
129            printk(KERN_INFO "LCD Device Driver\n");
130            return 0;
131    }
132    
133    static void __exit lcd_cleanup (void) {
134            unregister_chrdev(lcd_major, CHRDEV);
135            ctrl_outb(0x00, TMU_TOCR);
136            printk(KERN_INFO "LCD Device Driver Exit\n");
137    }
138    
139    module_init(lcd_init);
140    module_exit(lcd_cleanup);
141    
142    MODULE_LICENSE("GPL");

LCD制御で行う処理の概要は,LCD初期化時にデータシート記載のとおりに初期化のおまじないを行います(リスト1の114~128行目⁠⁠。初期化が済めばあとはデータバスにデータをLCDに対して送るだけとなります。RS端子がローの場合はLCD表示制御となり,RS端子がハイの場合は文字出力となります。

LCDに対して文字を出力するには,RS端子をハイにしておいて,データバスにASCIIコードを出力するだけで,図9のようにE端子をハイからローにすると実際にLCDに文字が表示されます。今回の回路がデータバスが4本のため,1回目に8ビットデータの下位4ビットを送付し,2回目に8ビットデータの上位を送付します(リスト1の68~84行目⁠⁠。

著者プロフィール

みついわゆきお

1986年日立製作所入所,その3年後に自社ワークステーションでの開発業務をきっかけにBSDを経てLinux利用を始める。

1991年日立を退社し,その後,ボランティアでLinux関連ツールの整備と開発しながらWindows否定運動およびLinux普及運動を開始し,Linuxディストリビューション草創期にはPlamoLinuxのメンテナンスにもかかわる。

2001年ごろより非営利ベースでボードコンピュータの開発を開始し,やがて,無償によりハードとソフトを開発したH8マイコンボードの販売を秋月電子にて開始した。

現在,ボードコンピュータ用基本ソフトMES2.5や,SHプロセッサ向けLinuxパッチおよびTOPPERS/JSPパッチを無償で一般に提供しながら,ティーエーシーやエムイーシステムより原価率100%を目標(ただし,販売店の営業・販売費用や開発・製造の際の差損を除く)としたSuperHボードコンピュータを販売中。

また,現在でも頑固にMS社否定及びWindows撲滅運動に邁進中。