summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHombreLaser <buran@silosneeded.com>2025-04-12 22:54:46 -0600
committerHombreLaser <buran@silosneeded.com>2025-04-12 22:54:46 -0600
commit31c0d30b4ae6da18a77579a14250d24eea244579 (patch)
tree0ebd70561f9058aacc2c4497524b48ee4bf86b65
parentb83696f7361018991b7580a52cf31ea4059392de (diff)
Add pico shock devlog #2
-rw-r--r--_posts/en/2025-04-12-picoshock_devlog_2.md240
-rw-r--r--assets/images/2025/minicom_2.pngbin0 -> 40596 bytes
2 files changed, 240 insertions, 0 deletions
diff --git a/_posts/en/2025-04-12-picoshock_devlog_2.md b/_posts/en/2025-04-12-picoshock_devlog_2.md
new file mode 100644
index 0000000..0a35c91
--- /dev/null
+++ b/_posts/en/2025-04-12-picoshock_devlog_2.md
@@ -0,0 +1,240 @@
+---
+layout: post
+title: "PicoShock Devlog #2"
+lang: en
+date: 2025-04-12
+tags: ["Programming", "PicoShock"]
+---
+
+These last couple of weeks I've kept my work on picoshock somewhat consistent, and I've also learnt a lot, really.
+
+For starters, my first log entry was filled to the brim with mistakes, some pretty dumb ones, too:
+
+- I didn't even start the PIO program.
+- I used `pio_sm_get` instead of `pio_sm_get_blocking`: the difference between the two is that the second
+ one waits for the RX FIFO to actually have some data to read. The first one, when the FIFO is empty,
+ has undefined behavior. That explains the readings I was getting: the program didn't even start and as such,
+ the FIFO wasn't getting filled.
+- The folks at the [raspberry pi forum](https://forums.raspberrypi.com/viewtopic.php?p=2309324) explained to me
+ the nuances of clock frequencies in PIO programs: although it can be the case that I want a precise clock frequency
+ matching that of the device I wish to interface (I'll have to do this when implementing the console mode), it sometimes is
+ not, and it's better to actually set the frequency higher.
+
+So the days I've been working on pico shock I've had a single goal: receive coherent data, as per the dualshock protocol.
+I've implemented the clock and acknowledge signals, too. So now, my PIO program looks like this:
+
+```asm
+.program dualshock
+.side_set 1
+
+wait 0 pin 2 side 1 ;; Wait for clock to go low, pull ACK high.
+.wrap_target
+wait_for_att:
+ set x, 8 side 1 ;; Set bit counter: we want to read a byte.
+ wait 0 pin 1 side 1 ;; Wait for ATT. PS2 wants to tell us something.
+
+read_loop:
+ wait 0 pin 2 side 1 ;; When clock drops from low to high,
+ wait 1 pin 2 side 1 ;; read the values.
+ in pins, 1 side 1 ;; Read the bit sent by the PS2.
+ jmp x-- read_loop side 1 ;; Decrement bit counter.
+
+acknowledge:
+ push [15] side 1 ;; We've read a byte, wait for 12us before pulling ACK low.
+ nop [14] side 1
+ nop side 0 [5] ;; Pull ACK low.
+.wrap
+
+% c-sdk {
+ void dualshock_program_init(PIO pio, uint sm, uint offset, uint command_pin, uint data_pin, uint ack_pin) {
+ pio_sm_config cfg = dualshock_program_get_default_config(offset);
+
+ sm_config_set_in_pins(&cfg, command_pin);
+ pio_sm_set_consecutive_pindirs(pio, sm, ack_pin, 1, false);
+ sm_config_set_out_pins(&cfg, data_pin, 1);
+ sm_config_set_sideset_pins(&cfg, ack_pin);
+ sm_config_set_in_shift(&cfg, true, false, 8);
+ sm_config_set_clkdiv_int_frac(&cfg, 50, 0);
+ pio_gpio_init(pio, ack_pin);
+ pio_sm_init(pio, sm, offset, &cfg);
+ }
+%}
+```
+
+It has grown quite a bit.
+
+As per my understanding, `sm_config_set_in_pins(&cfg, command_pin)` sets both the pin and its 5 consecutive ones as input pins.
+The pin you pass as an argument is called the base pin. As such, following the command pin I wired the clock and after that,
+the attention pins. I could be wrong here, too, but, for example, to wait on a pin other than the command, you refer to
+your pin with its bitmask. For example, `0b00000` is a 5 bit number. The first refers to the base, the second to the next one,
+etc. But, I have my doubts on this: in wait instructions, for example, if you write `wait 0 pin 0` you're waiting for your
+base pin to pull low... I think.
+
+As the pin following the command one is the ATT pin, that's my pin 1, and clock is my pin 2. So, I hope that:
+
+```asm
+wait 0 pin 2
+```
+
+Means that I'm waiting for my clock to pull low.
+
+I've implemented ACK as a side set pin: it's normally set high, but after reading a byte, I must wait 12us and then pull it low
+for (half, I'm still not sure how I will do that, meanwhile I'll try for a full PS2 clock cycle) a clock cycle.
+
+I'm also reading a single bit with every `in` instruction, as the playstation 2 pulls the clock low and then high and after that,
+sends a bit.
+
+# Frequencies
+
+If you've read my thread in the forum you probably know by now what I mean by me using the clock divider feature wrong. It wasn't
+actually because I wasn't setting the frequency I intended to (500 KHz) but because in reality I want to set it higher. So:
+`sm_config_set_clkdiv_int_frac(&cfg, 250, 0)` became `sm_config_set_clkdiv_int_frac(&cfg, 50, 0)`. I'm now setting the PIO frequency
+as, hopefully, 2.5 MHz. This means that `nop side 0`, the instruction that pulls ACK low, is wrong. As 2.5 MHz is 5 times faster
+than 500 KHz, so, this instruction should be `nop side 0 [5]` instead. 5 cycles for us is a cycle for the PS2.
+
+# What has changed?
+
+Well, now it seems I'm actually getting something out of the PS2, kind of. The printf sentence of my C program prints
+the number 800000 endlessly, which is off by 23 bits to the right (oh, yes, I want the ISR FIFO to shift to the right,
+I thought that LSB protocols shifted it to the left. Another one of the countless silly mistakes of my first post).
+The number I'm actually looking for is 1. Or 0x01 in hex notation.
+
+# What comes next
+
+Well, now that I've set up the state machine's frequency right, and receiving something that looks like relevant data, I
+now have to prove my hypothesis: should I shift everything I receive from the PS2 23 bits to the right to make sense of it?
+For this, I'll implement the data (out) pin, send something, and see if the number the PS2 sends me as a response is different
+from 800000. If it is, I'll shift that 23 bits to the right and see if it coincides with the protocol.
+
+Until next time! This is the hard part: after this, it probably won't be a walk in the park but I'm pretty certain the C portion of
+the library won't be that hard to write.
+
+# Another update
+
+Well, I was planning to post this on saturday, but I forgot, and when I had some free time to keep working on this, well, let's say
+I've made some progress.
+
+## Updates to dualshock.pio
+
+First, another fix to my pio program:
+
+```asm
+;; Before
+wait_for_att:
+ set x, 8 side 1 ;; Set bit counter: we want to read a byte.
+
+;; After
+ wait_for_att:
+ set x, 7 side 1
+```
+
+It seems that me making stupid mistakes is a constant on this, oh well. Don't be too harsh on me.
+
+I also implemented the data bus in pio:
+
+```asm
+.program dualshock_data
+
+.wrap_target
+wait_for_output:
+ jmp !osre wait_for_att ;; Stall while we don't have data to output
+ jmp wait_for_output
+
+wait_for_att:
+ set x, 7 ;; Set bit counter: we want to send a byte.
+ wait 0 pin 0 ;; Wait for ATT.
+
+out_loop:
+ wait 0 pin 1 ;; When clock drops from low to high,
+ wait 1 pin 1 ;; send our data.
+ out pins, 1 ;; Read the bit sent by the PS2.
+ jmp x-- out_loop ;; Decrement bit counter.
+.wrap
+
+% c-sdk {
+ void dualshock_data_program_init(PIO pio, uint sm, uint offset, uint data_pin,
+ uint att_pin) {
+ pio_sm_config cfg = dualshock_data_program_get_default_config(offset);
+
+ sm_config_set_in_pins(&cfg, att_pin);
+ sm_config_set_out_pins(&cfg, data_pin, 1);
+ sm_config_set_out_shift(&cfg, true, true, 8);
+ sm_config_set_clkdiv_int_frac(&cfg, 50, 0);
+ pio_sm_init(pio, sm, offset, &cfg);
+ }
+%}
+```
+
+Yes, a shameful copy paste of what I already had for the command pin, but ignoring acknowledge and using out instead of in.
+
+## Updates to the main loop
+
+Well, now I have access to a data bus, now I'm actually reading a byte, let's see what we get:
+
+```bash
+# Trust me, this is what minicom was printing, but I didn't take a screenshot,
+# and I'm still not using version control so I don't want to revert anything I have.
+# We'll see what's new on the C program shortly.
+1000000
+1000000
+1000000
+# etc...
+```
+
+Well, that's an interesting number. More interesting than 800000, that's for sure.
+
+Let's write this number in binary:
+`0000 0001 0000 0000 0000 0000 0000 0000`
+
+Huh. Interesting... We're waiting a 1, this is by no means a one... but, if we shift it 24 bits to the
+right... it is. So I told myself, well, I'm getting a 1, sort of. If I send data to the PS2 and if when
+shifting its responses 24 bits to the right we get the numbers we're expecting... that would
+mean I'm now getting the right numbers from the PS2, So that's what we're going to do:
+
+```c
+int main() {
+// PIO configuration, etc. You know the drill.
+
+ // We don't want to read weird values on the first loop.
+ uint32_t data = 0xff;
+
+ while (true) {
+ //sleep_ms(1000);
+
+ if ((data >> 24) == 0x01)
+ pio_sm_put_blocking(data_pio, data_sm, 0xff);
+
+ if ((data >> 24) == 0x42)
+ pio_sm_put_blocking(data_pio, data_sm, 0x41);
+
+ if ((data >> 24) == 0x00)
+ pio_sm_put_blocking(data_pio, data_sm, 0x5a);
+
+ data = pio_sm_get_blocking(pio, sm);
+
+ printf("%x\n", data);
+ }
+}
+```
+
+This is a rather crude pattern matching, I know. I got rid of the sleep directive to print more precise numbers to the
+console. Yes, they're going to be printed really fast in succession, but they would be a more accurate representation of this
+loop. And it's nothing that scrolling the terminal up can't fix.
+
+![Minicom screenshot](/assets/images/2025/minicom_2.png)
+
+Well... those numbers seem pretty familiar. According to the [Curious Inventor guide](https://store.curiousinventor.com/guides/PS2),
+this back and forth communication with the PS2 should look like this:
+
+|Byte # | 1| 2| 3| 4| 5|
+|-------|----|----|----|----|----|
+|Command|0x01|0x42|0x00|0x00|0x00|
+|-------|----|----|----|----|----|
+|Data |0xff|0x41|0x5a|0xff|0xff|
+
+Well, minus the last 2 data bytes which we're not sending (we're matching 0x00 with 0x5a) all of the command bytes are exactly these,
+when shifted 24 bits to the right, of course. This means that everything I read from the RX FIFO must be shifted 24 bits to the
+right, no biggie.
+
+Well, I'm pretty stoked. And this means that now comes the boring part: parsing all those bytes and sending appropriate responses.
+So exciting.
diff --git a/assets/images/2025/minicom_2.png b/assets/images/2025/minicom_2.png
new file mode 100644
index 0000000..9d59b4e
--- /dev/null
+++ b/assets/images/2025/minicom_2.png
Binary files differ