Compare commits
3 Commits
0d49d6fcbe
...
377d9f2d52
Author | SHA1 | Date |
---|---|---|
Riku Viitanen | 377d9f2d52 | |
Riku Viitanen | 1dc9bb96e4 | |
Riku Viitanen | 6301fbf3ed |
114
main.c
114
main.c
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (C) 2021, Mate Kukri <km@mkukri.xyz>
|
* Copyright (C) 2021, Mate Kukri <km@mkukri.xyz>
|
||||||
* Copyright (C) 2023, Riku Viitanen <riku.viitanen@protonmail.com>
|
* Copyright (C) 2023, 2024, Riku Viitanen <riku.viitanen@protonmail.com>
|
||||||
* Based on "pico-serprog" by Thomas Roth <code@stacksmashing.net>
|
* Based on "pico-serprog" by Thomas Roth <code@stacksmashing.net>
|
||||||
*
|
*
|
||||||
* Licensed under GPLv3
|
* Licensed under GPLv3
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DESCRIPTION "SPI flash chip programmer using Flashrom's serprog protocol"
|
#define DESCRIPTION "SPI flash chip programmer using Flashprog's serprog protocol"
|
||||||
#define WEBSITE "https://codeberg.org/Riku_V/pico-serprog/"
|
#define WEBSITE "https://codeberg.org/Riku_V/pico-serprog/"
|
||||||
|
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
|
@ -23,29 +23,47 @@
|
||||||
|
|
||||||
#define SPI_IF spi0 // Which PL022 to use
|
#define SPI_IF spi0 // Which PL022 to use
|
||||||
#define SPI_BAUD 12000000 // Default baudrate (12 MHz)
|
#define SPI_BAUD 12000000 // Default baudrate (12 MHz)
|
||||||
#define SPI_CS 5
|
#define SPI_CS_0 5 // The default CS pin
|
||||||
#define SPI_MISO 4
|
#define SPI_MISO 4
|
||||||
#define SPI_MOSI 3
|
#define SPI_MOSI 3
|
||||||
#define SPI_SCK 2
|
#define SPI_SCK 2
|
||||||
|
|
||||||
|
uint8_t spi_enabled = 0;
|
||||||
|
uint cs_pin = SPI_CS_0;
|
||||||
|
#define NUM_CS_AVAILABLE 4 // Number of usable chip selects
|
||||||
|
|
||||||
static const char progname[16] = "pico-serprog";
|
static const char progname[16] = "pico-serprog";
|
||||||
|
|
||||||
/* Map of supported serprog commands */
|
/* Map of supported serprog commands */
|
||||||
static const uint32_t cmdmap[8] = {
|
static const uint32_t cmdmap[8] = {
|
||||||
(1 << S_CMD_NOP) |
|
(1 << S_CMD_NOP) |
|
||||||
(1 << S_CMD_Q_IFACE) |
|
(1 << S_CMD_Q_IFACE) |
|
||||||
(1 << S_CMD_Q_CMDMAP) |
|
(1 << S_CMD_Q_CMDMAP) |
|
||||||
(1 << S_CMD_Q_PGMNAME) |
|
(1 << S_CMD_Q_PGMNAME) |
|
||||||
(1 << S_CMD_Q_SERBUF) |
|
(1 << S_CMD_Q_SERBUF) |
|
||||||
(1 << S_CMD_Q_BUSTYPE) |
|
(1 << S_CMD_Q_BUSTYPE) |
|
||||||
(1 << S_CMD_SYNCNOP) |
|
(1 << S_CMD_SYNCNOP) |
|
||||||
(1 << S_CMD_O_SPIOP) |
|
(1 << S_CMD_O_SPIOP) |
|
||||||
(1 << S_CMD_S_BUSTYPE) |
|
(1 << S_CMD_S_BUSTYPE) |
|
||||||
(1 << S_CMD_S_SPI_FREQ)|
|
(1 << S_CMD_S_SPI_FREQ) |
|
||||||
(1 << S_CMD_S_PIN_STATE)
|
(1 << S_CMD_S_PIN_STATE) |
|
||||||
|
(1 << S_CMD_S_SPI_CS)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void use_cs(uint pin)
|
||||||
|
{
|
||||||
|
gpio_put(pin, 1);
|
||||||
|
gpio_set_dir(pin, GPIO_OUT);
|
||||||
|
gpio_set_drive_strength(pin, GPIO_DRIVE_STRENGTH_12MA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pullup_cs(uint pin)
|
||||||
|
{
|
||||||
|
gpio_set_dir(pin, GPIO_IN);
|
||||||
|
gpio_pull_up(pin);
|
||||||
|
}
|
||||||
|
|
||||||
static void enable_spi(uint baud)
|
static void enable_spi(uint baud)
|
||||||
{
|
{
|
||||||
#ifdef PICO_DEFAULT_LED_PIN
|
#ifdef PICO_DEFAULT_LED_PIN
|
||||||
|
@ -54,10 +72,13 @@ static void enable_spi(uint baud)
|
||||||
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Setup chip select GPIO
|
/* Setup default CS as output, others as inputs with pull-ups */
|
||||||
gpio_init(SPI_CS);
|
for (uint8_t i = SPI_CS_0+1; i<SPI_CS_0+NUM_CS_AVAILABLE; i++) {
|
||||||
gpio_put(SPI_CS, 1);
|
gpio_init(i);
|
||||||
gpio_set_dir(SPI_CS, GPIO_OUT);
|
pullup_cs(i);
|
||||||
|
}
|
||||||
|
gpio_init(cs_pin);
|
||||||
|
use_cs(cs_pin);
|
||||||
|
|
||||||
// Setup PL022
|
// Setup PL022
|
||||||
spi_init(SPI_IF, baud);
|
spi_init(SPI_IF, baud);
|
||||||
|
@ -68,25 +89,40 @@ static void enable_spi(uint baud)
|
||||||
gpio_set_drive_strength(SPI_MISO, GPIO_DRIVE_STRENGTH_12MA);
|
gpio_set_drive_strength(SPI_MISO, GPIO_DRIVE_STRENGTH_12MA);
|
||||||
gpio_set_drive_strength(SPI_MOSI, GPIO_DRIVE_STRENGTH_12MA);
|
gpio_set_drive_strength(SPI_MOSI, GPIO_DRIVE_STRENGTH_12MA);
|
||||||
gpio_set_drive_strength(SPI_SCK, GPIO_DRIVE_STRENGTH_12MA);
|
gpio_set_drive_strength(SPI_SCK, GPIO_DRIVE_STRENGTH_12MA);
|
||||||
gpio_set_drive_strength(SPI_CS, GPIO_DRIVE_STRENGTH_12MA);
|
|
||||||
|
spi_enabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disable_pin(uint pin)
|
||||||
|
{
|
||||||
|
gpio_init(pin); // Set pin to SIO input
|
||||||
|
gpio_set_pulls(pin, 0, 0); // Disable all pulls
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_spi()
|
static void disable_spi()
|
||||||
{
|
{
|
||||||
// Set all pins to SIO inputs
|
for (uint8_t i=0; i<NUM_CS_AVAILABLE; i++)
|
||||||
gpio_init(SPI_CS);
|
disable_pin(SPI_CS_0 + i);
|
||||||
gpio_init(SPI_MISO);
|
disable_pin(SPI_MISO);
|
||||||
gpio_init(SPI_MOSI);
|
disable_pin(SPI_MOSI);
|
||||||
gpio_init(SPI_SCK);
|
disable_pin(SPI_SCK);
|
||||||
|
|
||||||
// Disable all pulls
|
|
||||||
gpio_set_pulls(SPI_CS, 0, 0);
|
|
||||||
gpio_set_pulls(SPI_MISO, 0, 0);
|
|
||||||
gpio_set_pulls(SPI_MOSI, 0, 0);
|
|
||||||
gpio_set_pulls(SPI_SCK, 0, 0);
|
|
||||||
|
|
||||||
// Disable SPI peripheral
|
// Disable SPI peripheral
|
||||||
spi_deinit(SPI_IF);
|
spi_deinit(SPI_IF);
|
||||||
|
|
||||||
|
spi_enabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_cs_pin(uint8_t cs)
|
||||||
|
{
|
||||||
|
cs += SPI_CS_0;
|
||||||
|
if (spi_enabled) {
|
||||||
|
if (cs_pin != cs) {
|
||||||
|
pullup_cs(cs_pin);
|
||||||
|
use_cs(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cs_pin = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void cs_select(uint cs_pin)
|
static inline void cs_select(uint cs_pin)
|
||||||
|
@ -198,7 +234,7 @@ static void process_command(uint8_t cmd, uint *baud) {
|
||||||
uint32_t rlen = 0;
|
uint32_t rlen = 0;
|
||||||
readbytes_blocking(&rlen, 3);
|
readbytes_blocking(&rlen, 3);
|
||||||
|
|
||||||
cs_select(SPI_CS);
|
cs_select(cs_pin);
|
||||||
|
|
||||||
while (wlen) {
|
while (wlen) {
|
||||||
uint32_t cur = MIN(wlen, sizeof buf);
|
uint32_t cur = MIN(wlen, sizeof buf);
|
||||||
|
@ -216,7 +252,7 @@ static void process_command(uint8_t cmd, uint *baud) {
|
||||||
rlen -= cur;
|
rlen -= cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
cs_deselect(SPI_CS);
|
cs_deselect(cs_pin);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case S_CMD_S_SPI_FREQ:
|
case S_CMD_S_SPI_FREQ:
|
||||||
|
@ -242,6 +278,15 @@ static void process_command(uint8_t cmd, uint *baud) {
|
||||||
disable_spi();
|
disable_spi();
|
||||||
sendbyte_blocking(S_ACK);
|
sendbyte_blocking(S_ACK);
|
||||||
break;
|
break;
|
||||||
|
case S_CMD_S_SPI_CS:
|
||||||
|
uint8_t cs_index = readbyte_blocking();
|
||||||
|
if (cs_index < NUM_CS_AVAILABLE) {
|
||||||
|
set_cs_pin(cs_index);
|
||||||
|
sendbyte_blocking(S_ACK);
|
||||||
|
} else {
|
||||||
|
sendbyte_blocking(S_NAK);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sendbyte_blocking(S_NAK);
|
sendbyte_blocking(S_NAK);
|
||||||
break;
|
break;
|
||||||
|
@ -280,7 +325,10 @@ int main()
|
||||||
bi_decl(bi_1pin_with_name(SPI_MISO, "MISO"));
|
bi_decl(bi_1pin_with_name(SPI_MISO, "MISO"));
|
||||||
bi_decl(bi_1pin_with_name(SPI_MOSI, "MOSI"));
|
bi_decl(bi_1pin_with_name(SPI_MOSI, "MOSI"));
|
||||||
bi_decl(bi_1pin_with_name(SPI_SCK, "SCK"));
|
bi_decl(bi_1pin_with_name(SPI_SCK, "SCK"));
|
||||||
bi_decl(bi_1pin_with_name(SPI_CS, "CS"));
|
bi_decl(bi_1pin_with_name(SPI_CS_0, "CS_0 (default)"));
|
||||||
|
bi_decl(bi_1pin_with_name(SPI_CS_0+1, "CS_1"));
|
||||||
|
bi_decl(bi_1pin_with_name(SPI_CS_0+2, "CS_2"));
|
||||||
|
bi_decl(bi_1pin_with_name(SPI_CS_0+3, "CS_3"));
|
||||||
|
|
||||||
// Setup USB
|
// Setup USB
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
11
readme.md
11
readme.md
|
@ -42,12 +42,19 @@ containing something like this will appear:
|
||||||
Read chip:
|
Read chip:
|
||||||
|
|
||||||
```
|
```
|
||||||
flashrom -p serprog:dev=/dev/ttyACMx,spispeed=32M -r flash.bin
|
flashprog -p serprog:dev=/dev/ttyACMx,spispeed=32M -r flash.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Write chip:
|
Write chip:
|
||||||
```
|
```
|
||||||
flashrom -p serprog:dev=/dev/ttyACMx,spispeed=32M -w flash.bin
|
flashprog -p serprog:dev=/dev/ttyACMx,spispeed=32M -w flash.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Multiple chips can be connected at the same time. Pins GP5-GP8 are Chip
|
||||||
|
Selects 0-3, respectively. The firmware defaults to using Chip Select 0.
|
||||||
|
```
|
||||||
|
flashprog -p serprog:dev=/dev/ttyACMx,cs=0 -r chip0.bin
|
||||||
|
flashprog -p serprog:dev=/dev/ttyACMx,cs=1 -r chip1.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
|
@ -28,4 +28,6 @@
|
||||||
#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
|
#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
|
||||||
#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
|
#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
|
||||||
|
|
||||||
|
#define S_CMD_S_SPI_CS 0x16 /* Select Chip Select to use */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue