1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/saul/init_devs/auto_init_saul_pwm.c
2021-02-23 18:02:06 +01:00

188 lines
5.8 KiB
C

/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/*
* @ingroup sys_auto_init_saul
* @{
*
* @file
* @brief Auto initialization of PWM pins directly mapped to SAUL reg
*
* @author Christian Amsüss <chrysn@fsfe.org>
*
* When this module is used, any PWM device assigned inside the configuration
* structs inside `pwm_params.h` in the @ref saul_pwm_dimmer_params_t and @ref
* saul_pwm_rgb_params_t is initialized at startup for 8-bit dimming at about
* 1kHz, and the indicated channels are exposed via SAUL.
*
* @}
*/
#include <inttypes.h>
#include "log.h"
#include "saul_reg.h"
#include "saul/periph.h"
#include "pwm_params.h"
#include "periph/pwm.h"
#if !defined(SAUL_PWM_FREQ)
#define SAUL_PWM_FREQ SAUL_PWM_FREQ_DEFAULT
#endif
/**
* @brief Define the number of configured dimmers
*/
#ifndef SAUL_PWM_NO_DIMMER
#define SAUL_PWM_DIMMER_NUMOF ARRAY_SIZE(saul_pwm_dimmer_params)
#else
#define SAUL_PWM_DIMMER_NUMOF 0
static const saul_pwm_dimmer_params_t saul_pwm_dimmer_params[0];
#endif
/**
* @brief Define the number of configured RGB LEDs
*/
#ifndef SAUL_PWM_NO_RGB
#define SAUL_PWM_RGB_NUMOF ARRAY_SIZE(saul_pwm_rgb_params)
#else
#define SAUL_PWM_RGB_NUMOF 0
static const saul_pwm_rgb_params_t saul_pwm_rgb_params[0];
#endif
/**
* @brief Memory for the registry RGB LED entries
*/
/* The static variable will be unused in the 0 case and thus not emitted. */
static saul_reg_t saul_reg_entries_rgb[SAUL_PWM_RGB_NUMOF];
/**
* @brief Memory for the registry dimmer entries
*/
/* The static variable will be unused in the 0 case and thus not emitted. */
static saul_reg_t saul_reg_entries_dimmer[SAUL_PWM_DIMMER_NUMOF];
/**
* @brief Reference to the driver for single-channel dimmers
*/
extern saul_driver_t dimmer_saul_driver;
/**
* @brief Reference to the driver for RGB LEDs
*/
extern saul_driver_t rgb_saul_driver;
/**
* Configure a PWM driver for LED output (1kHz, 8bit)
*/
static int configure(pwm_t dev)
{
LOG_DEBUG("[auto_init_saul] initializing PWM %u for LED operation,", dev);
uint32_t freq = pwm_init(dev, PWM_LEFT, SAUL_PWM_FREQ, saul_pwm_resolution);
LOG_DEBUG(" actual frequency %" PRIu32 ",\n", freq);
return freq != 0 ? 0 : -ENOTSUP;
}
/**
* Configure the PWM driver at the given index (inside saul_pwm_dimmer_params,
* overflowing into saul_pwm_rgb_params) unless that device came up previously,
* in which case the function returns without any action.
* */
static int configure_on_first_use(pwm_t dev, unsigned index)
{
/* Work around -Werror=type-limits that would otherwise trigger */
unsigned dimmer_numof = SAUL_PWM_DIMMER_NUMOF;
for (unsigned i = 0; i < dimmer_numof; ++i) {
pwm_t currentdev = saul_pwm_dimmer_params[i].channel.dev;
if (currentdev == dev) {
if (i == index) {
return configure(dev);
}
return 0;
}
}
/* Work around -Werror=type-limits that would otherwise trigger */
unsigned rgb_numof = SAUL_PWM_RGB_NUMOF;
for (unsigned i = 0; i < rgb_numof; ++i) {
for (int j = 0; j < 3; ++j) {
unsigned index = SAUL_PWM_DIMMER_NUMOF + i * 3 + j;
pwm_t currentdev = saul_pwm_rgb_params[i].channels[j].dev;
if (currentdev == dev) {
if (i == index) {
return configure(dev);
}
return 0;
}
}
}
return -ENOENT;
}
void auto_init_saul_pwm(void)
{
/* Work around -Werror=type-limits that would otherwise trigger */
unsigned dimmer_numof = SAUL_PWM_DIMMER_NUMOF;
for (unsigned i = 0; i < dimmer_numof; i++) {
const saul_pwm_dimmer_params_t *p = &saul_pwm_dimmer_params[i];
LOG_DEBUG("[auto_init_saul] initializing dimmer #%u\n", i);
saul_reg_entries_dimmer[i].dev = (void*)p;
saul_reg_entries_dimmer[i].name = p->name;
saul_reg_entries_dimmer[i].driver = &dimmer_saul_driver;
int err = configure_on_first_use(p->channel.dev, i);
if (err != 0) {
LOG_ERROR(
"[auto_init_saul] Error initializing device for dimmer #%u\n",
i);
/* not `continue`ing: we could run into this on a non-first use and
* then we couldn't break either */
}
/* set initial dark state */
phydat_t s;
s.val[0] = 0;
saul_reg_entries_dimmer[i].driver->write(p, &s);
/* add to registry */
saul_reg_add(&(saul_reg_entries_dimmer[i]));
}
/* Work around -Werror=type-limits that would otherwise trigger */
unsigned rgb_numof = SAUL_PWM_RGB_NUMOF;
for (unsigned i = 0; i < rgb_numof; i++) {
const saul_pwm_rgb_params_t *p = &saul_pwm_rgb_params[i];
LOG_DEBUG("[auto_init_saul] initializing RGB #%u\n", i);
saul_reg_entries_rgb[i].dev = (void*)p;
saul_reg_entries_rgb[i].name = p->name;
saul_reg_entries_rgb[i].driver = &rgb_saul_driver;
for (int j = 0; j < 3; ++j) {
unsigned index = SAUL_PWM_DIMMER_NUMOF + i * 3 + j;
int err = configure_on_first_use(p->channels[j].dev, index);
if (err != 0) {
LOG_ERROR(
"[auto_init_saul] Error initializing device for RGB #%u/%u\n",
i, j);
/* not `continue`ing: we could run into this on a non-first use and
* then we couldn't break either */
}
}
/* set initial dark state */
phydat_t s;
s.val[0] = 0;
s.val[1] = 0;
s.val[2] = 0;
saul_reg_entries_rgb[i].driver->write(p, &s);
/* add to registry */
saul_reg_add(&(saul_reg_entries_rgb[i]));
}
}