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.
This commit is contained in:
true 2024-10-25 17:27:46 -07:00
parent 64ce976b97
commit 8d82d83568
22 changed files with 315 additions and 206 deletions

View File

@ -152,6 +152,9 @@ SECTIONS
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
*(.ramfunc)
*(.ramfunc*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH

View File

@ -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 <CH59x_common.h>
#include <stdint.h>
#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);
}

View File

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

View File

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

View File

@ -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]);
}

View File

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

View File

@ -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();
}

View File

@ -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.
*
*/

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -7,6 +7,8 @@
#include <stdint.h>
#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];

View File

@ -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)
}
}
}
*/
}

View File

@ -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++) {

View File

@ -9,12 +9,15 @@
#include <string.h>
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;

View File

@ -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];

View File

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

View File

@ -220,6 +220,7 @@ void menu_2_edit_use(uint8_t idx)
}
__HIGH_CODE
void menu_2_disp(uint8_t idx)
{
int i;

View File

@ -325,6 +325,8 @@ void snek_init()
gamemode = 17;
}
__HIGH_CODE
void snek_disp(uint8_t idx)
{
// uint8_t i;

View File

@ -27,6 +27,7 @@ const uint16_t sleep_times[] = {
};
__HIGH_CODE
void menu_5_disp(uint8_t idx)
{
int8_t w, x;

View File

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

View File

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