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);