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

This commit is contained in:
Keir Fraser
2021-04-29 15:29:39 +01:00
parent fddd11bce0
commit d5c0650df4
16 changed files with 331 additions and 89 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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"
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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). */

View File

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

View File

@@ -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:
*/

View File

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

View File

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

View File

@@ -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
src/testmode.c Normal file
View File

@@ -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:
*/