feat: LED-Treiber, Licht-Task und UART-Testkonsole
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
#include "drivers/nl_led.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
static const nl_board_t *s_board;
|
||||
|
||||
void nl_led_init(const nl_board_t *board)
|
||||
{
|
||||
s_board = board;
|
||||
if (board->driver == NL_DRV_PWM)
|
||||
nl_pwm_leds_init(board);
|
||||
else
|
||||
nl_sm2135eh_init(board);
|
||||
}
|
||||
|
||||
void nl_led_set(const uint8_t ch[NL_CH_COUNT])
|
||||
{
|
||||
if (s_board == NULL)
|
||||
return;
|
||||
if (s_board->driver == NL_DRV_PWM)
|
||||
nl_pwm_leds_set(ch);
|
||||
else
|
||||
nl_sm2135eh_set(ch);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef NL_LED_H
|
||||
#define NL_LED_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "board/nl_board.h"
|
||||
|
||||
void nl_led_init(const nl_board_t *board);
|
||||
void nl_led_set(const uint8_t ch[NL_CH_COUNT]);
|
||||
|
||||
/* back ends */
|
||||
void nl_pwm_leds_init(const nl_board_t *board);
|
||||
void nl_pwm_leds_set(const uint8_t ch[NL_CH_COUNT]);
|
||||
void nl_sm2135eh_init(const nl_board_t *board);
|
||||
void nl_sm2135eh_set(const uint8_t ch[NL_CH_COUNT]);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "wm_include.h"
|
||||
#include "wm_gpio_afsel.h"
|
||||
|
||||
#include "drivers/nl_led.h"
|
||||
|
||||
static const nl_board_t *s_board;
|
||||
static bool s_on_pwm[NL_CH_COUNT]; /* pin currently routed to the PWM unit */
|
||||
static uint8_t s_last[NL_CH_COUNT];
|
||||
static bool s_have_last;
|
||||
|
||||
static void route_to_pwm(int8_t ch, uint8_t pin)
|
||||
{
|
||||
enum tls_io_name io = (enum tls_io_name)pin;
|
||||
switch (ch) {
|
||||
case 0: wm_pwm1_config(io); break;
|
||||
case 1: wm_pwm2_config(io); break;
|
||||
case 2: wm_pwm3_config(io); break;
|
||||
case 3: wm_pwm4_config(io); break;
|
||||
case 4: wm_pwm5_config(io); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static void drive_gpio(const nl_pwm_chan_t *c, bool led_on)
|
||||
{
|
||||
bool level = c->active_low ? !led_on : led_on;
|
||||
tls_gpio_cfg((enum tls_io_name)c->pin, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING);
|
||||
tls_gpio_write((enum tls_io_name)c->pin, level ? 1 : 0);
|
||||
}
|
||||
|
||||
void nl_pwm_leds_init(const nl_board_t *board)
|
||||
{
|
||||
s_board = board;
|
||||
s_have_last = false;
|
||||
for (int i = 0; i < NL_CH_COUNT; i++) {
|
||||
const nl_pwm_chan_t *c = &board->pwm[i];
|
||||
s_on_pwm[i] = false;
|
||||
if (c->pwm_ch < 0)
|
||||
continue;
|
||||
if (c->antiphase)
|
||||
tls_pwm_ineverse_init((u8)c->pwm_ch, board->pwm_freq_hz, 128, 0);
|
||||
else
|
||||
tls_pwm_init((u8)c->pwm_ch, board->pwm_freq_hz, 128, 0);
|
||||
tls_pwm_start((u8)c->pwm_ch);
|
||||
drive_gpio(c, false); /* dark until the engine sets a value */
|
||||
}
|
||||
}
|
||||
|
||||
void nl_pwm_leds_set(const uint8_t ch[NL_CH_COUNT])
|
||||
{
|
||||
u32 cpu_sr;
|
||||
uint32_t cmp, ch4;
|
||||
|
||||
if (s_have_last && memcmp(ch, s_last, NL_CH_COUNT) == 0)
|
||||
return;
|
||||
memcpy(s_last, ch, NL_CH_COUNT);
|
||||
s_have_last = true;
|
||||
|
||||
/* 1. update all duty cycles at once */
|
||||
cpu_sr = tls_os_set_critical();
|
||||
cmp = tls_reg_read32(HR_PWM_CMPDAT);
|
||||
ch4 = tls_reg_read32(HR_PWM_CH4_REG2);
|
||||
for (int i = 0; i < NL_CH_COUNT; i++) {
|
||||
const nl_pwm_chan_t *c = &s_board->pwm[i];
|
||||
uint8_t v = ch[i], duty;
|
||||
if (c->pwm_ch < 0 || v == 0 || v == 255)
|
||||
continue;
|
||||
duty = (c->active_low != c->antiphase) ? (uint8_t)(255 - v) : v;
|
||||
if (c->pwm_ch == 4)
|
||||
ch4 = (ch4 & ~0x0000FF00u) | ((uint32_t)duty << 8);
|
||||
else
|
||||
cmp = (cmp & ~(0xFFu << (c->pwm_ch * 8))) | ((uint32_t)duty << (c->pwm_ch * 8));
|
||||
}
|
||||
tls_reg_write32(HR_PWM_CMPDAT, cmp);
|
||||
tls_reg_write32(HR_PWM_CH4_REG2, ch4);
|
||||
tls_os_release_critical(cpu_sr);
|
||||
|
||||
/* 2. switch pins between GPIO (0 / 255) and PWM */
|
||||
for (int i = 0; i < NL_CH_COUNT; i++) {
|
||||
const nl_pwm_chan_t *c = &s_board->pwm[i];
|
||||
uint8_t v = ch[i];
|
||||
if (c->pwm_ch < 0)
|
||||
continue;
|
||||
if (v == 0 || v == 255) {
|
||||
drive_gpio(c, v == 255);
|
||||
s_on_pwm[i] = false;
|
||||
} else if (!s_on_pwm[i]) {
|
||||
route_to_pwm(c->pwm_ch, c->pin);
|
||||
s_on_pwm[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "wm_include.h"
|
||||
|
||||
#include "drivers/nl_led.h"
|
||||
|
||||
#define SM_ADDR_CURRENT 0xC0u
|
||||
#define SM_ADDR_WY 0xC5u
|
||||
#define SM_CHANNEL_WY 0x80u /* channel select bit 7: 0 = RGB, 1 = WY */
|
||||
|
||||
extern void delay_us(unsigned int us); /* provided by libwlan.a */
|
||||
|
||||
static uint8_t s_clk, s_dat, s_current;
|
||||
static uint8_t s_last[NL_CH_COUNT];
|
||||
static bool s_have_last;
|
||||
|
||||
static void pin(uint8_t p, int v)
|
||||
{
|
||||
tls_gpio_write((enum tls_io_name)p, (u8)v);
|
||||
}
|
||||
|
||||
static void bus_start(void)
|
||||
{
|
||||
pin(s_clk, 1); pin(s_dat, 1); delay_us(1);
|
||||
pin(s_dat, 0); delay_us(1);
|
||||
pin(s_clk, 0); delay_us(1);
|
||||
}
|
||||
|
||||
static void bus_stop(void)
|
||||
{
|
||||
pin(s_clk, 0); pin(s_dat, 0); delay_us(1);
|
||||
pin(s_clk, 1); delay_us(1);
|
||||
pin(s_dat, 1); delay_us(1);
|
||||
}
|
||||
|
||||
static void write_byte(uint8_t b)
|
||||
{
|
||||
for (uint8_t m = 0x80; m; m >>= 1) {
|
||||
pin(s_dat, (b & m) ? 1 : 0); delay_us(1);
|
||||
pin(s_clk, 1); delay_us(1);
|
||||
pin(s_clk, 0); delay_us(1);
|
||||
}
|
||||
/* ack clock; the SM2135EH does not drive an ack */
|
||||
pin(s_dat, 0); delay_us(1);
|
||||
pin(s_clk, 1); delay_us(1);
|
||||
pin(s_clk, 0); pin(s_dat, 0);
|
||||
}
|
||||
|
||||
static void sm_send(const uint8_t *d, int n)
|
||||
{
|
||||
bus_start();
|
||||
for (int i = 0; i < n; i++)
|
||||
write_byte(d[i]);
|
||||
bus_stop();
|
||||
}
|
||||
|
||||
void nl_sm2135eh_init(const nl_board_t *board)
|
||||
{
|
||||
uint8_t off[NL_CH_COUNT] = {0};
|
||||
s_clk = board->sm_clk_pin;
|
||||
s_dat = board->sm_dat_pin;
|
||||
s_current = board->sm_current;
|
||||
s_have_last = false;
|
||||
tls_gpio_cfg((enum tls_io_name)s_clk, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
|
||||
tls_gpio_cfg((enum tls_io_name)s_dat, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
|
||||
nl_sm2135eh_set(off);
|
||||
}
|
||||
|
||||
void nl_sm2135eh_set(const uint8_t ch[NL_CH_COUNT])
|
||||
{
|
||||
bool white = ch[NL_CH_CW] || ch[NL_CH_WW];
|
||||
|
||||
if (s_have_last && memcmp(ch, s_last, NL_CH_COUNT) == 0)
|
||||
return;
|
||||
memcpy(s_last, ch, NL_CH_COUNT);
|
||||
s_have_last = true;
|
||||
|
||||
if (!white) {
|
||||
uint8_t d[6] = {SM_ADDR_CURRENT, s_current, 0x00, ch[NL_CH_B], ch[NL_CH_G], ch[NL_CH_R]};
|
||||
sm_send(d, 6);
|
||||
} else {
|
||||
uint8_t h[3] = {SM_ADDR_CURRENT, s_current, SM_CHANNEL_WY};
|
||||
uint8_t d[3] = {SM_ADDR_WY, ch[NL_CH_WW], ch[NL_CH_CW]};
|
||||
sm_send(h, 3);
|
||||
sm_send(d, 3);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user