forked from dangiu/PicoMemcard
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial testing of custom SPI, able to read correctly CMD, unable to …
…answer using DAT and ACK
- Loading branch information
Showing
4 changed files
with
349 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
cmake_minimum_required(VERSION 3.13) | ||
|
||
include(pico_sdk_import.cmake) | ||
|
||
project(test_project C CXX ASM) | ||
set(CMAKE_C_STANDARD 11) | ||
set(CMAKE_CXX_STANDARD 17) | ||
pico_sdk_init() | ||
|
||
add_executable(test) | ||
|
||
pico_generate_pio_header(test ${CMAKE_CURRENT_LIST_DIR}/psxSPI.pio) | ||
|
||
target_sources(test PRIVATE test.c) | ||
|
||
pico_enable_stdio_uart(test 1) # enable only UART stdio | ||
|
||
pico_add_extra_outputs(test) | ||
|
||
target_link_libraries(test pico_stdlib hardware_pio) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# 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 () | ||
FetchContent_Declare( | ||
pico_sdk | ||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk | ||
GIT_TAG master | ||
) | ||
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}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
; Author: Daniele Giuliani | ||
; Program: Simple interface to read the modified SPI protocol | ||
; used by the PSX to communicate with controller/memory cards | ||
|
||
.program readCmd | ||
; Input pins mapping: | ||
; 0 - CMD | ||
; 1 - SEL | ||
; 2 - CLK | ||
wait 1 pin 1 ; initial wait to go in sync | ||
sel_high: | ||
wait 0 pin 1 | ||
.wrap_target | ||
wait 0 pin 2 ; wait for clock to fall | ||
wait 1 pin 2 ; wait for rising clock edge | ||
jmp pin sel_high ; jumpback if SEL is high (need to be low in order to read data) | ||
in pins 1 ; sample 1 bit from CMD line | ||
.wrap | ||
|
||
;.program writeDat | ||
; Output pins mapping: | ||
; 0 - DAT | ||
; Input pins mapping: | ||
; 0 - CLK | ||
;.wrap_target | ||
;set x, 7 ; reset counter in scratch register X | ||
;irq wait 1 ; wait for CPU to give start | ||
;write_bit: | ||
;wait 1 pin 0 ; wait for clock to be high | ||
;wait 0 pin 0 ; wait for falling clock edge | ||
; TODO BITS MUST BE INVERTED BEFORE PLACING IN TX OR USE MUTEX TO INVERT THEM AUTOMATICALLY | ||
;out pindirs 1 ; change direction of output bit (open collector behavior: input = leave high (1), output = set low (0)) | ||
;jmp x-- write_bit ; continue bit output until whole byte has been sent | ||
;nop [7] ; delay of at least 1 clock cycle to allow PSX to pickup last bit | ||
;set pindirs 0 ; deactivate ouptut (set output pin as input in order to float high) | ||
;.wrap | ||
|
||
.program writeDat | ||
; Output pins mapping: | ||
; 0 - DAT | ||
; Input pins mapping: | ||
; 0 - SEL | ||
; 1 - CLK | ||
sel_high: | ||
out null, 32 ; clear OSR | ||
set pindirs, 0 ; release DAT line | ||
.wrap_target | ||
set x, 7 ; reset counter in scratch register X | ||
pull block | ||
write_bit: | ||
wait 1 pin 1 ; wait for clock to be high | ||
wait 0 pin 1 ; wait for falling clock edge | ||
jmp pin sel_high ; jumpback if SEL is high (need to be low in order to write data) | ||
; TODO BITS MUST BE INVERTED BEFORE PLACING IN TX OR USE MUTEX TO INVERT THEM AUTOMATICALLY | ||
out pindirs 1 ; change direction of output bit (open collector behavior: input = leave high (1), output = set low (0)) | ||
jmp x-- write_bit ; continue bit output until whole byte has been sent | ||
.wrap | ||
|
||
.program sendAck | ||
; completely time-based, running with same clock as PSX protocol (250Khz) | ||
; waits for interrupt from CPU then lowers ACK line for 2 clock cycles | ||
.wrap_target | ||
irq wait 0 | ||
set pindirs, 1 [2] | ||
set pindirs, 0 | ||
.wrap | ||
|
||
|
||
% c-sdk { | ||
#define READ_CLKDIV 83 // with pico default clock (125 Mhz) results in a clock which six time the PSX clock (250 Khz) (actually slightly greater than that) | ||
#define PSX_CLKDIV 500 // with pico default clock (125 Mhz) results in a clock equal to PSX clock (250 Khz) | ||
#define ACK_IRQ 0 | ||
#define DAT_IRQ 1 | ||
|
||
static inline void readCmd_program_init(PIO pio, uint sm, uint offset, uint cmdPin) { | ||
pio_sm_config c = readCmd_program_get_default_config(offset); | ||
sm_config_set_in_pins(&c, cmdPin); | ||
pio_sm_set_consecutive_pindirs(pio, sm, cmdPin, 3, false); | ||
pio_gpio_init(pio, cmdPin); // CMD pin | ||
pio_gpio_init(pio, cmdPin + 1); // SEL pin | ||
pio_gpio_init(pio, cmdPin + 2); // CLK pin | ||
sm_config_set_in_shift(&c, true, true, 8); // shift ISR to right, autopush every 8 bits | ||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // join RX FIFO (we don't need TX fifo for this program) | ||
sm_config_set_jmp_pin(&c, cmdPin + 1); // set SEL as jmp pin | ||
sm_config_set_clkdiv(&c, READ_CLKDIV); | ||
|
||
pio_sm_init(pio, sm, offset, &c); | ||
//pio_sm_set_enabled(pio, sm, true); | ||
} | ||
|
||
static inline void sendAck_program_init(PIO pio, uint sm, uint offset, uint ackPin) { | ||
pio_sm_config c = sendAck_program_get_default_config(offset); | ||
pio_interrupt_clear(pio, ACK_IRQ); // clear interrupt if present | ||
pio_sm_set_pins_with_mask(pio, sm, 0x00000000, 1 << ackPin); // set ACK pin to low output | ||
pio_sm_set_consecutive_pindirs(pio, sm, ackPin, 1, false); // set ACK pin as input (initial configuration) | ||
pio_gpio_init(pio, ackPin); // init ACK pin | ||
sm_config_set_set_pins(&c, ackPin, 1); | ||
sm_config_set_clkdiv_int_frac(&c, PSX_CLKDIV, 0x00); | ||
|
||
pio_sm_init(pio, sm, offset, &c); | ||
pio_sm_set_enabled(pio, sm, true); | ||
} | ||
|
||
static inline void sendAck(PIO pio) { | ||
pio_interrupt_clear(pio, ACK_IRQ); | ||
} | ||
|
||
static inline void writeDat_program_init(PIO pio, uint sm, uint offset, uint datPin, uint selPin) { | ||
pio_sm_config c = writeDat_program_get_default_config(offset); | ||
|
||
/* Pin Configuration */ | ||
sm_config_set_in_pins(&c, selPin); // set base IN pin (SEL) | ||
sm_config_set_out_pins(&c, datPin, 1); // set base OUT pin (DAT) | ||
sm_config_set_set_pins(&c, datPin, 1); // set base SET pin (DAT) | ||
pio_interrupt_clear(pio, DAT_IRQ); // clear old interrupt if present | ||
pio_sm_set_pins_with_mask(pio, sm, 0x00000000, 1 << datPin); // set DAT pin to low output | ||
pio_sm_set_consecutive_pindirs(pio, sm, datPin, 1, false); // set DAT pin as input (initial configuration) | ||
pio_sm_set_consecutive_pindirs(pio, sm, selPin, 2, false); // set SEL and CLK pins as input | ||
pio_gpio_init(pio, datPin); // init DAT pin | ||
pio_gpio_init(pio, selPin); // init SEL pin | ||
pio_gpio_init(pio, selPin + 1); // init CLK pin | ||
|
||
/* FIFO configuration */ | ||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // join TX FIFO (we don't need RX fifo for this program) | ||
|
||
/* Clock configuration */ | ||
//sm_config_set_clkdiv(&c, READ_CLKDIV); | ||
|
||
/* Init SM */ | ||
pio_sm_init(pio, sm, offset, &c); | ||
pio_sm_set_enabled(pio, sm, true); | ||
} | ||
|
||
static inline void sendByte(PIO pio, uint sm, uint32_t byte) { | ||
byte = ~byte & (0x000000ff); // invert byte (0 must be ones in order to set pins to output and output low, 1 must be 0 to set pin to input and output high-z) | ||
pio_sm_put_blocking(pio, sm, byte); // place byte in tx fifo | ||
} | ||
%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#include <stdio.h> | ||
#include "pico/stdlib.h" | ||
#include "hardware/pio.h" | ||
#include "hardware/irq.h" | ||
#include "psxSPI.pio.h" | ||
|
||
#define PIN_DAT 5 | ||
#define PIN_CMD 6 | ||
#define PIN_SEL 7 | ||
#define PIN_CLK 8 | ||
|
||
#define PIN_ACK 9 | ||
|
||
#define ID_LO 0x41 | ||
#define ID_HI 0x5A | ||
|
||
#define R_PRESSED 0b11111011 | ||
#define L_PRESSED 0b11111110 | ||
#define NO_PRESSED 0xff | ||
#define SEND_ACK 0b100000000 | ||
|
||
|
||
uint smReadCmd; | ||
uint smSendAck; | ||
uint smWriteDat; | ||
|
||
|
||
void pio0_irq0() { | ||
/* SEL has gone high, reset ISR of smReadCmd (could contain garbage) before it goes low again*/ | ||
pio_sm_restart(pio0, smReadCmd); | ||
irq_clear(PIO0_IRQ_0); // clear IRQ flag | ||
pio_interrupt_clear(pio0, 0); | ||
} | ||
|
||
void process_joy_req(PIO pio) { | ||
sendAck(pio); // acknowledge top command | ||
|
||
uint32_t next_byte = 0; | ||
sendByte(pio, smWriteDat, ID_LO); // write lower ID byte | ||
|
||
next_byte = pio_sm_get_blocking(pio, smReadCmd) >> 24; // shift to get MSB | ||
if(next_byte != 0x42) { | ||
printf("\nWaiting for %.2x but received %.2x\n", 0x42, next_byte); | ||
return; | ||
} else { | ||
printf("%.2x ", next_byte); | ||
} | ||
sendAck(pio); | ||
sendByte(pio, smWriteDat, ID_HI); // write upper ID byte | ||
|
||
next_byte = pio_sm_get_blocking(pio, smReadCmd) >> 24; // shift to get MSB | ||
if(next_byte != 0x00) { | ||
printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); | ||
return; | ||
} else { | ||
printf("%.2x ", next_byte); | ||
} | ||
sendAck(pio); | ||
sendByte(pio, smWriteDat, R_PRESSED); // fake right d-pad being pressed | ||
|
||
next_byte = pio_sm_get_blocking(pio, smReadCmd) >> 24; // shift to get MSB | ||
if(next_byte != 0x00) { | ||
printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); | ||
return; | ||
} else { | ||
printf("%.2x ", next_byte); | ||
} | ||
sendAck(pio); | ||
sendByte(pio, smWriteDat, NO_PRESSED); // other buttons are all inactive | ||
|
||
next_byte = pio_sm_get_blocking(pio, smReadCmd) >> 24; // shift to get MSB | ||
if(next_byte != 0x00) { | ||
printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); | ||
return; | ||
} else { | ||
printf("%.2x ", next_byte); | ||
} | ||
// no ack and no send, transmission is over | ||
} | ||
|
||
int main() { | ||
stdio_init_all(); | ||
PIO pio = pio0; | ||
|
||
uint offsetReadCmd = pio_add_program(pio, &readCmd_program); | ||
uint offsetSendAck = pio_add_program(pio, &sendAck_program); | ||
uint offsetWriteDat = pio_add_program(pio, &writeDat_program); | ||
|
||
smReadCmd = pio_claim_unused_sm(pio, true); | ||
smSendAck = pio_claim_unused_sm(pio, true); | ||
smWriteDat = pio_claim_unused_sm(pio, true); | ||
|
||
sendAck_program_init(pio, smSendAck, offsetSendAck, PIN_ACK); | ||
writeDat_program_init(pio, smWriteDat, offsetWriteDat, PIN_DAT, PIN_SEL); | ||
readCmd_program_init(pio, smReadCmd, offsetReadCmd, PIN_CMD); | ||
|
||
/* | ||
selMonitor_program_init(pio, smSelMonitor, offsetSelMonitor, PIN_SEL); | ||
irq_set_exclusive_handler(PIO0_IRQ_0, pio0_irq0); | ||
pio_set_irq0_source_enabled(pio, pis_interrupt0, true); | ||
irq_set_enabled(PIO0_IRQ_0, true); | ||
*/ | ||
|
||
/* | ||
uint32_t i = 0; | ||
while(true) { | ||
if(i % 1000000 == 0) { | ||
sendAck(pio); | ||
} | ||
i++; | ||
} | ||
*/ | ||
|
||
//printf("\nSetup done, starting loop...\n"); | ||
|
||
pio_sm_set_enabled(pio, smReadCmd, true); | ||
while(true) { | ||
uint32_t item = pio_sm_get_blocking(pio, smReadCmd); | ||
item >>= 24; // shift to get MSB | ||
|
||
/* PRINT CMD RECEIVED */ | ||
printf("\n%.2x ", item); | ||
|
||
if(item == 0x01) | ||
process_joy_req(pio); | ||
|
||
} | ||
} |