get LED matrix, RGBLED working; get sizzle program (matrix program 1) working

This commit is contained in:
true 2024-08-03 11:43:02 -07:00
parent 27cbc558ce
commit bc7a378dcd
11 changed files with 165 additions and 110 deletions

View File

@ -14,7 +14,7 @@
#include "ch32v20x_adc.h"
#include "ch32v20x_bkp.h"
#include "ch32v20x_can.h"
//#include "ch32v20x_can.h"
#include "ch32v20x_crc.h"
#include "ch32v20x_dbgmcu.h"
#include "ch32v20x_dma.h"
@ -26,7 +26,7 @@
#include "ch32v20x_pwr.h"
#include "ch32v20x_rcc.h"
#include "ch32v20x_rtc.h"
#include "ch32v20x_spi.h"
//#include "ch32v20x_spi.h"
#include "ch32v20x_tim.h"
#include "ch32v20x_usart.h"
#include "ch32v20x_wwdg.h"

View File

@ -50,13 +50,6 @@ void gpio_init()
gpio.GPIO_Speed = GPIO_Speed_2MHz;
// per the datasheet, PB8 is an output-only pin on this specific submodel.
// however, the datasheet later conflicts and says this is A/I/O pin.
// so we'll try to use it as an input anyway.
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &gpio);
// unused osc pins
gpio.GPIO_Mode = GPIO_Mode_IPD;
gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7;
@ -98,7 +91,7 @@ void gpio_init()
gpio.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOA, &gpio);
// I2C on-board comms
// I2C SCL, SCA for on-board devices
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &gpio);
@ -139,6 +132,10 @@ int main(void)
// configure systick interrupt
systick_init();
rgb[0] = 10;
rgb[1] = 10;
rgb[2] = 10;
// do system shit
while(1) {
__WFI();

View File

@ -9,27 +9,36 @@
#include "i2c.h"
/* sends the IS31FL3729 general config.
void is31fl3729_set_global_current(uint8_t i2c_addr, uint8_t global_current)
{
i2c_write_reg_8b(i2c_addr, FL3729_REG_G_CURRENT, global_current);
}
void is31fl3729_set_scaling_current(uint8_t i2c_addr, uint8_t cs, uint8_t current)
{
if (cs > 0xf) return;
i2c_write_reg_8b(i2c_addr, FL3729_REG_SCALING + cs, current);
}
/* sends the IS31FL3729 initial config.
* does not configure per-channel current sink limits; do that separately.
* does not configure other sane defaults; do that separately.
*/
void is31fl3729_init(uint8_t i2c_addr, uint8_t config, uint8_t global_current)
{
uint8_t buf;
// enable device
#ifdef FL3729_SDB_PORT
FL3729_SDB_PORT->BSHR = FL3729_SDB_PIN;
#endif
// reset config registers
buf = FL3729_RESET_VALUE;
i2c_write_addr1b(i2c_addr, FL3729_REG_RESET, &buf, 1);
i2c_write_reg_8b(i2c_addr, FL3729_REG_CONFIG, FL3729_RESET_VALUE);
// write initial config
i2c_write_addr1b(i2c_addr, FL3729_REG_CONFIG, &config, 1);
i2c_write_addr1b(i2c_addr, FL3729_REG_G_CURRENT, &global_current, 1);
i2c_write_reg_8b(i2c_addr, FL3729_REG_CONFIG, config);
is31fl3729_set_global_current(i2c_addr, global_current);
}
uint8_t is31fl3729_get_addr(uint8_t adpin)
@ -38,26 +47,14 @@ uint8_t is31fl3729_get_addr(uint8_t adpin)
}
void is31fl3729_set_global_current(uint8_t i2c_addr, uint8_t current)
{
i2c_write_addr1b(i2c_addr, FL3729_REG_G_CURRENT, &current, 1);
}
void is31fl3729_set_scaling_current(uint8_t i2c_addr, uint8_t cs, uint8_t current)
{
if (cs > 0xf) return;
i2c_write_addr1b(i2c_addr, FL3729_REG_SCALING + cs, &current, 1);
}
/*
* sets current limit of multiple outputs simultaneously, starting from CS1.
* useful for initial register configuration.
*/
void is31fl3729_set_scaling_current_multi(uint8_t i2c_addr, uint8_t *current, uint8_t count)
void is31fl3729_set_scaling_current_multi(uint8_t i2c_addr, const uint8_t *current, uint8_t count)
{
if (!count) return;
count &= 0xf;
if (count > 16) count = 16;
i2c_write_addr1b(i2c_addr, FL3729_REG_SCALING, current, count);
}
@ -67,9 +64,9 @@ void is31fl3729_set_scaling_current_multi(uint8_t i2c_addr, uint8_t *current, ui
* sw: first switch segment to update. usually set this to 1 for the first switch.
* if set to 0, will default to 1.
* *out: output data buffer
* len: length of buffer
* len: length of buffer. up to end user to not exceed writing beyond register 0x90.
*/
void is31fl3729_set_outputs(uint8_t i2c_addr, uint8_t sw, uint8_t *out, uint8_t len)
void is31fl3729_set_outputs(uint8_t i2c_addr, uint8_t sw, const uint8_t *out, uint8_t len)
{
if (!sw) sw = 1;

View File

@ -25,24 +25,24 @@
#define FL3729_REG_OUTPUT 0x01
#define FL3729_REG_SCALING 0x90
#define FL3729_REG_CONFIG 0xA0
#define FL3729_REG_G_CURRENT 0xA1 // global current
#define FL3729_REG_PUPD 0xB0 // pull up / pull down
#define FL3729_REG_SS 0xB1 // spread spectrum
#define FL3729_REG_G_CURRENT 0xA1 // global current
#define FL3729_REG_PUPD 0xB0 // pull up / pull down
#define FL3729_REG_SS 0xB1 // spread spectrum
#define FL3729_REG_PWM 0xB2
#define FL3729_REG_RESET 0xCF
#define FL3729_GCC_MAX 64 // maximum global current level
#define FL3729_GCC_MAX 64 // maximum global current level
#define FL3729_CONF_SHDN_ENA 0
#define FL3729_CONF_SHDN_DIS ((1 << 0) << 0)
#define FL3729_CONF_SSD_SHDN (0 << 0) // software shutdown
#define FL3729_CONF_SSD_NRML (1 << 0) // normal operation
#define FL3729_CONF_OSDE_OFF 0
#define FL3729_CONF_OSDE_OPEN ((1 << 0) << 1)
#define FL3729_CONF_OSDE_SHORT ((1 << 1) << 1)
#define FL3729_CONF_OSDE_OFF (0 << 1)
#define FL3729_CONF_OSDE_OPEN (1 << 1)
#define FL3729_CONF_OSDE_SHORT (2 << 1)
#define FL3729_CONF_LOGIC_LOLEV 0
#define FL3729_CONF_LOGIC_HILEV ((1 << 0) << 3)
#define FL3729_CONF_LOGIC_LOLEV (0 << 3)
#define FL3729_CONF_LOGIC_HILEV (1 << 3)
#define FL3729_CONF_MATRIX_9x15 0x00
#define FL3729_CONF_MATRIX_8x16 0x10
@ -68,25 +68,15 @@
/*
typedef struct IS31FL3729_Conf {
uint8_t ad_pin;
uint8_t config;
uint8_t global_brightness;
} IS31FL3729_Conf;
*/
void is31fl3729_init(uint8_t i2c_addr, uint8_t config, uint8_t global_current);
uint8_t is31fl3729_get_addr(uint8_t adpin);
void is31fl3729_set_global_current(uint8_t i2c_addr, uint8_t current);
void is31fl3729_set_global_current(uint8_t i2c_addr, uint8_t global_current);
void is31fl3729_set_scaling_current(uint8_t i2c_addr, uint8_t cs, uint8_t current);
void is31fl3729_set_scaling_current_multi(uint8_t i2c_addr, uint8_t *current, uint8_t count);
void is31fl3729_set_scaling_current_multi(uint8_t i2c_addr, const uint8_t *current, uint8_t count);
void is31fl3729_set_outputs(uint8_t i2c_addr, uint8_t sw, uint8_t *out, uint8_t len);
void is31fl3729_set_outputs(uint8_t i2c_addr, uint8_t sw, const uint8_t *out, uint8_t len);

View File

@ -90,7 +90,7 @@ static uint16_t checksum()
void userconf_load()
{
uint8_t valid;
uint8_t valid = 0;
uint8_t page = CONF_FLASH_PAGES;

View File

@ -15,21 +15,17 @@
#define I2C_TIMEOUT 0xffff
#define I2C_TIMEOUT 0xefff
#define I2C_TIMEOUT_ACK_POLL 0x180
static uint32_t timeout;
static uint16_t timeout;
void i2c_init()
{
GPIO_InitTypeDef gpio = {0};
I2C_InitTypeDef i2c = {0};
gpio.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &gpio);
// ensure GPIO pins are configured before initializing
i2c.I2C_ClockSpeed = 666666;
i2c.I2C_Mode = I2C_Mode_I2C;
@ -100,7 +96,7 @@ uint8_t i2c_read_reg_8b(uint8_t addr, uint8_t reg)
return dat;
}
int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len)
int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, const uint8_t *data, uint8_t len)
{
timeout = I2C_TIMEOUT;
while((I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET) && timeout--);
@ -122,7 +118,9 @@ int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len)
if (!timeout) return -4;
while (len) {
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET) {
// fixme: can get stuck here if address isn't found.
// somehow all the above passes but this will fail
if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) != RESET) {
I2C_SendData(I2C1, *data++);
len--;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

View File

@ -17,7 +17,7 @@
void i2c_init();
int8_t i2c_read_addr1b(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
int8_t i2c_write_addr1b(uint8_t addr, uint8_t reg, const uint8_t *data, uint8_t len);
uint8_t i2c_read_reg_8b(uint8_t addr, uint8_t reg);
void i2c_write_reg_8b(uint8_t addr, uint8_t reg, uint8_t dat);

View File

@ -10,16 +10,16 @@
#define FL3729_SW_COUNT 4 // switches utilized
#define FL3729_CS_COUNT 16 // current sink outputs used by chip
#define FL3729_G_CURRENT 16 // initial global current setting
#define FL3729_G_CURRENT 15 // initial global current setting
const uint8_t cs_currents[FL3729_CS_COUNT] = {
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80
static const uint8_t cs_currents[FL3729_CS_COUNT] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f
};
const uint16_t pwm_cie_256in_1024out[] = {
static const uint16_t pwm_cie_256in_1024out[] = {
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15,
15, 16, 17, 17, 18, 19, 19, 20, 21, 22, 22, 23, 24, 25, 26, 27,
@ -70,10 +70,10 @@ void led_init()
// configure matrix
is31fl3729_init(FL3729_ADDR,
FL3729_CONF_SHDN_DIS | FL3729_CONF_OSDE_OFF | FL3729_CONF_MATRIX_4x16,
FL3729_CONF_SSD_NRML | FL3729_CONF_OSDE_OFF | FL3729_CONF_MATRIX_4x16,
FL3729_G_CURRENT);
is31fl3729_set_scaling_current_multi(FL3729_ADDR, (uint8_t *)cs_currents, sizeof(cs_currents));
is31fl3729_set_scaling_current_multi(FL3729_ADDR, cs_currents, FL3729_CS_COUNT);
// configure rear RGBLED
@ -94,7 +94,7 @@ void led_init()
TIM_CtrlPWMOutputs(RGB_TIM, ENABLE);
TIM_OC1PreloadConfig(RGB_TIM, TIM_OCPreload_Disable);
TIM_ARRPreloadConfig(RGB_TIM, ENABLE);
TIM_Cmd(TIM1, ENABLE);
TIM_Cmd(RGB_TIM, ENABLE);
}
void led_matrix_is_updated()
@ -104,9 +104,41 @@ void led_matrix_is_updated()
void led_matrix_send()
{
int8_t i, j;
uint8_t out[64];
// only render when there's something to render
if (led_matrix_updated) {
is31fl3729_set_outputs(FL3729_ADDR, 1, (uint8_t *)&led, FL3729_SW_COUNT * FL3729_CS_COUNT);
// convert led matrix
j = 0;
// the pepper body is linear; starts from top left,
// goes counter-clockwise, and ends at the top part
for (i = 0; i < LED_PEP_COUNT; i += 4) {
out[j + (16*0)] = led.section.pep[i + 0];
out[j + (16*1)] = led.section.pep[i + 1];
out[j + (16*2)] = led.section.pep[i + 2];
out[j + (16*3)] = led.section.pep[i + 3];
j++;
}
// pepper hat is a bit more fucked up. I laid this out
// with the elements backwards. rushjob fuckup. oops.
// I would like to start from the bottom right, counter clockwise,
// ending up at pepper's top right.
// for (i = 0; i < LED_HAT_COUNT; i += 4) { // clockwise starting from bottom right
j = 15;
for (i = 0; i < LED_HAT_COUNT; i += 4) {
out[j + (16*0)] = led.section.hat[i + 0];
out[j + (16*1)] = led.section.hat[i + 1];
out[j + (16*2)] = led.section.hat[i + 2];
out[j + (16*3)] = led.section.hat[i + 3];
j--;
}
// and send
is31fl3729_set_outputs(FL3729_ADDR, 1, out, FL3729_SW_COUNT * FL3729_CS_COUNT);
led_matrix_updated = 0;
}
}

View File

@ -16,7 +16,7 @@
#define FL3729_ADDR (FL3729_BASE_ADDR | FL3729_ADPIN_GND)
#define LED_PEP_COUNT 36 // all pepper body LEDs
#define LED_PEP_NOTOP 31 // pepper body LEDs not including the part under the hat
#define LED_PEP_NOTOP 30 // pepper body LEDs not including the part under the hat
#define LED_HAT_COUNT 28 // all pepper hat LEDs
#define LED_ALL_COUNT (LED_PEP_COUNT + LED_HAT_COUNT)
@ -24,10 +24,13 @@
typedef struct LedMatrix {
union {
uint8_t pep[LED_PEP_COUNT];
uint8_t hat[LED_HAT_COUNT];
uint8_t all[LED_ALL_COUNT];
struct section {
uint8_t pep[LED_PEP_COUNT];
uint8_t hat[LED_HAT_COUNT];
} section;
};
uint8_t all[LED_ALL_COUNT];
} LedMatrix;

View File

@ -57,17 +57,17 @@ static void pep_0_flash(uint8_t tick)
pep_work[1] ^= 0x1;
if (pep_work[1] & 1) {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = out;
led.section.pep[i] = out;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = out;
led.section.hat[i] = out;
}
} else {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = 0;
led.section.pep[i] = 0;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 0;
led.section.hat[i] = 0;
}
}
@ -94,7 +94,7 @@ static void pep_1_sizzle(uint8_t tick)
rnd2 = prng_get32();
// are we going to spike an LED?
trig = (trig > 0xf2) ? 1 : 0;
trig = (trig > 0xfa) ? 1 : 0;
if (trig) {
// which LED?
@ -106,13 +106,18 @@ static void pep_1_sizzle(uint8_t tick)
for (i = 0; i < LED_PEP_NOTOP; i++) {
if (trig && (rnd == i)) {
// go bright on this LED
led.pep[i] = 200;
led.section.pep[i] = 0xcf;
// also on the prior LED
if (i)
led.section.pep[i - 1] = 0x80;
else if (i < LED_PEP_NOTOP - 1)
led.section.pep[i + 1] = 0x80;
} else {
if (led.pep[i] < 48) led.pep[i]++;
else if (led.pep[i] > 64) led.pep[i]--;
if (led.section.pep[i] < 4) led.section.pep[i]++;
else if (led.section.pep[i] > 36) led.section.pep[i]--;
else {
if (rnd2 & 1) led.pep[i]++;
else led.pep[i]--;
if (rnd2 & 1) led.section.pep[i]++;
else led.section.pep[i]--;
}
rnd2 >>= 1;
@ -121,8 +126,10 @@ static void pep_1_sizzle(uint8_t tick)
// the hat just gets lit normally
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 200;
led.section.hat[i] = 0x3f;
}
led_matrix_is_updated();
}
/*
@ -148,12 +155,12 @@ static void pep_2_loops(uint8_t tick)
bot >>= 8;
for (i = 0; i < LED_PEP_COUNT; i++) {
if (i == bot) led.pep[i] = 255;
else if (led.pep[i]) led.pep[i]--;
if (i == bot) led.section.pep[i] = 255;
else if (led.section.pep[i]) led.section.pep[i]--;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
if (i == top) led.hat[i] = 255;
else if (led.hat[i]) led.hat[i]--;
if (i == top) led.section.hat[i] = 255;
else if (led.section.hat[i]) led.section.hat[i]--;
}
}
@ -169,10 +176,10 @@ static void pep_3_neon_sign(uint8_t tick)
// todo: implement flickering on/off
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = (tick & 1) ? 255 : 200;
led.section.pep[i] = (tick & 1) ? 255 : 200;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = (tick & 1) ? 255 : 200;
led.section.hat[i] = (tick & 1) ? 255 : 200;
}
led_matrix_is_updated();
@ -195,10 +202,10 @@ static void pep_4_alternate(uint8_t tick)
if (!pep_work[0]) {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = (pep_work[1] & 1) ? hi : lo;
led.section.pep[i] = (pep_work[1] & 1) ? hi : lo;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = (pep_work[1] & 1) ? lo : hi;
led.section.hat[i] = (pep_work[1] & 1) ? lo : hi;
}
pep_work[0] = userconf.pep_conf[PEP_4][PEP_4_CONF_FLASH_RATE];
@ -270,17 +277,17 @@ static void pep_5_nom(uint8_t tick)
// set pepper body LEDs to initial on state (or off if pepper is fully eated)
for (i = 0; i < LED_PEP_NOTOP; i++) {
led.pep[i] = end ? 255 : 0;
led.section.pep[i] = end ? 255 : 0;
}
// in this mode we need to light up the top pepper line
for (i = LED_PEP_NOTOP; i < LED_PEP_COUNT; i++) {
led.pep[i] = 200;
led.section.pep[i] = 200;
}
// clear eated pepper portions, gonna cry
if (end) {
for (i = start; i < end; i++) {
led.pep[i] = 0;
led.section.pep[i] = 0;
}
}
@ -294,7 +301,7 @@ static void pep_5_nom(uint8_t tick)
}
case 3: { // regen the pepper
if (led.pep[pep_work[1]] >= 0xfe) {
if (led.section.pep[pep_work[1]] >= 0xfe) {
// next segment
pep_work[1]++;
if (pep_work[i] >= (LED_PEP_NOTOP - pep_work[i])) {
@ -302,9 +309,9 @@ static void pep_5_nom(uint8_t tick)
pep_work[0] = 0;
}
} else {
led.pep[pep_work[1]] += 2;
led.section.pep[pep_work[1]] += 2;
if (pep_work[1]) {
led.pep[LED_PEP_NOTOP - pep_work[1]] = led.pep[pep_work[1]];
led.section.pep[LED_PEP_NOTOP - pep_work[1]] = led.section.pep[pep_work[1]];
}
led_matrix_is_updated();
}
@ -368,10 +375,10 @@ void ledprog_pep_init()
// reset LEDs
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = 0;
led.section.pep[i] = 0;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 0;
led.section.hat[i] = 0;
}
// global program initialization

View File

@ -59,9 +59,40 @@ void ui_init()
btn[1].cb_release = ui_btn_release_cb;
}
uint8_t tmp;
void ui_render()
{
tick++;
ledprog_pep[0](tick);
switch (mode) {
case MODE_RUN: {
break;
}
case MODE_PROGRAM: {
break;
}
case MODE_PARAMETER: {
break;
}
}
// temporary: testing
ledprog_pep[1](tick);
/*
if ((tick & 3) == 3) {
tmp++;
tmp &= 0x3f;
for (uint8_t i = 0; i < 64; i++) {
if (i == tmp) led.all[i] = 255;
else led.all[i] = 0;
}
led_matrix_is_updated();
}
*/
}