Merge pull request #18 from microsoft/rgbled
support for RGB LED status
This commit is contained in:
Коммит
ef9b3f9f34
5
bl/bl.h
5
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
87
bl/blmain.c
87
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) {
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
2
build.mk
2
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
|
||||
|
|
54
src/main.c
54
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) {
|
||||
|
|
39
stm32/pins.c
39
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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче