linux下am335x点亮LED

首先借用一张图说明linux应用程序和内核的关系

![](http://i2.51cto.com/images/blog/201807/28/ce7cdc22c42c5b93bd5604c0ba1878db.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

与裸机程序不同,linux下的应用开发并不直接访问硬件,而是由应用程序调用驱动来访问硬件,这是linux的系统结构,具体可参考《嵌入式linux应用开发完全手册》。


回到am335x,已经在uboot实现LED的操作,基本原理一致,设置GPIO输出,低电平点亮LED。如果想通过内核空间操作文件的方式访问GPIO,可参考[BeagleBone的GPIO控制 ](http://blog.sina.com.cn/s/blog_9e16dc4d01012x7z.html)

![](http://i2.51cto.com/images/blog/201807/25/3169db826031c0f7bf0be54f26ac0d91.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)


linux3.2中driver/leds目录下存放有led相关文件,在此编写led驱动模块。代码参照[Am335x 下GPIO控制实例](https://blog.csdn.net/hudaweikevin/article/details/16826995)

添加文件leds-run.c

```

#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#define TEST_IO_NUM 89
#define NAME_MISC "GpioTest"
#define NAME_MOUDULE "GpioTest1"
#define USE_MISC_MODE 1
static int major = 251;
void GpioTest(void);
static long GpioIOctl(struct file *filp, unsigned cmd, unsigned long arg)
{
GpioTest();
return 1;
}
void GpioTest(void)
{
int iCount = 0;
for(iCount = 0; iCount <=20; iCount++ )
{
if(iCount%2 == 0)
{
gpio_direction_output(TEST_IO_NUM, 1);
printk(KERN_INFO"#######LED statu is high.\r\n");
}
else
{
gpio_direction_output(TEST_IO_NUM, 0);
printk(KERN_INFO"#######LED statu is low.\r\n");
}
mdelay(3000);
}
printk(KERN_INFO"#######App run over!");
}
static int GpioOpen(struct inode *inode, struct file *file)
{
int iRen = -1;
iRen = gpio_request(TEST_IO_NUM, "LED");
if(iRen < 0)
{
printk(KERN_INFO"#######Failed to request the LED!");
}else
{
printk(KERN_INFO"#######Success to request the LED");
}
return iRen;
}
static int GpioClose(struct inode *inode, struct file *file)
{
printk(KERN_INFO"#######Free the LED");
gpio_free(TEST_IO_NUM);
return 1;
}
//****entry point for TEST GPIO module
static const struct file_operations gpio_test_driver = {
.owner = THIS_MODULE,
.unlocked_ioctl= GpioIOctl,
.llseek = no_llseek,
.open = GpioOpen,
.release = GpioClose,
};
#if USE_MISC_MODE
static struct miscdevice gpiotest_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = NAME_MISC,
.fops = &gpio_test_driver,
};
#endif
static int __init GpioTestInit(void)
{
int iRet;
printk(KERN_INFO"#######GpioTest modules is install!\r\n");
#if USE_MISC_MODE
iRet = misc_register(&gpiotest_misc_device);
if (iRet) {
printk(KERN_INFO"#######unable to register a misc device\r\n");
return iRet;
}
#else
iRet = register_chrdev(major, NAME_MOUDULE, &gpio_test_driver);
if (iRet < 0) {
printk(KERN_INFO"#######unable to register a chr device\r\n");
return iRet;
}
#endif
return iRet;
}
static void __exit GpioTestExit(void)
{
#if USE_MISC_MODE
misc_deregister(&gpiotest_misc_device);
#else
unregister_chrdev(major, NAME_MOUDULE);
#endif
printk(KERN_INFO"#######GpioTest modules is exit!\r\n");
}
module_init(GpioTestInit);
module_exit(GpioTestExit);
MODULE_AUTHOR("XXXXXXXXXXXX");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System status led");

```

driver/leds目录下修改Kconfig,添加一项:

config GPIO_LED
bool "Gpio LED test"
help
Just test the Gpio LED status

同目录下Makefile文件修改:

obj-$(CONFIG_INPUT_
obj-$(CONFIG_GPIO_LED)+=leds-run.o

通过make menuconfig,将驱动模块GPIO_LED编译进内核。


应用程序app.c

#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <linux/input.h>
#include <fcntl.h>
int main(int argc, char *argv)
{
int fd;
fd = open("/dev/GpioTest", O_RDWR);
if(fd < 0)
{
printf("***Can't open the gpiotest!\r\n");
return -1;
}
ioctl(fd, 0, 0);
close(fd);
printf("***App run over!\r\n");
return 1;
}

烧写内核,内核启动后打印“#######GpioTest modules is install!”,运行app,可以正常运行,可led没有按照程序进行亮灭操作。


细想整个过程发现,am335x的IO口是复用的,需要先完成mux设置。

再回到linux内核,需要明确linux的运行流程,此次参考了 linux内核代码分析1 TI am335x

Board-am335xevm.c(./arch/arm/mach-omap2)中开始执行,


MACHINE_START(AM335XEVM, "am335xevm")
/* Maintainer: Texas Instruments */
.atag_offset= 0x100,
.map_io= am335x_evm_map_io,
.init_early= am33xx_init_early,
.init_irq= ti81xx_init_irq,
.handle_irq     = omap3_intc_handle_irq,
.timer= &omap3_am33xx_timer,
.init_machine= am335x_evm_init,
MACHINE_END

转到启动程序am335x_evm_init:


猜你喜欢

转载自blog.51cto.com/2423357/2151459