Add support for RP2040 microcontroller

This commit is contained in:
Niklas Ekström 2022-10-18 10:40:41 +02:00
parent 30736877bd
commit e377afae11
4 changed files with 313 additions and 0 deletions

15
rp2040/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)
project(par_spi C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_executable(par_spi par_spi.c)
pico_add_extra_outputs(par_spi)
target_link_libraries(par_spi pico_stdlib hardware_spi)

19
rp2040/README.md Normal file
View File

@ -0,0 +1,19 @@
# RP2040 version
The code for the AVR microcontroller has been ported to the RP2040 microcontroller.
RP2040 is the microcontroller used on the Raspberry Pi Pico board.
## Build instructions
The [Raspberry Pi Pico SDK](https://github.com/raspberrypi/pico-sdk) must be installed.
Then, standing in the rp2040 subdirectory, execute:
```bash
mkdir build
cd build
export PICO_SDK_PATH=~/pico/pico-sdk
cmake ..
make
```
Copy the generated file `build/par_spi.uf2` to the microcontroller's flash.

206
rp2040/par_spi.c Normal file
View File

@ -0,0 +1,206 @@
/*
* Written in October 2022 by Niklas Ekström.
*
* Runs on RP2040 microcontroller instead of AVR as before,
* but uses the same protocol and Amiga software.
*/
#include "hardware/gpio.h"
#include "hardware/spi.h"
// Pin name GPIO Direction Comment Description
#define PIN_D(x) (0+x) // In/out
#define PIN_IRQ 8 // Output Active low
#define PIN_ACT 9 // Output Active low
#define PIN_CLK 10 // Input
#define PIN_REQ 11 // Input Active low
#define PIN_MISO 16 // Input Pull-up
#define PIN_SS 17 // Output Active low
#define PIN_SCK 18 // Output
#define PIN_MOSI 19 // Output
#define PIN_CDET 20 // Input Pull-up Card Detect
#define SPI_SLOW_FREQUENCY (400*1000)
#define SPI_FAST_FREQUENCY (16*1000*1000)
static uint32_t prev_cdet;
static void handle_request() {
uint32_t pins;
while (1) {
pins = gpio_get_all();
if (!(pins & (1 << PIN_REQ)))
break;
if ((pins & (1 << PIN_CDET)) != prev_cdet) {
gpio_put(PIN_IRQ, false);
gpio_set_dir(PIN_IRQ, true);
prev_cdet = pins & (1 << PIN_CDET);
}
}
uint32_t prev_clk = pins & (1 << PIN_CLK);
if ((pins & 0xc0) != 0xc0) {
uint32_t byte_count = 0;
bool read = false;
if (!(pins & 0x80)) { // READ1 or WRITE1
read = !!(pins & 0x40);
byte_count = pins & 0x3f;
gpio_put(PIN_ACT, 0);
} else { // READ2 or WRITE2
byte_count = (pins & 0x3f) << 7;
gpio_put(PIN_ACT, 0);
while (1) {
pins = gpio_get_all();
if ((pins & (1 << PIN_CLK)) != prev_clk)
break;
if (pins & (1 << PIN_REQ))
return;
}
read = !!(pins & 0x80);
byte_count |= pins & 0x7f;
prev_clk = pins & (1 << PIN_CLK);
}
if (read) {
spi_get_hw(spi0)->dr = 0xff;
uint32_t prev_ss = pins & (1 << PIN_SS);
while (1) {
while (!spi_is_readable(spi0))
tight_loop_contents();
uint32_t value = spi_get_hw(spi0)->dr;
while (1) {
pins = gpio_get_all();
if ((pins & (1 << PIN_CLK)) != prev_clk)
break;
if (pins & (1 << PIN_REQ))
return;
}
gpio_put_all(prev_ss | value);
gpio_set_dir_out_masked(0xff);
if (!byte_count)
break;
spi_get_hw(spi0)->dr = 0xff;
prev_clk = pins & (1 << PIN_CLK);
byte_count--;
}
} else {
while (1) {
while (1) {
pins = gpio_get_all();
if ((pins & (1 << PIN_CLK)) != prev_clk)
break;
if (pins & (1 << PIN_REQ))
return;
}
spi_get_hw(spi0)->dr = pins & 0xff;
while (!spi_is_readable(spi0))
tight_loop_contents();
(void)spi_get_hw(spi0)->dr;
if (!byte_count)
break;
prev_clk = pins & (1 << PIN_CLK);
byte_count--;
}
}
} else {
switch ((pins & 0x3e) >> 1) {
case 0: { // SPI_SELECT
gpio_put(PIN_SS, !(pins & 1));
gpio_put(PIN_ACT, 0);
break;
}
case 1: { // CARD_PRESENT
gpio_set_dir(PIN_IRQ, false);
gpio_put(PIN_ACT, 0);
while (1) {
pins = gpio_get_all();
if ((pins & (1 << PIN_CLK)) != prev_clk)
break;
if (pins & (1 << PIN_REQ))
return;
}
gpio_put(PIN_D(0), !gpio_get(PIN_CDET));
gpio_set_dir_out_masked(0xff);
break;
}
case 2: { // SPEED
spi_set_baudrate(spi0, pins & 1 ?
SPI_FAST_FREQUENCY :
SPI_SLOW_FREQUENCY);
gpio_put(PIN_ACT, 0);
break;
}
}
}
while (1) {
pins = gpio_get_all();
if (pins & (1 << PIN_REQ))
break;
}
}
int main() {
spi_init(spi0, SPI_SLOW_FREQUENCY);
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
gpio_pull_up(PIN_MISO);
gpio_init(PIN_SS);
gpio_put(PIN_SS, 1);
gpio_set_dir(PIN_SS, GPIO_OUT);
gpio_init(PIN_CDET);
gpio_pull_up(PIN_CDET);
for (int i = 0; i < 12; i++)
gpio_init(i);
gpio_put(PIN_ACT, 1);
gpio_set_dir(PIN_ACT, GPIO_OUT);
prev_cdet = gpio_get_all() & (1 << PIN_CDET);
while (1) {
handle_request();
gpio_set_dir_in_masked(0xff);
gpio_clr_mask(0xff);
gpio_put(PIN_ACT, 1);
while (spi_is_busy(spi0))
tight_loop_contents();
if (spi_is_readable(spi0))
(void)spi_get_hw(spi0)->dr;
}
}

View File

@ -0,0 +1,73 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
endif ()
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})