Compare commits
2 Commits
d1e8c49c54
...
279c7d3c68
Author | SHA1 | Date |
---|---|---|
true | 279c7d3c68 | |
true | e309c01d47 |
|
@ -0,0 +1,27 @@
|
|||
# GAT Nametag SC8 CH592 Firmware
|
||||
|
||||
main mcu firmware for the GAT Nametag originally shown at Supercon 8.
|
||||
|
||||
|
||||
## building
|
||||
|
||||
This is a MounRiver Studio project. Build in MRS.
|
||||
|
||||
|
||||
## bugs, quirks, omissions
|
||||
|
||||
- this micro has VERY SLOW flash. therefore, most user code is executed from RAM. additionally, the flash is protected and not really documented. will take time to reverse engineer it from the provided .a file to possibly determine if wait states can be adjusted.
|
||||
|
||||
- i2c master is bitbanged and may still have bugs.
|
||||
|
||||
- i2c slave is bitbanged and hasn't been tested at all.
|
||||
|
||||
- "idle mode" isn't really a power saving mode. no time to implement. need to do the following to implement this properly:
|
||||
- implement a low power mode in the sub MCU as well, tell it to go to sleep
|
||||
- get low power mode implemented and tested with gpio wakeup on this MCU
|
||||
- put rgbled controller into low power mode
|
||||
- configure accelerometer for wakeup with interrupt pin output
|
||||
- get the interrupt chain working from accel -> sub mcu -> main mcu
|
||||
- properly reinitialize and wake up once interrupt received and data matches expectations
|
||||
|
||||
- cpu usage calculation is pretty busted and is only meant to gauge how much free time may exist for doing more processing before the framerate drops.
|
|
@ -167,7 +167,18 @@ void oled_update_done()
|
|||
}
|
||||
|
||||
// power saving
|
||||
// todo: don't hardcode the movement values
|
||||
if (accel_get_movement() > 3) {
|
||||
idle_go_sleep = 0;
|
||||
|
||||
idle_time_still = 0;
|
||||
idle_time_menu = 0;
|
||||
}
|
||||
|
||||
// start going to sleep if the option is enabled and if we've been still for enough time
|
||||
if (uconf.sleep_timeout && (idle_time_still > uconf.sleep_timeout)) {
|
||||
idle_go_sleep = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MENU_TIMEOUT_TO_NAMETAG
|
||||
|
@ -210,68 +221,104 @@ void lowprio_task() {
|
|||
// can corrupt transactions
|
||||
SYS_DisableAllIrq(&interrupt_flags);
|
||||
|
||||
// temporary: re-send sub interrupts, sub button holds, enable rgb_hwen
|
||||
if (flags_lo & FLAG_CH32V_RESEND_CONF) {
|
||||
flags_lo &= ~FLAG_CH32V_RESEND_CONF;
|
||||
ch32sub_intr_defaults();
|
||||
btn_commit_hold();
|
||||
ch32sub_rgb_hwen(1);
|
||||
}
|
||||
|
||||
// process sub MCU interrupt, if pending
|
||||
ch32sub_process();
|
||||
|
||||
if (flags_lo & FLAG_RGBLED_SEND) {
|
||||
flags_lo &= ~FLAG_RGBLED_SEND;
|
||||
rgbled_send();
|
||||
}
|
||||
|
||||
if (flags_lo & FLAG_ACCEL_POLL) {
|
||||
flags_lo &= ~FLAG_ACCEL_POLL;
|
||||
accel_poll();
|
||||
}
|
||||
|
||||
// send the last oled frame data
|
||||
if (flags_lo & FLAG_OLED_UPDATE) {
|
||||
flags_lo &= ~FLAG_OLED_UPDATE;
|
||||
|
||||
/*** oled ***/
|
||||
if (oled.callback && !(oled.state & SSD1306_STATE_BUSY)) {
|
||||
if (ssd1306_cb_get()) {
|
||||
oled.callback();
|
||||
}
|
||||
// todo: implement proper sleep mode that saves power
|
||||
// and wakes up on interrupt, instead of this
|
||||
if (!idle_go_sleep) {
|
||||
// temporary: re-send sub interrupts, sub button holds, enable rgb_hwen
|
||||
if (flags_lo & FLAG_CH32V_RESEND_CONF) {
|
||||
flags_lo &= ~FLAG_CH32V_RESEND_CONF;
|
||||
ch32sub_intr_defaults();
|
||||
btn_commit_hold();
|
||||
ch32sub_rgb_hwen(1);
|
||||
}
|
||||
|
||||
// update
|
||||
// only update this frame if we're not in the middle of starting up
|
||||
if (uptime) {
|
||||
// process other tasks
|
||||
if (oled.state & SSD1306_STATE_INITIALIZED) {
|
||||
oled.callback = oled_update_done;
|
||||
}
|
||||
ssd1306_update();
|
||||
// process sub MCU interrupt, if pending
|
||||
ch32sub_process();
|
||||
|
||||
if (flags_lo & FLAG_RGBLED_SEND) {
|
||||
flags_lo &= ~FLAG_RGBLED_SEND;
|
||||
rgbled_send();
|
||||
}
|
||||
|
||||
cpu_use = SysTick->CNT;
|
||||
// send the last oled frame data
|
||||
if (flags_lo & FLAG_OLED_UPDATE) {
|
||||
flags_lo &= ~FLAG_OLED_UPDATE;
|
||||
|
||||
if (oled.callback && !(oled.state & SSD1306_STATE_BUSY)) {
|
||||
if (ssd1306_cb_get()) {
|
||||
oled.callback();
|
||||
}
|
||||
}
|
||||
|
||||
// update
|
||||
// only update this frame if we're not in the middle of starting up
|
||||
if (uptime) {
|
||||
// process other tasks
|
||||
if (oled.state & SSD1306_STATE_INITIALIZED) {
|
||||
oled.callback = oled_update_done;
|
||||
}
|
||||
ssd1306_update();
|
||||
}
|
||||
|
||||
cpu_use = SysTick->CNT;
|
||||
}
|
||||
|
||||
// re-enable IRQs
|
||||
SYS_RecoverIrq(interrupt_flags);
|
||||
|
||||
// render new rgbled frame
|
||||
// this is not included in cpu calcs :/
|
||||
if (flags_lo & FLAG_RGBLED_RUN) {
|
||||
flags_lo &= ~FLAG_RGBLED_RUN;
|
||||
|
||||
// make sure a valid program is selected
|
||||
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) {
|
||||
uconf.ledprog_rgb_idx = 0;
|
||||
}
|
||||
|
||||
// now run a program
|
||||
rgbled_runprog(st_tick >> 2);
|
||||
}
|
||||
} else {
|
||||
switch (idle_go_sleep) {
|
||||
case 1: {
|
||||
idle_go_sleep++;
|
||||
|
||||
// just entered the mode? then turn things off
|
||||
ssd1306_set_display(0);
|
||||
|
||||
uconf.flags |= UCONF_FLAGS_LEDS_DISABLE;
|
||||
rgbled_send();
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// check to see if we should wake
|
||||
if (accel_get_movement() > 3) {
|
||||
idle_go_sleep = 0;
|
||||
|
||||
idle_time_still = 0;
|
||||
idle_time_menu = 0;
|
||||
|
||||
// wake up things
|
||||
ssd1306_set_display(1);
|
||||
|
||||
uconf.flags &= ~UCONF_FLAGS_LEDS_DISABLE;
|
||||
rgbled_send();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// re-enable IRQs
|
||||
SYS_RecoverIrq(interrupt_flags);
|
||||
|
||||
// render new rgbled frame
|
||||
// this is not included in cpu calcs :/
|
||||
if (flags_lo & FLAG_RGBLED_RUN) {
|
||||
flags_lo &= ~FLAG_RGBLED_RUN;
|
||||
|
||||
// make sure a valid program is selected
|
||||
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) {
|
||||
uconf.ledprog_rgb_idx = 0;
|
||||
}
|
||||
|
||||
// now run a program
|
||||
rgbled_runprog(st_tick >> 2);
|
||||
}
|
||||
|
||||
// drop into lower clock rate
|
||||
SetSysClock(SYSCLK_FREQ_IDLE);
|
||||
}
|
||||
|
@ -342,6 +389,7 @@ void RTC_IRQHandler(void)
|
|||
}
|
||||
|
||||
idle_time_still++;
|
||||
idle_time_menu++;
|
||||
}
|
||||
|
||||
oled_tick++;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "misc/i8atan2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
|
@ -20,8 +21,11 @@
|
|||
AccelData accel;
|
||||
|
||||
uint8_t accel_found = 0;
|
||||
int16_t movement;
|
||||
uint16_t movement_worst;
|
||||
|
||||
uint8_t movement_idx; // index into "read" register
|
||||
int16_t movement_read[4]; // last read movement value
|
||||
int16_t movement; // last calculated movement value
|
||||
uint16_t movement_worst; // worst seen movement value
|
||||
|
||||
|
||||
// hardware
|
||||
|
@ -29,7 +33,6 @@ static stmdev_ctx_t dev_ctx;
|
|||
|
||||
|
||||
|
||||
|
||||
int32_t accel_i2c_write(void *handle, uint8_t reg, const uint8_t *bufp, uint16_t len)
|
||||
{
|
||||
(void)(handle);
|
||||
|
@ -96,6 +99,7 @@ void accel_init()
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void accel_poll()
|
||||
{
|
||||
uint8_t reg = 1;
|
||||
|
@ -111,13 +115,30 @@ 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;
|
||||
|
||||
// compute our shitty "movement" thing
|
||||
// awful way to detect being still
|
||||
reg = sizeof(movement_read) / sizeof(movement_read[0]);
|
||||
|
||||
movement_idx++;
|
||||
if (movement_idx == reg) {
|
||||
movement_idx = 0;
|
||||
movement = abs(movement_read[3] - movement_read[0]);
|
||||
if (movement > movement_worst) {
|
||||
movement_worst = movement;
|
||||
}
|
||||
}
|
||||
|
||||
movement_read[movement_idx] = abs(accel.x) + abs(accel.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
int8_t accel_get_rotation(struct AccelData *a)
|
||||
{
|
||||
int8_t nx, ny, ret;
|
||||
|
|
|
@ -27,8 +27,8 @@ typedef struct AccelData {
|
|||
|
||||
|
||||
extern AccelData accel;
|
||||
|
||||
extern uint8_t accel_found;
|
||||
|
||||
extern uint16_t movement_worst;
|
||||
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ void menu_6_disp(uint8_t idx)
|
|||
sprintf(txt, "m%i", abs(accel_get_movement()));
|
||||
ssd1306fb_set_cursor(104, 10);
|
||||
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
|
||||
sprintf(txt, "w%d", 0); // todo: fix this: movement_worst);
|
||||
sprintf(txt, "w%d", movement_worst);
|
||||
ssd1306fb_set_cursor(106, 17);
|
||||
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
|
||||
|
||||
|
|
|
@ -32,34 +32,34 @@ static const uint8_t uconf_edge_defaults[8][8] = {
|
|||
|
||||
|
||||
|
||||
static void uconf_defaults()
|
||||
void uconf_defaults()
|
||||
{
|
||||
int i;
|
||||
|
||||
uconf.ver = UCONF_VER;
|
||||
uconf.flags = UCONF_FLAGS_LEDS_ENABLE;
|
||||
uconf.framemod = UCONF_FRAMERATE_FULL;
|
||||
uconf.nameconf = UCONF_NAME_DISP_DEMOWAVE1 | UCONF_NAME_MODE_AUTOROTATE | UCONF_NAME_MODE_COLOR_INVERT;
|
||||
uconf.ver = UCONF_VER;
|
||||
uconf.flags = UCONF_FLAGS_LEDS_ENABLE;
|
||||
uconf.framemod = UCONF_FRAMERATE_FULL;
|
||||
uconf.nameconf = UCONF_NAME_DISP_DEMOWAVE1 | UCONF_NAME_MODE_AUTOROTATE | UCONF_NAME_MODE_COLOR_INVERT;
|
||||
// UCONF_NAME_DISP_DEMOWAVES1 | UCONF_NAME_MODE_AUTOROTATE | UCONF_NAME_MODE_COLOR_INVERT;
|
||||
if (uconf_flash_offset == 0xf0) {
|
||||
uconf.iter = 0;
|
||||
uconf.iter = 0;
|
||||
}
|
||||
uconf.font_idx = 4;
|
||||
uconf.char_spacing = 2;
|
||||
uconf.y_offset = 0;
|
||||
uconf.font_idx = 4;
|
||||
uconf.char_spacing = 2;
|
||||
uconf.y_offset = 0;
|
||||
|
||||
// todo: add LUT
|
||||
strcpy(uconf.name, "Supercon");
|
||||
|
||||
uconf.favcolor_hue = 170;
|
||||
uconf.favcolor_sat = 240;
|
||||
uconf.favcolor_val = 32;
|
||||
uconf.favcolor_hue = 170;
|
||||
uconf.favcolor_sat = 240;
|
||||
uconf.favcolor_val = 32;
|
||||
|
||||
uconf.altcolor_hue = 0;
|
||||
uconf.altcolor_sat = 240;
|
||||
uconf.altcolor_val = 32;
|
||||
uconf.altcolor_hue = 0;
|
||||
uconf.altcolor_sat = 240;
|
||||
uconf.altcolor_val = 32;
|
||||
|
||||
uconf.ledprog_rgb_idx = 4;
|
||||
uconf.ledprog_rgb_idx = 4;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uconf.ledprog_rgb[i] = 0;
|
||||
|
@ -67,10 +67,11 @@ static void uconf_defaults()
|
|||
|
||||
memcpy(uconf.ledprog_rgb_data, uconf_edge_defaults, sizeof(uconf_edge_defaults));
|
||||
|
||||
uconf.lsens_dark_thresh = 0x6a0; // todo: figure out what this should be by testing
|
||||
uconf.sleep_timeout = 20 * 60;
|
||||
uconf.lsens_dark_thresh = 0x6a0; // todo: figure out what this should be by testing
|
||||
uconf.menu_timeout = 5 * 60;
|
||||
uconf.sleep_timeout = 20 * 60;
|
||||
|
||||
uconf.checksum = checksum_gen((uint8_t *)&uconf, sizeof(uconf) - 2);
|
||||
uconf.checksum = checksum_gen((uint8_t *)&uconf, sizeof(uconf) - 2);
|
||||
}
|
||||
|
||||
static int8_t uconf_validate()
|
||||
|
|
|
@ -83,8 +83,9 @@ typedef struct UserConf {
|
|||
uint8_t padding0; // 52
|
||||
uint8_t ledprog_rgb[16]; // 68
|
||||
uint8_t ledprog_rgb_data[16][8]; // 196
|
||||
uint8_t padding1[52]; // 248
|
||||
uint16_t lsens_dark_thresh; // 250
|
||||
uint8_t padding1[50]; // 246
|
||||
uint16_t lsens_dark_thresh; // 248
|
||||
uint16_t menu_timeout; // 250
|
||||
uint16_t sleep_timeout; // 252
|
||||
uint16_t tempcx10_offset; // 253-254
|
||||
uint16_t checksum; // 255-256
|
||||
|
@ -106,6 +107,8 @@ extern uint8_t temp_degc_decimal;
|
|||
void uconf_load();
|
||||
void uconf_write();
|
||||
|
||||
void uconf_defaults();
|
||||
|
||||
|
||||
|
||||
#endif /* USER_CONFIG_H_ */
|
||||
|
|
Loading…
Reference in New Issue