diff --git a/gat_stand_fw/gat_stand_fw.launch b/gat_stand_fw/gat_stand_fw.launch index 08a05ce..08b0323 100644 --- a/gat_stand_fw/gat_stand_fw.launch +++ b/gat_stand_fw/gat_stand_fw.launch @@ -1,61 +1,62 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gat_stand_fw/user/main.c b/gat_stand_fw/user/main.c index 67ec1fc..79b9f23 100644 --- a/gat_stand_fw/user/main.c +++ b/gat_stand_fw/user/main.c @@ -12,6 +12,7 @@ #include +#include "src/adc.h" #include "src/btn.h" #include "src/gat_gpio.h" #include "src/port_pwr.h" @@ -32,9 +33,9 @@ void btn_bot_push_cb(uint8_t idx) static inline void systick_init(void) { - SysTick->CMP = (SystemCoreClock / 256 / 8) - 1; // we want a 256Hz interrupt + SysTick->CMP = (SystemCoreClock / 256) - 1; // we want a 256Hz interrupt SysTick->CNT = 0; // clear counter - SysTick->CTLR = 0xB; // start counter in /8 mode, enable interrupts, auto-reset counter + SysTick->CTLR = 0xF; // start counter in /1 mode, enable interrupts, auto-reset counter SysTick->SR = 0; // clear count comparison flag NVIC_EnableIRQ(SysTicK_IRQn); // enable interrupt @@ -65,15 +66,21 @@ static void gpio_init() // RGBLED (PA0, PA1, PA2) RGBLED_PORT->BSHR = RGBLED_PIN_R | RGBLED_PIN_G | RGBLED_PIN_B; - gpio.GPIO_Mode = GPIO_Mode_Out_PP; + gpio.GPIO_Mode = GPIO_Mode_AF_PP; gpio.GPIO_Pin = RGBLED_PIN_R | RGBLED_PIN_G | RGBLED_PIN_B; GPIO_Init(RGBLED_PORT, &gpio); // GAT power enable (PA3) GAT_EN_PORT->BCR = GAT_EN_PIN; + gpio.GPIO_Mode = GPIO_Mode_Out_PP; gpio.GPIO_Pin = GAT_EN_PIN; GPIO_Init(GAT_EN_PORT, &gpio); + // USB2 power enable (PB4) + USB2_EN_PORT->BCR = USB2_EN_PIN; + gpio.GPIO_Pin = USB2_EN_PIN; + GPIO_Init(USB2_EN_PORT, &gpio); + // GAT overcurrent detect (PA4) gpio.GPIO_Mode = GPIO_Mode_IPU; gpio.GPIO_Pin = GAT_OC_PIN; @@ -83,15 +90,10 @@ static void gpio_init() gpio.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14; GPIO_Init(GPIOB, &gpio); - // GAT GPIO will be configured later + // GAT GPIO is configured in gat_gpio.c // USB PA11, PA12 will be configured later - // USB2 power enable (PB4) - gpio.GPIO_Mode = GPIO_Mode_Out_PP; - gpio.GPIO_Pin = USB2_EN_PIN; - GPIO_Init(USB2_EN_PORT, &gpio); - // unused pins that are used for I2C passthrough gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING; gpio.GPIO_Pin = GPIO_Pin_15; @@ -117,7 +119,7 @@ int main(void) // enable peripheral clocks RCC_APB1PeriphClockCmd( RCC_APB1Periph_PWR | RCC_APB1Periph_BKP | - RCC_APB1Periph_I2C1, ENABLE); + RCC_APB1Periph_I2C1 | RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD | RCC_APB2Periph_ADC1, ENABLE); @@ -145,6 +147,9 @@ int main(void) // start up rgbled rgbled_init(); + // initialize light sense stuff + adc_init(); + // finally, get the system tick interrupt going systick_init(); @@ -158,14 +163,23 @@ int main(void) uint8_t st_tick; volatile uint32_t uptime; +__attribute__((interrupt("WCH-Interrupt-fast"))) void SysTick_Handler(void) { st_tick++; if (!st_tick) uptime++; + // update buttons btn_poll(); if (!(st_tick & 0x3)) { rgbled_update(); } + + // clear comparison flag + SysTick->SR = 0; + + if (SysTick->SR) { + while (1); + } } diff --git a/gat_stand_fw/user/src/adc.c b/gat_stand_fw/user/src/adc.c new file mode 100644 index 0000000..da7b477 --- /dev/null +++ b/gat_stand_fw/user/src/adc.c @@ -0,0 +1,211 @@ +/* + * lightsense.c + * + * Created on: Oct 18, 2024 + * Author: true + */ + + +#include +#include + +#include "adc.h" + + + + +static const uint8_t led_brightness_map[] = { + 47, 44, 42, 41, + 40, 38, 36, 34, + 32, 31, 30, 29, + 27, 25, 21, 19, + 17, 16, 15, 15, // indoors normal brightness + 14, 14, 13, 13, + 12, 12, 12, 11, + 11, 11, 10, 10, + 10, 9, 9, 9, + 8, 8, 8, 8, + 7, 7, 7, 7, + 7, 6, 6, 6 +}; + +static GPIO_InitTypeDef lsens_gpio = { + .GPIO_Mode = GPIO_Mode_Out_PP, + .GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN, + .GPIO_Speed = GPIO_Speed_2MHz +}; + +uint16_t lsens_val; + +static uint8_t lsens_mode = LSENS_READING_IDLE; + +uint8_t lsens_wait; +uint8_t lsens_coarse = 1; + + + +void adc_init() +{ + ADC_InitTypeDef adc = {0}; + + RCC_ADCCLKConfig(RCC_PCLK2_Div4); + + ADC_DeInit(ADC1); + adc.ADC_Mode = ADC_Mode_Independent; + adc.ADC_ScanConvMode = DISABLE; + adc.ADC_ContinuousConvMode = DISABLE; + adc.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; + adc.ADC_DataAlign = ADC_DataAlign_Right; + adc.ADC_NbrOfChannel = 1; + ADC_Init(ADC1, &adc); + + ADC_RegularChannelConfig(ADC1, LSENS_ADC_CH, 1, ADC_SampleTime_239Cycles5); + ADC_Cmd(ADC1, ENABLE); +} + +void adc_convert() +{ + ADC_SoftwareStartConvCmd(ADC1, ENABLE); +} + +void adc_read() +{ + uint16_t timeout = 0xfff; + while((!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) && timeout) timeout--; + if (timeout) { + lsens_val = ADC_GetConversionValue(ADC1); + } +} + +void adc_set_mode_lsens(uint8_t mode) +{ + lsens_mode = mode; + + if (mode == LSENS_OUTPUT) { + lsens_gpio.GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN; + lsens_gpio.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(LSENS_PORT, &lsens_gpio); + } +} + +uint8_t adc_get_mode_lsens() +{ + return lsens_mode; +} + +static void lsens_start() +{ + // set anode and cathode low + LSENS_PORT->BCR = LSENS_A_PIN | LSENS_K_PIN; + + adc_set_mode_lsens(LSENS_READING_START); + + // set cathode high, let it charge + LSENS_PORT->BSHR = LSENS_K_PIN; + + // set anode low + lsens_gpio.GPIO_Pin = LSENS_A_PIN; + lsens_gpio.GPIO_Mode = GPIO_Mode_IPD; + GPIO_Init(LSENS_PORT, &lsens_gpio); + + // set cathode as analog input + lsens_gpio.GPIO_Pin = LSENS_K_PIN; + lsens_gpio.GPIO_Mode = GPIO_Mode_AIN; + GPIO_Init(LSENS_PORT, &lsens_gpio); +} + +static void lsens_stop() +{ + lsens_gpio.GPIO_Pin = LSENS_A_PIN | LSENS_K_PIN; + lsens_gpio.GPIO_Mode = GPIO_Mode_Out_PP; + GPIO_Init(LSENS_PORT, &lsens_gpio); + + lsens_mode = LSENS_READING_IDLE; +} + +void adc_process_lsens() +{ + if (lsens_mode != LSENS_OUTPUT) { + // do what needs to be done by me to defeat the light enemys + switch (lsens_mode) { + case LSENS_READING_IDLE: { + // prepare LED, wait a little bit + lsens_start(); + adc_convert(); + lsens_wait = lsens_coarse; + + lsens_mode = LSENS_READING_START; + + break; + } + case LSENS_READING_START: { + if (!lsens_wait) { + // convert the LED + adc_convert(); + + lsens_mode = LSENS_READING_WAIT; + } + + lsens_wait--; + + break; + } + case LSENS_READING_WAIT: { + // read the light sensor value + adc_read(); + lsens_stop(); + + // calculate adjustments + if (lsens_val > LSENS_COARSE_UP) { + lsens_coarse++; + if (lsens_coarse > 0x3f) lsens_coarse = 0x3f; + } else if (lsens_val < LSENS_COARSE_DOWN) { + if (lsens_coarse) lsens_coarse--; + } + + lsens_wait = 255 - lsens_coarse; + + // wait a bit before doing it again + lsens_mode = LSENS_READING_TIMEOUT; + + break; + } + case LSENS_READING_TIMEOUT: { + if (!lsens_wait) { + // do it all again + lsens_mode = LSENS_READING_IDLE; + } + lsens_wait--; + } + } + } +} + +uint16_t adc_get_lsens() +{ + return lsens_val; +} + +uint8_t adc_get_lsens_coarse() +{ + return lsens_coarse; +} + +uint8_t adc_get_brightness(uint8_t level) +{ + if (!level) { + // are you outside? why? it's too fucking hot + // we'll shut down when in the presence of big nuclear fire + if (adc_get_lsens() < 400) { + // yup, outside or in a spotlight at 3ft away or something + return 0; + } + } + + if (level >= sizeof(led_brightness_map)) { + return led_brightness_map[sizeof(led_brightness_map) - 1]; + + } + + return led_brightness_map[level]; +} diff --git a/gat_stand_fw/user/src/adc.h b/gat_stand_fw/user/src/adc.h new file mode 100644 index 0000000..ae554ac --- /dev/null +++ b/gat_stand_fw/user/src/adc.h @@ -0,0 +1,50 @@ +/* + * lightsense.h + * + * Created on: Oct 18, 2024 + * Author: true + */ + +#ifndef USER_SRC_ADC_H_ +#define USER_SRC_ADC_H_ + + + +#define LSENS_DARK_THRESHOLD 0x7ff // baseline minimum value reading achieved in darkness + +#define LSENS_PORT GPIOA +#define LSENS_A_PIN GPIO_Pin_2 +#define LSENS_K_PIN GPIO_Pin_3 +#define LSENS_ADC_CH ADC_Channel_3 + +#define LSENS_COARSE_UP 0x690 // counts higher than this increase lsens_coarse, maximum 64 +#define LSENS_COARSE_DOWN 0x5a0 // counts lower than this decrease lsens_coarse, minimum 1 + +enum lsens_mode { + LSENS_READING_IDLE = 0, + LSENS_READING_START, + LSENS_READING_WAIT, + LSENS_READING_TIMEOUT, + LSENS_OUTPUT = 0xff +}; + + + +void adc_init(); + +void adc_convert(); +void adc_read(); + +void adc_set_mode_lsens(uint8_t mode); +uint8_t adc_get_mode_lsens(); + +void adc_process_lsens(); + +uint16_t adc_get_lsens(); +uint8_t adc_get_lsens_coarse(); + +uint8_t adc_get_brightness(uint8_t level); + + + +#endif /* USER_SRC_ADC_H_ */ diff --git a/gat_stand_fw/user/src/btn.c b/gat_stand_fw/user/src/btn.c index 45f9785..8525cce 100644 --- a/gat_stand_fw/user/src/btn.c +++ b/gat_stand_fw/user/src/btn.c @@ -43,19 +43,15 @@ void btn_init() void btn_poll() { uint8_t i; - uint8_t r; uint8_t ignore; uint8_t pushed; for (i = 0; i < BTN_COUNT; i++) { - pushed = 0; - ignore = btn[i]._mask & BTN_IGNORE; - r = BTN_PORT->INDR & (1 << (btn[i]._pintype & BTN_PIN_MASK)); // active low type buttons - if (!r) pushed = 1; + pushed = BTN_PORT->INDR & (1 << (btn[i]._pintype & BTN_PIN_MASK)) ? 0 : 1; if (pushed) { // hold counter diff --git a/gat_stand_fw/user/src/port_pwr.c b/gat_stand_fw/user/src/port_pwr.c index e1ede7d..dc300aa 100644 --- a/gat_stand_fw/user/src/port_pwr.c +++ b/gat_stand_fw/user/src/port_pwr.c @@ -17,15 +17,21 @@ #define GAT_ON_FLAG (1 << 0) #define USB2_ON_FLAG (1 << 1) -#define INIT_FLAG (0xa0 << 8) +#define INIT_FLAG (0xaf << 8) -static uint8_t port_pwr_state; +static uint16_t port_pwr_state; static uint8_t gat_oc_state_latch = 0; +void port_pwr_commit_bkp() +{ + BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state); + RTC_WaitForLastTask(); +} + void gat_on() { if (gat_oc_state_latch) return; @@ -33,7 +39,7 @@ void gat_on() GAT_EN_PORT->BSHR = GAT_EN_PIN; port_pwr_state |= GAT_ON_FLAG; - BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state); + port_pwr_commit_bkp(); } void gat_off() @@ -41,7 +47,7 @@ void gat_off() GAT_EN_PORT->BCR = GAT_EN_PIN; port_pwr_state &= ~GAT_ON_FLAG; - BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state); + port_pwr_commit_bkp(); } uint8_t gat_pwr_state() @@ -65,16 +71,21 @@ void gat_toggle() else gat_on(); } + void usb2_on() { + USB2_EN_PORT->BSHR = USB2_EN_PIN; + port_pwr_state |= USB2_ON_FLAG; - BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state); + port_pwr_commit_bkp(); } void usb2_off() { + USB2_EN_PORT->BCR = USB2_EN_PIN; + port_pwr_state &= ~USB2_ON_FLAG; - BKP_WriteBackupRegister(PORT_PWR_STATE_DR, port_pwr_state); + port_pwr_commit_bkp(); } uint8_t usb2_pwr_state() @@ -84,20 +95,25 @@ uint8_t usb2_pwr_state() void usb2_toggle() { - if (usb2_pwr_state()) gat_off(); - else gat_on(); + if (usb2_pwr_state()) usb2_off(); + else usb2_on(); } void port_pwr_init() { port_pwr_state = BKP_ReadBackupRegister(PORT_PWR_STATE_DR); + RTC_WaitForLastTask(); if ((port_pwr_state & INIT_FLAG) != INIT_FLAG) { // no battery retention. // automatically turn on all outputs - port_pwr_state |= INIT_FLAG; - gat_on(); - usb2_on(); + port_pwr_state = INIT_FLAG | USB2_ON_FLAG | GAT_ON_FLAG; + + // and commit state flags + port_pwr_commit_bkp(); } + + if (port_pwr_state & GAT_ON_FLAG) gat_on(); + if (port_pwr_state & USB2_ON_FLAG) usb2_on(); } diff --git a/gat_stand_fw/user/src/rgbled.c b/gat_stand_fw/user/src/rgbled.c index 9b573d6..4cc6498 100644 --- a/gat_stand_fw/user/src/rgbled.c +++ b/gat_stand_fw/user/src/rgbled.c @@ -17,9 +17,10 @@ #define GRN 1 #define BLU 2 -#define BRT_RED 200 -#define BRT_GRN 100 -#define BRT_BLU 200 +#define BRT_RED 80 +#define BRT_GRN 32 +#define BRT_BLU 36 +#define BRT_OFF 0 #define RGBLED_TIM TIM2 @@ -63,20 +64,17 @@ void rgbled_set() } } - RGBLED_TIM->CH1CVR = state[RED] ? BRT_RED : 0; - RGBLED_TIM->CH2CVR = state[GRN] ? BRT_GRN : 0; - RGBLED_TIM->CH3CVR = state[BLU] ? BRT_BLU : 0; + RGBLED_TIM->CH1CVR = state[BLU] ? BRT_BLU : BRT_OFF; + RGBLED_TIM->CH2CVR = state[GRN] ? BRT_GRN : BRT_OFF; + RGBLED_TIM->CH3CVR = state[RED] ? BRT_RED : BRT_OFF; } void rgbled_update() { - uint16_t w; - // VCR flash if clock isn't set - w = BKP_ReadBackupRegister(RTC_STATE_DR); - switch (w) { - case RTC_STATE_UNINITIALIZED: { - flash_timeout[BLU] = 254; + switch (rtc_state) { + case RTC_STATE_CLOCK_NOT_SET: { + flash_timeout[BLU] = 48; break; } default: { @@ -86,7 +84,9 @@ void rgbled_update() } flash_timeout[GRN] = gat_pwr_state() ? 0 : 0xff; - flash_timeout[RED] = gat_oc_state() ? 50 : 0xff; + flash_timeout[RED] = gat_oc_state() ? 16 : 0xff; + + rgbled_set(); } void rgbled_init() @@ -102,18 +102,19 @@ void rgbled_init() pwm.TIM_OCMode = TIM_OCMode_PWM1; pwm.TIM_OutputState = TIM_OutputState_Enable; - pwm.TIM_Pulse = 0; - pwm.TIM_OCPolarity = TIM_OCPolarity_High; + pwm.TIM_Pulse = BRT_OFF; + pwm.TIM_OCPolarity = TIM_OCPolarity_Low; + + TIM_OC1PreloadConfig(RGBLED_TIM, TIM_OCPreload_Disable); + TIM_OC2PreloadConfig(RGBLED_TIM, TIM_OCPreload_Disable); + TIM_OC3PreloadConfig(RGBLED_TIM, TIM_OCPreload_Disable); + TIM_ARRPreloadConfig(RGBLED_TIM, ENABLE); + TIM_OC1Init(RGBLED_TIM, &pwm); TIM_OC2Init(RGBLED_TIM, &pwm); TIM_OC3Init(RGBLED_TIM, &pwm); - TIM_CtrlPWMOutputs(RGBLED_TIM, ENABLE); - TIM_OC1PreloadConfig(RGBLED_TIM, TIM_OCPreload_Disable); - TIM_ARRPreloadConfig(RGBLED_TIM, ENABLE); - TIM_Cmd(RGBLED_TIM, ENABLE); - RGBLED_TIM->CH1CVR = 0; - RGBLED_TIM->CH2CVR = 0; - RGBLED_TIM->CH3CVR = 0; + RGBLED_TIM->CNT = 0; + TIM_Cmd(RGBLED_TIM, ENABLE); } diff --git a/gat_stand_fw/user/src/rgbled.h b/gat_stand_fw/user/src/rgbled.h index 3db5707..ca7481f 100644 --- a/gat_stand_fw/user/src/rgbled.h +++ b/gat_stand_fw/user/src/rgbled.h @@ -11,12 +11,13 @@ #define RGBLED_PORT GPIOA -#define RGBLED_PIN_R GPIO_Pin_0 +#define RGBLED_PIN_B GPIO_Pin_0 #define RGBLED_PIN_G GPIO_Pin_1 -#define RGBLED_PIN_B GPIO_Pin_2 +#define RGBLED_PIN_R GPIO_Pin_2 +void rgbled_init(); void rgbled_update(); diff --git a/gat_stand_fw/user/src/rtc.c b/gat_stand_fw/user/src/rtc.c index 02c093c..732d44f 100644 --- a/gat_stand_fw/user/src/rtc.c +++ b/gat_stand_fw/user/src/rtc.c @@ -116,6 +116,7 @@ int8_t rtc_init() // get RTC state // if things aren't configured it'll be initialized in a moment rtc_state = BKP_ReadBackupRegister(RTC_STATE_DR); + RTC_WaitForLastTask(); // is RTC already configured? if (BKP_ReadBackupRegister(RTC_INIT_DR) != RTC_INIT_PATTERN) { @@ -150,11 +151,14 @@ int8_t rtc_init() rtc_state = RTC_STATE_CLOCK_NOT_SET; BKP_WriteBackupRegister(RTC_STATE_DR, rtc_state); + RTC_WaitForLastTask(); BKP_WriteBackupRegister(RTC_INIT_DR, RTC_INIT_PATTERN); // RTC_NVIC_Config(); // RTC_Get(); } + RTC_WaitForLastTask(); + return 0; } diff --git a/gat_stand_fw/user/src/rtc.h b/gat_stand_fw/user/src/rtc.h index 9c7bd75..cf85959 100644 --- a/gat_stand_fw/user/src/rtc.h +++ b/gat_stand_fw/user/src/rtc.h @@ -13,6 +13,14 @@ +/* a small note about backup registers: + * + * the datasheet clearly states there are 42 16-bit registers. + * it does not cut out any exception for CH32V203 except CH32V203RB. + * however, the reference manual states that registers 11-42 are only + * for the _D8 chips, and not the _D6 V4B chips like this one. + * thus we only have _10_ backup registers, not 42. + */ #define RTC_INIT_DR BKP_DR1 #define RTC_STATE_DR BKP_DR2 @@ -35,6 +43,10 @@ typedef struct RTClock { +extern uint8_t rtc_state; + + + int8_t rtc_init(); int8_t rtc_set_clock(struct RTClock *c); diff --git a/gat_stand_fw/user/system_ch32v20x.c b/gat_stand_fw/user/system_ch32v20x.c index baf28f5..53bb64f 100644 --- a/gat_stand_fw/user/system_ch32v20x.c +++ b/gat_stand_fw/user/system_ch32v20x.c @@ -26,9 +26,9 @@ //#define SYSCLK_FREQ_120MHz_HSE 120000000 //#define SYSCLK_FREQ_144MHz_HSE 144000000 //#define SYSCLK_FREQ_HSI HSI_VALUE -//#define SYSCLK_FREQ_48MHz_HSI 48000000 +#define SYSCLK_FREQ_48MHz_HSI 48000000 //#define SYSCLK_FREQ_56MHz_HSI 56000000 -#define SYSCLK_FREQ_72MHz_HSI 72000000 +//#define SYSCLK_FREQ_72MHz_HSI 72000000 //#define SYSCLK_FREQ_96MHz_HSI 96000000 //#define SYSCLK_FREQ_120MHz_HSI 120000000 //#define SYSCLK_FREQ_144MHz_HSI 144000000