2021-04-03 18:36:40 +02:00
|
|
|
/**
|
2021-08-07 01:04:08 +02:00
|
|
|
* Copyright (C) 2021, Mate Kukri <km@mkukri.xyz>
|
|
|
|
* Based on "pico-serprog" by Thomas Roth <code@stacksmashing.net>
|
2021-04-03 18:36:40 +02:00
|
|
|
*
|
|
|
|
* Licensed under GPLv3
|
2021-08-07 01:04:08 +02:00
|
|
|
*
|
2021-04-03 18:36:40 +02:00
|
|
|
* Based on the spi_flash pico-example, which is:
|
|
|
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
2021-08-07 01:04:08 +02:00
|
|
|
* Also based on stm32-vserprog:
|
2021-04-03 18:36:40 +02:00
|
|
|
* https://github.com/dword1511/stm32-vserprog
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "pico/stdlib.h"
|
|
|
|
#include "pio/pio_spi.h"
|
|
|
|
#include "spi.h"
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
#define PIN_CS 2
|
|
|
|
#define PIN_MISO 3
|
|
|
|
#define PIN_MOSI 4
|
|
|
|
#define PIN_SCK 5
|
|
|
|
|
|
|
|
#define S_SUPPORTED_BUS (1 << 3) // BUS_SPI
|
|
|
|
|
2021-04-03 18:36:40 +02:00
|
|
|
#define S_CMD_MAP ( \
|
|
|
|
(1 << S_CMD_NOP) | \
|
|
|
|
(1 << S_CMD_Q_IFACE) | \
|
|
|
|
(1 << S_CMD_Q_CMDMAP) | \
|
|
|
|
(1 << S_CMD_Q_PGMNAME) | \
|
|
|
|
(1 << S_CMD_Q_SERBUF) | \
|
|
|
|
(1 << S_CMD_Q_BUSTYPE) | \
|
|
|
|
(1 << S_CMD_SYNCNOP) | \
|
|
|
|
(1 << S_CMD_O_SPIOP) | \
|
|
|
|
(1 << S_CMD_S_BUSTYPE) | \
|
|
|
|
(1 << S_CMD_S_SPI_FREQ)| \
|
|
|
|
(1 << S_CMD_S_PIN_STATE) \
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
static inline void cs_select(uint cs_pin)
|
|
|
|
{
|
2021-04-03 18:36:40 +02:00
|
|
|
asm volatile("nop \n nop \n nop"); // FIXME
|
|
|
|
gpio_put(cs_pin, 0);
|
|
|
|
asm volatile("nop \n nop \n nop"); // FIXME
|
|
|
|
}
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
static inline void cs_deselect(uint cs_pin)
|
|
|
|
{
|
2021-04-03 18:36:40 +02:00
|
|
|
asm volatile("nop \n nop \n nop"); // FIXME
|
|
|
|
gpio_put(cs_pin, 1);
|
|
|
|
asm volatile("nop \n nop \n nop"); // FIXME
|
|
|
|
}
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
static inline void readbytes(uint8_t *b, uint32_t len)
|
|
|
|
{
|
|
|
|
fread(b, len, 1, stdin);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint32_t getu24()
|
|
|
|
{
|
|
|
|
uint8_t buf[3];
|
|
|
|
fread(buf, sizeof buf, 1, stdin);
|
|
|
|
return (uint32_t) buf[0]
|
|
|
|
| ((uint32_t) buf[1] << 8)
|
|
|
|
| ((uint32_t) buf[2] << 16);
|
2021-04-03 18:36:40 +02:00
|
|
|
}
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
static inline void sendbytes(uint8_t *b, uint32_t len)
|
|
|
|
{
|
|
|
|
fwrite(b, len, 1, stdout);
|
2021-04-03 18:36:40 +02:00
|
|
|
}
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
static inline void process(pio_spi_inst_t *spi)
|
|
|
|
{
|
|
|
|
static uint8_t buf[4096];
|
2021-04-03 18:36:40 +02:00
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
for (;;) {
|
|
|
|
switch(getchar()) {
|
2021-04-03 18:36:40 +02:00
|
|
|
case S_CMD_NOP:
|
|
|
|
putchar(S_ACK);
|
|
|
|
break;
|
|
|
|
case S_CMD_Q_IFACE:
|
|
|
|
putchar(S_ACK);
|
|
|
|
putchar(0x01);
|
|
|
|
putchar(0x00);
|
|
|
|
break;
|
|
|
|
case S_CMD_Q_CMDMAP:
|
|
|
|
putchar(S_ACK);
|
2021-08-07 01:04:08 +02:00
|
|
|
memset(buf, 0, 32);
|
|
|
|
*(uint32_t *) buf = S_CMD_MAP;
|
|
|
|
sendbytes(buf, 32);
|
2021-04-03 18:36:40 +02:00
|
|
|
break;
|
|
|
|
case S_CMD_Q_PGMNAME:
|
|
|
|
putchar(S_ACK);
|
|
|
|
fwrite("pico-serprog\x0\x0\x0\x0\x0", 1, 16, stdout);
|
|
|
|
break;
|
|
|
|
case S_CMD_Q_SERBUF:
|
|
|
|
putchar(S_ACK);
|
|
|
|
putchar(0xFF);
|
|
|
|
putchar(0xFF);
|
|
|
|
break;
|
|
|
|
case S_CMD_Q_BUSTYPE:
|
|
|
|
putchar(S_ACK);
|
|
|
|
putchar(S_SUPPORTED_BUS);
|
|
|
|
break;
|
|
|
|
case S_CMD_SYNCNOP:
|
|
|
|
putchar(S_NAK);
|
|
|
|
putchar(S_ACK);
|
|
|
|
break;
|
|
|
|
case S_CMD_S_BUSTYPE:
|
|
|
|
{
|
|
|
|
int bustype = getchar();
|
|
|
|
if((bustype | S_SUPPORTED_BUS) == S_SUPPORTED_BUS) {
|
|
|
|
putchar(S_ACK);
|
|
|
|
} else {
|
|
|
|
putchar(S_NAK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case S_CMD_O_SPIOP:
|
|
|
|
{
|
|
|
|
uint32_t wlen = getu24();
|
|
|
|
uint32_t rlen = getu24();
|
|
|
|
|
|
|
|
cs_select(PIN_CS);
|
2021-08-07 01:04:08 +02:00
|
|
|
|
|
|
|
while (wlen) {
|
|
|
|
uint32_t cur = MIN(wlen, sizeof buf);
|
|
|
|
readbytes(buf, cur);
|
|
|
|
pio_spi_write8_blocking(spi, buf, cur);
|
|
|
|
wlen -= cur;
|
|
|
|
}
|
2021-04-03 18:36:40 +02:00
|
|
|
|
|
|
|
putchar(S_ACK);
|
2021-08-07 01:04:08 +02:00
|
|
|
|
|
|
|
while (rlen) {
|
|
|
|
uint32_t cur = MIN(rlen, sizeof buf);
|
|
|
|
pio_spi_read8_blocking(spi, buf, cur);
|
|
|
|
sendbytes(buf, cur);
|
|
|
|
rlen -= cur;
|
2021-04-03 18:36:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cs_deselect(PIN_CS);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case S_CMD_S_SPI_FREQ:
|
|
|
|
// TODO
|
|
|
|
putchar(S_ACK);
|
|
|
|
putchar(0x0);
|
|
|
|
putchar(0x40);
|
|
|
|
putchar(0x0);
|
|
|
|
putchar(0x0);
|
|
|
|
break;
|
|
|
|
case S_CMD_S_PIN_STATE:
|
|
|
|
//TODO:
|
|
|
|
getchar();
|
|
|
|
putchar(S_ACK);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
putchar(S_NAK);
|
2021-08-07 01:04:08 +02:00
|
|
|
}
|
|
|
|
fflush(stdout);
|
2021-04-03 18:36:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
stdio_init_all();
|
|
|
|
stdio_set_translate_crlf(&stdio_usb, false);
|
|
|
|
|
|
|
|
// Initialize CS
|
|
|
|
gpio_init(PIN_CS);
|
|
|
|
gpio_put(PIN_CS, 1);
|
|
|
|
gpio_set_dir(PIN_CS, GPIO_OUT);
|
|
|
|
|
|
|
|
// We use PIO 1
|
|
|
|
pio_spi_inst_t spi = {
|
|
|
|
.pio = pio1,
|
|
|
|
.sm = 0,
|
|
|
|
.cs_pin = PIN_CS
|
|
|
|
};
|
|
|
|
|
|
|
|
uint offset = pio_add_program(spi.pio, &spi_cpha0_program);
|
|
|
|
|
|
|
|
pio_spi_init(spi.pio, spi.sm, offset,
|
|
|
|
8, // 8 bits per SPI frame
|
2021-08-07 01:04:08 +02:00
|
|
|
2.5f, // 12.5 MHz @ 125 clk_sys
|
2021-04-03 18:36:40 +02:00
|
|
|
false, // CPHA = 0
|
|
|
|
false, // CPOL = 0
|
|
|
|
PIN_SCK,
|
|
|
|
PIN_MOSI,
|
|
|
|
PIN_MISO);
|
|
|
|
|
2021-08-07 01:04:08 +02:00
|
|
|
process(&spi);
|
2021-04-03 18:36:40 +02:00
|
|
|
return 0;
|
|
|
|
}
|