#include #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; } } }