Merge pull request #17 from microsoft/low_power_bl

run bootloader without PLL (low power)

Main changes:
* uart_start_rx/tx -> uart_rx/tx - blocking
* uart is used to detect initial low pulse (break)
This commit is contained in:
Michał Moskal 2021-03-16 05:08:33 +01:00 коммит произвёл GitHub
Родитель cbae1082d7 0941a5caa5
Коммит bf65d750c6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 185 добавлений и 125 удалений

58
bl/bl.h
Просмотреть файл

@ -14,19 +14,28 @@
#include "jd_physical.h"
#include "jd_control.h"
#define CPU_MHZ PLL_MHZ
#ifndef QUICK_LOG
#define QUICK_LOG 0
#endif
#define CPU_MHZ HSI_MHZ
typedef void (*cb_t)(void);
typedef struct ctx {
uint8_t jd_state;
uint8_t uart_mode;
uint8_t tx_full, rx_full;
uint8_t chunk_no;
uint8_t bl_ad_queued;
uint8_t id_counter;
uint8_t low_detected;
#if QUICK_LOG == 1
volatile uint32_t *log_reg;
uint32_t log_p0;
uint32_t log_p1;
#endif
// these three fields are sent directly from here, so don't move them
uint32_t session_id;
@ -36,12 +45,8 @@ typedef struct ctx {
uint32_t randomseed;
uint32_t service_class_bl;
uint8_t *uart_data;
uint32_t uart_bytesleft;
// timestamps
uint32_t now;
uint32_t low_start;
uint32_t tx_start_time;
uint32_t led_off_time;
uint32_t next_announce;
@ -55,24 +60,45 @@ typedef struct ctx {
uint8_t pagedata[FLASH_PAGE_SIZE];
} ctx_t;
#if QUICK_LOG == 1
#define LOG0_ON() *ctx->log_reg = ctx->log_p0
#define LOG1_ON() *ctx->log_reg = ctx->log_p1
#define LOG0_OFF() *ctx->log_reg = ctx->log_p0 << 16
#define LOG1_OFF() *ctx->log_reg = ctx->log_p1 << 16
#else
#define LOG0_ON() ((void)0)
#define LOG1_ON() ((void)0)
#define LOG0_OFF() ((void)0)
#define LOG1_OFF() ((void)0)
#endif
#define LOG0_PULSE() \
do { \
LOG0_ON(); \
LOG0_OFF(); \
} while (0)
#define LOG1_PULSE() \
do { \
LOG1_ON(); \
LOG1_OFF(); \
} while (0)
extern ctx_t ctx_;
void jd_process(ctx_t *ctx);
int jd_process(ctx_t *ctx);
void jd_prep_send(ctx_t *ctx);
void tim_init(void);
uint32_t tim_get_micros(void);
#define UART_MODE_NONE 0
#define UART_MODE_RX 1
#define UART_MODE_TX 2
void uart_init(ctx_t *ctx);
int uart_start_tx(ctx_t *ctx, const void *data, uint32_t numbytes);
void uart_start_rx(ctx_t *ctx, void *data, uint32_t maxbytes);
#define UART_END_TX 1
#define UART_END_RX 2
int uart_process(ctx_t *ctx);
int uart_tx(ctx_t *ctx, const void *data, uint32_t numbytes);
#define RX_LINE_BUSY 1
#define RX_LINE_IDLE 2
#define RX_RECEPTION_OK 3
int uart_rx(ctx_t *ctx, void *data, uint32_t maxbytes);
void uart_post_rx(ctx_t *ctx);
uint16_t crc16(const void *data, uint32_t size);

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

@ -71,53 +71,49 @@ void jd_prep_send(ctx_t *ctx) {
ctx->tx_full = 1;
}
void jd_process(ctx_t *ctx) {
uint32_t now = ctx->now;
int jd_process(ctx_t *ctx) {
int rx_status = uart_rx(ctx, &ctx->rxBuffer, sizeof(ctx->rxBuffer));
if (ctx->uart_mode == UART_MODE_NONE) {
if (pin_get(UART_PIN)) {
if (!ctx->rx_full && ctx->low_start && 9 <= now - ctx->low_start &&
now - ctx->low_start <= 50) {
ctx->rx_full = 1;
uart_start_rx(ctx, &ctx->rxBuffer, sizeof(ctx->rxBuffer));
} else if (ctx->tx_full == 1 && !ctx->tx_start_time) {
ctx->tx_start_time = now + 40 + (random(ctx) & 127);
} else if (ctx->tx_start_time && ctx->tx_start_time <= now) {
ctx->tx_start_time = 0;
if (uart_start_tx(ctx, &ctx->txBuffer, JD_FRAME_SIZE(&ctx->txBuffer)) == 0) {
// sent OK
ctx->tx_full = 2;
} else {
// not sent because line was low
// next loop iteration will pick it up as RX
}
}
ctx->low_start = 0;
} else {
if (!ctx->low_start)
ctx->low_start = now;
ctx->tx_start_time = 0;
if (rx_status == RX_RECEPTION_OK) {
if (valid_frame(ctx, &ctx->rxBuffer)) {
LOG0_PULSE();
ctx->rx_full = 1;
}
LOG0_PULSE();
uart_post_rx(ctx);
ctx->tx_start_time = 0;
return 1;
}
// only process frame when uart isn't busy
if (!ctx->tx_full && ctx->rx_full == 2) {
process_frame(ctx, &ctx->rxBuffer);
ctx->rx_full = 0;
}
} else {
switch (uart_process(ctx)) {
case UART_END_RX:
if (valid_frame(ctx, &ctx->rxBuffer))
ctx->rx_full = 2;
else
ctx->rx_full = 0;
break;
case UART_END_TX:
if (rx_status == RX_LINE_BUSY) {
LOG0_PULSE();
ctx->tx_start_time = 0;
return 1;
}
if (ctx->tx_full == 1 && !ctx->tx_start_time) {
ctx->tx_start_time = ctx->now + 40 + (random(ctx) & 127);
} else if (ctx->tx_start_time && ctx->tx_start_time <= ctx->now) {
ctx->tx_start_time = 0;
if (uart_tx(ctx, &ctx->txBuffer, JD_FRAME_SIZE(&ctx->txBuffer)) == 0) {
// sent OK
ctx->tx_full = 0;
break;
return 1;
} else {
// not sent because line was low
// next loop iteration will pick it up as RX
return 1;
}
}
identify(ctx);
bl_process(ctx);
// only process frame when uart isn't busy
if (!ctx->tx_full && ctx->rx_full) {
process_frame(ctx, &ctx->rxBuffer);
ctx->rx_full = 0;
return 1;
} else {
identify(ctx);
bl_process(ctx);
return 0;
}
}

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

@ -13,6 +13,10 @@ ctx_t ctx_;
void led_init(void) {
pin_setup_output(PIN_LED);
pin_setup_output(PIN_LED_GND);
#if QUICK_LOG == 1
pin_setup_output(PIN_X0);
pin_setup_output(PIN_X1);
#endif
pin_set(PIN_LED_GND, 0);
}
@ -45,7 +49,7 @@ uint32_t bl_adc_random_seed(void);
int main(void) {
__disable_irq();
clk_setup_pll();
// clk_setup_pll();
#if USART_IDX == 1
#ifdef STM32G0
@ -110,7 +114,7 @@ int main(void) {
bool app_valid = bl_fixup_app_handlers(ctx);
#if 1
#if 0
if (app_valid)
ctx->app_start_time = 512 * 1024;
else
@ -122,9 +126,10 @@ int main(void) {
while (1) {
uint32_t now = ctx->now = tim_get_micros();
// pin_pulse(PIN_LOG0, 1);
LOG1_PULSE();
jd_process(ctx);
if (jd_process(ctx))
continue;
if (now >= ctx->next_announce && !ctx->tx_full) {
memcpy(ctx->txBuffer.data, announce_data, sizeof(announce_data));
@ -134,13 +139,14 @@ int main(void) {
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;
}
} else {
led_set((now & 0xff) < ((now & 0x80000) ? 0x4 : 0xf));
led_set((now & 0x3f) < ((now & 0x80000) ? 0x1 : 0x4));
}
}
}

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

@ -40,29 +40,7 @@ static void uartDoesntOwnPin(void) {
LL_GPIO_SetPinMode(PIN_PORT, PIN_PIN, LL_GPIO_MODE_INPUT);
}
void uart_init(ctx_t *ctx) {
LL_GPIO_SetPinPull(PIN_PORT, PIN_PIN, LL_GPIO_PULL_UP);
LL_GPIO_SetPinSpeed(PIN_PORT, PIN_PIN, LL_GPIO_SPEED_FREQ_HIGH);
uartDoesntOwnPin();
USARTx->CR1 = LL_USART_DATAWIDTH_8B | LL_USART_PARITY_NONE | LL_USART_OVERSAMPLING_16 |
LL_USART_DIRECTION_TX;
USARTx->BRR = CPU_MHZ; // ->1MHz
#ifdef LL_USART_PRESCALER_DIV1
LL_USART_SetPrescaler(USARTx, LL_USART_PRESCALER_DIV1);
#endif
LL_USART_ConfigHalfDuplexMode(USARTx);
}
void uart_disable(ctx_t *ctx) {
LL_USART_Disable(USARTx);
uartDoesntOwnPin();
ctx->uart_mode = UART_MODE_NONE;
}
void uart_start_rx(ctx_t *ctx, void *data, uint32_t maxbytes) {
static void rx_setup(void) {
uartOwnsPin();
LL_USART_DisableDirectionTx(USARTx);
LL_USART_EnableDirectionRx(USARTx);
@ -70,53 +48,92 @@ void uart_start_rx(ctx_t *ctx, void *data, uint32_t maxbytes) {
LL_USART_Enable(USARTx);
while (!(LL_USART_IsActiveFlag_REACK(USARTx)))
;
ctx->uart_data = data;
ctx->uart_bytesleft = maxbytes;
ctx->rx_timeout = ctx->now + maxbytes * 15;
ctx->uart_mode = UART_MODE_RX;
}
int uart_process(ctx_t *ctx) {
void uart_init(ctx_t *ctx) {
#if QUICK_LOG == 1
ctx->log_reg = (volatile uint32_t *)&PORT(PIN_X0)->BSRR;
ctx->log_p0 = PIN(PIN_X0);
ctx->log_p1 = PIN(PIN_X1);
#endif
LL_GPIO_SetPinPull(PIN_PORT, PIN_PIN, LL_GPIO_PULL_UP);
LL_GPIO_SetPinSpeed(PIN_PORT, PIN_PIN, LL_GPIO_SPEED_FREQ_HIGH);
uartDoesntOwnPin();
USARTx->CR1 = LL_USART_DATAWIDTH_8B | LL_USART_PARITY_NONE | LL_USART_OVERSAMPLING_8 |
LL_USART_DIRECTION_TX;
USARTx->BRR = CPU_MHZ * 2; // ->1MHz
#ifdef LL_USART_PRESCALER_DIV1
LL_USART_SetPrescaler(USARTx, LL_USART_PRESCALER_DIV1);
#endif
LL_USART_ConfigHalfDuplexMode(USARTx);
rx_setup();
}
void uart_disable(ctx_t *ctx) {
LL_USART_Disable(USARTx);
uartDoesntOwnPin();
}
int uart_rx(ctx_t *ctx, void *data, uint32_t maxbytes) {
uint32_t isr = USARTx->ISR;
if (ctx->uart_mode == UART_MODE_RX) {
if (isr & USART_ISR_FE || ctx->now > ctx->rx_timeout) {
uart_disable(ctx);
return UART_END_RX;
} else if (isr & USART_ISR_RXNE) {
uint8_t c = USARTx->RDR;
if (ctx->uart_bytesleft) {
ctx->uart_bytesleft--;
*ctx->uart_data++ = c;
}
}
} else if (ctx->uart_mode == UART_MODE_TX) {
if (isr & USART_ISR_TXE) {
if (ctx->uart_bytesleft) {
ctx->uart_bytesleft--;
USARTx->TDR = *ctx->uart_data++;
} else {
if (!LL_USART_IsActiveFlag_TC(USARTx))
return 0;
LL_USART_Disable(USARTx);
LL_GPIO_SetPinMode(PIN_PORT, PIN_PIN, LL_GPIO_MODE_OUTPUT);
LL_GPIO_ResetOutputPin(PIN_PORT, PIN_PIN);
target_wait_us(12);
LL_GPIO_SetOutputPin(PIN_PORT, PIN_PIN);
uart_disable(ctx);
return UART_END_TX;
}
if (ctx->low_detected || !(isr & USART_ISR_FE)) {
if (isr & USART_ISR_BUSY)
return RX_LINE_BUSY;
return RX_LINE_IDLE;
}
ctx->low_detected = 0;
// wait for BUSY to be cleared - ie the low pulse has ended
while (isr & USART_ISR_BUSY)
isr = USARTx->ISR;
uart_post_rx(ctx); // clear errors
uint8_t *dp = data;
int32_t delaycnt = -10 * CPU_MHZ; // allow a bit more delay at the start
LOG0_PULSE();
while (maxbytes > 0) {
isr = USARTx->ISR;
if (isr & USART_ISR_RXNE) {
*dp++ = USARTx->RDR;
maxbytes--;
delaycnt = 0;
} else if (isr & USART_ISR_FE || delaycnt > 4 * CPU_MHZ) {
break;
} else {
delaycnt++;
}
}
return 0;
LOG0_PULSE();
return RX_RECEPTION_OK;
}
int uart_start_tx(ctx_t *ctx, const void *data, uint32_t numbytes) {
void uart_post_rx(ctx_t *ctx) {
(void)USARTx->RDR;
USARTx->ICR = USART_ISR_FE | USART_ISR_NE | USART_ISR_ORE;
(void)USARTx->RDR;
}
int uart_tx(ctx_t *ctx, const void *data, uint32_t numbytes) {
LL_USART_Disable(USARTx);
uartDoesntOwnPin();
LL_GPIO_ResetOutputPin(PIN_PORT, PIN_PIN);
gpio_probe_and_set(PIN_PORT, PIN_PIN, PIN_MODER | PIN_PORT->MODER);
if (!(PIN_PORT->MODER & PIN_MODER)) {
ctx->low_detected = 1;
rx_setup();
return -1;
}
target_wait_us(11);
LL_GPIO_SetOutputPin(PIN_PORT, PIN_PIN);
@ -128,11 +145,26 @@ int uart_start_tx(ctx_t *ctx, const void *data, uint32_t numbytes) {
while (!(LL_USART_IsActiveFlag_TEACK(USARTx)))
;
ctx->uart_data = (void *)data;
ctx->uart_bytesleft = numbytes;
ctx->uart_mode = UART_MODE_TX;
const uint8_t *sp = data;
target_wait_us(40);
while (numbytes > 0) {
uint32_t isr = USARTx->ISR;
if (isr & USART_ISR_TXE) {
numbytes--;
USARTx->TDR = *sp++;
}
}
while (!LL_USART_IsActiveFlag_TC(USARTx))
;
LL_USART_Disable(USARTx);
LL_GPIO_SetPinMode(PIN_PORT, PIN_PIN, LL_GPIO_MODE_OUTPUT);
LL_GPIO_ResetOutputPin(PIN_PORT, PIN_PIN);
target_wait_us(12);
LL_GPIO_SetOutputPin(PIN_PORT, PIN_PIN);
rx_setup();
return 0;
}