From 8d82d83568ec039c7c30286c8d65dbb7e0e0a8e3 Mon Sep 17 00:00:00 2001 From: true Date: Fri, 25 Oct 2024 17:27:46 -0700 Subject: [PATCH] fix i2c clock stretching, bit timings; speed up i2c; accelerometer working; many other fixes fixed i2c routine usage throughout the code. clock speed increased as rendering was taking too long. fixed aw20xxx LED enable code (I think). now handling buttons, though still having some problems. running even more code from RAM. using less EEPROM for config as we don't need it. hell we don't even need the pages we have. --- nametag8_CH592/Ld/Link.ld | 3 + nametag8_CH592/user/comm/soft_i2c_master.c | 59 +++--- nametag8_CH592/user/global.h | 7 +- nametag8_CH592/user/hw/aw20xxx.c | 32 ++-- nametag8_CH592/user/hw/ch32sub.c | 115 +++++++----- nametag8_CH592/user/hw/ch32sub.h | 7 + nametag8_CH592/user/hw/eeprom16.c | 10 +- nametag8_CH592/user/hw/gat/gat_gpio.c | 5 + nametag8_CH592/user/led/rgbled.c | 17 +- nametag8_CH592/user/main.c | 208 ++++++++++++--------- nametag8_CH592/user/misc/accel.c | 11 +- nametag8_CH592/user/misc/tinymt.c | 8 +- nametag8_CH592/user/port_intr.c | 10 +- nametag8_CH592/user/ui/btn.c | 8 +- nametag8_CH592/user/ui/menu_base.c | 5 + nametag8_CH592/user/ui/menu_entry_0.c | 4 +- nametag8_CH592/user/ui/menu_entry_1.c | 1 + nametag8_CH592/user/ui/menu_entry_2.c | 1 + nametag8_CH592/user/ui/menu_entry_3.c | 2 + nametag8_CH592/user/ui/menu_entry_5.c | 1 + nametag8_CH592/user/ui/menu_entry_6.c | 5 +- nametag8_CH592/user/user_config.h | 2 +- 22 files changed, 315 insertions(+), 206 deletions(-) diff --git a/nametag8_CH592/Ld/Link.ld b/nametag8_CH592/Ld/Link.ld index 7c2899c..9ad25f2 100644 --- a/nametag8_CH592/Ld/Link.ld +++ b/nametag8_CH592/Ld/Link.ld @@ -152,6 +152,9 @@ SECTIONS *(.srodata.cst2) *(.srodata .srodata.*) . = ALIGN(4); + *(.ramfunc) + *(.ramfunc*) + . = ALIGN(4); PROVIDE( _edata = .); } >RAM AT>FLASH diff --git a/nametag8_CH592/user/comm/soft_i2c_master.c b/nametag8_CH592/user/comm/soft_i2c_master.c index 3476518..08cf317 100644 --- a/nametag8_CH592/user/comm/soft_i2c_master.c +++ b/nametag8_CH592/user/comm/soft_i2c_master.c @@ -1,30 +1,41 @@ /* * soft_i2c.c * - * looked at random code and fixed it up for CH59x. + * looked at random i2c code, used as inspiration, and wrote some + * garbage for CH59x. * * i2c hardware peripheral on CH59x is shared with debug pins. - * also, i2c on CH59x is not attached to DMA. while using the - * peripheral would result in higher speeds and less power usage, - * living without debug is worse. maybe I'll use hw i2c later. + * i2c hw is also not attached to DMA. while using the peripheral + * even in interrupt mode would result in higher speeds and less + * power consumption, living without debug is worse. * * quirks and features: * - this implementation is blocking. - * - partial clock stretching is supported - * (only during start of write, and within read phase). - * - timings likely haven't been tested so long as this message exists. + * - clock stretching is supported, and somewhat tested + * + * known good settings: + * CYCLES_TO_HI = 5, CYCLES_TO_LOW = 2: ~400-500kHz + * CYCLES_TO_HI = 2, CYCLES_TO_LOW = 0: ~650KHz */ #include #include -#define CYCLES_TO_HI 5 // these settings will result in ~500KHz (32MHz HCLK) -#define CYCLES_TO_LO 2 +#define CYCLES_TO_HI 2 +#define CYCLES_TO_LO 0 -#define CYCLES_RD 2 // cycles spent in read routine -#define CYCLES_WR_HI 2 // extra cycles spent in write routine -#define CYCLES_WR_LO 4 +//#define CYCLES_RD 2 // cycles spent in read routine +//#define CYCLES_WR_HI 2 // extra cycles spent in write routine +//#define CYCLES_WR_LO 4 + +#define bit_delay_hi() { spin = delay_hi; while(spin--); } +#define bit_delay_lo() { spin = delay_lo; while(spin--); } + +#define rd_delay() bit_delay_hi() + +#define wr_delay_hi() bit_delay_hi() +#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--) #define SDA_PIN 4 @@ -59,14 +70,6 @@ static uint16_t delay_hi, delay_lo; static volatile uint16_t spin; -#define bit_delay_hi() spin = delay_hi; while(spin--) -#define bit_delay_lo() spin = delay_lo; while(spin--) - -#define rd_delay() bit_delay_hi() - -#define wr_delay_hi() bit_delay_hi() -#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--) - // re-run init any time the clock speed changes to recalculate delays. @@ -104,6 +107,7 @@ void i2cm_restart() { SDA_IN_HI(); bit_delay_hi(); SCL_IN_HI(); + while (!SCL_GET()); // clock stretch i2cm_start(); } @@ -124,7 +128,8 @@ void i2cm_stop() __attribute__((section(".ramfunc"))) uint8_t i2cm_rd(uint8_t ack) { - uint8_t x, in = 0; + int8_t x; + uint8_t in = 0; SDA_IN_HI(); @@ -138,15 +143,13 @@ uint8_t i2cm_rd(uint8_t ack) if (SDA_GET()) in |= 1; - SCL_OUTLO(); + SCL_OUTLO(); bit_delay_lo(); } if (ack) { SDA_OUTLO(); } // ack else { SDA_IN_HI(); } // nack SCL_IN_HI(); bit_delay_hi(); - - SDA_IN_HI(); SCL_OUTLO(); bit_delay_lo(); return in; @@ -156,7 +159,7 @@ uint8_t i2cm_rd(uint8_t ack) __attribute__((section(".ramfunc"))) uint8_t i2cm_wr(uint8_t dat) { - uint8_t x; + int8_t x; uint8_t ack; SCL_OUTLO(); @@ -165,8 +168,9 @@ uint8_t i2cm_wr(uint8_t dat) if (dat & 0x80) { SDA_IN_HI(); } else { SDA_OUTLO(); } - SCL_IN_HI(); wr_delay_hi(); + SCL_IN_HI(); while (!SCL_GET()); // clock stretch + wr_delay_hi(); dat <<= 1; @@ -179,6 +183,7 @@ uint8_t i2cm_wr(uint8_t dat) ack = SDA_GET(); SCL_OUTLO(); bit_delay_lo(); + return ack; } @@ -186,7 +191,7 @@ uint8_t i2cm_wr(uint8_t dat) __attribute__((section(".ramfunc"))) uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit) { - addr &= ~0x1; + addr &= 0xfe; addr |= reading_bit ? 1 : 0; return i2cm_wr(addr); } diff --git a/nametag8_CH592/user/global.h b/nametag8_CH592/user/global.h index 873c2a8..a543405 100644 --- a/nametag8_CH592/user/global.h +++ b/nametag8_CH592/user/global.h @@ -12,15 +12,16 @@ -#define SYSCLK_FREQ_NORMAL CLK_SOURCE_HSE_16MHz +#define SYSCLK_FREQ_NORMAL CLK_SOURCE_PLL_48MHz // CLK_SOURCE_HSE_16MHz #define SYSCLK_FREQ_USEI2C CLK_SOURCE_PLL_32MHz +#define SYSCLK_FREQ_IDLE CLK_SOURCE_HSE_8MHz extern const uint8_t vers[]; -extern uint8_t cpu_use; -extern uint8_t cpu_max; +extern uint16_t cpu_pct; +extern uint16_t cpu_pct_max; extern uint32_t uptime; extern uint16_t uptime_hour; diff --git a/nametag8_CH592/user/hw/aw20xxx.c b/nametag8_CH592/user/hw/aw20xxx.c index 7c1e39f..213a8f7 100644 --- a/nametag8_CH592/user/hw/aw20xxx.c +++ b/nametag8_CH592/user/hw/aw20xxx.c @@ -68,11 +68,7 @@ void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint aw->rows = rows; aw->config = imax & AW20X_CONF_IMAX_MASK; - // ensure we are on page 0 to start - aw20x_page(aw, 0); - while (AW20X_I2C_busy()); - - // wake up + // wake up (and set page to config page) aw20x_sleep(aw, 0); // enabled columns @@ -184,9 +180,10 @@ void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit) } /* * enables LEDs based on user LED count, zero-indexed - * AW20036 would be 0-35, AW00054 would be 0-53, and so on - * for example, LEDs 8-12 on AW20054 would enable C0R8, C1R0, C1R1, C1R2 - * all other LEDs are disabled + * assumes AW20X_MAX_LEDON_BITS per row but will only turn on active defined rows + * AW20036 would be 0-35, but AW20054 would be 0-71 and so on + * for example, LEDs 8-12 on AW20054 with 9 roww enabled + * would enable C0R8, C1R0, C1R1, C1R2. all other LEDs are disabled * * todo: * - read current state, and apply bitfields to the currently active state @@ -196,7 +193,7 @@ void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit) void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last) { uint8_t c, r; - uint8_t offset = 0; + uint8_t idx; uint8_t boff; uint8_t *buf; @@ -208,24 +205,25 @@ void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last) // bits are stored 6 bits per byte, 2 bytes per column, one bit for each row // for a maximum of the AW20X_MAX_ROWS of LED on bits // we only want to touch bits that exist on the chip and in the correct order + idx = 0; for (c = 0; c < aw->cols; c++) { buf = &aw_buf[c*2]; + buf[0] = buf[1] = 0; boff = 0; for (r = 0; r < AW20X_MAX_LEDON_BITS*2; r++) { - if (r >= aw->rows) break; // max bits to process + if (r + idx < first) continue; // only start at the first led + if (r + idx > last) break; // and stop at the last + + if (r >= aw->rows) continue; // max bits to process per row + if (r == AW20X_MAX_LEDON_BITS) { // only this many bits per byte boff += AW20X_MAX_LEDON_BITS; buf++; } - if (r+offset >= first) { - if (r+offset <= last) { - *buf |= (1 << r - boff); - } - } + *buf |= (1 << r - boff); } - - offset += aw->rows; + idx += AW20X_MAX_LEDON_BITS*2; } AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c*2); diff --git a/nametag8_CH592/user/hw/ch32sub.c b/nametag8_CH592/user/hw/ch32sub.c index a97b7c3..c74f731 100644 --- a/nametag8_CH592/user/hw/ch32sub.c +++ b/nametag8_CH592/user/hw/ch32sub.c @@ -19,9 +19,9 @@ -volatile uint8_t intr_flag = 0; +volatile uint8_t intr_pending = 0; -static void (*flag_cb[8])() = { +static void (*intr_cb[8])() = { btn_intr, 0, 0, @@ -34,38 +34,71 @@ static void (*flag_cb[8])() = { +__HIGH_CODE +void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len) +{ + i2c_read_reg16(SUB_I2C_ADDR, reg, dat, len); +} + +__HIGH_CODE +void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len) +{ + i2c_write_reg16(SUB_I2C_ADDR, reg, dat, len); +} + +__HIGH_CODE +uint8_t ch32sub_read_1b(uint16_t reg) +{ + uint8_t ret; + + ch32sub_read(reg, &ret, 1); + + return ret; +} + +__HIGH_CODE +void ch32sub_write_1b(uint16_t reg, uint8_t dat) +{ + i2c_addr(SUB_I2C_ADDR, 0); + i2c_wr(reg >> 8); + i2c_wr(reg & 0xff); + i2c_wr(dat); + i2c_stop(); +} + void ch32sub_isr() { - // we'll check what the MCU has to say when we're done processing - intr_flag = 1; + intr_pending = 1; } void ch32sub_process() { uint8_t flags; + uint8_t clear = 0; uint8_t i; - if (intr_flag) { - intr_flag = 0; - flags = 1; + if (intr_pending) { + intr_pending = 0; - // get interrupt flags - i2c_read_reg16(SUB_I2C_ADDR, REG_INTR_FLAGS, &flags, 1); + // get flags + flags = ch32sub_read_1b(REG_INTR_FLAGS); - while (flags) { - for (i = 0; i < 8; i++) { - if (intr_flag & (1 << i)) { - if (flag_cb[i]) flag_cb[i](); - else { - // unhandled interrupt; clear it - // ch32sub_write_1b(REG_INTR_FLAGS, i << 1); - } + // process flags + for (i = 0; i < 8; i++) { + if (flags & (1 << i)) { + if (intr_cb[i]) { + clear |= (i << 1); + intr_cb[i](); + } + else { + // unhandled interrupt; clear it? + // ch32sub_write_1b(REG_INTR_FLAGS, i << 1); } } - - // get interrupt flags (again) - i2c_read_reg16(SUB_I2C_ADDR, REG_INTR_FLAGS, &flags, 1); } + + // clear flags + ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, clear); } } @@ -81,31 +114,29 @@ void ch32sub_init() // note: this is handled as "high priority" within the interrupt handler now. // port_intr_cb_register(PORT_INTR_GPIOB, SUB_INTR_PIN_NR, ch32sub_isr); - -} - -// things to do -void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len) -{ - i2c_read_reg16(SUB_I2C_ADDR, reg, dat, len); -} - -void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len) -{ - i2c_write_reg16(SUB_I2C_ADDR, reg, dat, len); -} - -void ch32sub_write_1b(uint16_t reg, uint8_t dat) -{ - i2c_start(); - i2c_addr(SUB_I2C_ADDR, 0); - i2c_wr(reg >> 8); - i2c_wr(reg & 0xff); - i2c_wr(dat); - i2c_stop(); + // clear any interrupts now, to start from clean slate + ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, 0xff); } void ch32sub_rgb_hwen(uint8_t en) { ch32sub_write_1b(REG_RGB_HWEN, en); } + +void ch32sub_intr_defaults() +{ + int8_t i; + uint8_t dat[5]; + + // we want interrupted for all button events + for (i = 0; i < 5; i++) { + dat[i] = BTN_PUSH | BTN_HOLD | BTN_RELEASE; + } + + // enable button interrupt sources + ch32sub_write(REG_BTN1_INT_ENABLE, dat, 5); + + // enable all interrupt flags we care about + dat[0] = INT_BTN | INT_UTX_DONE | INT_UTX_TIMEOUT | INT_UTX_ERROR | INT_URX_RCVD; + ch32sub_write_1b(REG_INTR_ENABLE, dat[0]); +} diff --git a/nametag8_CH592/user/hw/ch32sub.h b/nametag8_CH592/user/hw/ch32sub.h index cd0bd32..da532d2 100644 --- a/nametag8_CH592/user/hw/ch32sub.h +++ b/nametag8_CH592/user/hw/ch32sub.h @@ -97,6 +97,12 @@ enum ch32sub_regmap { }; +#define BTN_PUSH (1 << 0) +#define BTN_HOLD (1 << 1) +#define BTN_RELEASE (1 << 2) +#define BTN_IGNORE (1 << 3) + + void ch32sub_init(); void ch32sub_isr(); @@ -106,6 +112,7 @@ void ch32sub_read(uint16_t reg, uint8_t *dat, uint8_t len); void ch32sub_write(uint16_t reg, uint8_t *dat, uint8_t len); void ch32sub_write_1b(uint16_t reg, uint8_t dat); +void ch32sub_intr_defaults(); void ch32sub_rgb_hwen(uint8_t en); diff --git a/nametag8_CH592/user/hw/eeprom16.c b/nametag8_CH592/user/hw/eeprom16.c index d8c906f..0d3e1b0 100644 --- a/nametag8_CH592/user/hw/eeprom16.c +++ b/nametag8_CH592/user/hw/eeprom16.c @@ -19,14 +19,13 @@ void e16_read(uint16_t addr, uint8_t *dat, uint32_t len) { if (len > EEPROM_SIZE) return; - i2c_start(); i2c_addr(EEPROM_I2C_ADDR, 0); i2c_wr(addr >> 8); i2c_wr(addr & 0xff); i2c_restart(); - i2c_addr(EEPROM_I2C_ADDR, 1); + i2c_wr(EEPROM_I2C_ADDR | 1); - while (len--) *dat++ = i2cm_rd(len > 0); + while (len--) *dat++ = i2c_rd(len > 0); i2c_stop(); } @@ -42,15 +41,16 @@ void e16_write(uint16_t addr, uint8_t *dat, uint16_t len) // it is your responsibility to correctly address for // page boundaries. most eeprom roll over page boundaries. - i2c_start(); i2c_addr(EEPROM_I2C_ADDR, 0); i2c_wr(addr >> 8); i2c_wr(addr & 0xff); while (len--) { - nack = i2cm_wr(*dat++); + nack = i2c_wr(*dat++); if (nack) break; } + + i2c_stop(); } diff --git a/nametag8_CH592/user/hw/gat/gat_gpio.c b/nametag8_CH592/user/hw/gat/gat_gpio.c index 5c2c767..16edce9 100644 --- a/nametag8_CH592/user/hw/gat/gat_gpio.c +++ b/nametag8_CH592/user/hw/gat/gat_gpio.c @@ -8,6 +8,11 @@ * - GP1 has UART0 TX and PWM9. * - GP2 has UART0 RX and PWM7. * + * errata: + * - bottom board marked REV3 has addon header mirrored. + * to manufacture this, GAT GPIO is cut and inoperable. + * todo: add strapping GPIO check to determine board version. + * */ diff --git a/nametag8_CH592/user/led/rgbled.c b/nametag8_CH592/user/led/rgbled.c index 65d0420..7bf1d92 100644 --- a/nametag8_CH592/user/led/rgbled.c +++ b/nametag8_CH592/user/led/rgbled.c @@ -61,10 +61,11 @@ void rgbled_init() { volatile uint32_t x; - ch32sub_rgb_hwen(1); + // make sure the hardware pin is on before calling. + // wait a little while to ensure controller is awake - x = GetSysClock() / 16384; + x = GetSysClock() / 131072; while (x--); // clear fade @@ -76,7 +77,7 @@ void rgbled_init() aw20x_set_dim_global(&awled, AW20X_DIM); aw20x_set_fade(&awled); - aw20x_led_enable_range(&awled, 0, 23); + aw20x_led_enable_range(&awled, 0, 47); // 9x4, but need to send 12x4 } void rgbled_flag_update() @@ -104,8 +105,14 @@ void rgbled_send() void rgbled_runprog(uint8_t tick_ctr) { + uint8_t idx = uconf.ledprog_rgb_idx; + // run program - if (rgb_pgm[uconf.ledprog_rgb_idx].prog) { - rgb_pgm[uconf.ledprog_rgb_idx].prog(uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx], tick_ctr); + if (rgb_pgm[idx].prog) { + // render + rgb_pgm[idx].prog(uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx], tick_ctr); + + // and for now, always force an update + led_matrix_needs_update = 1; } } diff --git a/nametag8_CH592/user/main.c b/nametag8_CH592/user/main.c index f5cfbb6..9cd2389 100644 --- a/nametag8_CH592/user/main.c +++ b/nametag8_CH592/user/main.c @@ -43,20 +43,25 @@ // global settings -#define OLED_UPDATE_RATE 8 // framerate of OLED; (256*(6/8)) / OLED_UPDATE_RATE; 8 = 24FPS +#define OLED_UPDATE_RATE 13 // framerate of OLED; { (256*(8/8)) / OLED_UPDATE_RATE }; 13 = 19FPS // flags #define FLAG_OLED_UPDATE (1 << 0) #define FLAG_RGBLED_RUN_PROG (1 << 1) +#define FLAG_PROG_TICK_INTR (1 << 7) -#define PROG_TICK_RATE (32768 / 256) +#define FLAG_RESET_SYSTICK (1 << 6) + +#define PROG_TICK_RATE ((32768 / 256) - 1) const uint8_t vers[] = "241015a"; -uint8_t cpu_use = 0; -uint8_t cpu_max = 0; +uint32_t cpu_use = 0; +uint32_t cpu_max = 0; +uint16_t cpu_pct = 0; +uint16_t cpu_pct_max = 0; uint32_t uptime = 0; uint16_t uptime_hour; @@ -67,9 +72,10 @@ uint32_t idle_time_menu; uint32_t idle_time_still; uint8_t idle_go_sleep; -static volatile uint8_t flags = 0; +static volatile uint8_t flags_lo = 0; +static uint8_t flags_hi = FLAG_RESET_SYSTICK; -static uint8_t st_tick = 0; // systick loop counter +static uint8_t st_tick = 0; // program tick counter static uint8_t oled_tick = 0; // oled framerate counter @@ -107,17 +113,22 @@ void rtc_reset_trig() void rtcisr_init() { - LClk32K_Cfg(Clk32K_LSI, ENABLE); // enable internal oscillator - Calibration_LSI(Level_128); // calibrate LSI fromm HSE + LClk32K_Cfg(Clk32K_LSI, ENABLE); // enable internal oscillator + Calibration_LSI(Level_128); // calibrate LSI fromm HSE rtc_reset_trig(); PFIC_EnableIRQ(RTC_IRQn); } +void systick_init(void) +{ + SysTick->CNT = 0; // clear counter + SysTick->CTLR = SysTick_CTLR_STCLK | SysTick_CTLR_STE; // enable counter in /1 mode +} + __HIGH_CODE void oled_update_done() { - int16_t a; int8_t rot; // reset oled callback, clear screen, and set default pixel mode and font size @@ -153,6 +164,7 @@ void oled_update_done() #ifdef MENU_TIMEOUT_TO_NAMETAG // root menu idle counting + // note: untested. if (menu == &menu_0) { if (!idle_time_menu) { idle_time_menu = uptime; @@ -167,87 +179,37 @@ void oled_update_done() } #endif - // do menu operations + // render menu menu_tick(); // calculate CPU usage - // note: we just consider missed ticks a percent. - // it's actually more like a tenth. fuck it. - // a = missed; - // todo: implement this - a = 0; - - if (uconf.framemod == UCONF_FRAMERATE_HALF) { - // the above calculation is tied to framerate. - // so this will compensate for half framerate mode... - a >>= 1; - } - - if (a > cpu_max) { - cpu_max = a; - } - cpu_use = a; - - - // reset missed interrupt counter - // missed = 0; + cpu_pct = (cpu_use * 100) / cpu_max; + if (cpu_pct > cpu_pct_max) cpu_pct_max = cpu_pct; } +__HIGH_CODE +void lowprio_task() { + uint32_t interrupt_flags; -int main() -{ - // configure clock - ch59x_xtal_conf(); - SetSysClock(SYSCLK_FREQ_USEI2C); - // note that system clock speed is decreased after every use of I2C. - - // enable DC-DC converter; brings significant power saving - PWR_DCDCCfg(ENABLE); - - // get i2c initialized since most stuff will need it - i2c_init(); - - // read the user config - uconf_load(); - - // initialize aux MCU - ch32sub_init(); - // and enable RGBLED controller hardware pin so the controller can wake up - ch32sub_rgb_hwen(1); - - // initialize accelerometer - accel_init(); - - // initialize RGBLED controller - rgbled_init(); - - // configure GAT aux GPIOs, get gat ID - gat_gpio_init(); - // configure GAT i2c slave - // not yet implemented - - // configure port-based interrupts (used for ch32sub interrupt) - port_intr_init(); - - // start up the OLED and menu system - ssd1306fb_set_target(&oled); - ssd1306_init(1); // we'll try to init later too, since sometimes they fail - menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode - - // configure main program tick interrupt - rtcisr_init(); - - while(1) { + while (1) { // sleep when we're doing nothing - __WFI(); + if (!flags_lo) { + __WFI(); + } - // only care about aux MCU when all other processing is done + // disable all IRQs when doing any I2C related stuff, as interrupts + // can corrupt transactions + SYS_DisableAllIrq(&interrupt_flags); + + // temporary: enable sub interrupts + ch32sub_intr_defaults(); + // process sub MCU interrupt, if pending ch32sub_process(); // send the last oled frame data - if (flags & FLAG_OLED_UPDATE) { - flags &= ~FLAG_OLED_UPDATE; + if (flags_lo & FLAG_OLED_UPDATE) { + flags_lo &= ~FLAG_OLED_UPDATE; /*** oled ***/ if (oled.callback && !(oled.state & SSD1306_STATE_BUSY)) { @@ -267,24 +229,90 @@ int main() } } - // render new OLED frame - if (flags & FLAG_RGBLED_RUN_PROG) { - flags &= ~FLAG_RGBLED_RUN_PROG; + // send the RGBLED data + // todo + + // capture CPU use + if (flags_lo & FLAG_PROG_TICK_INTR) { + flags_lo &= ~FLAG_PROG_TICK_INTR; + flags_hi |= FLAG_RESET_SYSTICK; + cpu_use = SysTick->CNT; + } + + // re-enable IRQs + SYS_RecoverIrq(interrupt_flags); + + // render new rgbled frame + if (flags_lo & FLAG_RGBLED_RUN_PROG) { + flags_lo &= ~FLAG_RGBLED_RUN_PROG; rgbled_runprog(st_tick); } + + // drop into lower clock rate + SetSysClock(SYSCLK_FREQ_IDLE); } } +int main() +{ + // configure clock + ch59x_xtal_conf(); + SetSysClock(SYSCLK_FREQ_USEI2C); + // note that system clock speed is decreased after every use of I2C. + + PWR_DCDCCfg(ENABLE); // enable DC-DC converter; brings significant power saving + + i2c_init(); // get i2c initialized since most stuff will need it + + uconf_load(); // read the user config + + ch32sub_init(); // initialize aux MCU + ch32sub_rgb_hwen(1); // and enable RGBLED controller hardware pin so the controller can wake up + + accel_init(); // initialize accelerometer + rgbled_init(); // initialize RGBLED controller + + gat_gpio_init(); // configure GAT aux GPIOs, get gat ID + // todo: implement // configure GAT i2c slave + + ssd1306fb_set_target(&oled); // start up the OLED and menu system + ssd1306_init(1); // we'll try to init later too, since sometimes OLED fails to init + menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode + + systick_init(); // start up the system tick, used for CPU percentage calculation + cpu_max = GetSysClock() / PROG_TICK_RATE; + + port_intr_init(); // configure port-based interrupts (used for ch32sub interrupt) + ch32sub_intr_defaults(); // configure interrupt sources on sub MCU - buttons, etc + + // configure main program tick interrupt + rtcisr_init(); + + // start the low priority task loop + lowprio_task(); +} + + __INTERRUPT __HIGH_CODE void RTC_IRQHandler(void) { + // clear systick for CPU usage counting + if (flags_hi & FLAG_RESET_SYSTICK) { + SysTick->CNT = 0; + flags_hi &= ~FLAG_RESET_SYSTICK; + flags_lo |= FLAG_PROG_TICK_INTR; + } + + // speed up + SetSysClock(SYSCLK_FREQ_NORMAL); + // clear interrupt flag and reset RTC rtc_reset_trig(); + // manual uptime counter st_tick++; - if (!st_tick) { uptime++; uptime_hour = (uint16_t)(uptime / 3600); @@ -305,24 +333,18 @@ void RTC_IRQHandler(void) rgbled_send(); // defer rendering - flags |= FLAG_RGBLED_RUN_PROG; + flags_lo |= FLAG_RGBLED_RUN_PROG; break; } case 1: { accel_poll(); // no break } - default: { - oled_tick++; - if (oled_tick >= OLED_UPDATE_RATE) { - oled_tick = 0; - flags |= FLAG_OLED_UPDATE; - } - } } - // read accelerometer data at 32Hz - if ((st_tick & 0x7) == 0x7) { - + oled_tick++; + if (oled_tick >= OLED_UPDATE_RATE) { + oled_tick = 0; + flags_lo |= FLAG_OLED_UPDATE; } } diff --git a/nametag8_CH592/user/misc/accel.c b/nametag8_CH592/user/misc/accel.c index 501991e..cf26449 100644 --- a/nametag8_CH592/user/misc/accel.c +++ b/nametag8_CH592/user/misc/accel.c @@ -33,7 +33,7 @@ int32_t accel_i2c_write(void *handle, uint8_t reg, const uint8_t *bufp, uint16_t { (void)(handle); - i2c_write_reg8(LIS2DW_I2C_ADDR, reg, bufp, len); + i2c_write_reg8(LIS2DW_I2C_ADDR_SDO_LOW, reg, bufp, len); return 0; } @@ -42,7 +42,7 @@ int32_t accel_i2c_read(void *handle, uint8_t reg, uint8_t *bufp, uint16_t len) { (void)(handle); - i2c_read_reg8(LIS2DW_I2C_ADDR, reg, bufp, len); + i2c_read_reg8(LIS2DW_I2C_ADDR_SDO_LOW, reg, bufp, len); return 0; } @@ -72,7 +72,7 @@ void accel_init() timeout = 0; accel_found = 1; } - } while (timeout); + } while (timeout--); } if (accel_found) { @@ -98,7 +98,7 @@ void accel_init() void accel_poll() { uint8_t reg = 1; - uint16_t xyz[3]; + int16_t xyz[3]; if (!accel_found) return; @@ -110,6 +110,9 @@ void accel_poll() // read acceleration data memset(xyz, 0x00, 3 * sizeof(int16_t)); lis2dw12_acceleration_raw_get(&dev_ctx, xyz); + accel.x = xyz[0] >>= 8; + accel.y = xyz[1] >>= 8; + accel.z = xyz[2] >>= 8; } } } diff --git a/nametag8_CH592/user/misc/tinymt.c b/nametag8_CH592/user/misc/tinymt.c index ca1937d..3322b82 100644 --- a/nametag8_CH592/user/misc/tinymt.c +++ b/nametag8_CH592/user/misc/tinymt.c @@ -7,6 +7,8 @@ #include #include "tinymt.h" +#include "CH59x_common.h" + static void tinymt32_next_state(tinymt32_t *s); @@ -91,7 +93,8 @@ const uint32_t TINYMT32_MASK = UINT32_C(0x7fffffff); * This function changes the internal state of tinymt32. * @param s pointer to tinymt internal state. */ -static void tinymt32_next_state (tinymt32_t* s) +__HIGH_CODE +void tinymt32_next_state (tinymt32_t* s) { uint32_t x; uint32_t y; @@ -128,7 +131,8 @@ static void tinymt32_next_state (tinymt32_t* s) * @param s pointer to tinymt internal state. * @return 32-bit unsigned pseudorandom number. */ -static uint32_t tinymt32_temper (tinymt32_t* s) +__HIGH_CODE +uint32_t tinymt32_temper (tinymt32_t* s) { uint32_t t0, t1; t0 = s->status[3]; diff --git a/nametag8_CH592/user/port_intr.c b/nametag8_CH592/user/port_intr.c index 61eaf78..081c9de 100644 --- a/nametag8_CH592/user/port_intr.c +++ b/nametag8_CH592/user/port_intr.c @@ -43,7 +43,9 @@ void port_intr_cb_register(uint8_t port, uint8_t idx, void (*fn)(void)) void port_intr_init() { - // enable port interrupt + // clear state then enable port interrupt + R16_PB_INT_IF = 0xff; + PFIC_EnableIRQ(GPIO_B_IRQn); } @@ -63,8 +65,8 @@ __INTERRUPT __HIGH_CODE void GPIOB_IRQHandler(void) { - uint8_t i; - uint8_t offset; + //uint8_t i; + //uint8_t offset; uint16_t flag = R16_PB_INT_IF; // clear flags @@ -77,6 +79,7 @@ void GPIOB_IRQHandler(void) } // general purpose fallback + /* for (i = 4; i < MAX_PIN; i++) { offset = i - 4; if (flag & (1 << i)) { @@ -85,4 +88,5 @@ void GPIOB_IRQHandler(void) } } } + */ } diff --git a/nametag8_CH592/user/ui/btn.c b/nametag8_CH592/user/ui/btn.c index 13aebaf..9dff031 100644 --- a/nametag8_CH592/user/ui/btn.c +++ b/nametag8_CH592/user/ui/btn.c @@ -21,18 +21,21 @@ uint8_t btn_held; +__HIGH_CODE void btn_push_cb(uint8_t idx) { btn_pushed |= (1 << idx); if (btn[idx].cb_push) btn[idx].cb_push(idx); } +__HIGH_CODE void btn_hold_cb(uint8_t idx) { btn_held |= (1 << idx); if (btn[idx].cb_hold) btn[idx].cb_hold(idx); } +__HIGH_CODE void btn_release_cb(uint8_t idx) { btn_pushed &= ~(1 << idx); @@ -41,6 +44,7 @@ void btn_release_cb(uint8_t idx) } +__HIGH_CODE void btn_commit_hold() { uint8_t i, x; @@ -66,6 +70,7 @@ void btn_commit_hold() } +__HIGH_CODE void btn_intr() { uint8_t i; @@ -76,7 +81,8 @@ void btn_intr() ch32sub_read(REG_BTN_PUSHED_LATCHED, btn_state, sizeof(btn_state)); // clear button interrupt flag - ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, INT_BTN); + // this is actually handled by the main routine so not needed here + // ch32sub_write_1b(REG_INTR_FLAGS_CLEAR, INT_BTN); // process callbacks for new events for (i = 0; i < BTN_COUNT; i++) { diff --git a/nametag8_CH592/user/ui/menu_base.c b/nametag8_CH592/user/ui/menu_base.c index c8e2c21..c3cae35 100644 --- a/nametag8_CH592/user/ui/menu_base.c +++ b/nametag8_CH592/user/ui/menu_base.c @@ -9,12 +9,15 @@ #include + MenuItem *menu; uint8_t menu_idx = 0; uint8_t mtick; + +__HIGH_CODE void menu_tick() { if (menu) { @@ -149,6 +152,7 @@ void menu_btn_use_none() } +__HIGH_CODE void menu_draw_buttons(uint8_t mode, uint8_t mask) { uint8_t w; @@ -274,6 +278,7 @@ void menu_draw_buttons(uint8_t mode, uint8_t mask) } } +__HIGH_CODE void menu_draw_tabs(uint8_t active_idx) { uint8_t h; diff --git a/nametag8_CH592/user/ui/menu_entry_0.c b/nametag8_CH592/user/ui/menu_entry_0.c index 1120086..4948497 100644 --- a/nametag8_CH592/user/ui/menu_entry_0.c +++ b/nametag8_CH592/user/ui/menu_entry_0.c @@ -95,6 +95,7 @@ static void menu_none_print_error(uint8_t *err1, uint8_t *err2, uint8_t *err3) return; } +__HIGH_CODE void menu_none_disp(uint8_t idx) { uint8_t i, j; @@ -239,7 +240,7 @@ MENU_0_DISP_CHAR_ROTATE: } if (uconf.flags & UCONF_FLAGS_SHOW_CPU_USAGE) { - sprintf(txt, "%3u%%", cpu_use); + sprintf(txt, "%3u%%", cpu_pct); ssd1306fb_set_cursor(90, 20); ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1); } @@ -247,6 +248,7 @@ MENU_0_DISP_CHAR_ROTATE: oled.state &= ~SSD1306_STATE_STR_HALFWIDTH; } +__HIGH_CODE void menu_0_disp(uint8_t idx) { char txt[12]; diff --git a/nametag8_CH592/user/ui/menu_entry_1.c b/nametag8_CH592/user/ui/menu_entry_1.c index a0483a0..e449a20 100644 --- a/nametag8_CH592/user/ui/menu_entry_1.c +++ b/nametag8_CH592/user/ui/menu_entry_1.c @@ -205,6 +205,7 @@ void menu_1_font_next() } while (!font_table[uconf.font_idx].tag_allowed); } +__HIGH_CODE void menu_1_disp(uint8_t idx) { int8_t w, x; diff --git a/nametag8_CH592/user/ui/menu_entry_2.c b/nametag8_CH592/user/ui/menu_entry_2.c index 208c248..2209e3c 100644 --- a/nametag8_CH592/user/ui/menu_entry_2.c +++ b/nametag8_CH592/user/ui/menu_entry_2.c @@ -220,6 +220,7 @@ void menu_2_edit_use(uint8_t idx) } +__HIGH_CODE void menu_2_disp(uint8_t idx) { int i; diff --git a/nametag8_CH592/user/ui/menu_entry_3.c b/nametag8_CH592/user/ui/menu_entry_3.c index 3780012..7913c90 100644 --- a/nametag8_CH592/user/ui/menu_entry_3.c +++ b/nametag8_CH592/user/ui/menu_entry_3.c @@ -325,6 +325,8 @@ void snek_init() gamemode = 17; } + +__HIGH_CODE void snek_disp(uint8_t idx) { // uint8_t i; diff --git a/nametag8_CH592/user/ui/menu_entry_5.c b/nametag8_CH592/user/ui/menu_entry_5.c index c004556..dda7e13 100644 --- a/nametag8_CH592/user/ui/menu_entry_5.c +++ b/nametag8_CH592/user/ui/menu_entry_5.c @@ -27,6 +27,7 @@ const uint16_t sleep_times[] = { }; +__HIGH_CODE void menu_5_disp(uint8_t idx) { int8_t w, x; diff --git a/nametag8_CH592/user/ui/menu_entry_6.c b/nametag8_CH592/user/ui/menu_entry_6.c index 2d8b990..fa05b4d 100644 --- a/nametag8_CH592/user/ui/menu_entry_6.c +++ b/nametag8_CH592/user/ui/menu_entry_6.c @@ -101,6 +101,7 @@ void menu_6_btn_use() btn_commit_hold(); } +__HIGH_CODE void menu_6_disp(uint8_t idx) { uint8_t i; @@ -220,11 +221,11 @@ void menu_6_disp(uint8_t idx) break; } case 5: { - sprintf(txt, "CPU Load: %3u%%", cpu_use); + sprintf(txt, "CPU Load: %3u%%", cpu_pct); ssd1306fb_set_cursor(10, -1); ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1); - sprintf(txt, "CPU Max: %3u%%", cpu_max); + sprintf(txt, "CPU Max: %3u%%", cpu_pct_max); ssd1306fb_set_cursor(10, 9); ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1); diff --git a/nametag8_CH592/user/user_config.h b/nametag8_CH592/user/user_config.h index e47e7a2..0561dd3 100644 --- a/nametag8_CH592/user/user_config.h +++ b/nametag8_CH592/user/user_config.h @@ -15,7 +15,7 @@ // some global options -#define FLASH_RSVD_PAGES 16 // how many FLASH_UCONF_BYTES to reserve/check +#define FLASH_RSVD_PAGES 8 // how many FLASH_UCONF_BYTES to reserve/check #define FLASH_UCONF_BYTES 256 // basically assumed everywhere #define MISC_WIGGLE_RATE (7 - 4);