From bd68aba756b5d0cf9b52daea6ecdf0b512234524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Neusch=C3=A4fer?= Date: Tue, 9 Jan 2024 02:39:43 +0100 Subject: [PATCH] Implement PIN_STATE command: Only set pins to output when requested This has the advantage that the pico-serprog can stay attached to the board even while a CPU etc. runs on the board and uses the flash. --- README.md | 5 +++++ main.c | 14 +++++++++++--- pio/spi.pio | 10 ++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 62c227a..5ede88e 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,11 @@ Dump a flashchip: flashrom -p serprog:dev=/dev/ttyACM0:115200,spispeed=12M -r foo.bin ``` +pico-serprog only switches the pins to output when requested by flashrom. This +means that you can leave your pico-serprog programmer attached to the flash; +you don't have to detach it before booting the board that you're programming. + + ## License The project is based on the spi_flash example by Raspberry Pi (Trading) Ltd. which is licensed under BSD-3-Clause. diff --git a/main.c b/main.c index f6b907c..13ddf07 100644 --- a/main.c +++ b/main.c @@ -79,7 +79,14 @@ void putu32(uint32_t d) { unsigned char write_buffer[4096]; +void apply_pin_state(const pio_spi_inst_t *spi, bool state) { + pio_spi_enable_outputs(spi->pio, spi->sm, state, PIN_SCK, PIN_MOSI, PIN_MISO); + gpio_set_dir(PIN_CS, state? GPIO_OUT : GPIO_IN); +} + void process(const pio_spi_inst_t *spi, int command) { + static bool pin_state = false; + switch(command) { case S_CMD_NOP: putchar(S_ACK); @@ -155,14 +162,15 @@ void process(const pio_spi_inst_t *spi, int command) { if (freq >= 1) { putchar(S_ACK); putu32(serprog_spi_init(freq)); + apply_pin_state(spi, pin_state); } else { putchar(S_NAK); } } break; case S_CMD_S_PIN_STATE: - //TODO: - getchar(); + pin_state = !!getchar(); + apply_pin_state(spi, pin_state); putchar(S_ACK); break; default: @@ -227,7 +235,7 @@ int main() { // Initialize CS gpio_init(PIN_CS); gpio_put(PIN_CS, 1); - gpio_set_dir(PIN_CS, GPIO_OUT); + gpio_set_dir(PIN_CS, GPIO_IN); // switch to output on S_CMD_S_PIN_STATE spi_offset = pio_add_program(spi.pio, &spi_cpha0_program); serprog_spi_init(1000000); // 1 MHz diff --git a/pio/spi.pio b/pio/spi.pio index 132c661..7dfc940 100644 --- a/pio/spi.pio +++ b/pio/spi.pio @@ -54,9 +54,9 @@ static inline void pio_spi_init(PIO pio, uint sm, uint prog_offs, uint n_bits, sm_config_set_in_shift(&c, false, true, n_bits); sm_config_set_clkdiv(&c, clkdiv); - // MOSI, SCK output are low, MISO is input + // MOSI, SCK output are low, MISO is input -- but we start in input mode pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_sck) | (1u << pin_mosi)); - pio_sm_set_pindirs_with_mask(pio, sm, (1u << pin_sck) | (1u << pin_mosi), (1u << pin_sck) | (1u << pin_mosi) | (1u << pin_miso)); + pio_sm_set_pindirs_with_mask(pio, sm, 0, (1u << pin_sck) | (1u << pin_mosi) | (1u << pin_miso)); pio_gpio_init(pio, pin_mosi); pio_gpio_init(pio, pin_miso); pio_gpio_init(pio, pin_sck); @@ -70,6 +70,12 @@ static inline void pio_spi_init(PIO pio, uint sm, uint prog_offs, uint n_bits, pio_sm_init(pio, sm, prog_offs, &c); pio_sm_set_enabled(pio, sm, true); } + +static inline void pio_spi_enable_outputs(PIO pio, uint sm, bool output, uint pin_sck, uint pin_mosi, uint pin_miso) { + uint mask = output? (1u << pin_sck) | (1u << pin_mosi) : 0; + pio_sm_set_pindirs_with_mask(pio, sm, mask, (1u << pin_sck) | (1u << pin_mosi) | (1u << pin_miso)); +} + %} ; SPI with Chip Select