rpi 设备驱动程序中的 lcd 程序不产生任何字符显示。但是 LCD 是通过 gpio 等内核辅助函数显示的,驱动程序在这里没有显示。我的兴趣是通过我自己的驱动程序进行通信,还请注意,LED 的闪烁是通过该驱动程序进行的,但为了缩短程序,我删除了该编程代码,甚至没有从该代码中指示用户空间代码,但驱动程序是编译和与用户空间应用程序通信没有任何错误。
bcm2835_pins.h:
#define BCM2835_PERI_BASE 0x3F000000
#define GPIO_BASE BCM2835_PERI_BASE + 0x200000
struct bcm2835_peri {
unsigned long addr_p;
int mem_fd;
void *map;
volatile unsigned int *addr;
};
struct bcm2835_peri gpio = {GPIO_BASE};
#define GPIO_PIN_INPUT(pin) *(gpio.addr + ((pin)/10)) &= ~(7<<(((pin)%10)*3))
#define GPIO_PIN_OUTPUT(pin) *(gpio.addr + ((pin)/10)) |= (1<<(((pin)%10)*3))
#define SET_GPIO_ALT(pin,a) *(gpio.addr + ((pin)/10)) |= (((a) <= 3?(a)+4:(a)==4?3:2) << (((pin)%10)*3))
#define GPIO_PIN_SET *(gpio.addr + 7) // after write to mem, set bits which are 1, ignores which are 0
#define GPIO_PIN_CLR *(gpio.addr + 10) // after write, clear bits which are 1, ignores which are 0
#define GPIO_PIN_READ(pin) *(gpio.addr + 13) &= (1 << (pin))
char_driver.c:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include "bcm2835_pins.h"
#define DRIVER_NAME "bhaskar_driver"
#define DRIVER_CLASS "bhaskar_class"
#define DEVICE_NAME "bhaskar_device"
#define DEV_MAX_MEM 100
static struct class *cl;
static struct device *device;
static struct cdev my_cdev;
static unsigned int firstminor = 0, count = 1, i = 0;
static dev_t dev;
static int ret;
static char driver_buf[DEV_MAX_MEM];
static int char_open(struct inode *inodep, struct file *filep);
static int char_close(struct inode *inodep, struct file *filep);
static ssize_t char_write(struct file *filep, const char __user *buf, size_t len, loff_t *offset);
static ssize_t char_read(struct file *filep, char __user *buf, size_t len, loff_t *offset);
static loff_t char_llseek(struct file *filep, loff_t offset, int whence);
void lcd_init(void);
void lcd_cmd(unsigned int a);
void lcd_data(unsigned int a);
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = char_open,
.release= char_close,
.write = char_write,
.read = char_read,
.llseek = char_llseek,
};
void lcd_cmd(unsigned int a)
{
int i;
unsigned int b;
GPIO_PIN_CLR |= 1 << 0; // RW = 0 // directly connectd to rpi ground pin
b = a & 0xf0;
b >>= 4;
GPIO_PIN_CLR |= 1 << 1; // RS = 0
*(gpio.addr + 7) &= (0xf << 3); // clearning data pins
//*(gpio.addr + 7) |= (b << 3); // cmd byte higher nibble
for(i = 0; i < 4; i++) {
if((b >> i) & 1) {
GPIO_PIN_SET |= 1 << (i+3);
msleep(50);
}
else {
GPIO_PIN_CLR |= 1 << (i+3);
msleep(50);
}
}
GPIO_PIN_SET |= 1 << 2; // EN = 1
msleep(50);
GPIO_PIN_CLR |= 1 << 2; // EN = 0
msleep(50);
b = a & 0x0f;
*(gpio.addr + 7) &= (0xf << 3); // clearning data pins
//*(gpio.addr + 7) |= (b << 3); // cmd byte lower nibble
for(i = 0; i < 4; i++) {
if((b >> i) & 1) {
GPIO_PIN_SET |= 1 << (i+3);
msleep(50);
}
else {
GPIO_PIN_CLR |= 1 << (i+3);
msleep(50);
}
}
GPIO_PIN_SET |= 1 << 2; // EN = 1
msleep(50);
GPIO_PIN_CLR |= 1 << 2; // EN = 0
msleep(50);
}
void lcd_data(unsigned int a)
{
int i;
unsigned int b;
GPIO_PIN_CLR |= 1 << 0; // RW = 0
b = a & 0xf0;
b >>= 4;
GPIO_PIN_SET |= 1 << 1; // RS = 1
*(gpio.addr + 7) &= (0x0f << 3); // clearning data pins
//*(gpio.addr + 7) |= (b << 3); // cmd byte higher nibble
for(i = 0; i < 4; i++) {
if((b >> i) & 1) {
GPIO_PIN_SET |= 1 << (i+3);
msleep(50);
}
else {
GPIO_PIN_CLR |= 1 << (i+3);
msleep(50);
}
}
GPIO_PIN_SET |= 1 << 2; // EN = 1
msleep(50);
GPIO_PIN_CLR |= 1 << 2; // EN = 0
msleep(50);
b = a & 0x0f;
*(gpio.addr + 7) &= (0x0f << 3); // clearning data pins
//*(gpio.addr + 7) |= (b << 3); // cmd byte lower nibble
for(i = 0; i < 4; i++) {
if((b >> i) & 1) {
GPIO_PIN_SET |= 1 << (i+3);
msleep(50);
}
else {
GPIO_PIN_CLR |= 1 << (i+3);
msleep(50);
}
}
GPIO_PIN_SET |= 1 << 2; // EN = 1
msleep(50);
GPIO_PIN_CLR |= 1 << 2; // EN = 0
msleep(50);
}
static int char_open(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "Open function called\n");
return 0;
}
static int char_close(struct inode *inodep, struct file *filep)
{
printk(KERN_INFO "Close function called\n");
return 0;
}
static ssize_t char_write(struct file *filep, const char __user *buf, size_t len, loff_t *offset)
{
int i,j, k;
int ret;
char *temp;
printk(KERN_INFO "Write function called\n");
ret = copy_from_user(driver_buf + filep->f_pos, buf, sizeof("Embedded Device"));
temp = driver_buf;
lcd_cmd(0x28);
lcd_cmd(0x01);
lcd_cmd(0x02);
lcd_cmd(0x0f);
lcd_cmd(0x80);
while(*temp) {
lcd_data(*temp);
temp++;
}
filep->f_pos += len;
printk(KERN_INFO "return value of copy_from_user():%d\n", ret);
return len;
}
static ssize_t char_read(struct file *filep, char __user *buf, size_t len, loff_t *offset)
{
int ret;
printk(KERN_INFO "Read function called\n");
ret = copy_to_user(buf, driver_buf + filep->f_pos, sizeof("Embedded Device"));
filep->f_pos += len;
printk(KERN_INFO "return value of copy_to_user():%d\n", ret);
return len;
}
static loff_t char_llseek(struct file *filep, loff_t offset, int whence)
{
loff_t newpos;
printk(KERN_INFO "llseek function called\n");
switch(whence) {
case SEEK_SET:
printk(KERN_INFO "llseek called with SEEK_SET option\n");
newpos = offset;
break;
case SEEK_CUR:
printk(KERN_INFO "llseek called with SEEK_CUR option\n");
newpos = filep->f_pos + offset;
break;
case SEEK_END:
printk(KERN_INFO "llseek called with SEEK_END option\n");
newpos = DEV_MAX_MEM + offset;
break;
}
filep->f_pos += offset;
return newpos;
}
void lcd_init(void)
{
GPIO_PIN_OUTPUT(0);
GPIO_PIN_OUTPUT(1);
GPIO_PIN_OUTPUT(2);
GPIO_PIN_OUTPUT(3);
GPIO_PIN_OUTPUT(4);
GPIO_PIN_OUTPUT(5);
GPIO_PIN_OUTPUT(6);
GPIO_PIN_OUTPUT(7);
GPIO_PIN_OUTPUT(8);
GPIO_PIN_OUTPUT(9);
GPIO_PIN_OUTPUT(10);
}
static int __init hello_init(void)
{
int i, j;
char str[50] = "Embedded System Device Driver Tutorial";
if((ret = alloc_chrdev_region(&dev, firstminor, count, DRIVER_NAME)) < 0) {
printk(KERN_INFO "device number registration failed\n");
return -1;
}
printk(KERN_INFO "static method of device registration shown below but used dynamic\n");
printk(KERN_INFO "/dev/bhaskar_device c %d %d\n", MAJOR(dev), MINOR(dev));
printk(KERN_INFO "return value of alloc_chrdev_region():%d\n", ret);
cdev_init(&my_cdev, &fops);
if((ret = cdev_add(&my_cdev, dev, count)) < 0) {
printk(KERN_INFO "cdev structure addition failed\n");
goto rem_add;
}
printk(KERN_INFO "return value of cdev_add():%d\n", ret);
if((cl = class_create(THIS_MODULE, DRIVER_CLASS)) == NULL) {
printk(KERN_INFO "driver class registration failed\n");
goto rem_class;
}
printk(KERN_INFO "memory where class structure is stored:%p\n", cl);
if((device = device_create(cl, NULL, dev, NULL, DEVICE_NAME)) == NULL) {
printk(KERN_INFO "device file creation failed\n");
goto rem_device;
}
printk(KERN_INFO "memory where device structure is stored:%p\n", device);
if((gpio.map = ioremap(GPIO_BASE, 1000)) == NULL) {
printk(KERN_INFO "memory assign failed\n");
return -1;
}
printk(KERN_INFO "which memory location is allocated:%p\n", gpio.map);
if((gpio.addr = (volatile unsigned int *)gpio.map) == NULL) {
printk(KERN_INFO "virtual memory assignment failed\n");
return -1;
}
printk(KERN_INFO "virtual memory where gpio is mapped:%p\n", gpio.addr);
printk(KERN_INFO "gpio pins assignment:\n");
printk(KERN_INFO "gpio pins 0 through 6 as output pins, pin 0 to lcd R/W, 1 to lcd RS,\
2 to EN, 3 to 6 connect to lcd data pins D4 to D7\n");
//*(gpio.addr + 37) |= 2; // Enabling pull-up control
//delay(100); // as per BCM2835 datasheet
//*(gpio.addr + 38) |= 0xfff; // Enabling pull-up to the first 12 pins
lcd_init();
lcd_cmd(0x28);// 4 bit data lines
//lcd_cmd(0x38); // 8 bit data lines
lcd_cmd(0x01);
lcd_cmd(0x02);
lcd_cmd(0x0f);
lcd_cmd(0x80);
lcd_data('A');
lcd_data('B');
lcd_data('C');
j = 0;
while(*(str + j)) {
lcd_data(*(str+j));
j++;
}
printk(KERN_INFO "module loaded successfully\n");
return 0;
rem_add:
unregister_chrdev_region(dev, count);
return -1;
rem_class:
cdev_del(&my_cdev);
unregister_chrdev_region(dev, count);
return -1;
rem_device:
class_destroy(cl);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, count);
return -1;
}
static void __exit hello_exit(void)
{
if(gpio.addr) {
iounmap(gpio.addr);
}
device_destroy(cl, dev);
class_destroy(cl);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, count);
printk(KERN_INFO "module unloaded successfully\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("bhaskar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Dummy");