From aa52d571495a1116d92f0bc56d4de6b468da7b6c Mon Sep 17 00:00:00 2001 From: true Date: Tue, 31 Oct 2023 07:46:11 -0700 Subject: [PATCH] Added more RGBLED programs, ADC fixups --- include/rand.h | 20 ++ src/adc.c | 37 ++-- src/led.c | 9 +- src/main.c | 27 +-- src/probe.c | 2 +- src/rand.c | 31 ++++ src/rgbprog.c | 345 ++++++++++++++++++++++++++++++++--- src/system/system_py32f0xx.c | 8 +- 8 files changed, 414 insertions(+), 65 deletions(-) create mode 100644 include/rand.h create mode 100644 src/rand.c diff --git a/include/rand.h b/include/rand.h new file mode 100644 index 0000000..f58b186 --- /dev/null +++ b/include/rand.h @@ -0,0 +1,20 @@ +/* + * rand.c: good enough for flashing led bits + * + * file creation: 20231031 0506 + */ + +#ifndef _INC_RAND_H +#define _INC_RAND_H + + +#include + + + +void rand_init(uint32_t init); +uint32_t rand(); + + + +#endif /* _INC_RAND_H */ \ No newline at end of file diff --git a/src/adc.c b/src/adc.c index 00ca8cb..16a1615 100644 --- a/src/adc.c +++ b/src/adc.c @@ -56,27 +56,28 @@ static uint8_t calibrate = 0; void adc_init() { - // ensure ADC is disabled + // ensure ADC is DISABLED to write to registers + // this is opposite of what the RM says... the RM is wrong ADC1->CR = 0; - // calibration configuration - ADC1->CCSR = LL_ADC_CAL_SAMPLINGTIME_8CYCLES | ADC_CCSR_CALSEL; - // enable VREFINT ADC->CCR = ADC_CCR_VREFEN; // ADC_CCR_TSEN | - // configure scan channels, sampling time (11 = temp, 12 = vrefint) - ADC1->CHSELR = CONF_SET1_AN | PROBE_AN | // note: SET1 and VREFEXT are - CONF_MODE_AN | CONF_SET0_AN | // shared and reflect one chan - ADC_CHSELR_CHSEL12; - ADC1->SMPR = SAMPLE_TIME; - - // run in one-shot mode (all channel conversion per trigger) + // enable end of conversion interrupt + ADC1->IER = ADC_IER_EOCIE; + + // run in one-shot mode (all channel conversion per trigger) // with wait mode (anti-overrun) active ADC1->CFGR1 = ADC_CFGR1_OVRMOD | ADC_CFGR1_WAIT; - // enable end of conversion interrupt - ADC1->IER = ADC_IER_EOCIE; + // configure scan channels, sampling time (11 = temp, 12 = vrefint) + ADC1->SMPR = SAMPLE_TIME; + ADC1->CHSELR = CONF_SET1_AN | PROBE_AN | // note: SET1 and VREFEXT are + CONF_MODE_AN | CONF_SET0_AN | // shared and reflect one chan + ADC_CHSELR_CHSEL12; + + // calibration configuration + ADC1->CCSR = LL_ADC_CAL_SAMPLINGTIME_8CYCLES | ADC_CCSR_CALSEL; // and enable the interrupt source in the NVIC NVIC_EnableIRQ(ADC_COMP_IRQn); @@ -103,12 +104,10 @@ void adc_go() adc_stop(); // restart sequence - adc_seq = 0; - - // enable and start ADC - ADC1->ISR = 0x1e; // clear all interrupt flags (per DS; mistranslated) - ADC1->CR = ADC_CR_ADEN; - ADC1->CR |= ADC_CR_ADSTART; + ADC1->CR = ADC_CR_ADEN; // enable ADC + adc_seq = 0; // reset channel read sequence + ADC1->ISR = 0x1e; // clear all interrupt flags (per DS; mistranslated) + ADC1->CR = ADC_CR_ADSTART | ADC_CR_ADEN; // begin conversion } /* diff --git a/src/led.c b/src/led.c index 563d77b..73dc771 100644 --- a/src/led.c +++ b/src/led.c @@ -1,6 +1,9 @@ /* * led.c: rgbled (and piezo) routines * + * LED functions expect 11-bit values (0-2047). + * Actual output is right shifted by one and clamped 0-999. + * * file creation: 20231015 0037 */ @@ -47,9 +50,9 @@ void led_next() if (!led_sel || (led_mode == MODE_RGB)) { // set PWMs in RGB mode, or when right LED set - PWM_RGB_R = (rgb[led_sel][RED] >> 1) + (rgb[led_sel][RED] >> 2); // 75% - PWM_RGB_G = (rgb[led_sel][GRN] >> 2) + (rgb[led_sel][GRN] >> 3); // 62% - PWM_RGB_B = (rgb[led_sel][BLU] ) + (rgb[led_sel][BLU] << 2); // 125% + PWM_RGB_R = (rgb[led_sel][RED] >> 2) + (rgb[led_sel][RED] >> 3); // 75% + PWM_RGB_G = (rgb[led_sel][GRN] >> 2) + (rgb[led_sel][GRN] >> 4); // 62% + PWM_RGB_B = (rgb[led_sel][BLU] >> 1); // 100% } else { // clear PWMs in piezo mode when piezo should be active PWM_RGB_R = PWM_RGB_G = PWM_RGB_B = 0; diff --git a/src/main.c b/src/main.c index f753f7c..ee39a20 100644 --- a/src/main.c +++ b/src/main.c @@ -10,11 +10,16 @@ #include "testo.h" #include "adc.h" -#include "flash.h" -#include "led.h" #include "probe.h" #include "userio.h" +#include "led.h" +#include "rgbprog.h" + +#include "rand.h" + +#include "flash.h" + uint16_t ctr; @@ -71,6 +76,8 @@ static inline void clk_init() LL_IOP_GRP1_PERIPH_GPIOB | LL_IOP_GRP1_PERIPH_GPIOF; + RCC->AHBENR |= LL_AHB1_GRP1_PERIPH_CRC; + RCC->APBENR1 = LL_APB1_GRP1_PERIPH_TIM3; RCC->APBENR2 = LL_APB1_GRP2_PERIPH_ADC1; } @@ -110,7 +117,9 @@ int main() while (1) { // run LED programs out of interrupt context at 256Hz if ((ctr & 0xf) == 0) { - + if (userio_get_mode() == MODE_FUN) { + rgbprog_run(); + } } // nap time @@ -122,7 +131,7 @@ int main() * main application interrupt */ -__attribute__ ((long_call, section(".ramfunc"))) void SysTick_Handler(void) +void SysTick_Handler(void) { uint16_t cs; @@ -142,13 +151,6 @@ __attribute__ ((long_call, section(".ramfunc"))) void SysTick_Handler(void) // shifted counter for use in the program cs = ctr >> 2; - // run LED program (if in LED mode) at 256Hz - if (!(cs & 0x3)) { - if (userio_get_mode() == MODE_FUN) { - rgbprog_run(); - } - } - // adc tested to result in about 61 reads/second if (!adc_next()) { // adc has new computed results @@ -156,6 +158,9 @@ __attribute__ ((long_call, section(".ramfunc"))) void SysTick_Handler(void) // figure out knobs, buttons, switches userio_parse(); + // initialize randomness + rand_init((knob[0] << 8) | knob[1]); + // show probe measurement results, or if not in a measurement mode, // run RGBLED program probe_measure(); diff --git a/src/probe.c b/src/probe.c index d7aba3e..639450e 100644 --- a/src/probe.c +++ b/src/probe.c @@ -71,7 +71,7 @@ static inline void probe_measure_cont() // indicate continuity if (x >= 2420) latch--; // hysteresis - led_setrgb(0, 0, 200, ((buzzer) ? 500 : 0)); + led_setrgb(0, 0, 250, ((buzzer) ? 100 : 0)); led_buzz(0); if (buzzer) led_buzz(1); } else { diff --git a/src/rand.c b/src/rand.c new file mode 100644 index 0000000..c16df3a --- /dev/null +++ b/src/rand.c @@ -0,0 +1,31 @@ +/* + * rand.c: good enough for flashing led bits + * + * file creation: 20231031 0501 + */ + +#include "py32f0xx_conf.h" + + + +uint8_t done = 0; + + + +void rand_init(uint32_t init) +{ + if (done) return; + + CRC->CR = CRC_CR_RESET; + while (CRC->CR & CRC_CR_RESET); + + CRC->DR = init; + + done = 1; +} + +uint32_t rand() +{ + CRC->DR = 1; + return CRC->DR; +} \ No newline at end of file diff --git a/src/rgbprog.c b/src/rgbprog.c index 473d095..fa6e0cd 100644 --- a/src/rgbprog.c +++ b/src/rgbprog.c @@ -1,37 +1,106 @@ /* * rgbprog.c: making your eyes light up * + * program notes: + * knob[0] is the left knob, 0-255. + * there are 8 programs selected by the knob[0] position. + * + * k0 passed to rgb programs is the 5 bits of position + * of the knob[0] value for the selected program. + * these can be used within the program. + * + * knob[1] is the right knob, 0-255. + * + * raw knob values can be read from adc_avg[ADC_SET0] (left) + * and adc_avg[ADC_SET1] (right). + * + * raw values are safe to use from the left knob, + * but will vary on the right knob depending on board version. + * thus it is recommended to only use the 8-bit smoothed + * value for the right knob. + * * file creation: 20231015 0119 */ #include "led.h" #include "hsv2rgb.h" +#include "rand.h" #include "userio.h" -void rgbprog_rainbow(); -void rgbprog_rainbow_offset(); +#define hsv2rgb(idx, h, s, v) hsv2rgb_8b(h, s, v, &rgb[idx].r, &rgb[idx].g, &rgb[idx].b) -static void (*proglist[8])(void) = { + + +void rgbprog_rainbow(uint8_t k0); +void rgbprog_rainbow_offset(uint8_t k0); +void rgbprog_static(uint8_t k0); +void rgbprog_flicker(uint8_t k0); +void rgbprog_randcolorfadebetween(uint8_t k0); +void rgbprog_randcolor(uint8_t k0); +void rgbprog_randcolorfadeinout(uint8_t k0); +void rgbprog_prog7(uint8_t k0); + +static void (*proglist[8])(uint8_t) = { rgbprog_rainbow, rgbprog_rainbow_offset, + rgbprog_static, + rgbprog_flicker, + rgbprog_randcolorfadebetween, + rgbprog_randcolor, + rgbprog_randcolorfadeinout, + rgbprog_prog7 }; -static uint8_t prog_active; -static uint8_t prog_next; -static uint8_t prog_cntr; - -static uint16_t brightness = 0; +static uint16_t brite = 0; static color_hsv hsv[2]; static color_rgb rgb[2]; +static color_rgb rfade; +void rgb_setled(uint8_t ledidx, color_rgb *rgb) +{ + led_setrgb(ledidx, rgb->r << brite, rgb->g << brite, rgb->b << brite); +} + +void rgb_fromhsv(uint8_t ledidx, uint16_t h, uint8_t s, uint8_t v) +{ + hsv2rgb_8b(h, s, v, &rgb[ledidx].r, &rgb[ledidx].g, &rgb[ledidx].b); +} + +void rgb_fade(uint8_t fade) +{ + uint8_t i; + + uint16_t mod, invmod; + + uint8_t *rf = (uint8_t *)&rfade; + uint8_t *r[2] = { (uint8_t *)&rgb[0], (uint8_t *)&rgb[1] }; + + + mod = fade + 1; + invmod = (255 - fade) + 1; + + for (i = 0; i < 3; i++) { + if (!fade) { + rf[i] = r[0][i]; + continue; + } + if (fade == 0xff) { + rf[i] = r[1][i]; + continue; + } + + rf[i] = ((r[0][i] * invmod) >> 8) + ((r[1][i] * mod) >> 8); + } +} + void rgbprog_run() { uint32_t i; @@ -39,8 +108,8 @@ void rgbprog_run() // if the button has been pushed, change the brightness if (userio_get_btn() > 0) { - brightness++; - if (brightness > 2) brightness = 0; + brite++; + brite &= 0x3; } // which program to run? @@ -48,7 +117,7 @@ void rgbprog_run() for (i = 32; i <= 256; i += 32) { if (knob[0] < i) { if (proglist[j]) { - proglist[j](); + proglist[j](knob[0] & 0x1f); } break; } @@ -56,7 +125,12 @@ void rgbprog_run() } } -void rgbprog_rainbow() +/* + * program 0: rainbow program + * + * both eyes are set to same rgb rainbow pattern + */ +void rgbprog_rainbow(uint8_t k0) { int16_t w; @@ -68,34 +142,251 @@ void rgbprog_rainbow() if (hsv[0].h < 0) hsv[0].h += 0x3000; hsv[0].h %= 0x3000; - hsv2rgb_8b(hsv[0].h >> 3, 255, 255, &rgb[0].r, &rgb[0].g, &rgb[0].b); - led_setrgb(0, rgb[0].r << brightness, rgb[0].g << brightness, rgb[0].b << brightness); - led_setrgb(1, rgb[0].r << brightness, rgb[0].g << brightness, rgb[0].b << brightness); + hsv2rgb(0, hsv[0].h >> 3, 255, 255); + rgb_setled(0, &rgb[0]); + rgb_setled(1, &rgb[0]); } -void rgbprog_rainbow_offset() +/* + * program 1: rainbow program + * + * both eyes are set to rgb rainbow pattern, + * with offset between the eyes + */ +void rgbprog_rainbow_offset(uint8_t k0) { - rgbprog_rainbow(); + rgbprog_rainbow(k0); - hsv[1].h = hsv[0].h; - hsv[1].h += (knob[0] - 32) << 6; + hsv[1].h = hsv[0].h; + hsv[1].h += k0 << 6; hsv[1].h %= 0x3000; - hsv2rgb_8b(hsv[1].h >> 3, 255, 255, &rgb[0].r, &rgb[0].g, &rgb[0].b); - led_setrgb(1, rgb[0].r << brightness, rgb[0].g << brightness, rgb[0].b << brightness); + hsv2rgb(1, hsv[1].h >> 3, 255, 255); + rgb_setled(1, &rgb[1]); } -void rgbprog_randcolorfade() +/* + * program 2: static color + * + * both eyes are set to a static color + * + * left knob adjusts saturation + * right knob adjusts color hue + */ +void rgbprog_static(uint8_t k0) { + hsv[0].h = knob[1] * 6; + hsv2rgb(0, hsv[0].h, 131 + (k0 << 2), 255); + rgb_setled(0, &rgb[0]); + rgb_setled(1, &rgb[0]); } -void rgbprog_randcolorfade_single() +/* + * program 3: flicker + * + * both eyes are set to a static flickering color + * left knob adjusts flicker level + * right knob adjusts color hue + */ +void rgbprog_flicker(uint8_t k0) { + uint8_t i; + uint8_t val; -} - -void rgbprog_randcolorfade_dual() -{ + // operate only 1/4 of the time + hsv[0].s++; + hsv[0].s &= 3; + if (hsv[0].s) return; + hsv[0].h = knob[1] * 6; + + // independent flicker for each eye + for (i = 0; i < 2; i++) { + // left knob sets flicker + if ((rand() & 0xff) > (k0 << 3)) { + // full bright + val = 0xff; + } else { + // flicker + val = 0x2f; + } + + hsv2rgb(i, hsv[0].h, 255, val); + rgb_setled(i, &rgb[i]); + } +} + +/* + * program 4: random fade between colors + * + * linear fade between two random colors + */ +void rgbprog_randcolorfadebetween(uint8_t k0) +{ + int16_t w; + + // set delay based on left knob + hsv[0].s++; + if (hsv[0].s > (k0 >> 1)) hsv[0].s = 0; + if (hsv[0].s) return; + + // update new colors at the end of every fade + hsv[0].v += 3; + if (hsv[0].v <= 2) { + // set new initial colors + hsv[0].h = hsv[1].h; + hsv[1].h = rand() % 1536; + + // clamp discrete colors to 64 + w = 4 * 6; + hsv[1].h /= w; + hsv[1].h *= w; + + hsv2rgb(0, hsv[0].h, 255, 255); + hsv2rgb(1, hsv[1].h, 255, 255); + } + + // do the fade + rgb_fade(hsv[0].v); + // and output the result + rgb_setled(0, &rfade); + rgb_setled(1, &rfade); +} + +/* + * program 5: + * + * change between two random colors + * + * left knob sets single color or dual color + * right knob sets speed + */ +void rgbprog_randcolor(uint8_t k0) +{ + // set delay based on right knob + hsv[1].h += knob[1]; + hsv[1].h++; + if (hsv[1].h >= 0x1000) { // 1/16 rate + hsv[1].h -= 0x1000; + + // update time + hsv[0].h = rand() % 1536; + hsv2rgb(0, hsv[0].h, 255, 255); + + if (k0 >= 16) { + rgb_setled(rand() & 1, &rgb[0]); + } else { + rgb_setled(0, &rgb[0]); + rgb_setled(1, &rgb[0]); + } + } +} + +/* + * program 6: + * + * fade up into a random color, hold, then fade out + * + * left knob sets dwell + * right knob sets cycle time +*/ +void rgbprog_randcolorfadeinout(uint8_t k0) +{ + uint16_t w; + + // operate only 1/4 of the time + hsv[0].s++; + hsv[0].s &= 3; + if (hsv[0].s) return; + + // hsv[1].h contains fade counter + // hsv[1].s contains dwell counter + // hsv[1].v contains our state + hsv[1].v &= 0x3; + + switch (hsv[1].v) { + case 0: + case 2: { + // ramp up/down + + // first run or new run? + if (!hsv[1].h) { + // set a new hue + hsv[0].h = rand() % 1536; + } + + // fade up or down + hsv[1].h += (knob[1]); + hsv[1].h++; + + // clamp value + if (hsv[1].h > 0x7ff) { + hsv[1].h = 0x7ff; + } + + // set output + w = hsv[1].v ? (0x7ff - hsv[1].h) : hsv[1].h; + w >>= 3; + + hsv2rgb(0, hsv[0].h, 255, (w & 0xff)); + + // are we done? + if (hsv[1].h == 0x7ff) { + hsv[1].h = 0; + hsv[1].v++; + } + + break; + } + + case 1: + case 3: { + // hold + + // just getting to this step? + if (!hsv[1].h) { + // initialize step + hsv[1].h++; + hsv[1].s = 0; + } else { + // delay here + w = hsv[1].s; + w += k0; + w++; + + // are we done? + if (w > 0x100) { + if (hsv[1].v == 3) { + hsv[1].h = 0; + } + + hsv[1].v++; + } else { + hsv[1].s = w & 0xff; + } + } + } + } + + rgb_setled(0, &rgb[0]); + rgb_setled(1, &rgb[0]); +} + +/* + * program 7: + * + * turns LEDs off. + * + * it's basically an empty program. + * if you want to write your own, do it here + * + * maybe you could write a smart morse generator, + * or a cop mode, or... + */ +void rgbprog_prog7(uint8_t k0) +{ + rgb[0].r = rgb[0].g = rgb[0].b = 0; + rgb_setled(0, &rgb[0]); + rgb_setled(1, &rgb[0]); } \ No newline at end of file diff --git a/src/system/system_py32f0xx.c b/src/system/system_py32f0xx.c index 866b7b6..5354b9a 100644 --- a/src/system/system_py32f0xx.c +++ b/src/system/system_py32f0xx.c @@ -15,15 +15,15 @@ #endif /* HSE_VALUE */ #if !defined (HSI_VALUE) -#define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/ +#define HSI_VALUE 8000000U /*!< Value of the Internal oscillator in Hz*/ #endif /* HSI_VALUE */ #if !defined (LSI_VALUE) -#define LSI_VALUE 32768U /*!< Value of LSI in Hz*/ +#define LSI_VALUE 32768U /*!< Value of LSI in Hz*/ #endif /* LSI_VALUE */ #if !defined (LSE_VALUE) -#define LSE_VALUE 32768U /*!< Value of LSE in Hz*/ +#define LSE_VALUE 32768U /*!< Value of LSE in Hz*/ #endif /* LSE_VALUE */ @@ -120,7 +120,7 @@ void SystemInit(void) /* Configure the Vector Table location add offset address ------------------*/ #ifdef VECT_TAB_SRAM SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ -#else +#elif !BOOTLOADED SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ #endif }