Linux驱动之GPIO函数、IO内存映射、混杂设备驱动

之前学习完了字符设备驱动的大体框架,现在我们就使用这个基本的框架来对硬件进行操作,例如通过指令控制led的状态,编写LED驱动。LED驱动有多种实现方式。

目录

GPIO函数

IO内存映射

混杂设备驱动


GPIO函数

首先加入需要的头文件。

#include <asm/gpio.h>

#include <mach/soc.h>

#include <mach/platform.h> 

GPIO属于资源,在内核中属于资源使用前就需要先申请,使用完就需要释放。 

使用gpio_request函数向内核申请需要的GPIO引脚。

int gpio_request(unsigned gpio, const char *label);

参数:

    gpio :GPIO引脚号

    本人使用的s5p6818,每组GPIO都有宏,然后加上组内编号。例如GPIOE13表示为              PAD_GPIO_E+13

    label:自定义标签,也可以说是名字吧,可以是NULL

返回0成功,返回小于0失败   

 使用gpio_free函数向内核释放使用的GPIO引脚。

void gpio_free(unsigned gpio);

//传入要释放的GPIO的端口号

根据s5p6818对GPIO接口操作的说明,对GPIO的操作分为:

选择复用功能    //每个引脚最多有4个复用功能,看原理图或手册选择

选择输入/输出模式

设置输出值/获取输入的值

有些引脚有不同的功能,使用前需要选择作用为GPIO,不同的板子可能对应的操作有些许差别。

我们把上面三个操作的函数介绍下,就写个小测试。

选择复用功能使用nxp_soc_gpio_set_io_func函数

void nxp_soc_gpio_set_io_func(unsigned int io, unsigned int func);

参数:

    io :GPIO的端口号

    func :使用宏来选择复用功能

 以上图为例,需要使用GPIOC17引脚作为GPIO,根据原理图GPIO功能在第二个,所以使用宏NX_GPIO_PADFUNC_1。

 选择输出输入模式使用gpio_direction_output,gpio_direction_input函数。

int gpio_direction_output(unsigned gpio, int value);

参数:

    gpio:GPIO端口号

    value:默认输出值

   

int gpio_direction_input(unsigned gpio):

//传入要设置的gpio端口号  

 设置输出值/获取输入的值使用gpio_set_value,gpio_get_value函数。

void gpio_set_value(unsigned gpio, int value);

参数:

    gpio:GPIO端口号

    value:输出的电平值

   

int gpio_get_value(unsigned gpio);

参数:

    gpio:GPIO端口号

//返回GPIO引脚的电平值

介绍完了,写一个LED的小测试程序吧。

led.h

#ifndef __LED_H
#define __LED_H

//定义命令的最大序数
#define IOC_MAX_NR 4 
//定义设备类型(幻数)
#define IOC_MAGIC 'L'

#define LED0 _IO(IOC_MAGIC,0)
#define LED1 _IO(IOC_MAGIC,1)
#define LED2 _IO(IOC_MAGIC,2)
#define LED3 _IO(IOC_MAGIC,3)


#endif

led_drv.c 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/ioctl.h>
#include <asm/gpio.h>
#include <mach/soc.h>
#include <mach/platform.h>
#include "led.h"

#define LED_MINOR 0

struct led_dest{
	int gpio;//gpio端口号
	char *name;//名称
};

//定义led的硬件信息
struct led_dest led_info[] = {
	[0] = {
		.gpio = PAD_GPIO_E+13,
		.name = "LED0",
	},
	[1] = {
		.gpio = PAD_GPIO_C+17,
		.name = "LED1",
	},
	[2] = {
		.gpio = PAD_GPIO_C+8,
		.name = "LED2",
	},
	[3] = {
		.gpio = PAD_GPIO_C+7,
		.name = "LED3",
	}
};

//设备号
dev_t dev;
//声明cdev
struct cdev led_cdev;
//设备类指针
struct class *led_class;
//设备指针
struct device *led_device;

/*
inode是文件的节点结构,用来存储文件静态信息
文件创建时,内核中就会有一个inode结构
file结构记录的是文件打开的信息
文件被打开时内核就会创建一个file结构
*/
int led_open(struct inode *inode, struct file *filp)
{
	printk("enter led_open!\n");

	return 0;
}

long led_ioctl(struct file *filp, unsigned int cmd, unsigned long data)
{
	printk("enter led_ioctl!\n");

	if(_IOC_TYPE(cmd) != IOC_MAGIC)   //如果命令中的幻数不是‘x’
		return -EINVAL;               //返回错误代码表示无效参数
	if(_IOC_NR(cmd) >= IOC_MAX_NR)    //如果命令中的序列数大于4
		return -EINVAL;               //返回错误代码表示无效参数
		
	gpio_set_value(led_info[_IOC_NR(cmd)].gpio, data);
	if(data)
		printk("LED%d:OFF!\n",_IOC_NR(cmd));
	else
		printk("LED%d:ON!\n",_IOC_NR(cmd));

	return 0;
}

int led_release(struct inode *inode, struct file *filp)
{
	printk("enter led_release!\n");

	return 0;
}

//声明操作函数集合
struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.unlocked_ioctl = led_ioctl,//ioctl接口
	.release = led_release,//对应用户close接口
};

//加载函数
int led_init(void)
{
	int ret,i;
	// 1.注册字符设备驱动
	ret = register_chrdev(0, "led_demo", &led_fops);
	if(ret<0){
		printk("register_chrdev failed!\n");
		goto failure_register_chrdev;
	}
	//构建设备号
	dev = MKDEV(ret,LED_MINOR);

	printk("register_chrdev success!\n");

	// 2.注册设备类
	/*成功会在/sys/class目录下出现led_class子目录*/
	led_class = class_create(THIS_MODULE, "led_class");
	if(IS_ERR(led_class)){
		printk("class_create failed!\n");
		ret = PTR_ERR(led_class);
		goto failure_class_create;
	}

	// 3.创建设备文件
	led_device = device_create(led_class, NULL, dev,NULL, "led");
	if(IS_ERR(led_device)){
		printk("device_create failed!\n");
		ret = PTR_ERR(led_device);
		goto failure_device_create;
	}

	// 4.申请gpio资源并初始化
    //ARRAY_SIZE(arr)求数组大小的宏,原型为sizeof(arr)/sizeof(arr[0])
	for(i=0;i<ARRAY_SIZE(led_info);i++){  
		//申请gpio
		ret = gpio_request(led_info[i].gpio, led_info[i].name);
		//设置复用功能
		if(i==0)
			nxp_soc_gpio_set_io_func(led_info[i].gpio,NX_GPIO_PADFUNC_0);
		else
			nxp_soc_gpio_set_io_func(led_info[i].gpio,NX_GPIO_PADFUNC_1);
		//设置输出模式,默认高电平---灭
		gpio_direction_output(led_info[i].gpio, 1);
	}

	return 0;

failure_device_create:
	class_destroy(led_class);// 3
failure_class_create:
	unregister_chrdev(MAJOR(dev), "led_demo");// 2
failure_register_chrdev:
	return ret;
}

//卸载函数
void led_exit(void)
{
	int i;

	//释放GPIO
	for(i=0;i<ARRAY_SIZE(led_info);i++){
		//LED熄灭
		gpio_set_value(led_info[i].gpio,1);
		gpio_free(led_info[i].gpio);
	}
	//销毁设备文件
	device_destroy(led_class, dev);
	//注销设备类
	class_destroy(led_class);
	//注销字符设备驱动
	unregister_chrdev(MAJOR(dev), "led_demo");
}

//声明为模块的入口和出口
module_init(led_init);
module_exit(led_exit);


MODULE_LICENSE("GPL");//GPL模块许可证
MODULE_AUTHOR("xin");//作者
MODULE_VERSION("1.0");//版本
MODULE_DESCRIPTION("led driver!");//描述信息

如果对 led_ioctl函数中_IOC_TYPE_IOC_NR两个宏不了解可以参考上一篇文章ioctl命令的统一格式

led_test.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "led.h"

int main()
{
	char ch = 0;

	int fd = open("/dev/led",O_RDWR);
	if(fd==-1){
		perror("open");
		exit(-1);
	}

	printf("open successed!fd = %d\n",fd);

	while(1){
		ch = getchar();

		if(ch=='q')
			break;

		switch(ch){
			case '1': ioctl(fd,LED0 ,0);//1灯亮
			break;
			
			case '2': ioctl(fd,LED0,1);//1灯灭
			break;
			
			case '3': ioctl(fd,LED1,0);//2灯亮
			break;
			
			case '4': ioctl(fd,LED1,1);//2灯灭
			break;
			
			case '5': ioctl(fd,LED2,0);//3灯亮
			break;
			
			case '6': ioctl(fd,LED2,1);//3灯灭
			break;
			
			case '7': ioctl(fd,LED3,0);//4灯亮
			break;
			
			case '8': ioctl(fd,LED3,1);//4灯灭
			break;
			
			default:
				printf("error input!\n");
			break;
		}
		while(ch=getchar()!='\n' && ch!=EOF)
		sleep(1);
	}

	close(fd);
	return 0;
}

 这样我们就可以通过应用程序输入字符1到8来控制LED灯状态。 

IO内存映射

我们使用函数去控制外设,是通过读写设备上的寄存器来进行的,每个寄存器都有物理地址在芯片手册中可以查到,但不管是在用户空间还是在内核空间,一律不能去直接访问寄存器的物理地址。内核中能够直接访问的地址是内核虚拟地址,所以需要MMU(内存管理单元)将寄存器的物理地址映射到内核虚拟地址空间再进行访问,之后驱动程序访问内核虚拟地址就是在间接访问寄存器的物理地址。

先引入两个需要使用到的函数头文件。

#include <linux/io.h>

#include <mach/platform.h>

使用ioremap建立映射。

#define ioremap(cookie,size)           __ioremap(cookie,size,0)

__ioremap函数原型为(arm/mm/ioremap.c):

void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);

参数:

phys_addr:需要映射的起始IO地址

size:要映射的空间的大小

flags:要映射的IO空间和权限有关的标志

该函数返回映射后的内核虚拟地址(3G-4G),接着便可以通过读写该返回的内核虚拟地址去访问之这段I/O内存资源

使用iounmap函数解除映射。

 void iounmap(void * addr);

参数:

addr:虚拟起始地址

 访问io内存的读写函数

读I/O内存
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);

写I/O内存
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);

参数:

addr:虚拟地址

 上面使用GPIO函数来控制LED灯,现在使用io内存映射,用虚拟地址来控制一个LED(GPIOE13)灯。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <mach/platform.h>
#include "led.h"

#define LED_MINOR 0

//声明IO内存映射地址
void __iomem *gpioe_base = NULL;

//设备号
dev_t dev;
//声明cdev
struct cdev led_cdev;
//设备类指针
struct class *led_class;
//设备指针
struct device *led_device;

/*
inode是文件的节点结构,用来存储文件静态信息
文件创建时,内核中就会有一个inode结构
file结构记录的是文件打开的信息
文件被打开时内核就会创建一个file结构
*/
int led_open(struct inode *inode, struct file *filp)
{
	printk("enter led_open!\n");

	return 0;
}

long led_ioctl(struct file *filp, unsigned int cmd, unsigned long data)
{
	printk("enter led_ioctl!\n");

	if(_IOC_TYPE(cmd) != IOC_MAGIC)   //如果命令中的幻数不是‘x’
		return - EINVAL;              //就返回错误代码表示无效参数
	if(_IOC_NR(cmd) >= IOC_MAX_NR)    //如果命令中的序列数大于4
		return - EINVAL;              //就返回错误代码表示无效参数
	if(data)
	{
		iowrite32(ioread32(gpioe_base)|(0x1<<13),gpioe_base);
		printk("LED%d:OFF!\n",_IOC_NR(cmd));
	}
	else
	{
		iowrite32(ioread32(gpioe_base)&~(0x1<<13),gpioe_base);
		printk("LED%d:ON!\n",_IOC_NR(cmd));
	}

	return 0;
}

int led_release(struct inode *inode, struct file *filp)
{
	printk("enter led_release!\n");

	return 0;
}

//声明操作函数集合
struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.unlocked_ioctl = led_ioctl,//ioctl接口
	.release = led_release,//对应用户close接口
};

//加载函数
int led_init(void)
{
	int ret;
	// 1.注册字符设备驱动
	ret = register_chrdev(0, "led_demo", &led_fops);
	if(ret<0){
		printk("register_chrdev failed!\n");
		goto failure_register_chrdev;
	}
	//构建设备号
	dev = MKDEV(ret,LED_MINOR);

	printk("register_chrdev success!\n");

	// 2.注册设备类
	/*成功会在/sys/class目录下出现led_class子目录*/
	led_class = class_create(THIS_MODULE, "led_class");
	if(IS_ERR(led_class)){
		printk("class_create failed!\n");
		ret = PTR_ERR(led_class);
		goto failure_class_create;
	}

	// 3.创建设备文件
	led_device = device_create(led_class, NULL, dev,NULL, "led");
	if(IS_ERR(led_device)){
		printk("device_create failed!\n");
		ret = PTR_ERR(led_device);
		goto failure_device_create;
	}

	// 4.IO内存映射
	gpioe_base = ioremap(PHY_BASEADDR_GPIOE, SZ_64);
	if(IS_ERR_OR_NULL(gpioe_base)){//失败
		printk("ioremap failed!\n");
		ret = -ENOMEM;
		goto failure_ioremap;
	}
	//初始化
	//设置复用功能 alt0  26 27位清0   addr:base+0x20
	
	iowrite32(ioread32(gpioe_base+0x20)&~(0x3<<26),gpioe_base+0x20);
	
	//设置输出模式  outenb 13位 置1   addr:base+0x04
	iowrite32(ioread32(gpioe_base+0x04)|(0x1<<13),gpioe_base+0x04);
	
	//设置默认值为高电平 out 13位 置1   addr:base
	iowrite32(ioread32(gpioe_base)|(0x1<<13),gpioe_base);


	return 0;
	
failure_ioremap:
	device_destroy(led_class, dev);
failure_device_create:
	class_destroy(led_class);
failure_class_create:
	unregister_chrdev(MAJOR(dev), "led_demo");
failure_register_chrdev:
	return ret;
}

//卸载函数
void led_exit(void)
{
	//解除IO映射
	iounmap(gpioe_base);
	//销毁设备文件
	device_destroy(led_class, dev);
	//注销设备类
	class_destroy(led_class);
	//注销字符设备驱动
	unregister_chrdev(MAJOR(dev), "led_demo");
}

//声明为模块的入口和出口
module_init(led_init);
module_exit(led_exit);


MODULE_LICENSE("GPL");//GPL模块许可证
MODULE_AUTHOR("xin");//作者
MODULE_VERSION("2.0");//版本
MODULE_DESCRIPTION("led driver!");//描述信息

gpioe_base = ioremap(PHY_BASEADDR_GPIOE, SZ_64);

PHY_BASEADDR_GPIOE这是内核定义的GPIOE的物理地址,SZ_64为64个字节

iowrite32(ioread32(gpioe_base+0x20)&~(0x3<<26),gpioe_base+0x20);

通过手册得知设置复用功能的寄存器在基地址上偏移0x20个地址。

先使用ioread32(gpioe_base+0x20)读取整个寄存器32位的值,然后ioread32(gpioe_base+0x20)&~(0x3<<26)把26和27位位置零,设置为GPIO功能,最后再写回去。初始化另外两个也是一样的意思,只是操作的寄存器不一样。

通过GPIO操作函数和io内存映射比较发现,内核gpio操作函数是通过封装IO内部映射来实现的,使用比较方便,但是只能用于GPIO操作。IO内存映射可以用于任意寄存器操作的场合

混杂设备驱动

在Linux驱动中,会把一些无法归类的设备定义为混杂设备——misc,它们是拥有着共同的特性的简单字符设备,它们的特点是共享统一的主设备号10,但每个设备可以选择一个单独的次设备号。

使用混杂设备需要头文件。

#include <linux/miscdevice.h>

混杂设备驱动相比于传统的字符设备来说,初始化很简单。字符设备需要先初始化cdev结构体,混杂设备也需要初始化miscdevice 结构体。

struct miscdevice  {

int minor;

const char *name;//设备文件名

const struct file_operations *fops;//操作函数集合

struct list_head list;

struct device *parent;

struct device *this_device;

const char *nodename;

umode_t mode;

};

//minor是次设备号,想要系统自动生成可以配置为MISC_DYNAMIC_MINOR

初始化完了 miscdevice 结构体就向内核注册这个混杂设备。

int misc_register(struct miscdevice * misc);

注销这个混杂设备。

int misc_deregister(struct miscdevice *misc);

这样就完成了一个混杂设备的使用,其实混杂设备的注册函数只创建了设备文件,其他的步骤都是在内核初始化阶段完成,在misc_init函数中完成。

那就看看使用混杂设备驱动怎么完成一个LED(GPIOE13)灯的控制吧。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <mach/platform.h>
#include <linux/miscdevice.h>
#include "led.h"


//声明IO内存映射地址
void __iomem *gpioe_base = NULL;

/*
inode是文件的节点结构,用来存储文件静态信息
文件创建时,内核中就会有一个inode结构
file结构记录的是文件打开的信息
文件被打开时内核就会创建一个file结构
*/
int led_open(struct inode *inode, struct file *filp)
{
	printk("enter led_open!\n");

	return 0;
}

long led_ioctl(struct file *filp, unsigned int cmd, unsigned long data)
{
	printk("enter led_ioctl!\n");
	
	if(_IOC_TYPE(cmd) != IOC_MAGIC)   //如果命令中的幻数不是‘x’
		return - EINVAL;              //就返回错误代码表示无效参数
	if(_IOC_NR(cmd) >= IOC_MAX_NR)    //如果命令中的序列数大于4
		return - EINVAL;              //就返回错误代码表示无效参数
	if(data)
	{
		iowrite32(ioread32(gpioe_base)|(0x1<<13),gpioe_base);
		printk("LED%d:OFF!\n",_IOC_NR(cmd));
	}
	else
	{
		iowrite32(ioread32(gpioe_base)&~(0x1<<13),gpioe_base);
		printk("LED%d:ON!\n",_IOC_NR(cmd));
	}

	return 0;
}

int led_release(struct inode *inode, struct file *filp)
{
	printk("enter led_release!\n");

	return 0;
}

//声明操作函数集合
struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.unlocked_ioctl = led_ioctl,//ioctl接口
	.release = led_release,//对应用户close接口
};

//分配初始化miscdevice
struct miscdevice led_dev = {
	.minor = MISC_DYNAMIC_MINOR,//系统分配次设备号
	.name = "led",//设备文件名
	.fops = &led_fops,//操作函数集合
};

//加载函数
int led_init(void)
{
	int ret;
	
	//注册miscdevice
	ret = misc_register(&led_dev);
	if(ret<0){
		printk("misc_register failed!\n");
		goto failure_misc_register;
	}

	//IO内存映射
	gpioe_base = ioremap(PHY_BASEADDR_GPIOE, SZ_64);
	if(IS_ERR_OR_NULL(gpioe_base)){//失败
		printk("ioremap failed!\n");
		ret = -ENOMEM;
		goto failure_ioremap;
	}
	
	//初始化
	//设置复用功能 alt0  26 27位清0   addr:base+0x20
	iowrite32(ioread32(gpioe_base+0x20)&~(0x3<<26),gpioe_base+0x20);

	//设置输出模式  outenb 13位 置1   addr:base+0x04
	iowrite32(ioread32(gpioe_base+0x04)|(0x1<<13),gpioe_base+0x04);
	
	//设置默认值为高电平 out 13位 置1   addr:base
	iowrite32(ioread32(gpioe_base)|(0x1<<13),gpioe_base);

	return 0;

failure_ioremap:
	misc_deregister(&led_dev);
failure_misc_register:
	return ret;
}

//卸载函数
void led_exit(void)
{
	//解除IO映射
	iounmap(gpioe_base);

	//注销miscdevice
	misc_deregister(&led_dev);
}

//声明为模块的入口和出口
module_init(led_init);
module_exit(led_exit);


MODULE_LICENSE("GPL");//GPL模块许可证
MODULE_AUTHOR("xin");//作者
MODULE_VERSION("3.0");//版本
MODULE_DESCRIPTION("led driver!");//描述信息

可以发现通过混杂设备驱动的框架来编写LED驱动,加载函数中轻便了不少,有许多的步骤都是内核完成。

 好了,以上就介绍完了字符设备通过GPIO函数或者IO内存映射来实现驱动,以及混杂设备怎么实现驱动的过程。有什么问题和建议欢迎在评论区中提出来哟。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开发板使用:CB-A(需要外接+5V) 1、在lichee中初始化RGB屏幕:KD027QVTPD022 W:\liuxing_csdn_tinav2.1\lichee\linux-3.4\drivers\video\sunxi\lcd\panels\default_panel.c static void LCD_panel_init(u32 sel) { u32 i; //printk("raoyiming +++ LCD_panel_init\n"); /**/ panel_rst(1); sunxi_lcd_delay_ms(1); panel_rst(0); sunxi_lcd_delay_ms(10); panel_rst(1); sunxi_lcd_delay_ms(120); return; } W:\liuxing_csdn_tinav2.1\lichee\linux-3.4\drivers\video\sunxi\lcd\panels\default_panel.h #define panel_rst(v) (sunxi_lcd_gpio_set_value(0, 0, v)) 第二个0是sys_config.fex中lcd_gpio_0 lcd_gpio_0 = port:PH07<1><0><default><0> 2、 W:\liuxing_csdn_tinav2.1\target\allwinner\astar-parrot\configs\sys_config.fex 生成的SPI的设备名: ;---------------------------------------------------------------------------------- ;[spi_board0] spi device configuration ;modalias = spi device name ;sflash_size = spi flash size, optional, if spi_board0 is nor flash , carefully ;max_speed_hz = max transfer speed ;bus_num = bus ID ;chip_select = chip select, 0,1 ;mode = SPI transfer mode ;---------------------------------------------------------------------------------- [spi_board0] ;modalias = "at25df641" modalias = "spidev" sflash_size = 32 max_speed_hz = 50000000 bus_num = 0 chip_select = 0 mode = 0 加入RGB的屏幕参数(如果希望调优请找模组厂协助): ;---------------------------------------------------------------------------------- ;lcd0 configuration ;lcd_if: 0:hv(sync+de); 1:8080; 2:ttl; 3:lvds; 4:dsi; 5:edp; 6:extend dsi ;lcd_x: lcd horizontal resolution ;lcd_y: lcd vertical resolution ;lcd_width: width of lcd in mm ;lcd_height: height of lcd in mm ;lcd_dclk_freq: in MHZ unit ;lcd_pwm_freq: in HZ unit ;lcd_pwm_pol: lcd backlight PWM polarity ;lcd_pwm_max_limit lcd backlight PWM max limit(<=255) ;lcd_hbp: hsync back porch ;lcd_ht: hsync total cycle ;lcd_vbp: vsync back porch ;lcd_vt: vysnc total cycle ;lcd_hspw: hsync plus width ;lcd_vspw: vysnc plus width ;lcd_lvds_if: 0:single link; 1:dual link ;lcd_lvds_colordepth: 0:8bit; 1:6bit ;lcd_lvds_mode: 0:NS mode; 1:JEIDA mode ;lcd_frm: 0:disable; 1:enable rgb666 dither; 2:enable rgb656 dither ;lcd_io_phase: 0:noraml; 1:intert phase(0~3bit: vsync phase; 4~7bit:hsync phase; ; 8~11bit:dclk phase; 12~15bit:de phase) ;lcd_gamma_en lcd gamma correction enable ;lcd_bright_curve_en lcd bright curve correction enable ;lcd_cmap_en lcd color map function enable ;deu_mode 0:smoll lcd screen; 1:large lcd screen(larger than 10inch) ;lcdgamma4iep: Smart Backlight parameter, lcd gamma vale * 10; ; decrease it while lcd is not bright enough; increase while lcd is too bright ;smart_color 90:normal lcd screen 65:retina lcd screen(9.7inch) ;---------------------------------------------------------------------------------- [lcd0_para] lcd_used = 1 lcd_driver_name = "default_lcd" lcd_if = 0 lcd_x = 320 lcd_y = 240 lcd_width = 0 lcd_height = 0 lcd_dclk_freq = 5 lcd_pwm_used = 1 lcd_pwm_ch = 0 lcd_pwm_freq = 50000 lcd_pwm_pol = 1 lcd_hbp = 60 lcd_ht = 390 lcd_hspw = 6 lcd_vbp = 6 lcd_vt = 250 lcd_vspw = 2 lcd_lvds_if = 0 lcd_lvds_colordepth = 0 lcd_lvds_mode = 0 lcd_frm = 1 lcd_gamma_en = 0 lcd_bright_curve_en = 0 lcd_cmap_en = 0 deu_mode = 0 lcdgamma4iep = 22 smart_color = 90 lcd_bl_en = port:PD13<1><0><default><1> lcd_power = "axp22_dc1sw" lcd_gpio_0 = port:PH07<1><0><default><0> lcd_gpio_1 = port:PL04<1><0><default><0> lcd_gpio_2 = port:PL11<1><0><default><1> ;lcdd0 = port:PD00<2><0><2><default> ;lcdd1 = port:PD01<2><0><2><default> lcdd2 = port:PD02<2><0><2><default> lcdd3 = port:PD03<2><0><2><default> lcdd4 = port:PD04<2><0><2><default> lcdd5 = port:PD05<2><0><2><default> lcdd6 = port:PD06<2><0><2><default> lcdd7 = port:PD07<2><0><2><default> ;lcdd8 = port:PD08<2><0><2><default> ;lcdd9 = port:PD09<2><0><2><default> lcdd10 = port:PD10<2><0><2><default> lcdd11 = port:PD11<2><0><2><default> lcdd12 = port:PD12<2><0><2><default> lcdd13 = port:PD13<2><0><2><default> lcdd14 = port:PD14<2><0><2><default> lcdd15 = port:PD15<2><0><2><default> ;lcdd16 = port:PD16<2><0><2><default> ;lcdd17 = port:PD17<2><0><2><default> lcdd18 = port:PD18<2><0><2><default> lcdd19 = port:PD19<2><0><2><default> lcdd20 = port:PD20<2><0><2><default> lcdd21 = port:PD21<2><0><2><default> lcdd22 = port:PD22<2><0><2><default> lcdd23 = port:PD23<2><0><2><default> lcdclk = port:PD24<2><0><3><default> lcdde = port:PD25<2><0><2><default> lcdhsync = port:PD26<2><0><2><default> lcdvsync = port:PD27<2><0><2><default> 3、原理:生成设备节点:/dev/spidev0.0。然后通用C格式的应用程序访问这个设备节点来初始化LCD。 编译刷机之后: 开机之后背光是亮的(背光被强制拉高了) root@TinaLinux:/# root@TinaLinux:/# find . -name spi* ./bin/spidev_test0 ./dev/spidev0.0 ./proc/irq/97/spi0 ./rom/bin/spidev_test0 ./rom/usr/lib/opkg/info/spidev_test0.control ./rom/usr/lib/opkg/info/spidev_test0.list ./sys/bus/spi ./sys/bus/spi/devices/spi0.0 ./sys/bus/spi/drivers/spidev ./sys/bus/spi/drivers/spidev/spi0.0 ./sys/bus/platform/devices/spi.0 ./sys/bus/platform/drivers/spi ./sys/bus/platform/drivers/spi/spi.0 ./sys/devices/platform/spi.0 ./sys/devices/platform/spi.0/spi_master ./sys/devices/platform/spi.0/spi_master/spi0 ./sys/devices/platform/spi.0/spi_master/spi0/spi0.0 ./sys/devices/platform/spi.0/spi_master/spi0/spi0.0/spidev ./sys/devices/platform/spi.0/spi_master/spi0/spi0.0/spidev/spidev0.0 ./sys/class/spi_master ./sys/class/spi_master/spi0 ./sys/class/spidev ./sys/class/spidev/spidev0.0 ./sys/kernel/debug/clk/hosc/pll_periph/pll_periphahb1/ahb1/spinlock ./sys/kernel/debug/clk/hosc/pll_periph/spi0 ./sys/kernel/debug/clk/hosc/spi1 ./sys/module/spidev ./usr/lib/opkg/info/spidev_test0.control ./usr/lib/opkg/info/spidev_test0.list root@TinaLinux:/# root@TinaLinux:/# (初始化屏幕之后是全绿:) root@TinaLinux:/# spidev_test0 spi mode: 0 bits per word: 8 max speed: 500000 Hz (500 KHz) send spi message success! root@TinaLinux:/# root@TinaLinux:/# (红绿蓝单色和一张静态图片的切换) root@TinaLinux:/# root@TinaLinux:/# root@TinaLinux:/# cb_test [ 203.906264] request_suspend_state: wakeup (0->0) at 203906241807 (1970-01-01 08:41:09.853073511 UTC) fb0 begining readCnt = 1 ****wyb 2017/7/3 9:36 x = 320 y = 240 bytes_per_pixel = 4 screensize = 307200 ----- RED 0 ----- GREEN ----- BLUE ----- RED 1 ----- GREEN ----- BLUE ^C root@TinaLinux:/# (绿红黑等单色循环测试) root@TinaLinux:/# root@TinaLinux:/# root@TinaLinux:/# fbtest **** wyb fbtest.c-391-main argc=1 **** wyb fbtest.c-453-main argc2=1 **** wyb fbtest.c-462-main opening framebuffer device success! **** wyb fbtest.c-471-main getting fix screeninfo success! **** wyb fbtest.c-480-main getting var screeninfo success! **** wyb fbtest.c-489-main setting mode success! **** wyb fbtest.c-498-main mmap'ing framebuffer device success! testing: ARGB for sizes: 320x240 ^C root@TinaLinux:/# root@TinaLinux:/# 4、改进方向: W:\liuxing_csdn_tinav2.1\lichee\linux-3.4\drivers\video\sunxi\lcd\panels\default_panel.c 在驱动中增加SPI初始化部分,然后还可以让开机自动进入红绿蓝的测试程序!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值