From d5c0650df4540de1d81262a38f112bff0fbef43d Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 29 Apr 2021 15:29:39 +0100 Subject: [PATCH] Implement a test mode for F7 (v3, Lightning Plus) and AT32F4xx models. --- inc/cdc_acm_protocol.h | 5 +- inc/mcu/stm32/common.h | 15 ++++++ inc/mcu/stm32/f7.h | 11 ---- inc/util.h | 3 ++ scripts/greaseweazle/usb.py | 6 ++- src/Makefile | 3 ++ src/board.c | 51 ++++++++++++++++++ src/floppy.c | 17 ++++++ src/mcu/at32f415/Makefile | 1 + src/mcu/at32f415/board.c | 2 +- src/mcu/at32f415/floppy.c | 40 +------------- src/mcu/at32f415/testmode.c | 64 ++++++++++++++++++++++ src/mcu/stm32f7/Makefile | 1 + src/mcu/stm32f7/board.c | 37 ------------- src/mcu/stm32f7/testmode.c | 61 +++++++++++++++++++++ src/testmode.c | 103 ++++++++++++++++++++++++++++++++++++ 16 files changed, 331 insertions(+), 89 deletions(-) create mode 100644 src/mcu/at32f415/testmode.c create mode 100644 src/mcu/stm32f7/testmode.c create mode 100644 src/testmode.c diff --git a/inc/cdc_acm_protocol.h b/inc/cdc_acm_protocol.h index 9b032aa..e7ea2a9 100644 --- a/inc/cdc_acm_protocol.h +++ b/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 /* diff --git a/inc/mcu/stm32/common.h b/inc/mcu/stm32/common.h index 3b1fd05..63bf0a4 100644 --- a/inc/mcu/stm32/common.h +++ b/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 diff --git a/inc/mcu/stm32/f7.h b/inc/mcu/stm32/f7.h index 8ac28de..c6a90d6 100644 --- a/inc/mcu/stm32/f7.h +++ b/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)) diff --git a/inc/util.h b/inc/util.h index 42cfb20..4f2b2c9 100644 --- a/inc/util.h +++ b/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); diff --git a/scripts/greaseweazle/usb.py b/scripts/greaseweazle/usb.py index 8deb05c..54118bd 100644 --- a/scripts/greaseweazle/usb.py +++ b/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" } diff --git a/src/Makefile b/src/Makefile index 3a036d5..7a726f5 100644 --- a/src/Makefile +++ b/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 diff --git a/src/board.c b/src/board.c index 526ce55..3719b9a 100644 --- a/src/board.c +++ b/src/board.c @@ -9,6 +9,57 @@ * See the file COPYING for more details, or visit . */ +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) { diff --git a/src/floppy.c b/src/floppy.c index 56a9f35..739c6c9 100644 --- a/src/floppy.c +++ b/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; diff --git a/src/mcu/at32f415/Makefile b/src/mcu/at32f415/Makefile index 406391b..f3f997a 100644 --- a/src/mcu/at32f415/Makefile +++ b/src/mcu/at32f415/Makefile @@ -1,5 +1,6 @@ OBJS += stm32.o OBJS += fpec.o +OBJS += testmode.o fpec.c: ln -sf ../stm32f1/$@ $@ diff --git a/src/mcu/at32f415/board.c b/src/mcu/at32f415/board.c index c9d08a3..277e8f9 100644 --- a/src/mcu/at32f415/board.c +++ b/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). */ diff --git a/src/mcu/at32f415/floppy.c b/src/mcu/at32f415/floppy.c index 9981868..12a6d5f 100644 --- a/src/mcu/at32f415/floppy.c +++ b/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); diff --git a/src/mcu/at32f415/testmode.c b/src/mcu/at32f415/testmode.c new file mode 100644 index 0000000..ca2f8a0 --- /dev/null +++ b/src/mcu/at32f415/testmode.c @@ -0,0 +1,64 @@ +/* + * at32f4xx/testmode.c + * + * Written & released by Keir Fraser + * + * This is free and unencumbered software released into the public domain. + * See the file COPYING for more details, or visit . + */ + +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: + */ diff --git a/src/mcu/stm32f7/Makefile b/src/mcu/stm32f7/Makefile index 4ded14d..c767b10 100644 --- a/src/mcu/stm32f7/Makefile +++ b/src/mcu/stm32f7/Makefile @@ -1,2 +1,3 @@ OBJS += stm32.o OBJS += fpec.o +OBJS += testmode.o diff --git a/src/mcu/stm32f7/board.c b/src/mcu/stm32f7/board.c index 5968f5b..56bc080 100644 --- a/src/mcu/stm32f7/board.c +++ b/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 }, diff --git a/src/mcu/stm32f7/testmode.c b/src/mcu/stm32f7/testmode.c new file mode 100644 index 0000000..929f4e6 --- /dev/null +++ b/src/mcu/stm32f7/testmode.c @@ -0,0 +1,61 @@ +/* + * f7/testmode.c + * + * Written & released by Keir Fraser + * + * This is free and unencumbered software released into the public domain. + * See the file COPYING for more details, or visit . + */ + +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: + */ diff --git a/src/testmode.c b/src/testmode.c new file mode 100644 index 0000000..f432325 --- /dev/null +++ b/src/testmode.c @@ -0,0 +1,103 @@ +/* + * testmode.c + * + * Written & released by Keir Fraser + * + * This is free and unencumbered software released into the public domain. + * See the file COPYING for more details, or visit . + */ + +#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: + */