Skip to content

PIO attempt ii #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 54 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
2d815ab
Take I
matteius Dec 23, 2023
7912865
Add SPI files
matteius Dec 23, 2023
e39126f
update CMakeLists
matteius Dec 23, 2023
c137574
correction
matteius Dec 23, 2023
3c82de4
Checkpt
matteius Dec 23, 2023
1c78f1f
Correction
matteius Dec 23, 2023
5a5c703
Correction
matteius Dec 23, 2023
69b8069
Correction
matteius Dec 23, 2023
1f73c18
resolve merge conflict
matteius Dec 23, 2023
d081a25
Correction
matteius Dec 23, 2023
f36c056
Correction
matteius Dec 23, 2023
24ad556
Correction
matteius Dec 23, 2023
226a709
Correction
matteius Dec 23, 2023
cf6de7a
Correction
matteius Dec 23, 2023
9f44f63
Correction
matteius Dec 23, 2023
555a6ed
Correction
matteius Dec 23, 2023
e9fc383
Correction
matteius Dec 23, 2023
bf3ec1c
Correction
matteius Dec 23, 2023
69d5ce0
Correction
matteius Dec 23, 2023
e36309b
Refactor based on original library which has pio
matteius Dec 23, 2023
f5f2bde
correction
matteius Dec 23, 2023
56b7871
correction
matteius Dec 23, 2023
65920c4
correction
matteius Dec 23, 2023
a921107
iterate on pio
matteius Dec 23, 2023
968df0f
iterate on pio
matteius Dec 23, 2023
80212dd
iterate on pio
matteius Dec 23, 2023
1da515f
iterate on pio
matteius Dec 23, 2023
2ab8276
Revert "iterate on pio"
matteius Dec 23, 2023
5086738
testing
matteius Dec 23, 2023
4b5dd03
testing
matteius Dec 23, 2023
371f0df
testing
matteius Dec 23, 2023
80fee6e
testing
matteius Dec 23, 2023
39d2814
testing
matteius Dec 23, 2023
1a833b0
testing
matteius Dec 23, 2023
1c0e9fd
test
matteius Dec 23, 2023
9b64744
test
matteius Dec 23, 2023
f666678
test
matteius Dec 23, 2023
0dd8c82
test
matteius Dec 23, 2023
011c56d
test
matteius Dec 23, 2023
c79f381
testing
matteius Dec 23, 2023
8c7a1f9
change around init
matteius Dec 23, 2023
27edd45
change around init
matteius Dec 23, 2023
a9e1642
change around init
matteius Dec 23, 2023
e2b25a3
change around init
matteius Dec 23, 2023
b4224af
change around init
matteius Dec 23, 2023
2672504
change around init
matteius Dec 23, 2023
50663f4
change around init
matteius Dec 23, 2023
3e0d4c3
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
f7feea5
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
8eed01b
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
9718db4
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
8e9779c
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
2b04e67
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
5fd410b
change around S_CMD_O_SPIOP
matteius Dec 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ project(pico_serprog)
pico_sdk_init()

add_executable(pico_serprog)
target_sources(pico_serprog PRIVATE main.c usb_descriptors.c)
target_link_libraries(pico_serprog PRIVATE pico_stdlib hardware_spi tinyusb_device)
pico_generate_pio_header(pico_serprog ${CMAKE_CURRENT_LIST_DIR}/spi.pio)
target_sources(pico_serprog PRIVATE main.c usb_descriptors.c pio_spi.c)
target_link_libraries(pico_serprog PRIVATE pico_stdlib hardware_spi hardware_pio tinyusb_device)
pico_add_extra_outputs(pico_serprog)

# enable usb output, disable uart output
pico_enable_stdio_usb(pico_serprog 1)
pico_enable_stdio_uart(pico_serprog 0)
137 changes: 92 additions & 45 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,81 @@
*
*/

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/clocks.h"
#include "pico/stdlib.h"
#include "pico/time.h"
#include "hardware/spi.h"
#include "tusb.h"
#include "serprog.h"
#include "pio_spi.h"



#define CDC_ITF 0 // USB CDC interface no
#define PIN_LED PICO_DEFAULT_LED_PIN

#define SPI_IF spi0 // Which PL022 to use
#define SPI_BAUD 4000000 // Default baudrate (4 MHz - SPI default)
#define SPI_BAUD 115200 // Default baudrate (4 MHz - SPI default)
#define SPI_CS 5
#define SPI_MISO 4
#define SPI_MOSI 3
#define SPI_SCK 2
#define MAX_BUFFER_SIZE 1024
#define MAX_OPBUF_SIZE 1024
#define SERIAL_BUFFER_SIZE 1024
#define MAX_BUFFER_SIZE 512
#define MAX_OPBUF_SIZE 512
#define SERIAL_BUFFER_SIZE 512
#define FREQ 1000000

// Define a global operation buffer and a pointer to track the current position
uint8_t opbuf[MAX_OPBUF_SIZE];
uint32_t opbuf_pos = 0;

static const pio_spi_inst_t spi = {
.pio = pio0,
.sm = 0,
.cs_pin = SPI_CS
};
static uint spi_offset;

static void wait_for_write(void)
{
do {
tud_task();
} while (!tud_cdc_n_write_available(CDC_ITF));
}

static inline float freq_to_clkdiv(uint32_t freq) {
float div = clock_get_hz(clk_sys) * 1.0 / (freq * pio_spi_cycles_per_bit);

if (div < 1.0)
div = 1.0;
if (div > 65536.0)
div = 65536.0;

return div;
}

static inline uint32_t clkdiv_to_freq(float div) {
return clock_get_hz(clk_sys) / (div * pio_spi_cycles_per_bit);
}

static void enable_spi(uint baud)
{
// Setup chip select GPIO
gpio_init(SPI_CS);
gpio_put(SPI_CS, 1);
gpio_set_dir(SPI_CS, GPIO_OUT);

// Setup PL022
spi_offset = pio_add_program(pio0, &spi_cpha0_program);
spi_init(SPI_IF, baud);
float clkdiv = freq_to_clkdiv(FREQ);
pio_spi_init(pio0, 0, pio_add_program(pio0, &spi_cpha0_program), 8, clkdiv, false, false, SPI_SCK, SPI_MOSI, SPI_MISO);


// Setup PL022
gpio_set_function(SPI_MISO, GPIO_FUNC_SPI);
gpio_set_function(SPI_MOSI, GPIO_FUNC_SPI);
gpio_set_function(SPI_SCK, GPIO_FUNC_SPI);
Expand Down Expand Up @@ -100,29 +144,42 @@ static inline uint8_t readbyte_blocking(void)
return b;
}

static void wait_for_write(void)
{
do {
tud_task();
} while (!tud_cdc_n_write_available(CDC_ITF));
}

static inline void sendbytes_blocking(const void *b, uint32_t len)
{
while (len) {
// wait_for_write();
wait_for_write();
uint32_t w = tud_cdc_n_write(CDC_ITF, b, len);
b += w;
len -= w;
}
}


void read_spi_and_send_via_usb(const pio_spi_inst_t *spi, const uint32_t rlen) {
static uint8_t rxbuf[MAX_BUFFER_SIZE];
memset(rxbuf, 0, MAX_BUFFER_SIZE); // Clear the rx buffer

// Ensure we send rlen bytes
uint32_t remaining = rlen;
while (remaining) {
uint32_t chunk_size = (remaining < MAX_BUFFER_SIZE) ? remaining : MAX_BUFFER_SIZE;
pio_spi_read8_blocking(spi, rxbuf, chunk_size);
remaining -= chunk_size;

// Transfer data via USB
sendbytes_blocking(rxbuf, chunk_size);
}
}


static inline void sendbyte_blocking(uint8_t b)
{
wait_for_write();
tud_cdc_n_write(CDC_ITF, &b, 1);
}


static void command_loop(void)
{
uint baud = spi_get_baudrate(SPI_IF);
Expand Down Expand Up @@ -202,46 +259,24 @@ static void command_loop(void)
uint8_t tx_buffer[MAX_BUFFER_SIZE]; // Buffer for transmit data
uint8_t rx_buffer[MAX_BUFFER_SIZE]; // Buffer for receive data

// Read data to be sent (if slen > 0)
if (slen > 0) {
readbytes_blocking(tx_buffer, slen);
}

// Perform SPI operation
cs_select(SPI_CS);
if (slen > 0) {
spi_write_blocking(SPI_IF, tx_buffer, slen);
}
if (rlen > 0 && rlen < MAX_BUFFER_SIZE ) {
spi_read_blocking(SPI_IF, 0, rx_buffer, rlen);
// Send ACK followed by received data
sendbyte_blocking(S_ACK);
if (rlen > 0) {
sendbytes_blocking(rx_buffer, rlen);
}
fread(tx_buffer, 1, slen, stdin);
pio_spi_write8_blocking(&spi, tx_buffer, slen);

cs_deselect(SPI_CS);
break;
}

// Send ACK after handling slen (before reading)
sendbyte_blocking(S_ACK);

// Handle receive operation in chunks for large rlen
putchar(S_ACK);
uint32_t chunk;
char buf[128];

for(uint32_t i = 0; i < rlen; i += chunk) {
chunk = MIN(rlen - i, sizeof(buf));
spi_read_blocking(SPI_IF, 0, buf, chunk);
// Send ACK followed by received data
sendbyte_blocking(S_ACK);
sendbytes_blocking(buf, rlen);
chunk = MIN(rlen - i, sizeof(rx_buffer));
pio_spi_read8_blocking(&spi, rx_buffer, chunk);
fwrite(rx_buffer, 1, chunk, stdout);
fflush(stdout);
}

cs_deselect(SPI_CS);
break;
}
case S_CMD_S_SPI_FREQ:
case S_CMD_S_SPI_FREQ:
{
uint32_t want_baud;
readbytes_blocking(&want_baud, 4);
Expand Down Expand Up @@ -342,9 +377,21 @@ static void command_loop(void)
int main()
{
// Setup USB
stdio_init_all();

stdio_set_translate_crlf(&stdio_usb, false);

tusb_init();
// Setup PL022 SPI
enable_spi(SPI_BAUD);

// Initialize CS
gpio_init(SPI_CS);
gpio_put(SPI_CS, 1);
gpio_set_dir(SPI_CS, GPIO_OUT);

spi_offset = pio_add_program(spi.pio, &spi_cpha0_program);
enable_spi(SPI_BAUD);

gpio_init(PIN_LED);
gpio_set_dir(PIN_LED, GPIO_OUT);
command_loop();
}
68 changes: 68 additions & 0 deletions pio_spi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include "pio_spi.h"

// Just 8 bit functions provided here. The PIO program supports any frame size
// 1...32, but the software to do the necessary FIFO shuffling is left as an
// exercise for the reader :)
//
// Likewise we only provide MSB-first here. To do LSB-first, you need to
// - Do shifts when reading from the FIFO, for general case n != 8, 16, 32
// - Do a narrow read at a one halfword or 3 byte offset for n == 16, 8
// in order to get the read data correctly justified.

void __time_critical_func(pio_spi_write8_blocking)(const pio_spi_inst_t *spi, const uint8_t *src, size_t len) {
size_t tx_remain = len, rx_remain = len;
// Do 8 bit accesses on FIFO, so that write data is byte-replicated. This
// gets us the left-justification for free (for MSB-first shift-out)
io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm];
io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm];
while (tx_remain || rx_remain) {
if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) {
*txfifo = *src++;
--tx_remain;
}
if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) {
(void) *rxfifo;
--rx_remain;
}
}
}

void __time_critical_func(pio_spi_read8_blocking)(const pio_spi_inst_t *spi, uint8_t *dst, size_t len) {
size_t tx_remain = len, rx_remain = len;
io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm];
io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm];
while (tx_remain || rx_remain) {
if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) {
*txfifo = 0;
--tx_remain;
}
if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) {
*dst++ = *rxfifo;
--rx_remain;
}
}
}

void __time_critical_func(pio_spi_write8_read8_blocking)(const pio_spi_inst_t *spi, uint8_t *src, uint8_t *dst,
size_t len) {
size_t tx_remain = len, rx_remain = len;
io_rw_8 *txfifo = (io_rw_8 *) &spi->pio->txf[spi->sm];
io_rw_8 *rxfifo = (io_rw_8 *) &spi->pio->rxf[spi->sm];
while (tx_remain || rx_remain) {
if (tx_remain && !pio_sm_is_tx_fifo_full(spi->pio, spi->sm)) {
*txfifo = *src++;
--tx_remain;
}
if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) {
*dst++ = *rxfifo;
--rx_remain;
}
}
}

24 changes: 24 additions & 0 deletions pio_spi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PIO_SPI_H
#define _PIO_SPI_H

#include "hardware/pio.h"
#include "spi.pio.h"

typedef struct pio_spi_inst {
PIO pio;
uint sm;
uint cs_pin;
} pio_spi_inst_t;

void pio_spi_write8_blocking(const pio_spi_inst_t *spi, const uint8_t *src, size_t len);

void pio_spi_read8_blocking(const pio_spi_inst_t *spi, uint8_t *dst, size_t len);

void pio_spi_write8_read8_blocking(const pio_spi_inst_t *spi, uint8_t *src, uint8_t *dst, size_t len);

#endif
Loading