AT32F4: Identify MCU and board at startup, blink a fail code on error.

Insert required delays for F403 clock bringup.
'gw info' now identifies V4 boards by name.
This commit is contained in:
Keir Fraser
2021-05-11 10:02:05 +01:00
parent 5bd5d19718
commit 6f4c89f735
5 changed files with 90 additions and 4 deletions

View File

@@ -10,3 +10,10 @@ extern unsigned int FLASH_PAGE_SIZE;
#define AT32F403A 0x07
#define AT32F407 0x08
extern unsigned int at32f4_series;
void identify_board_config(void);
/* On reset, SYSCLK=HSI at 8MHz. SYSCLK runs at 1MHz. */
void early_fatal(int blinks) __attribute__((noreturn));
#define early_delay_ms(ms) (delay_ticks((ms)*1000))
#define early_delay_us(us) (delay_ticks((us)*1))

View File

@@ -110,6 +110,7 @@ struct board_config {
void identify_board_config(void);
/* On reset, SYSCLK=HSI at 16MHz. SYSCLK runs at 2MHz. */
void early_fatal(int blinks) __attribute__((noreturn));
#define early_delay_ms(ms) (delay_ticks((ms)*2000))
#define early_delay_us(us) (delay_ticks((us)*2))

View File

@@ -17,6 +17,7 @@ from greaseweazle import version
model_id = { 1: { 0: 'F1',
1: 'F1 Plus' },
4: { 0: 'V4' },
7: { 0: 'F7 v1',
1: 'F7 Plus (Ant Goffart, v1)',
2: 'F7 Lightning',

View File

@@ -33,6 +33,68 @@ const static struct board_config _board_config = {
.msel_pins = _msel_pins
};
/* Blink the activity LED to indicate fatal error. */
void early_fatal(int blinks)
{
int i;
rcc->apb2enr |= RCC_APB2ENR_IOPBEN;
delay_ticks(10);
gpio_configure_pin(gpio_led, pin_led, GPO_pushpull(IOSPD_LOW, HIGH));
for (;;) {
for (i = 0; i < blinks; i++) {
gpio_write_pin(gpiob, 13, LOW);
early_delay_ms(150);
gpio_write_pin(gpiob, 13, HIGH);
early_delay_ms(150);
}
early_delay_ms(2000);
}
}
void identify_board_config(void)
{
uint16_t low, high;
uint8_t id = 0;
int i;
rcc->apb2enr |= RCC_APB2ENR_IOPCEN;
early_delay_us(2);
/* Pull PC[15:13] low, and check which are tied HIGH. */
for (i = 0; i < 3; i++)
gpio_configure_pin(gpioc, 13+i, GPI_pull_down);
early_delay_us(10);
high = (gpioc->idr >> 13) & 7;
/* Pull PC[15:13] high, and check which are tied LOW. */
for (i = 0; i < 3; i++)
gpio_configure_pin(gpioc, 13+i, GPI_pull_up);
early_delay_us(10);
low = (~gpioc->idr >> 13) & 7;
/* Each PCx pin defines a 'trit': 0=float, 1=low, 2=high.
* We build a 3^3 ID space from the resulting three-trit ID. */
for (i = 0; i < 3; i++) {
id *= 3;
switch ((high>>1&2) | (low>>2&1)) {
case 0: break; /* float = 0 */
case 1: id += 1; break; /* LOW = 1 */
case 2: id += 2; break; /* HIGH = 2 */
case 3: early_fatal(1); /* cannot be tied HIGH *and* LOW! */
}
high <<= 1;
low <<= 1;
}
/* Panic if the ID is unrecognised. */
if (id != 0)
early_fatal(2);
/* Single static config. */
gw_info.hw_submodel = id;
board_config = &_board_config;
}
static void mcu_board_init(void)
{
gpio_pull_up_pins(gpioa, 0x0101); /* PA0,8 */
@@ -44,9 +106,6 @@ static void mcu_board_init(void)
/* /RDY input line is externally pulled up. */
gpio_configure_pin(gpiob, 15, GPI_floating);
/* Single static config. */
board_config = &_board_config;
}
/*

View File

@@ -24,6 +24,9 @@ static void clock_init(void)
while (!(rcc->cr & RCC_CR_HSERDY))
cpu_relax();
if (at32f4_series == AT32F403)
delay_ms(2);
/* PLLs, scalers, muxes. */
rcc->cfgr = (RCC_CFGR_PLLMUL(9) | /* PLL = 9*8MHz = 72MHz */
RCC_CFGR_PLLSRC_PREDIV1 |
@@ -35,11 +38,17 @@ static void clock_init(void)
while (!(rcc->cr & RCC_CR_PLLRDY))
cpu_relax();
if (at32f4_series == AT32F403)
delay_us(200);
/* Switch to the externally-driven PLL for system clock. */
rcc->cfgr |= RCC_CFGR_SW_PLL;
while ((rcc->cfgr & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL)
cpu_relax();
if (at32f4_series == AT32F403)
delay_us(200);
/* Internal oscillator no longer needed. */
rcc->cr &= ~RCC_CR_HSION;
}
@@ -67,13 +76,22 @@ static void identify_mcu(void)
unsigned int flash_kb = *(uint16_t *)0x1ffff7e0;
if (flash_kb <= 128)
FLASH_PAGE_SIZE = 1024;
at32f4_series = *(uint8_t *)0x1ffff7f3; /* UID[95:88] */
switch (at32f4_series) {
case AT32F403:
case AT32F415:
break;
default:
early_fatal(4);
}
}
void stm32_init(void)
{
identify_mcu();
cortex_init();
identify_mcu();
identify_board_config();
clock_init();
peripheral_init();
cpu_sync();