diff --git a/firmware/retro_tech_fw/code/global.h b/firmware/retro_tech_fw/code/global.h index 5e32cb9..b6921e5 100644 --- a/firmware/retro_tech_fw/code/global.h +++ b/firmware/retro_tech_fw/code/global.h @@ -11,9 +11,7 @@ -#define SYSCLK_FREQ_NORMAL SYSCLK_FREQ_24MHz_HSI -#define SYSCLK_FREQ_USEI2C SYSCLK_FREQ_24MHz_HSI -#define SYSCLK_FREQ_IDLE SYSCLK_FREQ_12MHz_HSI +#define SYSCLK_FREQ_STARTUP SYSCLK_FREQ_16MHz_HSI diff --git a/firmware/retro_tech_fw/code/main.c b/firmware/retro_tech_fw/code/main.c index c739b6a..7589d05 100644 --- a/firmware/retro_tech_fw/code/main.c +++ b/firmware/retro_tech_fw/code/main.c @@ -52,9 +52,9 @@ void awu_init(void) AWU_SetWindowValue(47); AutoWakeUpCmd(ENABLE); - // if rising edge and interrupt isn't set on EXTI line 27, - // interrupt won't fire. - EXTI->RTENR = EXTI_RTENR_TR27; + // in order to fire AWU interrupt, enable EXTI interrupt on rising edge on EXTI line 27. + // this isn't explicitly stated in the DS, but AWU interrupt == EXTI line27 interrupt. + EXTI->RTENR = EXTI_RTENR_TR27; EXTI->INTENR = EXTI_INTENR_MR27; NVIC_EnableIRQ(AWU_IRQn); @@ -64,9 +64,9 @@ void gpio_init() { GPIO_InitTypeDef gpio = {0}; + // only one GPIO speed on this bad boy gpio.GPIO_Speed = GPIO_Speed_50MHz; - // jogwheel digital inputs, active low (PA4-PA6) gpio.GPIO_Mode = GPIO_Mode_IPU; gpio.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6; @@ -75,7 +75,7 @@ void gpio_init() // lightsense LED cathode (PA7, A8) gpio.GPIO_Mode = GPIO_Mode_AIN; gpio.GPIO_Pin = GPIO_Pin_7; - GPIOA->BSHR = GPIO_Pin_7; + GPIOA->BCR = GPIO_Pin_7; GPIO_Init(GPIOA, &gpio); // potentiometer (PB1, A9) diff --git a/firmware/retro_tech_fw/code/src/adc.c b/firmware/retro_tech_fw/code/src/adc.c index 9cd57a4..75b92a6 100644 --- a/firmware/retro_tech_fw/code/src/adc.c +++ b/firmware/retro_tech_fw/code/src/adc.c @@ -84,25 +84,31 @@ void adc_read() } } -void adc_use_lsens() +void adc_lsens_input() { GPIO_InitTypeDef gpio = {0}; // configure GPIO gpio.GPIO_Mode = GPIO_Mode_AIN; + gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Pin = LSENS_K_PIN; GPIO_Init(LSENS_K_PORT, &gpio); +} +void adc_lsens_start() +{ // enable injected channel + // note: this code is not done ADC_AutoInjectedConvCmd(ADC1, ENABLE); } -void adc_stop_lsens() +void adc_lsens_output() { GPIO_InitTypeDef gpio = {0}; // configure GPIO gpio.GPIO_Mode = GPIO_Mode_Out_PP; + gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Pin = LSENS_K_PIN; GPIO_Init(LSENS_K_PORT, &gpio); } @@ -116,13 +122,13 @@ uint8_t adc_get_pot() if (pot < POT_LO) pot = 0; else pot -= POT_LO; // scale to upper bound - pot <<= 10; + pot <<= 12; pot /= POT_HI; // 8 bits is good enough for us - pot >>= 2; + pot >>= 4; - return 255 - (pot & 0xff); + return (pot & 0xff); } uint16_t adc_get_lsens() diff --git a/firmware/retro_tech_fw/code/src/adc.h b/firmware/retro_tech_fw/code/src/adc.h index 74c1516..8e93876 100644 --- a/firmware/retro_tech_fw/code/src/adc.h +++ b/firmware/retro_tech_fw/code/src/adc.h @@ -29,8 +29,9 @@ void adc_config_lsens(); void adc_convert(); void adc_read(); -void adc_use_lsens(); -void adc_reset_lsens(); +void adc_lsens_input(); +void adc_lsens_start(); +void adc_lsens_output(); uint8_t adc_get_pot(); uint16_t adc_get_lsens(); diff --git a/firmware/retro_tech_fw/code/src/ui.c b/firmware/retro_tech_fw/code/src/ui.c index c62b297..fb46315 100644 --- a/firmware/retro_tech_fw/code/src/ui.c +++ b/firmware/retro_tech_fw/code/src/ui.c @@ -8,6 +8,8 @@ #include +#include "ui.h" + #include "adc.h" #include "btn.h" #include "config.h" @@ -58,303 +60,6 @@ static uint8_t config_save_timer; -void ui_btn_push_cb(uint8_t idx) -{ - uint8_t i, w; - // are both buttons pushed? - if ((btn[0]._mask & BTN_PUSH) && (btn[1]._mask & BTN_PUSH)) { - // are none held? - if (!(btn[0]._mask & BTN_HOLD) && !(btn[1]._mask & BTN_HOLD)) { - // can only enter programming mode if the cursor is flashing - if (userconf.cursor_color != CONF_CURSOR_OFF) { - // put both buttons into ignore mode, so hold and release events - // do not fire - btn[0]._mask |= BTN_IGNORE; - btn[1]._mask |= BTN_IGNORE; - - // both buttons are pushed at the same time quickly, and not held - // this will toggle modes - mode++; - - // parameter mode only works if a program is enabled to adjust - if (mode == MODE_PARAMETER) { - if (!userconf.ledprog_ena_mask) mode = MODE_RUN; - } - // parameter mode is the last mode - if (mode > MODE_PARAMETER) { - mode = MODE_RUN; - } - - // ensure a valid program is selected - if (mode == MODE_PARAMETER) { - w = preview_idx; - for (i = 0; i < 8; i++) { - w &= 0x7; - if (userconf.ledprog_ena_mask & (1 << w)) { - preview_idx = w; - break; - } - w++; - } - } - - // reset any LED program - led_rgb_firstrun(); - - // configure the preview index to be the first available - // depending on the mode - if (mode == MODE_PROGRAM) preview_idx = 0; - if (mode == MODE_PARAMETER) { - /* - preview_idx = 0; - for (i = 0; i < 5; i++) { - if (userconf.ledprog_ena_mask & (1 << preview_idx)) { - preview_idx = i; - break; - } - } - */ - } - - return; - } - } - } - - // there are no on-push events. - switch (mode) { - case MODE_RUN: { - - } - } -} - -void ui_btn_hold_cb(uint8_t idx) -{ - switch (mode) { - case MODE_PARAMETER: { - switch (idx) { - case 0: { - if (rgb_prog_is_editing) { - userconf.ledprog_setting[preview_idx][0]++; - } - } - } - } - } -} - -void ui_btn_release_cb(uint8_t idx) -{ - uint8_t i; - uint8_t w; - - switch (mode) { - /* button logic flow: - * - * mode changes happen by pressing both buttons. - * this is handled in the push event handler. - * - * if cursor is off, mode changing cannot occur. - */ - - /* - * NORMAL MODE: cursor is flashing (or off if disabled). - * - * cursor changes are committed to EEPROM about a second after changing is done. - * - * any program which is enabled will run. the active program randomly changes after random delays. - */ - case MODE_RUN: { - switch (idx) { - case 0: { // - top button: changes cursor color (white, green, orange, off) - userconf.cursor_color++; - userconf.cursor_color &= 0x3; - - // force cursor to change immediately, force cursor on - cursor_flash = 0; - cursor_state = 0; - - config_save_timer = UI_CONF_SAVE_TIMEOUT; - - break; - } - - case 1: { // - bot button: changes cursor flash rate. press and hold - // while cursor is not off to enter program change mode. - userconf.cursor_flash++; - userconf.cursor_flash &= 0x7; - - config_save_timer = UI_CONF_SAVE_TIMEOUT; - - break; - } - } - - break; - } - - /* - * PROGRAM CHANGE MODE: cursor is on. - * - * by default, all are disabled. selected program will flash. - * cursor will light on the selected program if it is enabled. - * - * letters in TECH preview the currently selected program. - * letters in RETRO will each preview their own program (any flash / twinkle will always have idle light) - */ - case MODE_PROGRAM: { - switch (idx) { - case 0: { // - top button: tap enables or disables the program. push and hold does nothing. - w = userconf.ledprog_ena_mask; - if (userconf.ledprog_ena_mask & (1 << preview_idx)) { - userconf.ledprog_ena_mask &= ~(1 << preview_idx); - } else { - userconf.ledprog_ena_mask |= (1 << preview_idx); - } - - break; - } - case 1: { // - bot button: tap selects the next program index. push and hold does nothing. - preview_idx++; - if (preview_idx >= 5) preview_idx = 0; - - break; - } - } - - break; - } - - /* - * PARAMETER CHANGE MODE: cursor is off (or rather, very dimly on). - * - * letters in RETRO only show enabled programs. dark for disabled programs. - * RETRO letters will flash to indicate currently selected program. - * - * letters in TECH preview the current program, at some fixed brightness. - * - * - top button: change some parameter - * - knob: change some parameter (color/hue, etc) - */ - case MODE_PARAMETER: { - switch (idx) { - case 0: { // - top button: when editing disabled: selects the next program - // when editing enabled: tapped or held: increments a value, with loop - if (rgb_prog_is_editing) { - userconf.ledprog_setting[preview_idx][0]++; - } else { - w = preview_idx; - for (i = 0; i < 8; i++) { - w++; - w &= 0x7; - if (userconf.ledprog_ena_mask & (1 << w)) { - preview_idx = w; - break; - } - } - } - break; - } - case 1: { // - bot button: enables / disables editing of selected program - rgb_prog_is_editing = !rgb_prog_is_editing; - - break; - } - } - - break; - } - } -} - -static void ui_cursor_flash() -{ - uint8_t color, flash; - uint8_t level = 0; - - color = userconf.cursor_color; - flash = userconf.cursor_flash; - - switch (mode) { - case MODE_RUN: { - if (rgb_prog_idx != 4) { - if (!cursor_flash) { - // toggle on/off - cursor_state++; - cursor_state &= 1; - - // set new cursor rate, force cursor on - cursor_flash = cursor_flash_rates[flash] >> 1; - - // set all colors off - cursor[0] = cursor[1] = cursor[2] = 0; - } - - // wind down counter - cursor_flash--; - - // set brightness of led, if we're in an on state - if (color < CONF_CURSOR_OFF) { - if (cursor_state) { - // first frame of on = not quite full brightness - level = (cursor_flash == cursor_flash_rates[flash] - 1) ? 160 : 255; - - // at final frames, dim - if (cursor_flash <= 4) { - level >>= (4 - cursor_flash); - } - } - - // set the level on the cursor - if (cursor[color] != level) { - cursor[color] = led_gamma(level); - led_is_updated(); - } - } else { - // clear any cursors that may have been left on - cursor[0] = 0; - cursor[1] = 0; - cursor[2] = 0; - } - } - - break; - } - case MODE_PROGRAM: { - // cursor is on if this program is flagged as on - cursor[0] = (userconf.ledprog_ena_mask & (1 << preview_idx)) ? 127 : 0; - cursor[1] = 0; - cursor[2] = 0; - - break; - } - case MODE_PARAMETER: { - // cursor is on when program is being edited - cursor[0] = rgb_prog_is_editing ? 127 : 0; - cursor[1] = 0; - cursor[2] = 0; - - break; - } - } -} - -void ui_init() -{ - btn[0].hold = 420 >> 1; - btn[0].repeat = (1000 / 20) >> 1; - btn[0].cb_push = ui_btn_push_cb; - btn[0].cb_hold = ui_btn_hold_cb; - btn[0].cb_release = ui_btn_release_cb; - - btn[2].hold = 420 >> 1; - btn[2].repeat = 0; - btn[2].cb_push = ui_btn_push_cb; - btn[2].cb_hold = ui_btn_hold_cb; - btn[2].cb_release = ui_btn_release_cb; -} - static void rgb_prog_random_timer_generate() { uint32_t t; @@ -391,6 +96,345 @@ static uint8_t rgb_prog_random_select() return 1; } + + +void ui_btn_push_cb(uint8_t idx) +{ + // there are no on-push events. + switch (mode) { + case MODE_RUN: { + + } + } +} + +void ui_btn_hold_cb(uint8_t idx) +{ + uint8_t i, w; + + switch (idx) { + // enter programming mode when holding jogwheel in normal run mode + case UI_JOG_PUSH: { + // can only enter programming mode if the cursor is flashing + if (userconf.cursor_color != CONF_CURSOR_OFF) { + // put main button into ignore mode, + // so hold and release events do not fire + btn[UI_JOG_PUSH]._mask |= BTN_IGNORE; + + // set the next UI mode, and make sure we aren't in edit mode when changing modes + mode++; + rgb_prog_is_editing = 0; + + // parameter mode only works if a program is enabled to adjust + if (mode == MODE_PARAMETER) { + if (!userconf.ledprog_ena_mask) mode = MODE_RUN; + } + // parameter mode is the last mode + if (mode > MODE_PARAMETER) { + mode = MODE_RUN; + } + + // ensure a valid program is selected for editing + if (mode == MODE_PARAMETER) { + w = preview_idx; + for (i = 0; i < 8; i++) { + w &= 0x7; + if (userconf.ledprog_ena_mask & (1 << w)) { + preview_idx = w; + break; + } + w++; + } + } + + // randomly select a new program when editing is complete + // (this fixes bug where disabled program continues to run) + if (mode == MODE_RUN) { + rgb_prog_random_select(); + } + + + // reset any LED program + led_rgb_firstrun(); + + // configure the preview index to be the first available + // depending on the mode + if (mode == MODE_PROGRAM) preview_idx = 0; + if (mode == MODE_PARAMETER) { + /* + preview_idx = 0; + for (i = 0; i < 5; i++) { + if (userconf.ledprog_ena_mask & (1 << preview_idx)) { + preview_idx = i; + break; + } + } + */ + } + } + break; + } + } + + switch (mode) { + case MODE_PARAMETER: { + if (rgb_prog_is_editing) { + switch (idx) { + case UI_JOG_UP: { userconf.ledprog_setting[preview_idx][0]++; break; } + case UI_JOG_DN: { userconf.ledprog_setting[preview_idx][0]--; break; } + } + } + break; + } + } +} + +void ui_btn_release_cb(uint8_t idx) +{ + uint8_t i; + uint8_t w; + + switch (mode) { + /* button logic flow: + * + * mode changes happen by pressing both buttons. + * this is handled in the push event handler. + * + * if cursor is off, mode changing cannot occur. + */ + + /* + * NORMAL MODE: cursor is flashing (or off if disabled). + * + * cursor changes are committed to EEPROM about a second after changing is done. + * + * any program which is enabled will run. the active program randomly changes after random delays. + */ + case MODE_RUN: { + switch (idx) { + case UI_JOG_UP: { // - top button: changes cursor color (white, green, orange, off) + userconf.cursor_color++; + userconf.cursor_color &= 0x3; + + // force cursor to change immediately, force cursor on + cursor_flash = 0; + cursor_state = 0; + + config_save_timer = UI_CONF_SAVE_TIMEOUT; + + break; + } + + case UI_JOG_DN: { // - bot button: changes cursor flash rate. press and hold + // while cursor is not off to enter program change mode. + userconf.cursor_flash++; + userconf.cursor_flash &= 0x7; + + config_save_timer = UI_CONF_SAVE_TIMEOUT; + + break; + } + } + + break; + } + + /* + * PROGRAM CHANGE MODE: cursor is on. + * + * by default, all are disabled. selected program will flash. + * cursor will light on the selected program if it is enabled. + * + * letters in TECH preview the currently selected program. + * letters in RETRO will each preview their own program (any flash / twinkle will always have idle light) + */ + case MODE_PROGRAM: { + switch (idx) { + case UI_JOG_PUSH: { // - top button: tap enables or disables the program. push and hold does nothing. + w = userconf.ledprog_ena_mask; + if (userconf.ledprog_ena_mask & (1 << preview_idx)) { + userconf.ledprog_ena_mask &= ~(1 << preview_idx); + } else { + userconf.ledprog_ena_mask |= (1 << preview_idx); + } + + break; + } + case UI_JOG_UP: { // - bot button: tap selects the next program index. push and hold does nothing. + preview_idx++; + if (preview_idx >= 5) preview_idx = 0; + + break; + } + case UI_JOG_DN: { // - bot button: tap selects the next program index. push and hold does nothing. + if (preview_idx == 0) preview_idx = 5; + preview_idx--; + break; + } + } + + break; + } + + /* + * PARAMETER CHANGE MODE: cursor is off (or rather, very dimly on). + * + * letters in RETRO only show enabled programs. dark for disabled programs. + * RETRO letters will flash to indicate currently selected program. + * + * letters in TECH preview the current program, at some fixed brightness. + * + * - top button: change some parameter + * - knob: change some parameter (color/hue, etc) + */ + case MODE_PARAMETER: { + switch (idx) { + case UI_JOG_PUSH: { // - ctr button: enables / disables editing of selected program + rgb_prog_is_editing = !rgb_prog_is_editing; + + break; + } + case UI_JOG_UP: { // - top button: when editing disabled: selects the next program + // when editing enabled: tapped or held: increments a value, with loop + if (rgb_prog_is_editing) { + userconf.ledprog_setting[preview_idx][0]++; + } else { + w = preview_idx; + for (i = 0; i < 8; i++) { + w++; + w &= 0x7; + if (userconf.ledprog_ena_mask & (1 << w)) { + preview_idx = w; + break; + } + } + } + break; + } + case UI_JOG_DN: { // - bot button: when editing disabled: selects the previous program + // when editing enabled: tapped or held: decrement a value, with loop + if (rgb_prog_is_editing) { + userconf.ledprog_setting[preview_idx][0]--; + } else { + w = preview_idx; + for (i = 0; i < 8; i++) { + if (!w) w = 8; + w--; + if (userconf.ledprog_ena_mask & (1 << w)) { + preview_idx = w; + break; + } + } + } + break; + } + + } + + break; + } + } +} + +static void ui_cursor_flash() +{ + uint8_t color, flash; + uint8_t level = 0; + uint8_t new_state = 0; + + color = userconf.cursor_color; + flash = userconf.cursor_flash; + + switch (mode) { + case MODE_RUN: { + // flash the cursor in all but the auto-typing program + if (rgb_prog_idx != 4) { + if (!cursor_flash) { + new_state = 1; + + // flash on/off toggle + cursor_state++; + cursor_state &= 1; + + // set new flash rate + cursor_flash = cursor_flash_rates[flash] >> 1; + + // clear cursor + cursor[0] = cursor[1] = cursor[2] = 0; + led_is_updated(); + } + + // set led to programmed brightness if it's supposed to be on + if (cursor_state) { + // first frame of on = not quite full brightness + level = (new_state) ? 160 : 255; + + // at final frames, dim, but only for slower modes + if (flash < 5) { + if (cursor_flash < 12) { + level >>= (4 - (cursor_flash >> 2)); + } + } + + // set the level on the cursor + level = led_gamma(level); + if (cursor[color] != level) { + cursor[color] = level; + led_is_updated(); + } + } else { + // clear any cursors that may have been left on + if (cursor[0] | cursor[1] | cursor[2]) { + cursor[0] = cursor[1] = cursor[2] = 0; + led_is_updated(); + } + } + + cursor_flash--; + } + + break; + } + case MODE_PROGRAM: { + // cursor is on if this program is flagged as on + cursor[0] = (userconf.ledprog_ena_mask & (1 << preview_idx)) ? 127 : 0; + cursor[1] = 0; + cursor[2] = 0; + + break; + } + case MODE_PARAMETER: { + // cursor is on when program is being edited + cursor[0] = rgb_prog_is_editing ? 127 : 0; + cursor[1] = 0; + cursor[2] = 0; + + break; + } + } +} + +void ui_init() +{ + btn[0].hold = 420 >> 1; + btn[0].repeat = (1000 / 20) >> 1; + btn[0].cb_push = ui_btn_push_cb; + btn[0].cb_hold = ui_btn_hold_cb; + btn[0].cb_release = ui_btn_release_cb; + + btn[1].hold = 420 >> 1; + btn[1].repeat = (1000 / 20) >> 1; + btn[1].cb_push = ui_btn_push_cb; + btn[1].cb_hold = ui_btn_hold_cb; + btn[1].cb_release = ui_btn_release_cb; + + btn[2].hold = 420 >> 1; + btn[2].repeat = (1000 / 20) >> 1; + btn[2].cb_push = ui_btn_push_cb; + btn[2].cb_hold = ui_btn_hold_cb; + btn[2].cb_release = ui_btn_release_cb; +} + void ui_render() { uint8_t i; @@ -530,6 +574,7 @@ void ui_render() // rapidly flash lsens if ((tick & 0x7) == 0) { + adc_lsens_output(); LSENS_A_PORT->OUTDR ^= LSENS_A_PIN; } @@ -574,6 +619,7 @@ void ui_render() // slowly flash lsnes if ((tick & 0x20) == 0) { + adc_lsens_output(); LSENS_A_PORT->OUTDR ^= LSENS_A_PIN; } diff --git a/firmware/retro_tech_fw/code/src/ui.h b/firmware/retro_tech_fw/code/src/ui.h index 3cf6292..37aa567 100644 --- a/firmware/retro_tech_fw/code/src/ui.h +++ b/firmware/retro_tech_fw/code/src/ui.h @@ -10,6 +10,12 @@ +#define UI_JOG_UP 0 // BTN0 +#define UI_JOG_PUSH 1 // BTN1 +#define UI_JOG_DN 2 // BTN2 + + + extern const uint16_t cursor_flash_rates[8]; diff --git a/firmware/retro_tech_fw/code/system_ch32x035.c b/firmware/retro_tech_fw/code/system_ch32x035.c index 3bdc2ec..9618016 100644 --- a/firmware/retro_tech_fw/code/system_ch32x035.c +++ b/firmware/retro_tech_fw/code/system_ch32x035.c @@ -1,60 +1,21 @@ -/********************************** (C) COPYRIGHT ******************************* +/******************************************************************************* * File Name : system_ch32x035.c - * Author : WCH - * Version : V1.0.0 - * Date : 2023/04/06 - * Description : CH32X035 Device Peripheral Access Layer System Source File. -********************************************************************************* -* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. -* Attention: This software (modified or not) and binary are used for -* microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ + #include "ch32x035.h" #include "global.h" -/* -* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after -* reset the HSI is used as SYSCLK source). -*/ -/* Clock Definitions */ -/* -#ifdef SYSCLK_FREQ_8MHz_HSI -uint32_t SystemCoreClock = SYSCLK_FREQ_8MHz_HSI; // System Clock Frequency (Core Clock) -#elif defined SYSCLK_FREQ_12MHz_HSI -uint32_t SystemCoreClock = SYSCLK_FREQ_12MHz_HSI; // System Clock Frequency (Core Clock) -#elif defined SYSCLK_FREQ_16MHz_HSI -uint32_t SystemCoreClock = SYSCLK_FREQ_16MHz_HSI; // System Clock Frequency (Core Clock) -#elif defined SYSCLK_FREQ_24MHz_HSI -uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz_HSI; // System Clock Frequency (Core Clock) -#else -uint32_t SystemCoreClock = HSI_VALUE; // System Clock Frequency (Core Clock) -#endif -*/ uint32_t SystemCoreClock; __I uint8_t AHBPrescTable[16] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; -/* system_private_function_proto_types */ + void SetSysClock(uint32_t clock); -/* -#ifdef SYSCLK_FREQ_8MHz_HSI -static void SetSysClockTo8_HSI( void ); -#elif defined SYSCLK_FREQ_12MHz_HSI -static void SetSysClockTo12_HSI( void ); -#elif defined SYSCLK_FREQ_16MHz_HSI -static void SetSysClockTo16_HSI( void ); -#elif defined SYSCLK_FREQ_24MHz_HSI -static void SetSysClockTo24_HSI( void ); -#elif defined SYSCLK_FREQ_48MHz_HSI -static void SetSysClockTo48_HSI( void ); -#endif -*/ - -static void SetSysClockToX_HSI(uint32_t div, uint32_t latency); +static void SetSysClockToX_HSI(uint32_t div, uint8_t latency); /********************************************************************* @@ -67,10 +28,16 @@ static void SetSysClockToX_HSI(uint32_t div, uint32_t latency); */ void SystemInit (void) { - RCC->CTLR |= (uint32_t)0x00000001; - RCC->CFGR0 |= (uint32_t)0x00000050; - RCC->CFGR0 &= (uint32_t)0xF8FFFF5F; - SetSysClock(SYSCLK_FREQ_NORMAL); + // ensure internal oscillator is running and ready + RCC->CTLR |= (uint32_t)RCC_HSION; + while (!(RCC->CTLR & RCC_HSIRDY)) {}; + + // default to 8MHz before doing anything else + // this is POR default + RCC->CFGR0 = (uint32_t)RCC_HPRE_DIV6; + + // set user-requested startup clock + SetSysClock(SYSCLK_FREQ_STARTUP); } /********************************************************************* @@ -87,12 +54,9 @@ void SystemCoreClockUpdate (void) SystemCoreClock = HSI_VALUE; tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)]; - if(((RCC->CFGR0 & RCC_HPRE) >> 4) < 8) - { + if(((RCC->CFGR0 & RCC_HPRE) >> 4) < 8) { SystemCoreClock /= tmp; - } - else - { + } else { SystemCoreClock >>= tmp; } } @@ -107,10 +71,11 @@ void SystemCoreClockUpdate (void) void SetSysClock(uint32_t clock) { switch (clock) { - case SYSCLK_FREQ_48MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV1, FLASH_ACTLR_LATENCY_2); break; } - case SYSCLK_FREQ_24MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV2, FLASH_ACTLR_LATENCY_1); break; } - case SYSCLK_FREQ_16MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV3, FLASH_ACTLR_LATENCY_1); break; } - case SYSCLK_FREQ_12MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV4, FLASH_ACTLR_LATENCY_0); break; } + case SYSCLK_FREQ_48MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV1, FLASH_ACTLR_LATENCY_2); break; } + case SYSCLK_FREQ_24MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV2, FLASH_ACTLR_LATENCY_1); break; } + case SYSCLK_FREQ_16MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV3, FLASH_ACTLR_LATENCY_1); break; } + case SYSCLK_FREQ_12MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV4, FLASH_ACTLR_LATENCY_0); break; } + case SYSCLK_FREQ_3MHz_HSI: { SetSysClockToX_HSI(RCC_HPRE_DIV16, FLASH_ACTLR_LATENCY_0); break; } default: { SetSysClockToX_HSI(RCC_HPRE_DIV6, FLASH_ACTLR_LATENCY_0); clock = 8000000; @@ -119,36 +84,24 @@ void SetSysClock(uint32_t clock) } SystemCoreClock = clock; - - /* -#ifdef SYSCLK_FREQ_8MHz_HSI - SetSysClockTo8_HSI(); -#elif defined SYSCLK_FREQ_12MHz_HSI - SetSysClockTo12_HSI(); -#elif defined SYSCLK_FREQ_16MHz_HSI - SetSysClockTo16_HSI(); -#elif defined SYSCLK_FREQ_24MHz_HSI - SetSysClockTo24_HSI(); -#elif defined SYSCLK_FREQ_48MHz_HSI - SetSysClockTo48_HSI(); -#endif - */ } -static void SetSysClockToX_HSI(uint32_t div, uint32_t latency) +static void SetSysClockToX_HSI(uint32_t div, uint8_t latency) { - uint32_t actlr; uint32_t cfgr0; - /* Flash 2 wait state */ - actlr = FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY); - FLASH->ACTLR = (uint32_t)actlr | FLASH_ACTLR_LATENCY_2; + // set flash access to 2 wait states (boot default is 0 at 48MHz??) + FLASH->ACTLR = (uint32_t)FLASH_ACTLR_LATENCY_2; + + // the vendor didn't wait here. but switching from slow to high speed + // often causes crashes without this. + asm("nop"); asm("nop"); asm("nop"); /* HCLK = SYSCLK = APB1 */ - cfgr0 = RCC->CFGR0 &= (uint32_t)0xFFFFFF0F; - RCC->CFGR0 = (uint32_t)cfgr0 | (div & 0xf0); + cfgr0 = RCC->CFGR0 &= (uint32_t)~RCC_HPRE; + RCC->CFGR0 = (uint32_t)(cfgr0 | (div & 0xf0)); /* Flash set wait state */ - FLASH->ACTLR = (uint32_t)actlr | (latency & 0x03); + FLASH->ACTLR = (uint32_t)(latency & 0x03); } diff --git a/firmware/retro_tech_fw/code/system_ch32x035.h b/firmware/retro_tech_fw/code/system_ch32x035.h index a59876f..d34cfca 100644 --- a/firmware/retro_tech_fw/code/system_ch32x035.h +++ b/firmware/retro_tech_fw/code/system_ch32x035.h @@ -18,6 +18,7 @@ +#define SYSCLK_FREQ_3MHz_HSI 3000000 #define SYSCLK_FREQ_8MHz_HSI 8000000 #define SYSCLK_FREQ_12MHz_HSI 12000000 #define SYSCLK_FREQ_16MHz_HSI 16000000