完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
开始编写LED驱动程序
1.需要用到的函数ioremap 因为linux内核并不像单片机一样是直接用寄存器地址控制的,操作系统有内存寻址的架构。所以我们需要把物理地址转换成Linux可以操作的地址。这个转换的过程就需要调用ioremap函数,下面的它的函数原型: #include void __iomen *ioremap(resource_size_t res_cookie, size_t size); void iounmap(volatile void __iomen *cookie); /* virtual_addr = ioremap(physical_addr, size); * 把physical_addr开始的size映射为虚拟地址,返回值时该段虚拟地址的首地址。 * physical_addr和size都会按页取整 */ 2.firefly3288 led原理图 WORK_LED使用GPIO8_A1,POWER_LED使用GPIO8_A2。 这两个LED引脚在高电平时熄灭,低电平时点亮。 3.Led初始化步骤
/* rk3288 GPIO8_A1 */ /* a. 使能 GPIO8 * set CRU to enable GPIO8 * CRU_CLKGATE14_CON 0xFF760000 + 0x198 * (1<<(8+16)) | (0<<8) */
/* b. 设置 GPIO8_A1 用于 GPIO * set PMU/GRF to configure GPIO8_A1 as GPIO * GRF_GPIO8A_IOMUX 0xFF770000 + 0x0080 * bit[3:2] = 0b00 * (3<<(2+16)) | (0<<2) */
/* c. 设置 GPIO8_A1 作为 output 引脚 * set GPIO_SWPORTA_DDR to configure GPIO8_A1 as output * GPIO_SWPORTA_DDR 0xFF7F0000 + 0x0004 * bit[1] = 0b1 */
/* d. 设置 GPIO8_A1 输出高电平 * set GPIO_SWPORTA_DR to configure GPIO8_A1 output 1 * GPIO_SWPORTA_DR 0xFF7F0000 + 0x0000 * bit[1] = 0b1 */ /* e. 设置 GPIO8_A1 输出低电平 * set GPIO_SWPORTA_DR to configure GPIO8_A1 output 0 * GPIO_SWPORTA_DR 0xFF7F0000 + 0x0000 * bit[1] = 0b0 */ Led操作步骤 和上面第四步时一样的。 源码 Makefile KERN_DIR = /home/book/Documents/100ask_firefly-rk3288/linux-4.4 all: make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o led_app led_app.c -Wno-error=unused-but-set-variable clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order rm -f hello_drv_test myled_drv-y:=led_drv.o board_demoo.o obj-m += myled_drv.o led_drv.c #include #include #include #include #include #include #include #include #include #include "led_ops.h" static int major = 0; static struct class *led_class; struct led_operations *p_led_ops; static int led_drv_open(struct inode *node, struct file *file) { int minor = iminor(node); printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); p_led_ops->init(minor); return 0; } static ssize_t led_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { int err; char status; struct inode *inode = file_inode(file); int minor = iminor(inode); printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); err = copy_from_user(&status, buf, 1); printk("write status:%x n", status); p_led_ops->ctl(minor, status); return 1; } static int led_drv_close(struct inode *node, struct file *file) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } static struct file_operations led_drv = { .owner = THIS_MODULE, .open = led_drv_open, .read = led_drv_read, .write = led_drv_write, .release = led_drv_close, }; static int __init led_drv_init(void) { int err; int i = 0; major = register_chrdev(0, "myled", &led_drv); led_class = class_create(THIS_MODULE, "led_class"); err = PTR_ERR(led_class); if(IS_ERR(led_class)) { unregister_chrdev(major, "myled"); printk(KERN_WARNING "class creatge failed %dn", err); return -1; } p_led_ops = get_board_led_ops(); for(i=0;i device_create(led_class, NULL, MKDEV(major, i), NULL, "myled%d", i); printk("%s %sled_drv_initn", __FILE__, __FUNCTION__); return 0; } static void __exit led_drv_exit(void) { int i; printk("%s %sled_drv_exitn", __FILE__, __FUNCTION__); for(i=0;i device_destroy(led_class, MKDEV(major, i)); class_destroy(led_class); unregister_chrdev(major, "myled"); } module_init(led_drv_init); module_exit(led_drv_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("chen"); board_demoo.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "led_ops.h" #define CRU_BASE_PHY_ADDRESS ((unsigned long)(0xff760000)) #define GRF_BASE_PHY_ADDRESS ((unsigned long)(0xff770000)) #define GPIO8_BASE_PHY_ADDRESS ((unsigned long)(0xff7f0000)) #define CRU_CLKGATE14_PHY_CON (0x0198) #define GRF_GPIO8A_PHY_IOMUX (0x0080) #define GPIO_SWPORTA_PHY_DR (0x0000) #define GPIO_SWPORTA_PHY_DDR (0x0004) static volatile unsigned int *CRU_CLKGATE14_CON; static volatile unsigned int *GRF_GPIO8A_IOMUX; static volatile unsigned int *GPIO8_SWPORTA_DDR; static volatile unsigned int *GPIO8_SWPORTA_DR; static int board_demoo_led_init(int which) { printk("%s %s line %d, led %dn", __FILE__, __FUNCTION__, __LINE__, which); if(!CRU_CLKGATE14_CON) { CRU_CLKGATE14_CON = ioremap(CRU_BASE_PHY_ADDRESS + CRU_CLKGATE14_PHY_CON, 4); GRF_GPIO8A_IOMUX = ioremap(GRF_BASE_PHY_ADDRESS + GRF_GPIO8A_PHY_IOMUX, 4); GPIO8_SWPORTA_DDR = ioremap(GPIO8_BASE_PHY_ADDRESS + GPIO_SWPORTA_PHY_DDR, 4); GPIO8_SWPORTA_DR = ioremap(GPIO8_BASE_PHY_ADDRESS + GPIO_SWPORTA_PHY_DR, 4); } if(which == 0) { *CRU_CLKGATE14_CON = (1<<(8+16)) | (0<<8); *GRF_GPIO8A_IOMUX |= (3<<(2+16)) | (0<<2); *GPIO8_SWPORTA_DDR |= (1<<1); } else if(which == 1) { *CRU_CLKGATE14_CON = (1<<(8+16)) | (0<<8); *GRF_GPIO8A_IOMUX |= (3<<(4+16)) | (0<<4); *GPIO8_SWPORTA_DDR |= (1<<2); } return 0; } static int board_demoo_led_ctl(int which, char status) { printk("%s %s line %d, led %d, %sn", __FILE__, __FUNCTION__, __LINE__, which, status?"on":"off"); if(which == 0) { if(status) { /* on: output 0 */ *GPIO8_SWPORTA_DR &= ~(1<<1); } else { /* off: output 1 */ *GPIO8_SWPORTA_DR |= (1<<1); } } else if(which == 1) { if(status) { *GPIO8_SWPORTA_DR &= ~(1<<2); } else { *GPIO8_SWPORTA_DR |= (1<<2); } } return 0; } static struct led_operations board_demoo_led_ops = { .num = 2, .init = board_demoo_led_init, .ctl = board_demoo_led_ctl, }; struct led_operations *get_board_led_ops(void) { return &board_demoo_led_ops; } led_ops.h #ifndef __LED_OPS_H_ #define __LED_OPS_H_ struct led_operations { int num; int (*init)(int which); /* init led, which:led num */ int (*ctl)(int which, char status); /* control led, whic:led num,status:0-On 1-Off */ }; struct led_operations *get_board_led_ops(void); #endif led_app.c #include #include #include #include #include #include void showUsage(void) { printf("app [dev_path] [on,off]n"); } int main(int argc, char *argv[]) { char status; if(argc < 3) { showUsage(); return -1; } int fd = open(argv[1], O_RDWR); if(fd < 0) { printf("app open device failed path:%s", argv[1]); return -1; } if(0 == strcmp(argv[2], "on")) { status = 1; int ret = write(fd, &status, 1); if(ret <= 0) { printf("app write device fialed %s",argv[2]); return -1; } else { printf("app write device %x", status); } } else if(0 == strcmp(argv[2], "off")) { status = 0; int ret = write(fd, &status, 1); if(ret <= 0) { printf("app write device fialed %s",argv[2]); return -1; } else { printf("app write device %x", status); } } return 0; } |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
rk1126实现BT601输入,输入不带IIC接口的驱动程序
1418 浏览 0 评论
1337 浏览 1 评论
2443 浏览 3 评论
RK3568 Android11让系统ntp校准时间生效,需要设置些什么
3172 浏览 1 评论
5204 浏览 2 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-20 18:01 , Processed in 0.924007 second(s), Total 72, Slave 56 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号