diff --git a/bl/bl.h b/bl/bl.h index 27f5bcf..830e7bd 100644 --- a/bl/bl.h +++ b/bl/bl.h @@ -30,6 +30,7 @@ typedef struct ctx { uint8_t bl_ad_queued; uint8_t id_counter; uint8_t low_detected; + uint16_t id_queued; #if QUICK_LOG == 1 volatile uint32_t *log_reg; @@ -48,7 +49,7 @@ typedef struct ctx { // timestamps uint32_t now; uint32_t tx_start_time; - uint32_t led_off_time; + uint32_t led_on_time; uint32_t next_announce; uint32_t next_id_blink; uint32_t app_start_time; @@ -91,6 +92,8 @@ void tim_init(void); uint32_t tim_get_micros(void); +void blled_init(uint32_t period); +void blled_set_duty(uint32_t duty); void uart_init(ctx_t *ctx); int uart_tx(ctx_t *ctx, const void *data, uint32_t numbytes); diff --git a/bl/bljd.c b/bl/bljd.c index 888d318..89be2ad 100644 --- a/bl/bljd.c +++ b/bl/bljd.c @@ -53,6 +53,10 @@ static void ctrl_handle_packet(ctx_t *ctx, jd_packet_t *pkt) { case JD_CONTROL_CMD_RESET: target_reset(); break; + case JD_GET(JD_CONTROL_REG_BOOTLOADER_FIRMWARE_IDENTIFIER): + case JD_GET(JD_CONTROL_REG_FIRMWARE_IDENTIFIER): + ctx->id_queued = pkt->service_command; + break; } } diff --git a/bl/blmain.c b/bl/blmain.c index 13045e4..7b83f97 100644 --- a/bl/blmain.c +++ b/bl/blmain.c @@ -10,7 +10,22 @@ static void start_app(void) { ctx_t ctx_; +// The LED_BL will be run at 10/BL_LED_PERIOD and 30/BL_LED_PERIOD +#ifndef BL_LED_PERIOD +#define BL_LED_PERIOD 300 +#endif + +#ifdef LED_RGB_COMMON_CATHODE +#define SET_LED(v) blled_set_duty(v) +#else +#define SET_LED(v) blled_set_duty(BL_LED_PERIOD - (v)) +#endif + void led_init(void) { +#ifdef PIN_BL_LED + SET_LED(0); + blled_init(BL_LED_PERIOD); +#else pin_setup_output(PIN_LED); pin_setup_output(PIN_LED_GND); #if QUICK_LOG == 1 @@ -18,15 +33,21 @@ void led_init(void) { pin_setup_output(PIN_X1); #endif pin_set(PIN_LED_GND, 0); +#endif +#if QUICK_LOG == 1 + pin_setup_output(PIN_X0); + pin_setup_output(PIN_X1); +#endif } +#ifndef PIN_BL_LED void led_set(int state) { pin_set(PIN_LED, state); } +#endif void led_blink(int us) { - ctx_.led_off_time = tim_get_micros() + us; - led_set(1); + ctx_.led_on_time = tim_get_micros() + us; } uint32_t random(ctx_t *ctx) { @@ -71,12 +92,9 @@ int main(void) { ctx_t *ctx = &ctx_; led_init(); - led_set(1); tim_init(); uart_init(ctx); - led_blink(256 * 1024); // initial (on reset) blink - uint32_t r0 = bl_adc_random_seed(); ctx->randomseed = r0; @@ -109,6 +127,9 @@ int main(void) { DMESG("ID: %x %x", (uint32_t)BL_DEVICE_ID, (uint32_t)(BL_DEVICE_ID >> 32)); + // wait a tiny bit, to desynchronize various bootloaders (so that eg PWM don't fire in sync) + target_wait_us(random(ctx) & 0xff); + ctx->service_class_bl = announce_data[2]; ctx->next_announce = 1024 * 1024; @@ -122,6 +143,9 @@ int main(void) { (void)app_valid; #endif ctx->app_start_time = 0x80000000; + // we delay the first LED light up randomly, so it's not very likely to get synchronized with + // other bootloaders + uint32_t led_cnt_down = (ctx->randomseed & 0xff) + 10; while (1) { uint32_t now = ctx->now = tim_get_micros(); @@ -131,23 +155,49 @@ int main(void) { if (jd_process(ctx)) continue; - if (now >= ctx->next_announce && !ctx->tx_full) { - memcpy(ctx->txBuffer.data, announce_data, sizeof(announce_data)); - jd_prep_send(ctx); - ctx->next_announce = now + 512 * 1024; + if (!ctx->tx_full) { + if (now >= ctx->next_announce) { + memcpy(ctx->txBuffer.data, announce_data, sizeof(announce_data)); + jd_prep_send(ctx); + ctx->next_announce = now + 512 * 1024; + } else if (ctx->id_queued) { + ((uint32_t *)ctx->txBuffer.data)[0] = + 4 | (JD_SERVICE_NUMBER_CONTROL << 8) | (ctx->id_queued << 16); + ((uint32_t *)ctx->txBuffer.data)[1] = bl_dev_info.device_class; + ctx->id_queued = 0; + jd_prep_send(ctx); + } } if (now >= ctx->app_start_time) start_app(); - if (ctx->led_off_time) { - if (ctx->led_off_time < now) { - led_set(0); - ctx->led_off_time = 0; + led_cnt_down--; +#ifdef PIN_BL_LED + if (led_cnt_down == 0) { + led_cnt_down = 10; + if (ctx->led_on_time < now) { + if (now & 0x80000) + SET_LED(30); + else + SET_LED(10); + } else { + SET_LED(0); } - } else { - led_set((now & 0x3f) < ((now & 0x80000) ? 0x1 : 0x4)); } +#else + if (led_cnt_down == 1) { + if (ctx->led_on_time < now) { + led_set(1); + } + } else if (led_cnt_down == 0) { + led_set(0); + if (now & 0x80000) + led_cnt_down = 5; + else + led_cnt_down = 10; + } +#endif } } @@ -158,10 +208,17 @@ static void busy_sleep(int ms) { } static void led_panic_blink(void) { +#ifdef PIN_BL_LED + SET_LED(40); + busy_sleep(70); + SET_LED(0); + busy_sleep(70); +#else led_set(1); busy_sleep(70); led_set(0); busy_sleep(70); +#endif } void jd_panic(void) { diff --git a/bl/blpwm.c b/bl/blpwm.c new file mode 100644 index 0000000..9625ff7 --- /dev/null +++ b/bl/blpwm.c @@ -0,0 +1,64 @@ +#include "bl.h" + +#ifdef PIN_BL_LED + +#ifdef STM32F0 +#if PIN_BL_LED == PB_1 +#define TIMx TIM3 +#define TIMx_CLK_ENABLE __HAL_RCC_TIM3_CLK_ENABLE +#define CHANNEL 4 +#define AF LL_GPIO_AF_1 +#endif +#elif defined(STM32G0) +#if PIN_BL_LED == PA_6 +#define TIMx TIM3 +#define TIMx_CLK_ENABLE __HAL_RCC_TIM3_CLK_ENABLE +#define CHANNEL 1 +#define AF LL_GPIO_AF_1 +#endif +#else +#error "unsupported MCU" +#endif + +#ifndef TIMx +#error "unsupported PIN_BL_LED" +#endif + +void blled_init(uint32_t period) { + TIMx_CLK_ENABLE(); + + pin_setup_output_af(PIN_BL_LED, AF); + + // LL_TIM_SetPrescaler(TIMx, 2); + LL_TIM_SetAutoReload(TIMx, period - 1); + LL_TIM_GenerateEvent_UPDATE(TIMx); + LL_TIM_EnableARRPreload(TIMx); + + if (TIMx == TIM1) + TIMx->BDTR |= TIM_BDTR_MOE; + +#define MODE (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE) +#if CHANNEL == 1 + TIMx->CCMR1 = MODE; +#elif CHANNEL == 2 + TIMx->CCMR1 = MODE << 8; +#elif CHANNEL == 3 + TIMx->CCMR2 = MODE; +#elif CHANNEL == 4 + TIMx->CCMR2 = MODE << 8; +#else +#error "wrong channel" +#endif + + uint32_t chmask = 1 << (4 * (CHANNEL - 1)); + LL_TIM_CC_EnableChannel(TIMx, chmask); + + LL_TIM_EnableCounter(TIMx); + LL_TIM_GenerateEvent_UPDATE(TIMx); +} + +void blled_set_duty(uint32_t duty) { + WRITE_REG(*(&TIMx->CCR1 + CHANNEL - 1), duty); +} + +#endif \ No newline at end of file diff --git a/bl/bluart.c b/bl/bluart.c index a408eb8..dae9011 100644 --- a/bl/bluart.c +++ b/bl/bluart.c @@ -82,7 +82,7 @@ void uart_disable(ctx_t *ctx) { int uart_rx(ctx_t *ctx, void *data, uint32_t maxbytes) { uint32_t isr = USARTx->ISR; - if (ctx->low_detected || !(isr & USART_ISR_FE)) { + if (!ctx->low_detected && !(isr & USART_ISR_FE)) { if (isr & USART_ISR_BUSY) return RX_LINE_BUSY; return RX_LINE_IDLE; diff --git a/build.mk b/build.mk index f2248cb..463a363 100644 --- a/build.mk +++ b/build.mk @@ -250,5 +250,7 @@ ff: full-flash full-flash: ifeq ($(NOBL),) $(MAKE) BL=1 r + # let bootloader generate device id (it's more like a millisecond, but let's be safe here) + @sleep 1 endif $(MAKE) r diff --git a/src/main.c b/src/main.c index f02aa7d..b03efa0 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,6 @@ void log_pin_set(int line, int v) { #endif } -static uint64_t led_off_time; - // AP2112 // reg 85ua // reg back 79uA @@ -64,7 +62,7 @@ static uint64_t led_off_time; static void do_nothing(void) {} void sleep_forever(void) { target_wait_us(500000); - led_set(0); + jd_status(JD_STATUS_OFF); int cnt = 0; for (;;) { pin_pulse(PIN_P0, 2); @@ -80,18 +78,8 @@ void sleep_forever(void) { } } -void led_set(int state) { - pin_set(PIN_LED, state); -} - -void led_blink(int us) { - led_off_time = tim_get_micros() + us; - led_set(1); -} - int main(void) { led_init(); - led_set(1); if ((jd_device_id() + 1) == 0) target_reset(); @@ -100,25 +88,13 @@ int main(void) { adc_init_random(); // 300b rtc_init(); uart_init(); + jd_init(); -#if 0 - while(1) { - led_set(1); - pwr_pin_enable(1); - target_wait_us(300000); - pwr_pin_enable(0); - target_wait_us(100000); - led_set(0); - target_wait_us(10 * 1000 * 1000); - } -#endif - - led_blink(200000); // initial (on reset) blink - // When BMP attaches, and we're in deep sleep mode, it will scan us as generic Cortex-M0. // The flashing scripts scans once, resets the target (using NVIC), and scans again. // The delay is so that the second scan detects us as the right kind of chip. + // TODO this may no longer be the case with latest BMP uint32_t startup_wait = tim_get_micros() + 300000; while (1) { @@ -131,16 +107,6 @@ int main(void) { jd_services_tick(); - if (led_off_time) { - int timeLeft = led_off_time - now_long; - if (timeLeft <= 0) { - led_off_time = 0; - led_set(0); - } else if (timeLeft < 1000) { - continue; // don't sleep - } - } - if (startup_wait) { if (in_future(startup_wait)) continue; // no sleep @@ -153,13 +119,23 @@ int main(void) { } static void led_panic_blink(void) { +#ifdef PIN_LED_R + // TODO should we actually PWM? + pin_setup_output(PIN_LED_R); + // it doesn't actually matter if LED_RGB_COMMON_CATHODE is defined, as we're just blinking + pin_set(PIN_LED_R, 0); + target_wait_us(70000); + pin_set(PIN_LED_R, 1); + target_wait_us(70000); +#else pin_setup_output(PIN_LED); pin_setup_output(PIN_LED_GND); pin_set(PIN_LED_GND, 0); - led_set(1); + pin_set(PIN_LED, 1); target_wait_us(70000); - led_set(0); + pin_set(PIN_LED, 0); target_wait_us(70000); +#endif } void hw_panic(void) { diff --git a/stm32/pins.c b/stm32/pins.c index d969a5f..851b8e3 100644 --- a/stm32/pins.c +++ b/stm32/pins.c @@ -35,33 +35,40 @@ void pin_setup_input(int pin, int pull) { uint32_t currentpin = PIN_MASK(pin); LL_GPIO_SetPinMode(GPIOx, currentpin, LL_GPIO_MODE_INPUT); LL_GPIO_SetPinPull(GPIOx, currentpin, - pull == -1 ? LL_GPIO_PULL_DOWN - : pull == 1 ? LL_GPIO_PULL_UP - : pull == 0 ? LL_GPIO_PULL_NO : (jd_panic(), 0)); + pull == -1 ? LL_GPIO_PULL_DOWN + : pull == 1 ? LL_GPIO_PULL_UP + : pull == 0 ? LL_GPIO_PULL_NO + : (jd_panic(), 0)); } void pin_setup_analog_input(int pin) { if ((uint8_t)pin == 0xff) return; - LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Pin = PIN_MASK(pin); - LL_GPIO_Init(PIN_PORT(pin), &GPIO_InitStruct); + + GPIO_TypeDef *GPIOx = PIN_PORT(pin); + uint32_t currentpin = PIN_MASK(pin); + LL_GPIO_SetPinPull(GPIOx, currentpin, LL_GPIO_PULL_NO); + LL_GPIO_SetPinMode(GPIOx, currentpin, LL_GPIO_MODE_ANALOG); } // TODO use this everywhere void pin_setup_output_af(int pin, int af) { if ((uint8_t)pin == 0xff) return; - LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = PIN_MASK(pin); - GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; - GPIO_InitStruct.Pull = LL_GPIO_PULL_DOWN; - GPIO_InitStruct.Alternate = af; - LL_GPIO_Init(PIN_PORT(pin), &GPIO_InitStruct); + + GPIO_TypeDef *GPIOx = PIN_PORT(pin); + uint32_t currentpin = PIN_MASK(pin); + + LL_GPIO_SetPinSpeed(GPIOx, currentpin, LL_GPIO_SPEED_FREQ_HIGH); + LL_GPIO_SetPinOutputType(GPIOx, currentpin, LL_GPIO_OUTPUT_PUSHPULL); + LL_GPIO_SetPinPull(GPIOx, currentpin, LL_GPIO_PULL_DOWN); + + if (currentpin < LL_GPIO_PIN_8) + LL_GPIO_SetAFPin_0_7(GPIOx, currentpin, af); + else + LL_GPIO_SetAFPin_8_15(GPIOx, currentpin, af); + + LL_GPIO_SetPinMode(GPIOx, currentpin, LL_GPIO_MODE_ALTERNATE); } void pin_pulse(int pin, int times) { diff --git a/stm32/pwm.c b/stm32/pwm.c index 6bbb295..2a19f86 100644 --- a/stm32/pwm.c +++ b/stm32/pwm.c @@ -49,7 +49,8 @@ static const struct PinPWM pins[] = { {PA_6, 1, LL_GPIO_AF_1, TIM3}, // SERVO on jdm-v2,3 {PA_11, 4, LL_GPIO_AF_2, TIM1}, // POWER on jdm-v3 {PB_0, 3, LL_GPIO_AF_1, TIM3}, // GLO0 on jdm-v3, also TIM1:2N - {PB_1, 1, LL_GPIO_AF_0, TIM14}, // GLO1 on jdm-v3; also TIM3:4, TIM1:3N + {PB_1, 4, LL_GPIO_AF_1, TIM3}, // GLO1 on jdm-v3; also TIM3:4, TIM1:3N + //{PB_1, 1, LL_GPIO_AF_0, TIM14}, // GLO1 on jdm-v3; also TIM3:4, TIM1:3N {PA_10, 3, LL_GPIO_AF_2, TIM1}, // SND {PA_4, 1, LL_GPIO_AF_4, TIM14}, // SND {PA_7, 1, LL_GPIO_AF_4, TIM14}, // servo