7セグメントLED表示器のデバイスドライバを作成しました
あけましておめでとうございます。
今年も、暇を見つけては少しずつ何か作ったりしてみたいと思っています。
よろしくお願いします。
さて、今回は前回の記事(id:cupnes:20121231:1356955476)で調査していた7セグメントLED表示器の、カソードコモンのものである「R362T」のLinux用デバイスドライバを作成してみました。
といっても、赤色LEDについて試した時(id:cupnes:20121231:1356945578)のものに、少し手を加えた程度です。
I/Oポートの接続について
7セグメント表示器の各LEDには、A、B、C、D、E、F、G、DPと名前がついています。
このLEDの名前と7セグメントLEDのピン番号、T-SH7706LSR側のピン番号とSH7706におけるI/Oポート番号を以下の表に示します。
なお、T-SH7706LSR側のピン番号は、全てCN2 PIOのものです。
LEDの名前 | A | B | C | D | E | F | G | DP |
---|---|---|---|---|---|---|---|---|
7セグメントLEDのピン番号 | 7 | 6 | 4 | 2 | 1 | 9 | 10 | 5 |
T-SH7706LSR側のピン番号 | 39 | 40 | 41 | 42 | 31 | 32 | 33 | 34 |
I/Oポート | PA3 | PA2 | PA1 | PA0 | PB3 | PB2 | PB1 | PB0 |
抵抗は、今回の実験では300Ωを、7セグメントLED表示器の3番ピンとT-SH7706LSRの44番ピン(GND)の間に繋いでいます。
なお、7セグメント表示器側のGNDは3番ピン以外に8番ピンも使用できます。
デバイスドライバのソースコード
ファイルの配置なども以前の記事(id:cupnes:20121231:1356945578)と同様で、今回必要なファイルは以下の2つです。
- led7seg.c
- Makefile
コンパイル方法なども、ファイルの名前が変わった程度で、以前の記事(id:cupnes:20121231:1356945578)と同様です。
「led7seg.c」
#include <linux/init.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/io.h> #include <linux/uaccess.h> #include <linux/fs.h> #include <linux/cdev.h> #define LED7SEG_MAJOR 243 #define LED7SEG_MINORS 1 #define LED7SEG_NAME "shminled7seg" #define PADR 0xA4000120 /* 8bit access */ #define PACR 0xA4000100 /* 16bit access */ #define PBDR 0xA4000122 /* 8bit access */ #define PBCR 0xA4000102 /* 16bit access */ /* A ------- | | F| |B | G | ------- | | E| |C | D | ------- .DP */ #define SEG_A 0x80 #define SEG_B 0x40 #define SEG_C 0x20 #define SEG_D 0x10 #define SEG_E 0x08 #define SEG_F 0x04 #define SEG_G 0x02 #define SEG_DP 0x01 static struct cdev led7segdev; static int led7seg_open(struct inode *inode, struct file *file) { return 0; } static int led7seg_release(struct inode *inode, struct file *file) { return 0; } static void led7seg_set7Seg(unsigned char pattern) { unsigned char pc_pat, pd_pat, tmp; pc_pat = (pattern >> 4) & 0x0F; pd_pat = pattern & 0x0F; tmp = __raw_readb(PADR) & 0xF0; __raw_writeb(tmp | pc_pat,PADR); tmp = __raw_readb(PBDR) & 0xF0; __raw_writeb(tmp | pd_pat,PBDR); } static void led7seg_setNumber(unsigned char num) { switch(num){ case 0: led7seg_set7Seg(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F); break; case 1: led7seg_set7Seg(SEG_B | SEG_C); break; case 2: led7seg_set7Seg(SEG_A | SEG_B | SEG_D | SEG_E | SEG_G); break; case 3: led7seg_set7Seg(SEG_A | SEG_B | SEG_C | SEG_D | SEG_G); break; case 4: led7seg_set7Seg(SEG_B | SEG_C | SEG_F | SEG_G); break; case 5: led7seg_set7Seg(SEG_A | SEG_C | SEG_D | SEG_F | SEG_G); break; case 6: led7seg_set7Seg(SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G); break; case 7: led7seg_set7Seg(SEG_A | SEG_B | SEG_C); break; case 8: led7seg_set7Seg(SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G); break; case 9: led7seg_set7Seg(SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); break; } } static void led7seg_setDP(void) { led7seg_set7Seg(SEG_DP); } static void led7seg_setLightDown(void) { led7seg_set7Seg(0x00); } static ssize_t led7seg_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) { unsigned char led7segdata; get_user(led7segdata,buf); if('0' <= led7segdata && led7segdata <= '9'){ led7seg_setNumber((unsigned char)(led7segdata - '0')); }else if(led7segdata == '.'){ led7seg_setDP(); }else if(led7segdata == '-'){ led7seg_setLightDown(); } (*offset)++; return 1; } struct file_operations led7seg_fops = { .owner = THIS_MODULE, .open = led7seg_open, .write = led7seg_write, .release = led7seg_release, }; static int __init led7seg_init(void) { dev_t dev = MKDEV(LED7SEG_MAJOR, 0); int ret; cdev_init(&led7segdev, &led7seg_fops); ret = cdev_add(&led7segdev, dev, LED7SEG_MINORS); if (ret){ printk(KERN_WARNING "shminled7seg: device add failed7seg.\n"); goto err0; } __raw_writew((__raw_readw(PACR)&~0x00FF)|0x0055,PACR); /* PA0-3 output */ __raw_writew((__raw_readw(PBCR)&~0x00FF)|0x0055,PBCR); /* PB0-3 output */ return 0; err0: unregister_chrdev_region(dev, LED7SEG_MINORS); return ret; } static void __exit led7seg_exit(void) { dev_t dev = MKDEV(LED7SEG_MAJOR, 0); __raw_writeb(__raw_readb(PADR)&~0x0F,PADR); /* PA0DT-PA3DT =0 */ __raw_writeb(__raw_readb(PBDR)&~0x0F,PBDR); /* PB0DT-PB3DT =0 */ cdev_del(&led7segdev); unregister_chrdev_region(dev, LED7SEG_MINORS); } module_init(led7seg_init); module_exit(led7seg_exit); MODULE_LICENSE("GPL");
「Makefile」
KERNELDIR ?= ../linux-2.6.39.4 PWD := $(shell pwd) obj-m := led7seg.o all: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
使用方法
「カーネルオブジェクトのコピー」などは、以前の記事(id:cupnes:20121231:1356945578)と同様ですので、省略します。
デバイスドライバの追加
# mknod /dev/shminled7seg c 243 0 # insmod led7seg.ko # echo 0 > /dev/shminled7seg # 「0」を表示 # echo 1 > /dev/shminled7seg # 「1」を表示 # echo . > /dev/shminled7seg # 「.」を表示 # echo - > /dev/shminled7seg # 消灯
数字の「0」〜「9」までと「.(ドット)」は、それぞれ書き込むとその数字、あるいはドットが表示されます。
また、消灯の際には「-」を書き込んでください。