drivers: Dev. spec. PWM functionality for SX1509B
Add device specific functions for initiating and controlling PWM output pins. Signed-off-by: Erik Robstad <erik.robstad@nordicsemi.no>
This commit is contained in:
parent
6bc79ce33a
commit
1feb49fd22
8 changed files with 358 additions and 34 deletions
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Aapo Vienamo
|
||||
* Copyright (c) 2018 Peter Bigot Consulting, LLC
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2019-2020 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2020 ZedBlox Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
|
@ -15,6 +15,7 @@
|
|||
#include <device.h>
|
||||
#include <init.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/gpio/gpio_sx1509b.h>
|
||||
#include <drivers/i2c.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <sys/util.h>
|
||||
|
@ -62,6 +63,7 @@ struct sx1509b_drv_data {
|
|||
struct gpio_driver_data common;
|
||||
const struct device *i2c_master;
|
||||
struct sx1509b_pin_state pin_state;
|
||||
uint16_t led_drv_enable;
|
||||
struct sx1509b_debounce_state debounce_state;
|
||||
struct k_sem lock;
|
||||
|
||||
|
@ -110,6 +112,14 @@ enum {
|
|||
SX1509B_REG_CLOCK_FOSC_INT_2MHZ = 2 << 5,
|
||||
};
|
||||
|
||||
/* Register bits for SX1509B_REG_MISC */
|
||||
enum {
|
||||
SX1509B_REG_MISC_LOG_A = 1 << 3,
|
||||
SX1509B_REG_MISC_LOG_B = 1 << 7,
|
||||
/* ClkX = fOSC */
|
||||
SX1509B_REG_MISC_FREQ = 1 << 4,
|
||||
};
|
||||
|
||||
/* Pin configuration register addresses */
|
||||
enum {
|
||||
SX1509B_REG_INPUT_DISABLE = 0x00,
|
||||
|
@ -123,6 +133,8 @@ enum {
|
|||
SX1509B_REG_INTERRUPT_SENSE_B = 0x14,
|
||||
SX1509B_REG_INTERRUPT_SENSE_A = 0x16,
|
||||
SX1509B_REG_INTERRUPT_SOURCE = 0x18,
|
||||
SX1509B_REG_MISC = 0x1f,
|
||||
SX1509B_REG_LED_DRV_ENABLE = 0x20,
|
||||
SX1509B_REG_DEBOUNCE_CONFIG = 0x22,
|
||||
SX1509B_REG_DEBOUNCE_ENABLE = 0x23,
|
||||
};
|
||||
|
@ -135,6 +147,12 @@ enum {
|
|||
SX1509B_EDGE_BOTH = 0x03,
|
||||
};
|
||||
|
||||
/* Intensity register addresses for all 16 pins */
|
||||
static const uint8_t intensity_registers[16] = { 0x2a, 0x2d, 0x30, 0x33,
|
||||
0x36, 0x3b, 0x40, 0x45,
|
||||
0x4a, 0x4d, 0x50, 0x53,
|
||||
0x56, 0x5b, 0x60, 0x65 };
|
||||
|
||||
/**
|
||||
* @brief Write a big-endian word to an internal address of an I2C slave.
|
||||
*
|
||||
|
@ -230,6 +248,44 @@ static void sx1509_int_cb(const struct device *dev,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int write_pin_state(const struct sx1509b_config *cfg,
|
||||
struct sx1509b_drv_data *drv_data,
|
||||
struct sx1509b_pin_state *pins, bool data_first)
|
||||
{
|
||||
struct {
|
||||
uint8_t reg;
|
||||
struct sx1509b_pin_state pins;
|
||||
} __packed pin_buf;
|
||||
int rc;
|
||||
|
||||
pin_buf.reg = SX1509B_REG_INPUT_DISABLE;
|
||||
pin_buf.pins.input_disable = sys_cpu_to_be16(pins->input_disable);
|
||||
pin_buf.pins.long_slew = sys_cpu_to_be16(pins->long_slew);
|
||||
pin_buf.pins.low_drive = sys_cpu_to_be16(pins->low_drive);
|
||||
pin_buf.pins.pull_up = sys_cpu_to_be16(pins->pull_up);
|
||||
pin_buf.pins.pull_down = sys_cpu_to_be16(pins->pull_down);
|
||||
pin_buf.pins.open_drain = sys_cpu_to_be16(pins->open_drain);
|
||||
pin_buf.pins.polarity = sys_cpu_to_be16(pins->polarity);
|
||||
pin_buf.pins.dir = sys_cpu_to_be16(pins->dir);
|
||||
pin_buf.pins.data = sys_cpu_to_be16(pins->data);
|
||||
|
||||
if (data_first) {
|
||||
rc = i2c_reg_write_word_be(drv_data->i2c_master,
|
||||
cfg->i2c_slave_addr,
|
||||
SX1509B_REG_DATA, pins->data);
|
||||
if (rc == 0) {
|
||||
rc = i2c_write(drv_data->i2c_master, &pin_buf.reg,
|
||||
sizeof(pin_buf) - sizeof(pins->data),
|
||||
cfg->i2c_slave_addr);
|
||||
}
|
||||
} else {
|
||||
rc = i2c_write(drv_data->i2c_master, &pin_buf.reg,
|
||||
sizeof(pin_buf), cfg->i2c_slave_addr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sx1509b_config(const struct device *dev,
|
||||
gpio_pin_t pin,
|
||||
gpio_flags_t flags)
|
||||
|
@ -237,10 +293,6 @@ static int sx1509b_config(const struct device *dev,
|
|||
const struct sx1509b_config *cfg = dev->config;
|
||||
struct sx1509b_drv_data *drv_data = dev->data;
|
||||
struct sx1509b_pin_state *pins = &drv_data->pin_state;
|
||||
struct {
|
||||
uint8_t reg;
|
||||
struct sx1509b_pin_state pins;
|
||||
} __packed pin_buf;
|
||||
struct sx1509b_debounce_state *debounce = &drv_data->debounce_state;
|
||||
int rc = 0;
|
||||
bool data_first = false;
|
||||
|
@ -267,6 +319,19 @@ static int sx1509b_config(const struct device *dev,
|
|||
|
||||
k_sem_take(&drv_data->lock, K_FOREVER);
|
||||
|
||||
if (drv_data->led_drv_enable & BIT(pin)) {
|
||||
/* Disable LED driver */
|
||||
drv_data->led_drv_enable &= ~BIT(pin);
|
||||
rc = i2c_reg_write_word_be(drv_data->i2c_master,
|
||||
cfg->i2c_slave_addr,
|
||||
SX1509B_REG_LED_DRV_ENABLE,
|
||||
drv_data->led_drv_enable);
|
||||
|
||||
if (rc) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
pins->open_drain &= ~BIT(pin);
|
||||
if ((flags & GPIO_SINGLE_ENDED) != 0) {
|
||||
if ((flags & GPIO_LINE_OPEN_DRAIN) != 0) {
|
||||
|
@ -314,37 +379,12 @@ static int sx1509b_config(const struct device *dev,
|
|||
debounce->debounce_enable &= ~BIT(pin);
|
||||
}
|
||||
|
||||
pin_buf.reg = SX1509B_REG_INPUT_DISABLE;
|
||||
pin_buf.pins.input_disable = sys_cpu_to_be16(pins->input_disable);
|
||||
pin_buf.pins.long_slew = sys_cpu_to_be16(pins->long_slew);
|
||||
pin_buf.pins.low_drive = sys_cpu_to_be16(pins->low_drive);
|
||||
pin_buf.pins.pull_up = sys_cpu_to_be16(pins->pull_up);
|
||||
pin_buf.pins.pull_down = sys_cpu_to_be16(pins->pull_down);
|
||||
pin_buf.pins.open_drain = sys_cpu_to_be16(pins->open_drain);
|
||||
pin_buf.pins.polarity = sys_cpu_to_be16(pins->polarity);
|
||||
pin_buf.pins.dir = sys_cpu_to_be16(pins->dir);
|
||||
pin_buf.pins.data = sys_cpu_to_be16(pins->data);
|
||||
|
||||
LOG_DBG("CFG %u %x : ID %04x ; PU %04x ; PD %04x ; DIR %04x ; DAT %04x",
|
||||
pin, flags,
|
||||
pins->input_disable, pins->pull_up, pins->pull_down,
|
||||
pins->dir, pins->data);
|
||||
if (data_first) {
|
||||
rc = i2c_reg_write_word_be(drv_data->i2c_master,
|
||||
cfg->i2c_slave_addr,
|
||||
SX1509B_REG_DATA, pins->data);
|
||||
if (rc == 0) {
|
||||
rc = i2c_write(drv_data->i2c_master,
|
||||
&pin_buf.reg,
|
||||
sizeof(pin_buf) - sizeof(pins->data),
|
||||
cfg->i2c_slave_addr);
|
||||
}
|
||||
} else {
|
||||
rc = i2c_write(drv_data->i2c_master,
|
||||
&pin_buf.reg,
|
||||
sizeof(pin_buf),
|
||||
cfg->i2c_slave_addr);
|
||||
}
|
||||
|
||||
rc = write_pin_state(cfg, drv_data, pins, data_first);
|
||||
|
||||
if (rc == 0) {
|
||||
struct {
|
||||
|
@ -611,8 +651,12 @@ static int sx1509b_init(const struct device *dev)
|
|||
SX1509B_REG_DIR,
|
||||
drv_data->pin_state.dir);
|
||||
}
|
||||
if (rc != 0) {
|
||||
goto out;
|
||||
if (rc == 0) {
|
||||
rc = i2c_reg_write_byte_be(
|
||||
drv_data->i2c_master, cfg->i2c_slave_addr,
|
||||
SX1509B_REG_MISC,
|
||||
SX1509B_REG_MISC_LOG_A | SX1509B_REG_MISC_LOG_B |
|
||||
SX1509B_REG_MISC_FREQ);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -649,6 +693,80 @@ static const struct gpio_driver_api api_table = {
|
|||
#endif
|
||||
};
|
||||
|
||||
int sx1509b_led_intensity_pin_configure(const struct device *dev,
|
||||
gpio_pin_t pin)
|
||||
{
|
||||
const struct sx1509b_config *cfg = dev->config;
|
||||
struct sx1509b_drv_data *drv_data = dev->data;
|
||||
struct sx1509b_pin_state *pins = &drv_data->pin_state;
|
||||
int rc;
|
||||
|
||||
/* Can't do I2C bus operations from an ISR */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
if (pin >= ARRAY_SIZE(intensity_registers)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
k_sem_take(&drv_data->lock, K_FOREVER);
|
||||
|
||||
/* Enable LED driver */
|
||||
drv_data->led_drv_enable |= BIT(pin);
|
||||
rc = i2c_reg_write_word_be(drv_data->i2c_master, cfg->i2c_slave_addr,
|
||||
SX1509B_REG_LED_DRV_ENABLE,
|
||||
drv_data->led_drv_enable);
|
||||
|
||||
/* Set intensity to 0 */
|
||||
if (rc == 0) {
|
||||
rc = i2c_reg_write_byte_be(drv_data->i2c_master,
|
||||
cfg->i2c_slave_addr,
|
||||
intensity_registers[pin], 0);
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
|
||||
pins->input_disable |= BIT(pin);
|
||||
pins->pull_up &= ~BIT(pin);
|
||||
pins->dir &= ~BIT(pin);
|
||||
pins->data &= ~BIT(pin);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = write_pin_state(cfg, drv_data, pins, false);
|
||||
}
|
||||
|
||||
out:
|
||||
k_sem_give(&drv_data->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sx1509b_led_intensity_pin_set(const struct device *dev, gpio_pin_t pin,
|
||||
uint8_t intensity_val)
|
||||
{
|
||||
const struct sx1509b_config *cfg = dev->config;
|
||||
struct sx1509b_drv_data *drv_data = dev->data;
|
||||
int rc;
|
||||
|
||||
/* Can't do I2C bus operations from an ISR */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
if (pin >= ARRAY_SIZE(intensity_registers)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
k_sem_take(&drv_data->lock, K_FOREVER);
|
||||
|
||||
rc = i2c_reg_write_byte_be(drv_data->i2c_master, cfg->i2c_slave_addr,
|
||||
intensity_registers[pin], intensity_val);
|
||||
|
||||
k_sem_give(&drv_data->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct sx1509b_config sx1509b_cfg = {
|
||||
.common = {
|
||||
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0),
|
||||
|
|
45
include/drivers/gpio/gpio_sx1509b.h
Normal file
45
include/drivers/gpio/gpio_sx1509b.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_SX1509B_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_SX1509B_H_
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/gpio.h>
|
||||
|
||||
/**
|
||||
* @brief Configure a pin for LED intensity.
|
||||
*
|
||||
* Configure a pin to be controlled by SX1509B LED driver using
|
||||
* the LED intensity functionality.
|
||||
* To get back normal GPIO funcionality, configure the pin using
|
||||
* the standard GPIO API.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param pin Pin number.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EWOULDBLOCK if function is called from an ISR.
|
||||
* @retval -ERANGE if pin number is out of range.
|
||||
* @retval -EIO if I2C fails.
|
||||
*/
|
||||
int sx1509b_led_intensity_pin_configure(const struct device *dev,
|
||||
gpio_pin_t pin);
|
||||
|
||||
/**
|
||||
* @brief Set LED intensity of selected pin.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param pin Pin number.
|
||||
* @param intensity_val Intensity value.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -EIO if I2C fails.
|
||||
*/
|
||||
int sx1509b_led_intensity_pin_set(const struct device *dev, gpio_pin_t pin,
|
||||
uint8_t intensity_val);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_SX1509B_H_ */
|
13
samples/drivers/led_sx1509b_intensity/CMakeLists.txt
Normal file
13
samples/drivers/led_sx1509b_intensity/CMakeLists.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(led_sx1509b_intensity)
|
||||
|
||||
FILE(GLOB app_sources src/*.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
21
samples/drivers/led_sx1509b_intensity/README.rst
Normal file
21
samples/drivers/led_sx1509b_intensity/README.rst
Normal file
|
@ -0,0 +1,21 @@
|
|||
.. _sx1509b_intensity:
|
||||
|
||||
SX1509B LED Intensity
|
||||
######################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
This sample controls the intensity of the color LEDs in a Thingy:52 lightwell.
|
||||
The red, green and blue LED fade up one by one, and this repeats forever.
|
||||
|
||||
Building and Running
|
||||
********************
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/drivers/led_sx1509b_intensity
|
||||
:board: thingy52_nrf52832
|
||||
:goals: build flash
|
||||
:compact:
|
||||
|
||||
The log is configured to output to RTT. Segger J-Link RTT Viewer can be used to view the log.
|
|
@ -0,0 +1,8 @@
|
|||
/* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&sx1509b {
|
||||
status = "okay";
|
||||
};
|
12
samples/drivers/led_sx1509b_intensity/prj.conf
Normal file
12
samples/drivers/led_sx1509b_intensity/prj.conf
Normal file
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_LOG_MINIMAL=n
|
||||
CONFIG_LOG_PRINTK=y
|
||||
|
||||
CONFIG_I2C=y
|
14
samples/drivers/led_sx1509b_intensity/sample.yaml
Normal file
14
samples/drivers/led_sx1509b_intensity/sample.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
sample:
|
||||
description: Demonstration of the SX1509B LED driver intensity functionality
|
||||
name: SX1509B intensity sample
|
||||
tests:
|
||||
sample.drivers.led.sx1509b_intensity:
|
||||
platform_allow: thingy52_nrf52832
|
||||
tags: LED
|
||||
depends_on: i2c
|
93
samples/drivers/led_sx1509b_intensity/src/main.c
Normal file
93
samples/drivers/led_sx1509b_intensity/src/main.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/gpio/gpio_sx1509b.h>
|
||||
|
||||
#define NUMBER_OF_LEDS 3
|
||||
#define GREEN_LED DT_GPIO_PIN(DT_NODELABEL(led0), gpios)
|
||||
#define BLUE_LED DT_GPIO_PIN(DT_NODELABEL(led1), gpios)
|
||||
#define RED_LED DT_GPIO_PIN(DT_NODELABEL(led2), gpios)
|
||||
|
||||
enum sx1509b_color { sx1509b_red = 0, sx1509b_green, sx1509b_blue };
|
||||
|
||||
const struct device *sx1509b_dev;
|
||||
static struct k_delayed_work rgb_work;
|
||||
static uint8_t which_color = sx1509b_red;
|
||||
static uint8_t iterator;
|
||||
|
||||
static const gpio_pin_t rgb_pins[] = {
|
||||
RED_LED,
|
||||
GREEN_LED,
|
||||
BLUE_LED,
|
||||
};
|
||||
|
||||
static void rgb_work_handler(struct k_work *work)
|
||||
{
|
||||
if (which_color == sx1509b_red) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, RED_LED, iterator);
|
||||
|
||||
iterator++;
|
||||
|
||||
if (iterator >= 255) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, RED_LED, 0);
|
||||
which_color = sx1509b_green;
|
||||
iterator = 0;
|
||||
}
|
||||
} else if (which_color == sx1509b_green) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, GREEN_LED, iterator);
|
||||
|
||||
iterator++;
|
||||
|
||||
if (iterator >= 255) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, GREEN_LED,
|
||||
0);
|
||||
which_color = sx1509b_blue;
|
||||
iterator = 0;
|
||||
}
|
||||
} else if (which_color == sx1509b_blue) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, BLUE_LED, iterator);
|
||||
|
||||
iterator++;
|
||||
|
||||
if (iterator >= 255) {
|
||||
sx1509b_led_intensity_pin_set(sx1509b_dev, BLUE_LED, 0);
|
||||
which_color = sx1509b_red;
|
||||
iterator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
k_delayed_work_submit(&rgb_work, K_MSEC(10));
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk("SX1509B intensity sample\n");
|
||||
|
||||
sx1509b_dev = device_get_binding(DT_PROP(DT_NODELABEL(sx1509b), label));
|
||||
|
||||
if (sx1509b_dev == NULL) {
|
||||
printk("Error binding SX1509B device\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUMBER_OF_LEDS; i++) {
|
||||
err = sx1509b_led_intensity_pin_configure(sx1509b_dev,
|
||||
rgb_pins[i]);
|
||||
|
||||
if (err) {
|
||||
printk("Error configuring pin for LED intensity\n");
|
||||
}
|
||||
}
|
||||
|
||||
k_delayed_work_init(&rgb_work, rgb_work_handler);
|
||||
k_delayed_work_submit(&rgb_work, K_NO_WAIT);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue