瀏覽代碼

Implement a test mode for F7 (v3, Lightning Plus) and AT32F4xx models.

Keir Fraser 3 年之前
父節點
當前提交
d5c0650df4

+ 4 - 1
inc/cdc_acm_protocol.h

@@ -70,7 +70,10 @@
 /* CMD_GET_PIN, length=3, pin#. Successful ACK is followed by pin-level byte
  * (1=High, 0=Low). Unsupported pin returns ACK_BAD_PIN and no pin level. */
 #define CMD_GET_PIN        20
-#define CMD_MAX            20
+/* CMD_TEST_MODE, length=10, 0x6e504b4e, 0x382910d3 
+ * Responds ACK_OKAY and then switches to board test mode until reset. */
+#define CMD_TEST_MODE      21
+#define CMD_MAX            21
 
 
 /*

+ 15 - 0
inc/mcu/stm32/common.h

@@ -92,6 +92,21 @@ void fpec_init(void);
 void fpec_page_erase(uint32_t flash_address);
 void fpec_write(const void *data, unsigned int size, uint32_t flash_address);
 
+/* Pin mappings */
+enum { _A = 0, _B, _C, _D, _E, _F, _G, _H, _I };
+enum { _OD = 0, _PP };
+struct pin_mapping {
+    uint8_t pin_id;
+    uint8_t gpio_bank;
+    uint8_t gpio_pin;
+    bool_t  push_pull;
+};
+GPIO gpio_from_id(uint8_t id);
+uint8_t write_mapped_pin(
+    const struct pin_mapping *map, int pin_id, bool_t level);
+uint8_t read_mapped_pin(
+    const struct pin_mapping *map, int pin_id, bool_t *p_level);
+
 /*
  * Local variables:
  * mode: C

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

@@ -99,13 +99,6 @@ enum {
     F7SM_v3,
 };
 
-struct pin_mapping {
-    uint8_t pin_id;
-    uint8_t gpio_bank;
-    uint8_t gpio_pin;
-    bool_t  push_pull;
-};
-
 struct board_config {
     uint8_t hse_mhz;
     bool_t hse_byp;
@@ -118,10 +111,6 @@ struct board_config {
 extern const struct board_config *board_config;
 void identify_board_config(void);
 
-GPIO gpio_from_id(uint8_t id);
-uint8_t write_mapped_pin(
-    const struct pin_mapping *map, int pin_id, bool_t level);
-
 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))

+ 3 - 0
inc/util.h

@@ -103,6 +103,9 @@ static inline int printk(const char *format, ...) { return 0; }
 void floppy_init(void);
 void floppy_process(void);
 
+/* Test mode */
+void testmode_process(void);
+
 /* CRC-CCITT */
 uint16_t crc16_ccitt(const void *buf, size_t len, uint16_t crc);
 

+ 5 - 1
scripts/greaseweazle/usb.py

@@ -42,6 +42,8 @@ class Cmd:
     EraseFlux       = 17
     SourceBytes     = 18
     SinkBytes       = 19
+    GetPin          = 20
+    TestMode        = 21
     str = {
         GetInfo: "GetInfo",
         Update: "Update",
@@ -62,7 +64,9 @@ class Cmd:
         Reset: "Reset",
         EraseFlux: "EraseFlux",
         SourceBytes: "SourceBytes",
-        SinkBytes: "SinkBytes"
+        SinkBytes: "SinkBytes",
+        GetPin: "GetPin",
+        TestMode: "TestMode"
     }
 
 

+ 3 - 0
src/Makefile

@@ -10,6 +10,9 @@ OBJS += timer.o
 OBJS += util.o
 OBJS += floppy.o
 
+OBJS-$(stm32f7)  += testmode.o
+OBJS-$(at32f415) += testmode.o
+
 OBJS-$(debug) += console.o
 
 SUBDIRS += mcu usb

+ 51 - 0
src/board.c

@@ -9,6 +9,57 @@
  * See the file COPYING for more details, or visit <http://unlicense.org>.
  */
 
+GPIO gpio_from_id(uint8_t id)
+{
+    switch (id) {
+    case _A: return gpioa;
+    case _B: return gpiob;
+    case _C: return gpioc;
+    case _D: return gpiod;
+    case _E: return gpioe;
+    case _F: return gpiof;
+    case _G: return gpiog;
+#if MCU == STM32F7
+    case _H: return gpioh;
+    case _I: return gpioi;
+#endif
+    }
+    ASSERT(0);
+    return NULL;
+}
+
+uint8_t write_mapped_pin(
+    const struct pin_mapping *map, int pin_id, bool_t level)
+{
+    const struct pin_mapping *pin;
+
+    for (pin = map; pin->pin_id != 0; pin++)
+        if (pin->pin_id == pin_id)
+            goto found;
+
+    return ACK_BAD_PIN;
+
+found:
+    gpio_write_pin(gpio_from_id(pin->gpio_bank), pin->gpio_pin, level);
+    return ACK_OKAY;
+}
+
+uint8_t read_mapped_pin(
+    const struct pin_mapping *map, int pin_id, bool_t *p_level)
+{
+    const struct pin_mapping *pin;
+
+    for (pin = map; pin->pin_id != 0; pin++)
+        if (pin->pin_id == pin_id)
+            goto found;
+
+    return ACK_BAD_PIN;
+
+found:
+    *p_level = gpio_read_pin(gpio_from_id(pin->gpio_bank), pin->gpio_pin);
+    return ACK_OKAY;
+}
+
 /* Pull up currently unused and possibly-floating pins. */
 static void gpio_pull_up_pins(GPIO gpio, uint16_t mask)
 {

+ 17 - 0
src/floppy.c

@@ -117,6 +117,7 @@ static enum {
     ST_source_bytes,
     ST_sink_bytes,
     ST_update_bootloader,
+    ST_testmode,
 } floppy_state = ST_inactive;
 
 static uint32_t u_cons, u_prod;
@@ -1336,6 +1337,15 @@ static void process_command(void)
         }
         break;
     }
+    case CMD_TEST_MODE: {
+        uint32_t sig1 = *(uint32_t *)&u_buf[2];
+        uint32_t sig2 = *(uint32_t *)&u_buf[6];
+        if (len != 10) goto bad_command;
+        if (sig1 != 0x6e504b4e) goto bad_command;
+        if (sig2 != 0x382910d3) goto bad_command;
+        floppy_state = ST_testmode;
+        break;
+    }
 #endif
     default:
         goto bad_command;
@@ -1429,6 +1439,13 @@ void floppy_process(void)
         update_continue();
         break;
 
+#if MCU != STM32F1
+    case ST_testmode:
+        watchdog.armed = FALSE;
+        testmode_process();
+        break;
+#endif
+
     default:
         break;
 

+ 1 - 0
src/mcu/at32f415/Makefile

@@ -1,5 +1,6 @@
 OBJS += stm32.o
 OBJS += fpec.o
+OBJS += testmode.o
 
 fpec.c:
 	ln -sf ../stm32f1/$@ $@

+ 1 - 1
src/mcu/at32f415/board.c

@@ -15,7 +15,7 @@
 static void mcu_board_init(void)
 {
     gpio_pull_up_pins(gpioa, 0x0101); /* PA0,8 */
-    gpio_pull_up_pins(gpiob, 0xdc03); /* PB0-1,10-12,14-15 */
+    gpio_pull_up_pins(gpiob, 0x1803); /* PB0-1,11-12 */
     gpio_pull_up_pins(gpioc, 0xffff); /* PC0-15 */
 
     /* Flippy TRK0_DISABLE output: Set inactive (LOW). */

+ 2 - 38
src/mcu/at32f415/floppy.c

@@ -51,15 +51,7 @@ typedef uint16_t timcnt_t;
 #define irq_index 40
 void IRQ_40(void) __attribute__((alias("IRQ_INDEX_changed"))); /* EXTI15_10 */
 
-enum { _A = 0, _B, _C, _D, _E, _F, _G };
-
-struct pin_mapping {
-    uint8_t pin_id;
-    uint8_t gpio_bank;
-    uint8_t gpio_pin;
-};
-
-const static struct pin_mapping msel_pins[] = {
+const struct pin_mapping msel_pins[] = {
     { 10, _A,  3 },
     { 12, _B,  9 },
     { 14, _A,  4 },
@@ -67,41 +59,13 @@ const static struct pin_mapping msel_pins[] = {
     {  0,  0,  0 }
 };
 
-const static struct pin_mapping user_pins[] = {
+const struct pin_mapping user_pins[] = {
     {  2, _A,  6 },
     {  4, _A,  5 },
     {  6, _A,  7 },
     {  0,  0,  0 }
 };
 
-GPIO gpio_from_id(uint8_t id)
-{
-    switch (id) {
-    case _A: return gpioa;
-    case _B: return gpiob;
-    case _C: return gpioc;
-    }
-    ASSERT(0);
-    return NULL;
-}
-
-uint8_t write_mapped_pin(
-    const struct pin_mapping *map, int pin_id, bool_t level)
-{
-    const struct pin_mapping *pin;
-
-    for (pin = map; pin->pin_id != 0; pin++)
-        if (pin->pin_id == pin_id)
-            goto found;
-
-    return ACK_BAD_PIN;
-
-found:
-    gpio_write_pin(gpio_from_id(pin->gpio_bank), pin->gpio_pin, level);
-    return ACK_OKAY;
-}
-
-
 /* We sometimes cast u_buf to uint32_t[], hence the alignment constraint. */
 #define U_BUF_SZ 16384
 static uint8_t u_buf[U_BUF_SZ] aligned(4);

+ 64 - 0
src/mcu/at32f415/testmode.c

@@ -0,0 +1,64 @@
+/*
+ * at32f4xx/testmode.c
+ * 
+ * Written & released by Keir Fraser <keir.xen@gmail.com>
+ * 
+ * This is free and unencumbered software released into the public domain.
+ * See the file COPYING for more details, or visit <http://unlicense.org>.
+ */
+
+const static struct pin_mapping in_pins[] = {
+    {  8, _B, 10 },
+    { 26, _B,  4 },
+    { 28, _B,  3 },
+    { 30, _A, 15 },
+    { 34, _B, 15 },
+    {  0,  0,  0 }
+};
+
+const static struct pin_mapping out_pins[] = {
+    { 18, _B,  8 },
+    { 20, _B,  6 },
+    { 22, _A,  2 },
+    { 24, _B,  7 },
+    { 32, _B,  5 },
+    { 33, _B, 14 },
+    {  0,  0,  0 }
+};
+
+extern const struct pin_mapping msel_pins[];
+extern const struct pin_mapping user_pins[];
+
+void testmode_set_pin(unsigned int pin, bool_t level)
+{
+    int rc;
+    rc = write_mapped_pin(out_pins, pin, level);
+    if (rc != ACK_OKAY)
+        rc = write_mapped_pin(msel_pins, pin, level);
+    if (rc != ACK_OKAY)
+        rc = write_mapped_pin(user_pins, pin, level);
+}
+
+bool_t testmode_get_pin(unsigned int pin)
+{
+    bool_t level;
+    int rc = read_mapped_pin(in_pins, pin, &level);
+    if (rc != ACK_OKAY)
+        level = FALSE;
+    return level;
+}
+
+void testmode_get_option_bytes(void *buf)
+{
+    memcpy(buf, (void *)0x1ffff800, 16);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "Linux"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

+ 1 - 0
src/mcu/stm32f7/Makefile

@@ -1,2 +1,3 @@
 OBJS += stm32.o
 OBJS += fpec.o
+OBJS += testmode.o

+ 0 - 37
src/mcu/stm32f7/board.c

@@ -12,43 +12,6 @@
 #define gpio_led gpiob
 #define pin_led 13
 
-enum { _A = 0, _B, _C, _D, _E, _F, _G, _H, _I };
-enum { _OD = 0, _PP };
-
-GPIO gpio_from_id(uint8_t id)
-{
-    switch (id) {
-    case _A: return gpioa;
-    case _B: return gpiob;
-    case _C: return gpioc;
-    case _D: return gpiod;
-    case _E: return gpioe;
-    case _F: return gpiof;
-    case _G: return gpiog;
-    case _H: return gpioh;
-    case _I: return gpioi;
-    }
-    ASSERT(0);
-    return NULL;
-}
-
-uint8_t write_mapped_pin(
-    const struct pin_mapping *map, int pin_id, bool_t level)
-{
-    const struct pin_mapping *pin;
-
-    for (pin = map; pin->pin_id != 0; pin++)
-        if (pin->pin_id == pin_id)
-            goto found;
-
-    return ACK_BAD_PIN;
-
-found:
-    gpio_write_pin(gpio_from_id(pin->gpio_bank), pin->gpio_pin, level);
-    return ACK_OKAY;
-}
-
-
 const static struct pin_mapping _msel_pins_std[] = {
     { 10, _B,  1 },
     { 12, _B,  0 },

+ 61 - 0
src/mcu/stm32f7/testmode.c

@@ -0,0 +1,61 @@
+/*
+ * f7/testmode.c
+ * 
+ * Written & released by Keir Fraser <keir.xen@gmail.com>
+ * 
+ * This is free and unencumbered software released into the public domain.
+ * See the file COPYING for more details, or visit <http://unlicense.org>.
+ */
+
+const static struct pin_mapping in_pins[] = {
+    {  8, _B,  2 },
+    { 26, _A,  3 },
+    { 28, _A,  1 },
+    { 30, _A,  0 },
+    { 34, _C,  2 },
+    {  0,  0,  0 }
+};
+
+const static struct pin_mapping out_pins[] = {
+    { 18, _C,  4 },
+    { 20, _A,  7 },
+    { 22, _A,  2 },
+    { 24, _A,  6 },
+    { 32, _C,  3 },
+    { 33, _C,  1 },
+    {  0,  0,  0 }
+};
+
+void testmode_set_pin(unsigned int pin, bool_t level)
+{
+    int rc;
+    rc = write_mapped_pin(out_pins, pin, level);
+    if (rc != ACK_OKAY)
+        rc = write_mapped_pin(board_config->msel_pins, pin, level);
+    if (rc != ACK_OKAY)
+        rc = write_mapped_pin(board_config->user_pins, pin, level);
+}
+
+bool_t testmode_get_pin(unsigned int pin)
+{
+    bool_t level;
+    int rc = read_mapped_pin(in_pins, pin, &level);
+    if (rc != ACK_OKAY)
+        level = FALSE;
+    return level;
+}
+
+void testmode_get_option_bytes(void *buf)
+{
+    memcpy(buf, (void *)0x1fff0000, 32);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "Linux"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

+ 103 - 0
src/testmode.c

@@ -0,0 +1,103 @@
+/*
+ * testmode.c
+ * 
+ * Written & released by Keir Fraser <keir.xen@gmail.com>
+ * 
+ * This is free and unencumbered software released into the public domain.
+ * See the file COPYING for more details, or visit <http://unlicense.org>.
+ */
+
+#define CMD_option_bytes 0
+#define CMD_pins         1
+#define CMD_led          2
+
+struct cmd {
+    uint32_t cmd;
+    union {
+        uint8_t pins[64/8];
+        uint32_t x[28/4];
+    } u;
+};
+
+struct rsp {
+    union {
+        uint8_t opt[32];
+        uint8_t pins[64/8];
+        uint32_t x[32/4];
+    } u;
+};
+
+#define TEST_BIT(p,n) (!!((p)[(n)/8] & (1<<((n)&7))))
+#define SET_BIT(p,n) ((p)[(n)/8] |= (1<<((n)&7)))
+
+void testmode_set_pin(unsigned int pin, bool_t level);
+bool_t testmode_get_pin(unsigned int pin);
+void testmode_get_option_bytes(void *buf);
+
+static void set_pins(uint8_t *pins)
+{
+    int i;
+    bool_t level;
+
+    for (i = 0; i <= 34; i++) {
+        level = TEST_BIT(pins, i);
+        testmode_set_pin(i, level);
+    }
+}
+
+static void get_pins(uint8_t *pins)
+{
+    int i;
+    bool_t level;
+
+    for (i = 0; i <= 34; i++) {
+        level = testmode_get_pin(i);
+        if (level)
+            SET_BIT(pins, i);
+    }
+}
+
+void testmode_process(void)
+{
+    int len = ep_rx_ready(EP_RX);
+    struct cmd cmd;
+    struct rsp rsp;
+
+    if (len < 0)
+        return;
+
+    len = min_t(int, len, 32);
+    usb_read(EP_RX, &cmd, len);
+    if (len < 32)
+        return;
+
+    memset(&rsp, 0, 32);
+
+    switch (cmd.cmd) {
+    case CMD_option_bytes: {
+        testmode_get_option_bytes(rsp.u.opt);
+        break;
+    }
+    case CMD_pins: {
+        set_pins(cmd.u.pins);
+        get_pins(rsp.u.pins);
+        break;
+    }
+    case CMD_led: {
+        act_led(!!cmd.u.pins[0]);
+        break;
+    }
+    }
+
+    usb_write(EP_TX, &rsp, 32);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "Linux"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */