mirror of
https://github.com/keirf/greaseweazle-firmware.git
synced 2025-10-31 11:06:44 -07:00
Implement a test mode for F7 (v3, Lightning Plus) and AT32F4xx models.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
src/board.c
51
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
src/floppy.c
17
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,5 +1,6 @@
|
||||
OBJS += stm32.o
|
||||
OBJS += fpec.o
|
||||
OBJS += testmode.o
|
||||
|
||||
fpec.c:
|
||||
ln -sf ../stm32f1/$@ $@
|
||||
|
||||
@@ -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). */
|
||||
|
||||
@@ -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
src/mcu/at32f415/testmode.c
Normal file
64
src/mcu/at32f415/testmode.c
Normal 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:
|
||||
*/
|
||||
@@ -1,2 +1,3 @@
|
||||
OBJS += stm32.o
|
||||
OBJS += fpec.o
|
||||
OBJS += testmode.o
|
||||
|
||||
@@ -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
src/mcu/stm32f7/testmode.c
Normal file
61
src/mcu/stm32f7/testmode.c
Normal 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
103
src/testmode.c
Normal 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:
|
||||
*/
|
||||
Reference in New Issue
Block a user