×
单片机 > 单片机程序设计 > 详情

【重温经典】mini2440驱动程序之LED驱动(基于Linux-2.6.32.2)

发布时间:2024-05-10 发布时间:
|

一、LED资源介绍

1、LED对应的GPIO(已上拉)

LED1 nLED1 GPB5


LED2 nLED2 GPB6


LED3 nLED3 GPB7


LED4 nLED4 GPB8


2、硬件电路

二、驱动代码(mini2440_leds.c)

以混杂设备注册,主要实现了ioctl接口,应用程序操作时,只需要打开这个设备文件,然后发一个ioctl的命令就会进入到内核空间,接着调用该驱动的ioctl函数来设置相应的状态。


(1)、设置GPIO为输出模式

for (i = 0; i < 4; i++) {

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); //配置文件输出模式

s3c2410_gpio_setpin(led_table[i], 0); //输出低电平,点亮4个GPIO

}

GPIO的s3c2410_gpio_cfgpin函数中的第二个参数S3C2410_GPIO_OUTPUT(值为0xFFFFFFF1,即高31:4为1,3:1为0,最低位为1),通过查看s3c2410_gpio_cfgpin得知,设置了GPIO对应的位为01,是代表输出模式,这个可以从s3c2440芯片手册上GPIO寄存器得知:

这里贴一下s3c2410_gpio_cfgpin函数的实现:


void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

{

void __iomem *base = S3C24XX_GPIO_BASE(pin);

unsigned long mask;

unsigned long con;

unsigned long flags;

if (pin < S3C2410_GPIO_BANKB) {

mask = 1 << S3C2410_GPIO_OFFSET(pin);

} else {

mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;

}

switch (function) {

case S3C2410_GPIO_LEAVE:

mask = 0;

function = 0;

break;

case S3C2410_GPIO_INPUT:

case S3C2410_GPIO_OUTPUT:

case S3C2410_GPIO_SFN2:

case S3C2410_GPIO_SFN3:

if (pin < S3C2410_GPIO_BANKB) {

function -= 1;

function &= 1;

function <<= S3C2410_GPIO_OFFSET(pin);

} else {

function &= 3;

function <<= S3C2410_GPIO_OFFSET(pin)*2;

}

}

/* modify the specified register wwith IRQs off */

local_irq_save(flags);

con = __raw_readl(base + 0x00);

con &= ~mask;

con |= function;

__raw_writel(con, base + 0x00);

local_irq_restore(flags);

}

(2)、编写ioctl接口

static int sbc2440_leds_ioctl(

struct inode *inode,

struct file *file,

unsigned int cmd,

unsigned long arg)

{

switch(cmd) {

case 0:

case 1:

if (arg > 4) {

return -EINVAL;

}

s3c2410_gpio_setpin(led_table[arg], !cmd); //注意,应用程序设为on(GPIO输出高电平)状态时,即驱动程序输出低电平;应用程序设为off(GPIO输出低电平)状态时,即驱动程序输出高电平,因为该硬件电路(上拉)决定。

return 0;

default:

return -EINVAL;

}

}

另外设置和读取GPIO pin的函数为s3c2410_gpio_getpin/s3c2410_gpio_setpin。


s3c2410_gpio_getpin的函数实现为:


unsigned int s3c2410_gpio_getpin(unsigned int pin)

{

void __iomem *base = S3C24XX_GPIO_BASE(pin);

unsigned long offs = S3C2410_GPIO_OFFSET(pin);

return __raw_readl(base + 0x04) & (1<< offs);

}

s3c2410_gpio_setpin的函数实现为:


void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)

{

void __iomem *base = S3C24XX_GPIO_BASE(pin);

unsigned long offs = S3C2410_GPIO_OFFSET(pin);

unsigned long flags;

unsigned long dat;

local_irq_save(flags);

dat = __raw_readl(base + 0x04);

dat &= ~(1 << offs);

dat |= to << offs;

__raw_writel(dat, base + 0x04);

local_irq_restore(flags);

}

我们注意到访问s3c2440的GPIO寄存器使用__raw_readl/__raw_writel函数,也就是直接访问GPIO寄存器。


static inline u32 __raw_readl(const volatile void __iomem *addr)

{

return *(const volatile u32 __force *) addr;

}

static inline void __raw_writel(u32 b, volatile void __iomem *addr)

{

*(volatile u32 __force *) addr = b;

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32 USB HID 键盘