From d5b5c8af589319054e42097f96baac0457ba96fa Mon Sep 17 00:00:00 2001 From: Kevin Santo Cappuccio Date: Tue, 29 Aug 2023 20:38:43 -0700 Subject: [PATCH 1/4] Update README.md with how I control the CH446Qs --- JumperlessNano/README.md | 249 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 247 insertions(+), 2 deletions(-) diff --git a/JumperlessNano/README.md b/JumperlessNano/README.md index 6772c39..16babd0 100644 --- a/JumperlessNano/README.md +++ b/JumperlessNano/README.md @@ -276,7 +276,7 @@ Index Name Number Nodes Bridges 17 Net 17 17 9,8 {9-8} ``` -## Pathfinding +# Pathfinding This is the *really* tricky part. I probably wrote all this code about 4 times, trashed it and started over from scratch with only the lessons learned from the last attempt. Earlier versions would add connections one at a time, but you'd end up in weird states because it has no knowledge of what other paths it needs to make room for. So the final version here clears the connections from the last update, takes in all the connections to be made, and finds paths for the whole board every time you add a new wire. All the old connections usually follow the same paths as last time unless they need to be nudged over to make room for some other path, and the actual connection won't be interrupted at all. @@ -615,7 +615,252 @@ path net node1 type chip0 x0 y0 node2 type chip1 x ``` - +# Part 3 - Controlling the Crosspoint Switches + + +## What crosspoint switches crave +Okay, so now we have all our paths filled out with what chips need to have which X and Y inputs connected to make the magic happen. + +The CH446Qs are basically clones of the MT8816, except for one important difference, they accept serial addressing. The datasheet is kinda vague about how, but it turns out it's just a kinda weird version of SPI. +![Screenshot 2023-08-29 at 7 18 05 PM](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/b2d8d286-f4ab-4744-9115-da5f1b8976bd) + + +Basically, all the chips see the same data signal, and whichever one sees a pulse on the STB when the last bit comes in will connect or disconnect the selected X and Y inputs. The state of the DAT line when the Strobe comes in determines whether it's connecting or disconnecting. That stretched out clock line shows that it doesn't care about real time, which comes in handy. + +## PIO State Machine +So I have to do something that's kinda like SPI but not quite, this looks like a job for the RP2040 PIO State Machines. + +Even knowing assembly, the learning curve for writing a PIO program is steep. The documentation is really hit-or-miss, the examples are uncommented and written like they're playing code golf, insanely terse. Like these people do realize you can name variables after what they do, right? And these are the Official examples in the datasheet. Anyway after a few days of staring at what looks like gibberish, it starts to click. + +I copied the SPI.pio example and edited it from there. Let me try to explain some of the things I learned to hopefully make it easier for you to write a PIO program in the future. + +I'm just compiling this with the online pioasm compiler and then pasting the compiled code into spi.pio.h + +https://wokwi.com/tools/pioasm + +Here's where we are: +![start](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/7fc8357f-2b50-4341-9832-10d94d4cb595) + + + +;this is basically spi but it sets a system IRQ on the last bit to allow the chip select pulse to happen + + +``` +.program spi_ch446_multi_cs +.side_set 1 + +.wrap_target +bitloop: + + out pins, 1 side 0x0 [2] + + nop side 0x1 [2] + + jmp x-- bitloop side 0x1 + + out pins, 1 side 0x1 + + mov x, y side 0x1 + + irq 0 side 0x1 + + wait 0 irq 0 rel side 0x1 + + jmp !osre bitloop side 0x0 + +public entry_point: ; Must set X,Y to n-2 before starting! + + + pull ifempty side 0x0 [1] ; Block with CSn high (minimum 2 cycles) + + nop side 0x0 [1]; CSn front porch + + +.wrap + +``` +What wasn't explained well is what the hell a sideset pin is. Basically you do your normal-ish assembly code on the left, and then each operation also affects the sideset pin on the right. It's kind of a hack to allow you to control 2 pins in a single clock cycle. In this case, the sideset pin is attached to the CLK, and pins, 1 is DAT. + +So, whats going on is that in the regular code, I'm sending a byte to the sm register with this line + +pio_sm_put(pio, sm, chAddress); +(the last bit of chAddress is set to 1 or 0 depending if I want to connect or disconnect) + +and that pull ifempty will pull in a byte to the working register and send it out one bit at a time while toggling the clock. When it's out of data to send, it triggers a system interrupt request that can be seen outside of the PIO state machine and I deal with it in an ISR in CH446Q.cpp + +At this point, here's where we are in the timing diagram: + +![IRG](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/92b8b1f4-fae2-453b-b174-3a69154230d1) + +Now we need to select the correct CS line to make the right chip make the connection +``` +void isrFromPio(void) +{ + switch (chipSelect) + { + case CHIP_A: + { + digitalWriteFast(CS_A, HIGH); + break; + } + case CHIP_B: + { + digitalWriteFast(CS_B, HIGH); + break; + } + case CHIP_C: + { + digitalWriteFast(CS_C, HIGH); + break; + } + case CHIP_D: + { + digitalWriteFast(CS_D, HIGH); + break; + } + case CHIP_E: + { + digitalWriteFast(CS_E, HIGH); + break; + } + case CHIP_F: + { + digitalWriteFast(CS_F, HIGH); + break; + } + case CHIP_G: + { + digitalWriteFast(CS_G, HIGH); + break; + } + case CHIP_H: + { + digitalWriteFast(CS_H, HIGH); + break; + } + case CHIP_I: + { + digitalWriteFast(CS_I, HIGH); + break; + } + case CHIP_J: + { + digitalWriteFast(CS_J, HIGH); + break; + } + case CHIP_K: + { + digitalWriteFast(CS_K, HIGH); + break; + } + case CHIP_L: + { + digitalWriteFast(CS_L, HIGH); + break; + } + } + + +``` +![csHigh](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/95b52b1f-7d4a-4ab9-9eb4-9ff492b6118f) + +``` +delayMicroseconds(1); +``` +![csLow](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/a4529b4c-401f-464a-a9dd-03701ef6b916) +``` + digitalWriteFast(CS_A, LOW); + digitalWriteFast(CS_B, LOW); + digitalWriteFast(CS_C, LOW); + digitalWriteFast(CS_D, LOW); + digitalWriteFast(CS_E, LOW); + digitalWriteFast(CS_F, LOW); + digitalWriteFast(CS_G, LOW); + + digitalWriteFast(CS_H, LOW); + digitalWriteFast(CS_I, LOW); + digitalWriteFast(CS_J, LOW); + digitalWriteFast(CS_K, LOW); + digitalWriteFast(CS_L, LOW); + + irq_flags = pio0_hw->irq; + pio_interrupt_clear(pio, PIO0_IRQ_0); + hw_clear_bits(&pio0_hw->irq, irq_flags);//clears the IRQ + +} +``` +The reason I had to do it in an external interrupt instead of in the PIO code is because there's a limit to how many pins can be attached to a single state machine, 8. And this is just way easier to do. + +## The C +This all runs on the second core just so it can stay somewhat timing sensitive while not worrying about what's going on elsewhere. How this process is triggered is that when the pathfinding algorithm is finished running in core 0, it sets +``` +volatile int sendAllPathsCore2 = 1; // this signals the core 2 to send all the paths to the CH446Q +``` +Then in loop1, is just constantly checks if that's a 1 and will send the paths and set it back to 0. Just a reminder that the cores on an RP2040 share global variables, because it's very useful. + +Here's what the SendAllPaths() functions look like. +``` +void sendAllPaths(void) // should we sort them by chip? for now, no +{ + + for (int i = 0; i < numberOfPaths; i++) + { + sendPath(i, 1); + } + +} + +void sendPath(int i, int setOrClear) +{ + + uint32_t chAddress = 0; + + int chipToConnect = 0; + int chYdata = 0; + int chXdata = 0; + + for (int chip = 0; chip < 4; chip++) + { + if (path[i].chip[chip] != -1) + { + chipSelect = path[i].chip[chip]; + + chipToConnect = path[i].chip[chip]; + + chYdata = path[i].y[chip]; + chXdata = path[i].x[chip]; + + chYdata = chYdata << 5; + chYdata = chYdata & 0b11100000; + + chXdata = chXdata << 1; + chXdata = chXdata & 0b00011110; + + chAddress = chYdata | chXdata; + + if (setOrClear == 1) + { + chAddress = chAddress | 0b00000001; // this last bit determines whether we set or unset the path + } + + chAddress = chAddress << 24; + + // delayMicroseconds(50); + + delayMicroseconds(30); + + pio_sm_put(pio, sm, chAddress); + + delayMicroseconds(40); + //} + } + } +} +``` +The whole process to connect the whole board takes a couple milliseconds at most. But you can shave down these delays if you have some reason to go faster. + +## To be continued in part 4 - LEDs From 5aa6bf2521d0fe91734e35a8ab8c86a409115d37 Mon Sep 17 00:00:00 2001 From: Kevin Santo Cappuccio Date: Tue, 29 Aug 2023 20:39:42 -0700 Subject: [PATCH 2/4] Update README.md --- JumperlessNano/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JumperlessNano/README.md b/JumperlessNano/README.md index 16babd0..d86417a 100644 --- a/JumperlessNano/README.md +++ b/JumperlessNano/README.md @@ -615,7 +615,7 @@ path net node1 type chip0 x0 y0 node2 type chip1 x ``` -# Part 3 - Controlling the Crosspoint Switches +# Controlling the Crosspoint Switches ## What crosspoint switches crave From 6e11e6ced07a3e640453483b7980a5bcf3658f08 Mon Sep 17 00:00:00 2001 From: Kevin Santo Cappuccio Date: Tue, 29 Aug 2023 20:44:57 -0700 Subject: [PATCH 3/4] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index b236884..252fd33 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,11 @@ The connections are real and fully analog (-8V to +8V, up to around 1 MHz before https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/2c203686-e02e-4a0c-b5eb-0cab925386fb + +### If you want to read about how the code and stuff works, [the README in JumperlessNano](https://github.com/Architeuthis-Flux/Jumperless/tree/main/JumperlessNano) goes through how each part works in more detail. + +### Or check out the [Hackaday.io page](https://hackaday.io/project/191238-jumperless) and the [Hackaday Blog Writeup](https://hackaday.com/2023/08/25/hackaday-prize-2023-jumperless-the-jumperless-jumperboard/) + And no, it's not an FPGA. ![IMG_3827](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/963cac46-b46d-4c64-a201-00305d2d0bbc) From 2588259253a0ab1a4fd42eab9a5292adbc02cc35 Mon Sep 17 00:00:00 2001 From: Kevin Santo Cappuccio Date: Wed, 6 Sep 2023 11:07:46 -0700 Subject: [PATCH 4/4] Create Getting Started.md --- Getting Started.md | 240 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 Getting Started.md diff --git a/Getting Started.md b/Getting Started.md new file mode 100644 index 0000000..d4a08de --- /dev/null +++ b/Getting Started.md @@ -0,0 +1,240 @@ +

Cool, so you have this super sexy object now. How do turn it into an actual prototyping tool? The answer is software. 

+ + +

After you've unboxed (and maybe assembled) your Jumperless, we're going to need a way to talk to it. 

+ + +

Now, the Jumperless is very open and will accept netlists from any program with some basic formatting, if you hate Wokwi and want to use something else, this project log should give you an idea of what format it accepts over serial so you can write your own Bridge to any software you like. But for now, I'm focusing on Wokwi because I think it's better to have solid support for one workflow than shitty support for a bunch.

+ + +

First, we need to download the App and latest firmware here.

+ +

Updating The Firmware

+ + +

I ship these with the latest firmware installed, so if you just received your Jumperless in the mail, you can skip the firmware update. But I usually push minor fixes to that firmware.uf2 file every few days, so it's probably worth doing anyway.

+ + +

+ +

On your Jumperless, there will be a little button on the opposite side of the USB port. This is the USB Boot button and works exactly the same as a Raspberry Pi Pico.  

+ +
+ +

1. Hold the USB Boot button and plug the Jumperless into your computer. 

+ + +
+ + +
+ + +

2. A drive should pop up called RPI-RP2. Drag the firmware.uf2 file into it and it should reset and you're done!

+ +
+ + +

Installing the App

+ + +

I'm showing this on a fresh install of macOS, but Windows should be roughly the same.

+ + +

1. On the releases page, download JumperlessWokwiBridgeMacOS.zip (or the .exe for windows) and firmware.uf2

+ + +
+ + +
+ + +

2. It should automatically unzip in your downloads folder. Note that this won't run correctly from anywhere but your Applications folder, so drag it there.

+ + +
+ + +

3. Click it to try to run it. Unless you've set your security setting to allow apps from anywhere, it's going to complain.

+ + +
+ + +

4. Click Cancel and go to  Settings > Privacy and Security > scroll down and click Open Anyway

+ + +
+ + +

5. It's going to complain again and just click Open

+ + +
+ + +

Hot tip: run 

+ + +
sudo spctl --master-disable
+ + +

in Terminal to give you another checkbox for Anywhere under Settings > Privacy and Security > Allow Apps From. And you won't have to go through this again for other shoddy software.

+ + +
+ + +

6. If everything goes well, you should now be presented with a Terminal window like this

+ + +
+ + +

Note that on MacOS, it should just autodetect and connect to the Jumperless if it's plugged in when you start the app, if not, just plug it in and type 'r' to rescan the ports until it finds it. 

+ + +

Okay, now the app is set up, what do we paste into there to connect to our Wokwi project?

+ + +

Getting Wokwi Set Up

+ + +

You'll need a stable link to your Wokwi project, and it will only make one when you're signed in and have saved your project to "My Projects". After that the links are saved in a text file in the JumperlessWokwiBridge app and you'll be able to select projects you've used before from a list.

+ + +
  1. Go to wokwi.com + + +Screenshot 2023-09-05 at 2.53.39 PM
  2. + + + Click Sign Up/Sign In and enter your email (or use Google or Github) + +Screenshot 2023-09-05 at 2.54.14 PM
  3. + + + Click the link they email you to sign in + + +Screenshot 2023-09-05 at 2.54.36 PM
    Screenshot 2023-09-05 at 2.54.57 PM
  4. + + + Click Go To Your Projects, then New Project > Arduino Nano + +Screenshot 2023-09-05 at 2.55.08 PM
    Screenshot 2023-09-05 at 2.55.13 PM
    Screenshot 2023-09-05 at 2.55.20 PM
  5. + + + Click Save and give your project a name + + +Screenshot 2023-09-05 at 2.55.38 PM
    Screenshot 2023-09-05 at 2.55.47 PM  + +(note that the URL has now changed to a unique link)
  6. + + + +Click blue “+” (top center) to Add New Part and scroll down to Half Breadboard and click it + + + +Screenshot 2023-09-05 at 3.10.47 PM
    Screenshot 2023-09-05 at 3.11.02 PM   + +It will put it somewhere random, so click somewhere that’s not a hole to drag it. + + + +Screenshot 2023-09-05 at 3.11.07 PM
  7. + + +Open the JumperlessWokwiBridge App and resize the windows so you can see both + + + +Screenshot 2023-09-05 at 2.56.14 PM
    Screenshot 2023-09-05 at 2.58.03 PM +(on mac it will autodetect the port if it’s plugged in, on windows you’ll need to select the COM port here first, if the Jumperless wasn’t connected when you opened the app, press ‘r’ the Enter to rescan the ports)
  8. + + +Copy the URL of the Wokwi project you just made + +Screenshot 2023-09-05 at 2.58.12 PM
  9. + + +Paste that URL into the Bridge App window and press Enter + + +Screenshot 2023-09-05 at 2.58.29 PM
    Screenshot 2023-09-05 at 2.58.34 PM
  10. + + +Name the project and hit Enter (it will save the link so next time you’ll only need to choose it from a list by entering the number) + +Screenshot 2023-09-05 at 2.58.46 PM
  11. + +Now draw some wires on Wokwi by clicking a hole on the breadboard and dragging the wire to somewhere else + + +Screenshot 2023-09-05 at 2.59.10 PM
  12. + +As soon as you press Save, the changes you made to the Wokwi project should show up on the Jumperless and you should be ready to start prototyping like a future person + +Screenshot 2023-09-05 at 2.59.22 PM
+ + + + +

Extra Tips for using Jumperless like a Pro

+ +

Here are some non-steps but more general tips:

+ +

Debug Flags

+ + +
  • If your Bridge app’s terminal is full of a bunch of debugging stuff, you should probably turn the debug flags off until you want to see a particular thing. Sending that much data over serial can occasionally cause the serial drivers to trip over themselves. Here’s how to turn those off:
+ + +
  1. From the main Menu (which it defaults to unless you’re in a sub menu,) type ‘d’ then Enter to go to the “toggle debug flags” menu. + + + Screenshot 2023-09-05 at 3.25.54 PM
    Screenshot 2023-09-05 at 3.26.06 PM
  2. Type ‘0’ then Enter to turn them all off. Then ‘m’ and Enter to return to the main Menu +Screenshot 2023-09-05 at 3.26.27 PM
+ +

+ +

App Menu

+ + +
  • If you want to do things that pertain to the Jumperless Wokwi Bridge App itself, type “menu” and then Enter (Note: after the part where you enter the Wokwi project link and choose a port, all this output you’re seeing is from the Jumperless’s onboard RP2040, and the Bridge app is just acting like the Serial Monitor from Arduino) +Screenshot 2023-09-05 at 3.38.56 PM
+ +

Using the DACs and ADCs

+ +
  • To use the DACs, you’ll need to add 2 potentiometers to your Wokwi project and connect the Signal (center) pin to where you want it connected on the board. DAC 0 0-5V will be pot1 and DAC 1 ±8V will be pot2.
+ + +
  1. Blue “+” to Add New Part > scroll down to Potentiometer (the linear Potentiometer will work too if you prefer) and click it +Screenshot 2023-09-05 at 3.46.51 PM
    Screenshot 2023-09-05 at 3.47.00 PM
    Screenshot 2023-09-05 at 3.47.10 PM
    Screenshot 2023-09-05 at 3.47.41 PM
  2. If you want the brightness and hue to track the voltage for DAC 1 ±8V, you’ll need to connect ADC3 (±8V scaled) to the same pin as DAC 1. ADC 0-3 are mapped to a Logic Analyzer pins 0-3 in Wokwi, I haven’t come up with a good way display the readings and I’m open to suggestions for how to show them without making the serial output a total mess. But in the code, AnalogRead(26,27,28, or 29) will work as expected, scaled to 0-5V for ADC 0-2 and ±8V for ADC 3. Anyway, here’s how to connect them: + +Add New Part > Logic Analyzer (8 channels) + +Screenshot 2023-09-05 at 3.59.02 PM
    Screenshot 2023-09-05 at 3.59.57 PM + + Connect D3 (ADC 3) to the same breadboard row as pot2:Sig (DAC 1) and the brightness will track the output. + +Screenshot 2023-09-05 at 4.00.24 PM  + + (Note: the pins are numbered the same as the ADCs, so D0 = ADC0 (pin 26), D1 = ADC1 (pin 27), etc.)
  3. To control the DACs, enter Wavegen from the main Menu by typing ‘w’ +Screenshot 2023-09-05 at 4.05.12 PM
  4. + Enter 5 or 8 twice to turn on the 0-5V or the ±8V DAC. The first time you enter it, it won’t turn it on so you can change the settings before you start it to avoid frying things. + +Screenshot 2023-09-05 at 4.08.49 PM
  5. +When you type ‘a’ or ‘o’ to change the Amplitude or Offset respectively, it expects numbers in the format ‘3.0’. It will wait for you to enter a decimal and then a number. +![Screenshot 2023-09-05 at 4 11 58 PM](https://github.com/Architeuthis-Flux/Jumperless/assets/20519442/444aadd6-8896-4d3d-857e-41bca201c80d) + + + + + +

    I’ll add more tricks as I think of them. If you have any questions about how to use any particular thing, or suggestions for things to work on supporting, let me know.

    + +

    You can email me at KevinC@ppucc.io or message me through any channel you prefer.