Merge pull request #18 from microsoft/rgbled

support for RGB LED status
This commit is contained in:
Michał Moskal 2021-03-18 20:42:41 +01:00 коммит произвёл GitHub
Родитель ac56d865f6 a0b7655247
Коммит ef9b3f9f34
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 187 добавлений и 73 удалений

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -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) {

64
bl/blpwm.c Normal file
Просмотреть файл

@ -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;

Просмотреть файл

@ -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,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) {

Просмотреть файл

@ -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