Update time!
It’s been quite a while since the last update, but I’ve been busy working on the project! There was quite some progress on a couple of topics.
Battery and charge management:
The board was designed and ordered in April, but it took 3 weeks to arrive. It’s not my finest layout, mainly because I was in a rush to order everything before a business trip. Was a good decision though, looking at the long delivery time…
The board includes 3 main components:
- The BQ25792 battery management IC
- STUSB4500 USB PD controller
- MAX17205G fuel gauge
Assembly was straight forward and I even found two matching 2200mAh batteries on my junk pile for testing. The good thing about the BQ25792 and the STUSB4500 is that they can operate in stand-alone mode, so I was able to give the board a try before writing some code.
The outcome was that the PD negotiation and the battery discharge path were working as expected. There is just one annoying thing about the STUSB4500: it negotiates 20V from factory. I made the wise decision to specify all components for 20V operation, but in the end, I just want 15V@3A max.
The most important thing was not working: charging. It took almost 2h of troubleshooting to find out that I messed up a connection on the BQ. The SDRV charge pump output was tied directly to battery+ instead of a decoupling capacitor to battery+. It was a stupid mistake on my end, but looking back, the description in the datasheet might be a bit misleading for a non-native speaker:
So… back to the workbench. I desoldered the BQ, disconnected the SDRV pin, applied UV soldermask, soldered the BQ back on and attached the required decoupling cap. (see if you can find the bodge in the picture
)
And surprise, charging was working too!
The MAX17205G was impossible to test without a firmware, so I kept ignoring it for the moment. To limit the number of possible failures, I actually even bypassed the MAX circuit (the red wire in the picture). In the meantime, I also found the MAX17320. It might be a better choice, as it has pretty much the same features, but includes battery protection by default. Will think about it…
At that point, everything that could be tested without a firmware was tested. Which means SysCon time…
SysCon:
I was already in the process of designing a PCB for the SysCon when I decided to do it the quick & dirty way on a protoboard. It makes changing the pinout much easier.
Then for the last 2 weeks I was working on a simple firmware to control the power management.
Programming is my biggest weakness, that’s why it always takes me a bit longer
I wanted to write the HAL for the BQ and the STUSB from scratch to adapt them to my needs and I started with the register maps. There, I took the long and safe way by doing everything with masks and shifts instead of bitfields, it should make the code more portable.
Even though I’m using the STM32 HAL for all the uC stuff, I added another layer of abstraction to compress all references to the STM32 HAL into a single source file. It will make my life easier in case I have to port the code to a PIC or something. It might happen, because I’m not planning to stay with the L476. It’s way too much (and way too expensive for what it does). But the replacement will most likely be another STM32, maybe something in the F0 or L0 range.
Now I have most of the code I need to control the BQ and STUSB, the MAX17205 is still missing.
Next step was testing:
Because I didn’t want to update the STUSB NVM to only negotiate 15V max by default, my first idea was to re-negotiate the PDO contract after booting. The state machine looked something like this:
Charger plugged -> init STUSB PDO -> renegotiate PDO with source -> init BQ with current PDO -> enable charging
The renegotiation part was working, the charger started at 20V and after setting the PDOs it changed to 15V. The big problem was that the BQ did not like this. I could never get it to charge after the initialization and it ended up in a weird state. The charge status bits said “fast charge”, the STAT pin was LOW (indicates charging) and all fault bits were ok – but the charge current was 0. No idea how the BQ can end up in this state. It almost looks like it crashed somehow, only reinserting the batteries fixed it. Charging was working fine when I skipped the 15V renegotiation. It could be that the BQ cannot handle the situation when the STUSB discharges the VBUS to 0V for a couple of milliseconds before switching to the new contract, but it shouldn’t care when it’s not currently charging.
Skipping the discharge (there is a bit for that) or increasing the discharge time might have improved it, but the overall situation was too sketchy for me. Instead, I tried to update the STUSB NVM to negotiate 15V max by default, that way I can skip the re-negotiation altogether.
This turned out to be a real pain in the ass, the STUSB4500 documentation is the worst I’ve seen in a long time. The functionality of lots of bits is not properly explained, so the usual approach was always trial and error. The next issue was that the register map in the software guide is not complete, there are reserved registers that do actually have a purpose + in the case of the NVM there are plenty of undocumented registers/functions. The only support from ST is to “check out the official STUSB4500 library, you will find everything there”. This is exactly what I had to do… I found the undocumented registers in one of their header files and I had to reverse-engineer the NVM update functions to implement them in my code. I still have no idea what I’m actually writing to the NVM, the data array was exported by ST’s configuration software and there is no documentation on what each byte does. It somehow works though, now I have a function to update the NVM.
After that was sorted out, I tried charging again and now it works reliably. The bonus of this approach is that I don’t really have to interface with the STUSB4500 anymore, as everything is handled automatically. Now I can just observe the two PDO PG pins and from that I can obtain the input current limit I have to set in the BQ.
Adding the power switch:
The next thing to implement was the soft power switch. This one was very interesting…
A quick observation on the charger I’m using: The voltage difference between the charger GND and my PC UCB GND is about 70V RMS. There is no energy behind it, because you can load it down to a couple of mV using a 10k resistor. It is enough to cause weird things though… grounding issues… my favorite issues.
One thing that happens is that my debugger loses the JTAG connection to the SysCon when I touch the USB C socket on the battery management board with the USB C cable. The SysCon keeps operating just fine though. To fix this issue for debugging, I just shorted the shields of the charger’s second USB C port and one of my PC’s USBs, this seems to do the trick for now.
The more concerning issue could be observed on the power switch: when hotplugging the charger, it would sometimes show random behavior. Sometimes it turned off, sometimes it turned on. I’m pretty sure that it was not caused by the grounding issues with my PC, because it also happened when the setup was floating.
The current power management implementation states that the SysCon has to turn on to handle charging when a charger is plugged. I was doing it by latching the power switch directly from the ATTACH output of the STUSB, this pin indicates an attached charger. Turns out the pin state is not defined when no charger is plugged (as the STUSB is unpowered there to reduce quiescent current). It’s a little oversight on my end and this finally convinced me to ditch the soft latching power switch altogether. The only benefit it would provide is that you can force the system off in case the SysCon crashes.
It was time to find a new solution:
My next idea was to handle the latching in firmware. I can just hook up the push button to the EN of the SysCon supply rail and have a PMOS in parallel. The PMOS is controlled by the SysCon and the first thing after booting is to drive this pin low. That way, the system stays on. To determine when the system should turn off, I've included a diode in series with the push button and I’m getting the button state from there.
For powering the SysCon automatically when hotplugging a charger, I make use of my charge detect circuitry on the regulator board. It is essentially just a 3.3V Zener diode connected to VBUS, so charge_detect will go HIGH as soon as the STUSB enabled VBUS.
This implementation works very well so far, the only drawback is that shutting down the system is handled by the SysCon. If the SysCon encounters an unhandled exception, it will not be able to turn off the system (this happened already, that’s how I know
). I will have to take good care when writing the code to always allow the system to shut down, if I proceed in this direction.
With all the circuitry working, it was time to implement a simple state machine to handle charging, power on and power off. It's actually 2 state machines, one for charging and one to keep track of the system state.
I will spare you with more boring details, here is the next achievement for the project. My custom mainboard is able to run off batteries for the first time. You can hotplug a charger and the SysCon is able to turn on and off the PS2 on its own. There are still some quirks with my state machine, error handling is mostly missing for example, but for sure I will improve the code.
For now it works:
Now that it “works”, I’m thinking about things to test/measure to verify that everything works as expected. The only thing I measured so far is the battery quiescent current of the whole system in standby mode and full batteries: ~28uA (including the PS2 RTC). Looks good for now!
Power management architecture:
I’m handling this topic separately, because it does not have a big influence on all the SysCon stuff.
The main reason for being so focused on power sequencing is an issue I’ve noticed with all custom regulator modifications I’ve done in the last 6 months. This is also present on my modified and custom board. In about 1 of 20 power cycles, the red power LED does not turn on and the system consumes ~1.5A. Resetting the power always fixes the problem. I can think of 2 possible issues:
The first would be the fact that I always removed the POR chip of the MechaCon. The second would be power sequencing, because I never noticed this issue before removing the stock regulators.
I was thinking about how to best implement the power sequencing in the last couple of weeks, but always came to the same conclusion: it is not possible on the current custom mainboard revision. This is because I tied the SBY 3V5 and SBY 1V8 rails to the 3V5 ad 1V8 rails internally, without a way to separate them. It will never allow me to power the MechaCon first.
If I’m aiming for reliability, I might have to go for the stock power supply architecture. That means I will have to allow the MechaCon to turn on the voltage rails. It has the benefit that I can give the MechaCon a purpose again (because now it’s not doing much) and I don’t have to handle the sequencing in the SysCon (that will save me quite some pins).
To test whether or not this fixes the issue, I took my trusty modified 79k mainboard and hooked up my power management system to imitate the stock regulators. To do it I designed a little PCB with two load switches for enabling the 3V5 and 1V8 rails (they are just tied to the standby rails, no new regulators needed). They are soldered to the mainboard and controlled by the MechaCon. On top of that, the MechaCon controls the 1V25 regulator on the regulator board. The 5V, 2V5, SBY 3V5 and SBY 1V8 rails are still provided by the regulator board and enabled by the SysCon.
With this setup, the MechaCon controls the sequencing of the 1V25, 1V8 and 3V5 rails. The other rails don’t really need sequencing and I just turn them on at the same time using the SysCon.
To replace the POR chip that I removed, I added the LM809M3-2.63 reset IC from my reverse engineered memory card instead. It should keep the MechaCon in reset until the SBY 3V5 rail is high enough.
Here is the setup:
First tests were very successful! There was not a single hiccup, but I will do some more testing to reproduce the issues I had. If this is more reliable, I will implement the changes into the next revision of my mainboard.
SD memory card:
I really wanted a good reason to try the new cheap flex PCB service from JLC and the first useful thing that crossed my mind is a compact memory card. One of the requirements for my portable is a memory card socket and it would be a good compromise if I could somehow develop a smaller memory card for it.
This is what I did, the new memory card has the size and form factor of an SD card. Not just that, the pinout is also compatible with MX4SIO memory cards. With a modified MX4SIO, I can connect this memory card to any PS2. The only thing to modify is the ACK line: the 47R resistor to GND on the MX4SIO needs to be removed and the ACK needs to be connected to pin 9 of the SD socket.
On my portable I could even include 2 full size SD sockets for the memory card and the MX4SIO. Using either the card detect or the lock switch, I could differentiate between the two. That way I could even swap the cards or connect 2 memory cards for copying savegames.
Pretty interesting ideas, but I will think about the benefits and drawbacks a little more, before I implement something!
The card itself works so far. The flex PCB looks nice and the price is a real game changer for flex PCBs. Because I’m constrained to ~1.45mm in height, I ordered the thinnest PCB (0.11mm) and removed the stiffener completely. This makes soldering the components a bit harder, but it is needed for the card to fit. Then I just fuse the flex PCB to a 3D printed frame to make it rigid. The cutout for the components could then be filled with epoxy to seal everything. Done. Looks really cute!
The only concerning thing is the ENIG plating, the pins look really scratched already after about 20 mating cycles. I don’t see a hard gold option on the JLC configurator, so the only option for the future might be to increase the copper thickness to 1/2oz (currently 1/3oz).
Some other stuff I was working on:
Now that I have my Fluke 52, I was playing around with temperature measurements on the EE. With my fan I get around 34°C using 1V core voltage and ~37°C at 1.25V. This matches the readings from PS2Temps, the MechaCon readings just take about 10min longer to settle (because the temperature sensor is next to the EE). Good to know that using PS2Temp is a good option to observe the EE temperature.
I started evaluating different fans and thinking about a cooling solution for the portable. On the pictures above you can see the KDB0305HA3-00 blower fan. It's 30x30x3.5mm and using the same heatsink as before, it manages to keep the EE at 38°C on 1V. It's very loud though, that's a no-go.
The next fan on my list is the sepa HY45T05A. It's 45x45x5mm and a lot more silent. Another interesting option might be a Nintendo Switch fan.
This topic is still ongoing, I'm also looking for suitable heat sinks, as the one I have is not ideal for blower fans.
I should really do more frequent updates, this post got pretty long again!