瀏覽代碼

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.

Keir Fraser 3 年之前
父節點
當前提交
6f4c89f735
共有 5 個文件被更改,包括 90 次插入4 次删除
  1. 7 0
      inc/mcu/at32/f4.h
  2. 1 0
      inc/mcu/stm32/f7.h
  3. 1 0
      scripts/greaseweazle/tools/info.py
  4. 62 3
      src/mcu/at32f4/board.c
  5. 19 1
      src/mcu/at32f4/stm32.c

+ 7 - 0
inc/mcu/at32/f4.h

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

+ 1 - 0
inc/mcu/stm32/f7.h

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

+ 1 - 0
scripts/greaseweazle/tools/info.py

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

+ 62 - 3
src/mcu/at32f4/board.c

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

+ 19 - 1
src/mcu/at32f4/stm32.c

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