XpandShield MK II

Both the 74HC589 and 74HC165 can be cascaded, so they will appear as one 16 bit device when read. Both the 74HC589 and 74HC165 can be attached using SPI, so no bit banging is necessary for either of them. With cascading two of either, they will require two SPI reads not 8 or 16 steps.

There would be no advantage or reason to wire in parallel, you should cascade when using more than one. As I said above, if you attach using SPI you only need two SPI read operations, not 16 bit bang reads.

1 Like

exactly. SPI is much much faster.
But before I … wait.

(reads datasheet)

Ok. Assume this:
I send a bunch of commands and data to the OLED, but while I do this I pull “clock inhibit” high (so they ignores the clock). Then I deselect OLED, pull SH/LD high (so it shifts data and stop loading), pull “clock inhibit” low, and reads it from HC165. Or a daisy-chained set of HC165.

Will the above execute correctly as I expected? Or, will I, say, mess up some stuff (and return empty handed)?

Yes, you treat CLK INH as your SPI chip select (CS) and you have a separate CS signal for your OLED. You pull CLK INH low when you want to read from the 165 and pull the OLED CS low when you want to send commands or data to the OLED.

The 165 CLK pin is SPI CLK. QH is SPI MISO.

If you have another digital output to spare, it goes to SH/LD. You pull it low when you want to load the state of the buttons into the shift register and pull it high when reading the register using SPI.

SH/LD can always be the opposite of CLK INH so instead of a digital output you can use an inverter from CLK INH to SH/LD. It depends on whether you have an available output or want to add an inverter.

For chained chips you connect SH/LD, CLK INH and CLK of the chips together. QH of one chip goes to SER of the next (and the last chip’s QH is SPI MISO). You can chain as many chips as you want this way.

Another option is to just tie CLK INH permanently low and use SH/LD as your SPI CS. Doing this means your CS is pulled high to enable SPI reading, which is the opposite of what’s normal. This doesn’t matter much if you’re controlling it as a GPIO line.

If you want to get a bit fancier and save a digital output pin, you can just tie the OLED CS and SH/LD to one output pin. When this pin is low the OLED is selected (and button states are loaded into the 165) and when high the 165 is selected.

Thanks for validating my ideas.
(irrelevant: so why do we need the HC589 for)?

Anyhow, I ordered 5 pcs of 165. I’ll probably rig it up to a SOP-DIP converter and run some breadboard experiment.

As I said above, the 589 has a tri-state output (it can be put in high impedance state). This would be required if you had more that just the shift register on the MISO input. Otherwise it would conflict with any other device using MISO on the same SPI bus. You can’t have more than one output driving MISO and any given time.

Since with your current design the 165 is the only thing on MISO (and only the OLED is on MOSI) there is nothing sharing the line, so a tri-state output isn’t required. If you decided to add another device that needed to send data on MISO, using a 589 would be a better choice.

Making a breadboard prototype is always a good plan.

1 Like

The wiring for this would be:

(DIGITAL OUT A, B and C are each any GPIO output from the microcontroller.)

74HC165 OLED Microcontroller

* You may be able to use an RC network to reset the OLED once on power up, if you wanted to save a digital output.

SER of the last (or only) 74HC165 is tied to GND. When chaining, SER of each is connected to QH of the next.

:point_up_2: I would do that.

A usual 2D game flow is draw a frame, then read the inputs, repeat…
So it’d save one operation to have the display update also latch the buttons.

Worst case you can just toggle the OLED’s CS line and back to unselected without SPI transfer to load the 165.
The OLED won’t care.

Control over CLK INH isn’t needed.

In this scenario the 165s will constantly load the button states as long as the OLED is selected so the buttons SPI read right after a display update will be fresh button data.

I’m getting almost into janky territory buuut :innocent: with every other SPI devices having a proper tri-state you could also just use a resistor (maybe 10K) on its output to turn the 165’s output into a weak-ish pullup/pulldown.

If everything else is properly high-Z tri-stated it’ll work.

The 165’s output will be “drowned” by whatever other SPI device is actively outputting until they’re all de-selected, at which point the MCU will see the pullup/pulldown.

Resistor might need to be lowered to 1K if there’s a lot of capacitance on the line but I don’t expect that to be an issue on a tiny game controller with short traces.

Nooooo! Tie it up to VCC!
That way if you have a version with 1x 165 and one with 2x or 3x 165 the same firmware will see the excessive reads as unpressed buttons.
( Unless your buttons are pulldowns when inactive & short to +VCC )

In a production scenario I’d even consider sacrificing one bit per 165 to indicate the last one if there was the possibility of different tier models.

The fewer firmwares the better, reduces human errors and all that :stuck_out_tongue:

Being able to send the new firmware for the new model and have it also work with the old hardware still in production lets the factory flash the same file on all boards / MCUs
it’s one fewer headache.

But this is a game controller. I’m not even sure what the intent of having a display is. Probably for settings or similar. Therefore, you’re not likely to be updating the display as often as you want to read the buttons. But it doesn’t matter. You would just leave the OLED selected whenever you’re not reading the buttons, which (as you realised) results in the button state continually being echoed to the shifter register.

But the firmware will likely have to inform the USB interface about what buttons are actually physically available, so it will have to know this somehow, meaning there would be no need to simplify things by doing excessive reads for “phantom” buttons.

Tie SER to GND or VCC. It doesn’t matter. It’s just not a good idea to leave a CMOS input floating.

There’s an easy way to make it so that you can determine how many 165s are chained, through software, without needing any additional inputs for configuration.

You tie SER of the end one to GND (or whatever the level of a pressed button is), as I suggested. During initialisation, you read for the maximum number of chips that you could have chained. If you read all 8 buttons pressed for a chip, then that chip isn’t present. (It’s unlikely that a user will hold down all 8 buttons for a given chip during initialisation.)

Of course, this doesn’t work if what you’re reading isn’t all momentary push buttons. I.e. some can be “latched” to an on state. It still works if at least one is momentary and the user never presses all the momentary ones during initialisation (but why would a user do this? They’d just end up with it looking like a less capable model and have buttons that didn’t work).

However, if all the “latched” switches are common to all model tiers, you just make sure you put them on an always populated chip (or use direct inputs on the microcontroller itself for these).

Ah. Because it’s not one bit, but instead a sink or a source of logic levels. And this sink or source can mess up with anything else that is sent along the line.

The screen will supposedly be outputting the input in real time (so you can see the actual position and make adjustments if needed, like resetting the joystick center or calibrate the min/max range), or you can run “software hacks” to make your gaming experience a little bit “easier” (e,g. repeatedly press a key when you hold a key down)

I’m not sure how much impact it will be, but since we can drive the display at (mostly) 60fps on a Arduboy running a complicated game sketch, I wouldn’t think there will be too much lag.
Or, we can have a specific button (or a key combo) to bring up the display (and related features)
Or, like some DIY KSP controller, feature gauges and indicators.
Or, just write a game for it. Maybe our Choplifter game will finally have analog pitch/yaw/throttle/roll/collective/anti-torque, along with buttons for gears (and guns?) and lights.

I’m actually rather reluctant to solder even SOPs, because the “soldering wick” is a extremely recent addition to my collection (3 weeks vs 6 years), and the “solder sucker” broke (and I never see enough reason to buy a new one).
So, without any kind of solder-removal equipment, I went and soldered the SOP16.
I’ll perhaps wick it. The two pins at the top (that I soldered first) look like they are touching (but are actually not). Then I’ll pop in the pins and then wash the board.

Chances are that I will just use the two pins initially occupied by the A and B buttons.

Sounds rather neat, but I don’t want to tie the pins together.

I think, what will happen, is that I will do the wiring so the signal generated by the absence of a 165 will be equal to the signal generated by all of the buttons (that are supposed to wire to the 165) not being pressed.

Then, since THAT is said, I can make it so certain features (i.e. L2R2 trigger, C/Z buttons, center push, stick-type switch, menus) are wired to the second 165 (rather than the one wired directly to CIPO).

Actually, I think I will need three registers. But again, the above apply.

You can use just the soldering iron tip to remove the excess: wipe the tip on a wet sponge to remove almost all the solder on it then put it on the pins, it’ll suck it up but less aggressively than the copper wick which can take away too much.

And I’ve accidentally bent pins with the wick snagging on them or cooling down too quickly and sticking to one pin as I’m pulling it away. :scream:

Everyone got their tricks so whatever works for you is best :stuck_out_tongue:

I don’t see why you need more than two.

If you use a Pro Micro, and wire the way I’ve suggested, you will have:

For OLED and 165 support:

  • A single digital out for selecting either the OLED or the 165s (goes to OLED CS and SH/LD of both 165s
  • A digital out for OLED DC
  • A digital out for OLED RES. This is optional. If you wanted one more GPIO pin, you could use an RC circuit for OLED RES.

This gives 16 digital inputs on the two 165s, plus 9 ADC inputs on the Pro Micro, plus 3 GPIO on the Pro Micro. So that’s 19 digital inputs (or the 3 on the Pro Micro can be outputs). If you don’t use all 9 ADC inputs, any of them can be digital inputs or outputs.

From what you’ve said you want so far, that should be enough, unless you’ve added something else you haven’t mentioned.

P.S. If you want to allow for in-circuit serial programming (ICSP) with a fully built board, you should add a jumper of some type between the 165 QH and MISO. You would open the jumper for ICSP and close it for normal use.

I don’t have a wet sponge.

It’s quite difficult to pull off with a tiny USB 8W soldering iron.
I miss my 30W and 60W(thermo-regulated) 220V soldering iron of the old. I left it at school and someone took it, but their tips are quite unwieldy for SOPs.
I’m considering purchasing one of their soldering stations and fit it with a switching power supply instead of a power coil (so it can work from 110V-240V AC), but it’s too bulky to carry around.

Technically I can just purchase a two-prong 220V iron and plug it to 110V and it will still run. But for exactly how hot, I do not know.

Exactly. And since I had bought the solder wick, I’ll use them.

I have 13 two-lead tactile switch, 4 sideways push button, a stick-type switch (4 direction and center push) and two ThumbPointer center push.
that total 24 inputs.
I can use two registers, but then I will need to wire 8 pins somewhere.
Analog side, I have two ThumbPointer (2 pot each) and two sliders. 6 AN provide just enough.

I don’t think I will need a 589 because I do not really need a latch for the input – I just need a tri-state buffer gate simple so the output can go into high impedance state when the chip is not selected.
I can go further and toss in such a gate in a independent SOP-8, but that felt like too much complicacy.

That’s why I said to just add a jumper. It will likely be rare that you need to use ICSP, especially if you install a bootloader that allows firmware updates from USB. With a bootloader, about the only reason to use ISCP would be to update the bootloader itself.

The jumper could just be a pre-bridged solder jumper. Or, you could put pre-bridged pads for a two pin header and only solder in the header and a jumper if you cut the bridge. Or, you could have a header and jumper that you always install.

P.S. If you decide that you need ICSP capability at all, you should also add pads for an ICSP header, to make it easy to connect the programmer.

Your original design didn’t mention the stick switch or thumbpointer centre switches.

Register issues aside, we now need to figure out the reason my 165 decide to not clock in any data.

datasheet here
And here is how I wire it:

VCC <- 5V   PL  <- 13
CE  <- 4    CP  <- SCK
D3 <- 12    D4  <- 8
D2 <- 11    D5  <- 7
D1 <- 10    D6  <- 6
D0 <- 9     D7  <- 5
DS <- GND   Q7A <- NC
Q7 <- MISO  GND <- GND

And when I upload my sketch, the serial output nothing but HHHHHHHH.
Which make sense, since all the digital pins are set HIGH.
So I unplug a random wire (e.g. D1 <- 10), and I plug it to GND (D1 <- GND)
But the output (serial) is still HHHHHHHH.
So I tried grounding other pins. like grouding D7.
When I ground D7, the output becomes LLLLLLLL. So the register is fine. It’s just not shifting the bits.
Which really get me. so I ground PL, to no avail. The register did in fact stopped loading bits, as changes to D7 did not impact the output.
So I ground CE, which did not have any influence.
Then I switched to using Q7A, which give me LLLLLLLLs instead of HHHHHHHHs (complementary output).
I tried tie DS to MOSI and sent random bytes (such as 0x23), but it didn’t help.

I must be missing something, perhaps something actually quite simple. But I don’t know what it is.

I took this picture so you can help (proof that I wired everything correctly).
Green and Yellow are parallel wires. Black GND. White is serial. orange is CE, blue is parallel load. brown is clock, red is 5V.
The 165 chip (dot) is facing toward the camera. The angled side (of chip) is facing right.

Since the 165 shifts on the rising edge of the clock, you should be using SPI mode 2, not mode 0. With mode 2 data is read on the falling edge before shifting on the rising edge.

If the latching pin is kept enabled (grounded) it won’t clock bits out, it just outputs D7 to Q7 and inverted D7 to Q7A.

You need to set it low, then back to high, then clock the data in.

oh wait, I read the sketch wrong…
You are setting it back to high. :thinking:

And the chip specs says it should be fine when clocked at least up to 30Mhz on 5V.

What if it’s the LED on pin D13? (It shouldn’t) but try using pin D14 (A0) instead