rpi 设备驱动程序中的 lcd 程序不产生任何字符显示

问题描述 投票:0回答:0

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");
c linux driver raspberry-pi3
© www.soinside.com 2019 - 2024. All rights reserved.