树莓派-LED篇

Posted skdev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树莓派-LED篇相关的知识,希望对你有一定的参考价值。

1 leds驱动

新增文件:arch\\arm\\boot\\dts\\overlays\\example-overlay.dts

/dts-v1/;

/plugin/;

 

/

compatible = "brcm,bcm2835";

 

fragment@0

target = <&gpio>;

__overlay__

leds_pins: leds_pins

brcm,pins = <25>;

brcm,function = <1>; /* out */

;

;

;

 

fragment@1

target = <&i2c_arm>;

__overlay__

#address-cells = <1>;

#size-cells = <0>;

status = "okay";

 

aw9523b: aw9523b@5b

compatible = "xxx,aw9523b-leds";

reg = <0x5b>;

pinctrl-names = "default";

pinctrl-0 = <&leds_pins>;

reset-gpios = <&gpio 25 0>;

status = "okay";

;

;

;

 

__overrides__

aw9523b = <&aw9523b>,"status";

;

;

 

linux\\arch\\arm\\boot\\dts\\overlays\\Makefile

dtbo-$(RPI_DT_OVERLAYS) += example-leds.dtbo

 

 

linux\\drivers\\leds\\leds-aw9523b.c

/*

 * TI LP8860 4-Channel LED Driver

 *

 * Copyright (C) 2014 Texas Instruments

 *

 * Author: Dan Murphy <dmurphy@ti.com>

 *

 * This program is free software; you can redistribute it and/or

 * modify it under the terms of the GNU General Public License

 * version 2 as published by the Free Software Foundation.

 *

 */

 

#include <linux/i2c.h>

#include <linux/init.h>

#include <linux/leds.h>

#include <linux/module.h>

#include <linux/mutex.h>

#include <linux/of.h>

#include <linux/of_gpio.h>

#include <linux/gpio.h>

#include <linux/slab.h>

#include <linux/delay.h>

 

 

#define AW9523B_REG_CHIPID 0x10

#define AW9523B_CHIPID_VALUE 0x23

#define AW9523B_LED_OFFSET 3

#define AW9523B_COLOR_OFFSET 3

 

static struct mutex aw9523b_mutex;

 

enum led_ids

LED1,

LED2,

LED3,

LED_NUM,

;

 

enum led_colors

LED1_RED = 0,

LED1_GREEN = 1,

LED1_BLUE = 2,

LED2_RED = 3,

LED2_GREEN = 4,

LED2_BLUE = 5,

LED3_RED = 6,

LED3_GREEN = 7,

LED3_BLUE = 8,

;

 

struct aw9523b_led

struct aw9523b_led_platform_data *pdata;

struct i2c_client *client;

struct rw_semaphore rwsem;

struct work_struct work;

 

/*

 * Making led_classdev as array is not recommended, because array

 * members prevent using 'container_of' macro. So repetitive works

 * are needed.

 */

struct led_classdev cdev_led1r;

struct led_classdev cdev_led1g;

struct led_classdev cdev_led1b;

 

struct led_classdev cdev_led2r;

struct led_classdev cdev_led2g;

struct led_classdev cdev_led2b;

 

struct led_classdev cdev_led3r;

struct led_classdev cdev_led3g;

struct led_classdev cdev_led3b;

 

 

enum led_ids led_id;

enum led_colors color;

enum led_brightness brightness;

 

int reset_gpio;

;

 

static inline u8 aw9523b_get_base_offset(enum led_ids id, enum led_colors color)

return id * AW9523B_LED_OFFSET + color;

 

static inline u8 aw9523b_get_reg_addr(enum led_ids id, enum led_colors color,

u8 reg_offset)

return reg_offset + aw9523b_get_base_offset(id, color);

 

 

/*--------------------------------------------------------------*/

/* AW9523BGU core functions */

/*--------------------------------------------------------------*/

 

static int aw9523b_write_byte(struct i2c_client *client, u8 reg, u8 val)

int ret;

 

mutex_lock(&aw9523b_mutex);

ret = i2c_smbus_write_byte_data(client, reg, val);

 

if (ret >= 0)

mutex_unlock(&aw9523b_mutex);

return 0;

 

dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\\n",

__func__, reg, val, ret);

mutex_unlock(&aw9523b_mutex);

 

return ret;

 

static int aw9523b_read_byte(struct i2c_client *client, u8 reg, u8 *val)

int ret;

 

mutex_lock(&aw9523b_mutex);

ret = i2c_smbus_read_byte_data(client, reg);

if (ret < 0)

mutex_unlock(&aw9523b_mutex);

return -EIO;

 

*val = ret;

mutex_unlock(&aw9523b_mutex);

return 0;

 

static void aw9523b_reset(struct i2c_client *client)

struct aw9523b_led *led = i2c_get_clientdata(client);

/* Configure RESET GPIO (L: RESET, H: RESET cancel) */

gpio_direction_output(led->reset_gpio, 0);

 

/* Tacss = min 0.1ms */

udelay(20);

gpio_direction_output(led->reset_gpio, 1);

udelay(100);

 

aw9523b_write_byte(client,0x12,0x00);   //OUT4~9配置为呼吸灯模式

aw9523b_write_byte(client,0x12,0x00);   //OUT4~9配置为呼吸灯模式  

aw9523b_write_byte(client,0x13,0x00);   //OUT0~3配置为呼吸灯模式

aw9523b_write_byte(client,0x13,0x00);   //OUT0~3配置为呼吸灯模式

static void aw9523b_set_brightness(struct aw9523b_led *led, enum led_ids id,

enum led_colors color, enum led_brightness brightness)

u8 reg;

int ret;

 

reg = aw9523b_get_reg_addr(id, color, 0x20);

ret = aw9523b_write_byte(led->client, reg, brightness);

if(ret <0)

aw9523b_reset(led->client);

 

#define AW9523B_SET_REGISTER(reg_addr, reg_name) \\

static ssize_t aw9523b_store_reg##reg_addr(struct device *dev, \\

struct device_attribute *attr, const char *buf, size_t count) \\

\\

struct aw9523b_led *led = i2c_get_clientdata(to_i2c_client(dev));\\

unsigned long val; \\

int ret; \\

if (!count) \\

return -EINVAL; \\

ret = kstrtoul(buf, 16, &val); \\

if (ret) \\

return ret; \\

down_write(&led->rwsem); \\

aw9523b_write_byte(led->client, reg_addr, (u8) val); \\

up_write(&led->rwsem); \\

return count; \\

\\

static struct device_attribute aw9523b_reg##reg_addr##_attr = \\

.attr = .name = reg_name, .mode = 0644, \\

.store = aw9523b_store_reg##reg_addr, \\

;

 

AW9523B_SET_REGISTER(0x20, "0x20");

AW9523B_SET_REGISTER(0x21, "0x21");

AW9523B_SET_REGISTER(0x22, "0x22");

AW9523B_SET_REGISTER(0x23, "0x23");

AW9523B_SET_REGISTER(0x24, "0x24");

AW9523B_SET_REGISTER(0x25, "0x25");

AW9523B_SET_REGISTER(0x26, "0x26");

AW9523B_SET_REGISTER(0x27, "0x27");

AW9523B_SET_REGISTER(0x28, "0x28");

AW9523B_SET_REGISTER(0x29, "0x29");

AW9523B_SET_REGISTER(0x2a, "0x2a");

AW9523B_SET_REGISTER(0x2b, "0x2b");

AW9523B_SET_REGISTER(0x2c, "0x2c");

AW9523B_SET_REGISTER(0x2d, "0x2d");

AW9523B_SET_REGISTER(0x2e, "0x2e");

AW9523B_SET_REGISTER(0x2f, "0x2f");

 

static struct device_attribute *aw9523b_addr_attributes[] =

&aw9523b_reg0x20_attr,

&aw9523b_reg0x21_attr,

&aw9523b_reg0x22_attr,

&aw9523b_reg0x23_attr,

&aw9523b_reg0x24_attr,

&aw9523b_reg0x25_attr,

&aw9523b_reg0x26_attr,

&aw9523b_reg0x27_attr,

&aw9523b_reg0x28_attr,

&aw9523b_reg0x29_attr,

&aw9523b_reg0x2a_attr,

&aw9523b_reg0x2b_attr,

&aw9523b_reg0x2c_attr,

&aw9523b_reg0x2d_attr,

&aw9523b_reg0x2e_attr,

&aw9523b_reg0x2f_attr,

;

 

static void aw9523b_enable_adv_conf(struct aw9523b_led *led)

int i, ret;

 

for (i = 0; i < ARRAY_SIZE(aw9523b_addr_attributes); i++)

ret = device_create_file(&led->client->dev,

aw9523b_addr_attributes[i]);

if (ret)

dev_err(&led->client->dev, "failed: sysfs file %s\\n",

aw9523b_addr_attributes[i]->attr.name);

goto failed_remove_files;

 

return;

 

failed_remove_files:

for (i--; i >= 0; i--)

device_remove_file(&led->client->dev,

aw9523b_addr_attributes[i]);

 

static void aw9523b_disable_adv_conf(struct aw9523b_led *led)

int i;

 

for (i = 0; i < ARRAY_SIZE(aw9523b_addr_attributes); i++)

device_remove_file(&led->client->dev,

aw9523b_addr_attributes[i]);

 

static void aw9523b_led_work(struct work_struct *work)

struct aw9523b_led *led = container_of(work, struct aw9523b_led, work);

 

//printk("led%d: color = %d,brightness = %d\\n",led->led_id, led->color, led->brightness);

aw9523b_set_brightness(led, led->led_id, led->color, led->brightness);

 

#define AW9523B_CONTROL_RGBS(name, id, clr) \\

static void aw9523b_set_##name##_brightness(struct led_classdev *led_cdev,\\

enum led_brightness value) \\

\\

struct aw9523b_led *led = \\

container_of(led_cdev, struct aw9523b_led, cdev_##name); \\

led->led_id = id; \\

led->color = clr; \\

led->brightness = value; \\

schedule_work(&led->work); \\

 

AW9523B_CONTROL_RGBS(led1r, LED1, LED1_RED);

AW9523B_CONTROL_RGBS(led1g, LED1, LED1_GREEN);

AW9523B_CONTROL_RGBS(led1b, LED1, LED1_BLUE);

 

AW9523B_CONTROL_RGBS(led2r, LED2, LED2_RED);

AW9523B_CONTROL_RGBS(led2g, LED2, LED2_GREEN);

AW9523B_CONTROL_RGBS(led2b, LED2, LED2_BLUE);

 

AW9523B_CONTROL_RGBS(led3r, LED3, LED3_RED);

AW9523B_CONTROL_RGBS(led3g, LED3, LED3_GREEN);

AW9523B_CONTROL_RGBS(led3b, LED3, LED3_BLUE);

 

static int aw9523b_register_led_classdev(struct aw9523b_led *led)

int ret;

 

INIT_WORK(&led->work, aw9523b_led_work);

 

//led1//

led->cdev_led1r.name = "led1_R";

led->cdev_led1r.brightness = LED_OFF;

led->cdev_led1r.brightness_set = aw9523b_set_led1r_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led1r.name);

goto failed_unregister_led1_R;

 

led->cdev_led1g.name = "led1_G";

led->cdev_led1g.brightness = LED_OFF;

led->cdev_led1g.brightness_set = aw9523b_set_led1g_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led1g.name);

goto failed_unregister_led1_G;

 

led->cdev_led1b.name = "led1_B";

led->cdev_led1b.brightness = LED_OFF;

led->cdev_led1b.brightness_set = aw9523b_set_led1b_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led1b.name);

goto failed_unregister_led1_B;

 

//led2//

led->cdev_led2r.name = "led2_R";

led->cdev_led2r.brightness = LED_OFF;

led->cdev_led2r.brightness_set = aw9523b_set_led2r_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led2r.name);

goto failed_unregister_led2_R;

 

led->cdev_led2g.name = "led2_G";

led->cdev_led2g.brightness = LED_OFF;

led->cdev_led2g.brightness_set = aw9523b_set_led2g_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led2g.name);

goto failed_unregister_led2_G;

 

led->cdev_led2b.name = "led2_B";

led->cdev_led2b.brightness = LED_OFF;

led->cdev_led2b.brightness_set = aw9523b_set_led2b_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led2b.name);

goto failed_unregister_led2_B;

 

//led3//

led->cdev_led3r.name = "led3_R";

led->cdev_led3r.brightness = LED_OFF;

led->cdev_led3r.brightness_set = aw9523b_set_led3r_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led3r);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led3r.name);

goto failed_unregister_led3_R;

 

led->cdev_led3g.name = "led3_G";

led->cdev_led3g.brightness = LED_OFF;

led->cdev_led3g.brightness_set = aw9523b_set_led3g_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led3g);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led3g.name);

goto failed_unregister_led3_G;

 

led->cdev_led3b.name = "led3_B";

led->cdev_led3b.brightness = LED_OFF;

led->cdev_led3b.brightness_set = aw9523b_set_led3b_brightness;

 

ret = led_classdev_register(&led->client->dev, &led->cdev_led3b);

if (ret < 0)

dev_err(&led->client->dev, "couldn't register LED %s\\n",

led->cdev_led3b.name);

goto failed_unregister_led3_B;

 

return 0;

 

failed_unregister_led3_B:

led_classdev_unregister(&led->cdev_led3g);

failed_unregister_led3_G:

led_classdev_unregister(&led->cdev_led3r);

failed_unregister_led3_R:

led_classdev_unregister(&led->cdev_led2b);

failed_unregister_led2_B:

led_classdev_unregister(&led->cdev_led2g);

failed_unregister_led2_G:

led_classdev_unregister(&led->cdev_led2r);

failed_unregister_led2_R:

led_classdev_unregister(&led->cdev_led1b);

failed_unregister_led1_B:

led_classdev_unregister(&led->cdev_led1g);

failed_unregister_led1_G:

led_classdev_unregister(&led->cdev_led1r);

failed_unregister_led1_R:

 

return ret;

 

static void aw9523b_unregister_led_classdev(struct aw9523b_led *led)

cancel_work_sync(&led->work);

led_classdev_unregister(&led->cdev_led1r);

led_classdev_unregister(&led->cdev_led1g);

led_classdev_unregister(&led->cdev_led1b);

led_classdev_unregister(&led->cdev_led2r);

led_classdev_unregister(&led->cdev_led2g);

led_classdev_unregister(&led->cdev_led2b);

led_classdev_unregister(&led->cdev_led3r);

led_classdev_unregister(&led->cdev_led3g);

led_classdev_unregister(&led->cdev_led3b);

 

int aw9523b_match_id(struct i2c_client *client)

u8 id = 0;

int tries = 5;

 

while(tries > 0)

aw9523b_read_byte(client,AW9523B_REG_CHIPID,&id);

printk("read led control chip id: 0x%x\\n", id);

if (id == AW9523B_CHIPID_VALUE)

printk("matched");

return 0;

tries--;

return 1;

 

static int aw9523b_init(struct aw9523b_led *led)

int ret = 0;

struct i2c_client *client = led->client;

 

if (led->reset_gpio)

gpio_set_value(led->reset_gpio, 0);

 

/* Tacss = min 0.1ms */

udelay(20);

gpio_set_value(led->reset_gpio, 1);

udelay(100);

 

ret = aw9523b_match_id(client);

if(ret)

dev_err(&led->client->dev, "Cannot read chip\\n");

goto out;

 

aw9523b_write_byte(client,0x12,0x00);   //OUT4~9配置为呼吸灯模式

aw9523b_write_byte(client,0x12,0x00);   //OUT4~9配置为呼吸灯模式  

aw9523b_write_byte(client,0x13,0x00);   //OUT0~3配置为呼吸灯模式

aw9523b_write_byte(client,0x13,0x00);   //OUT0~3配置为呼吸灯模式

 

return 0;

out:

if (ret)

if (led->reset_gpio)

gpio_set_value(led->reset_gpio, 0);

return ret;

 

static int aw9523b_probe(struct i2c_client *client,

const struct i2c_device_id *id)

int ret;

struct aw9523b_led *led;

int gpio = 0;

 

printk("%s:enter\\n",__FUNCTION__);

mutex_init(&aw9523b_mutex);

 

led = kzalloc(sizeof(struct aw9523b_led), GFP_KERNEL);

if (!led)

dev_err(&client->dev, "failed to allocate driver data\\n");

return -ENOMEM;

 

if (client->dev.of_node)

/* Get GPIO from device tree */

gpio = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);

if (gpio < 0)

dev_err(&client->dev,

"Failed to retrieve reset-gpios from device tree\\n");

return gpio;

 

/* GPIO request and configuration */

ret = devm_gpio_request_one(&client->dev, gpio,

GPIOF_OUT_INIT_HIGH, "aw9523b_reset");

if (ret)

dev_err(&client->dev, "Failed to request reset pin\\n");

goto failed_free;

 

led->reset_gpio = gpio;

led->client = client;

 

init_rwsem(&led->rwsem);

 

i2c_set_clientdata(client, led);

 

ret = aw9523b_init(led);

if (ret)

goto failed_free;

 

ret = aw9523b_register_led_classdev(led);

if (ret)

dev_err(&client->dev, "led register err: %d\\n", ret);

goto failed_free;

 

//aw9523b_enable_adv_conf(led);

printk("%s:exit\\n",__FUNCTION__);

return 0;

 

failed_free:

kfree(led);

 

return ret;

 

static int aw9523b_remove(struct i2c_client *client)

struct aw9523b_led *led = i2c_get_clientdata(client);

 

gpio_set_value(led->reset_gpio, 0);

aw9523b_unregister_led_classdev(led);

 

//aw9523b_disable_adv_conf(led);

 

kfree(led);

return 0;

 

static const struct i2c_device_id aw9523b_id[] =

"aw9523b", 0 ,

;

MODULE_DEVICE_TABLE(i2c, aw9523b_id);

 

#ifdef CONFIG_OF

static const struct of_device_id of_aw9523b_leds_match[] =

.compatible = "xxx,aw9523b-leds", ,

,

;

MODULE_DEVICE_TABLE(of, of_aw9523b_leds_match);

#endif

 

static struct i2c_driver aw9523b_driver =

.driver =

.name = "aw9523b",

.of_match_table = of_match_ptr(of_aw9523b_leds_match),

,

.probe = aw9523b_probe,

.remove = aw9523b_remove,

.id_table = aw9523b_id,

;

module_i2c_driver(aw9523b_driver);

 

MODULE_DESCRIPTION("AW9523B LED driver");

MODULE_AUTHOR("Thornton Wu <447116230@qq.com>");

MODULE_LICENSE("GPL");

 

linux\\drivers\\leds\\Makefile

obj-m += leds-aw9523b.o

2 KERNEL编译

export PATH=$PATH:/home/thornton/work/pi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=/home/thornton/work/pi/firmware modules_install

 

3 KERNEL更新

将RPI T卡插在LINUX系统下,会弹出两个盘,一个是KERENL盘和一个BOOT盘

将firmware/lib拷到KERNEL盘,其他拷到BOOT盘

 

4 启动驱动

/boot/config.txt

dtoverlay=example-leds

 

/etc/ modules

leds-aw9523b

 

/etc/udev/rules.d/ 99-com.rules

SUBSYSTEM=="leds", PROGRAM="/bin/sh -c '\\

        chmod 666 /sys/class/leds/led1_R/brightness;\\

        chmod 666 /sys/class/leds/led1_G/brightness;\\

        chmod 666 /sys/class/leds/led1_B/brightness;\\

        chmod 666 /sys/class/leds/led2_R/brightness;\\

        chmod 666 /sys/class/leds/led2_G/brightness;\\

        chmod 666 /sys/class/leds/led2_B/brightness;\\

        chmod 666 /sys/class/leds/led3_R/brightness;\\

        chmod 666 /sys/class/leds/led3_G/brightness;\\

        chmod 666 /sys/class/leds/led3_B/brightness;\\

'"

 

以上是关于树莓派-LED篇的主要内容,如果未能解决你的问题,请参考以下文章

树莓派使用threading函数实现多按键控制LED灯

树莓派使用threading函数实现多按键控制LED灯

python怎么编程控制树莓派led

云中树莓派:利用声音传感器控制Led灯

《树莓派项目实战》第四节 用LED点阵显示爱心

关闭树莓派的 LED