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:
Коммит
bf65d750c6
58
bl/bl.h
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);
|
||||
|
||||
|
|
80
bl/bljd.c
80
bl/bljd.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
16
bl/blmain.c
16
bl/blmain.c
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
156
bl/bluart.c
156
bl/bluart.c
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче