Almost any voltage with QC
Kicad 8 projects and Arduino code : QC_Fab.zip
QickCharge using tiny412
The QuickCharge protocol lets you “negociate” voltage through USB on smart power supplies.
This page is a short documentation about my journey testing QuickCharge capabilities. I did it for myself and mainly for learning purposes.
I like things small and efficient. This is why this project is ATTiny412-based. (could actually be even smaller/simpler processor). The board was redesigned to make it very “Fab-able”.
Long story short (TL;DR;)
The code was written to be as compatible as possible :
- If what’s needed is just a QC2.0 standard voltage (see below, e.g. : 12V) , set the
TARGET_DCV
(e.g. to120
as it’s configured in dcV) and the code will use QC2.0 only, maximizing compatibility with power supplies and minimizing needed program memory. - If you need a finer value, the code will use QC3.0 and get the closest value as a target reference.
- If you don’t set
TARGET_DCV
(for example, commenting it), the code will look at the potentiometer pin and use it as a target. This also means that if you declareTARGET_DCV
to get a fixed value, you don’t actually need to populate the board with a potentiometer as the code won’t look at it. - Depending on you declared
USECLASS
to beCLASSB
(for 3.6V-20V range) orCLASSA
(for 3.6V-12V range), the potentiometer will cover the desired range. This allows finer adjustment forCLASSA
power supply (max 12V).
All the “fast chargers” tested so far are compatible, even when only declared as PD
(not explicitely QC
) - read dedicated section to know the difference. However, some appeared to be CLASSA
only (12V max) when used with QC
even though they can deliver up to 20V when used in PD
mode. Also, some were able to ramp up to 20V
in continuous mode but not as QC2.0 standard voltage (asking for 19.9V will to the trick, for example). Strange.
- The code was modified to let you see things : the interval between each step was very much increased (200ms instead of 5ms).
- It was a previous test on my first prototype board : the code jumps directly to 12V via QC2.0 and then switches to coutinuous (steps) mode, increasing (very slowly) the voltage by 0.2V steps (you don’t see all of them because my display is very slow to refresh actual voltage). This will actually happen so fast that it will look nearly instantaneous (after the 2sec handshake, though).
The QC protocol
The CHY103 datasheet provide a good overview about the QC3 protocol : handshake and voltage selection. Voltages are selected based on three voltage levels applied to D+/D- pins :
- 0V
- 0.6V
- 3.3V
CHY100 datasheet specifies voltage thresholds of 0.325V and 2V, so 0.6V is a safe (and generally documented) value for the “intermediary” voltage.
- There are two “classes” for QC power :
- Class A max voltage is 12V
- Class B max voltage is 20V
- Minimum voltage is supposed to be 3.6V or 3.2V but I actually measured the lowest voltage to be ~4V on most power supply.
The QC protocol in brief :
- Starts with ~2sec handshake : D+ is set to 0.6V and D- is left floating. The charge will try to pull D- at the D+ and if D- remains floating for about 2sec, the charger will enter QC mode.
- Voltage is then set by changing D+ and D- voltages values.
QC2.0 voltages :
D+ | D- | Output |
---|---|---|
0.6V | GND | 5V |
3.3V | 0.6V | 9V |
0.6V | 0.6V | 12V |
3.3V | 3.3V | 20V |
QC3.0 addition :
D+ | D- | Output |
---|---|---|
0.6V | 3.3V | enter continous mode |
0.6V | 0.6V (glitch) | Decrease 0.2V |
3.3V (glitch) | 3.3V | Increase 0.2V |
After each glitch, the signals must return to “coutinous mode” (D+ = 0.6V, D-=3.3V). Glitches are 5ms in this code.
A more detailed explaination about the protocol and the code is documented in the arduino code commented head section.
The board
The schematic is pretty simple (USB only view) :
D+
0.6V
voltage is realized by a resistor bridge (R1
andR2
) when the corresponding pin is set as an input. When set as an output, the pin imposes its own voltage that can be0V = LOW
(actually never used) or3.3V = HIGH
D-
0.6V
is realized by theADC
(code will automatically select available internal reference). Instead of changing theADC
value to get the0V
or3.3V
, we simply set the pin as a digital output when needed.- two
1k
resistors protect the lines in case something goes wrong
The full schematic includes :
- a
10k
(or reasonably close, not critical) potentiometer -RV1
- to provide a selectable input readable by an analog pin - a resistor bridge (
R6
andR7
) to divide theVBUS
voltage by11
: we’ll do the more complex maths later. (see notes about ADC on the sense pin) - a
3.3V
regulator and its capacitor : this value has been chosen to ease the output voltages values onD+/D-
- and of course our cute and lovely little
atTiny412
and itsUPDI
access for programming
Before you go further, I strongly recommend that you have a look at the code and know your goal as you might not want to populate the entire board depending on your usage.
I packed everything together. And I still use thick traces [min 0.64mm, usually more, especially on power lines]. Thick traces are easier to mill (with more than reasonable 0.5mm clearance), more robust and handle more current and force. So why would we wear out our bits removing more copper?
This is my very first test of 3D printing (and actually just using) a stencil. All I did was to export the “Mask” layer as SVG, removed the big connectors (USB and OUTPUT) and made it 3D with a three-line code in OpenSCAD. It was printed in PETG
(for robustness, but could have been PLA) with a 0.25mm
nozzle on a Prusa MK3S. Slowing down (@~70%) the printer gave good results.
Well. Yeah, ok : this is ugly. Probably too thick stencil : there is too much solder paste. But looks at the right place and as long as the solder joins by capilarity, it should be good. I had ordered a hot plate (the PCB is so small it will entirely fit on a MHP430), but couldn’t really wait to get it, so I used a hot air gun. Discovered that I had to provide a fair air flow to melt it.
These are the components placed before being soldered. Tight package is cool. But not that easy to place the components without moving the previous ones.
I would have expect a little bit better result and had to remove the USB connector because some paste was short-circuiting the GND anv VBUS underneath, but all the rest was ok.
Hero video
And this is working just great!
Notes and comments
An arduino library exists but doesn’t take advantage of DAC and will be more resources/hardware/pins-consuming.
“Indication” LED
I added an “indication” led that lets me have a very rough idea of the voltage : with a 10k
resistor the led will be very shy at 5V and be more visible when approaching 20V. This value might be adapted for ClassB. (3k3
or 4k7
probably are good values for ClassB, I didn’t test)
Stronger power lines
I put a quite thick solder cover on the power lines between my USB connector and output terminal block. This is because I want to make sure that my traces will handle high currents without resistance. It makes my board uglier but more reliable.
Resistor divider, ADC timing and maths
R6 = 47k
and R7 = 4k7
form a resistor divider by a factor 11 : those values were chosen to ease components list (10x multiples are very common in stocks) and let VBUS
reach 20V (or more) safely :
- you might also use
10k
and1k
for example but this will sink more current (~2mA at 20V) - or
100k
and10k
but that might require small code tweaks
Using high impedance resistance devider will sink less current but will maybe require small ADC timing adjustments and/or parallel small capacitor (e.g. 100nF
in parallel with R7
) to avoid noise on the sensing pin.
This voltage sensor is used as a feedback.
Getting the value in dcV from the voltage divider requires some maths :
- voltage reference is simply the 3.3V to ease the code : so 33dcV is 1023 (10bits ADC range)
- the voltage divider provides a factor of 1/11 for explained reasons
So we should compute a 11x33/1023 ~= 0.355 multiplication to get the actual voltage in dcV from the ADC conversion. This is achieved by approximating 0.355
by ( 1 + 1/2 - 1/16 - 1/32 + 1/64) / 4
, that is “quite” easy to compute with limited computational resources. This code complexification is the (not-that-high-)price to pay for high code compatibility and versatility on a chip with limited resources.
“Universal” UPDI access
I put a “double” foot print on the board to reach the UPDI pin : you can either solder a 2 pins 2.54mm SMD header to get your GND-UPDI contacts, or solder a unique through hole pin. This last solution gives more robustness for testing purposes and will work fine if you connect your GND reference into the terminal block (or if you’re connected to a USB port with the same GND reference).
I actually solder a UPDI connector for testing purposes only. On my end board I usually simply program my code by pressing a wire on the UPDI pad and leave it unpopulated.
Drilled USB connector versions
I added a drilled USB connector version. I’m not a huge fan of using those, especially for power-related boards or testing purposes.
Wide power regions
I intentionally created wide power regions on the top : this allows one to solder wires instead of populating with a terminal block connector.
QuickCharge (QC) VS Power Delivery (PD)
Quick Charge and Power Delivery stand out as two prominent players, each with distinct features and specifications.
Quick Charge is often associated with Qualcomm Snapdragon-powered devices, while Power Delivery is more commonly found in a wide array of devices due to its open standard nature.
While both technologies aim to provide rapid charging, Power Delivery offers broader compatibility and versatility, especially with the rise of USB Type-C as a universal standard. However, Quick Charge remains popular for its efficiency and fast-charging capabilities in Qualcomm-powered devices. My choice of investigating QC is essentially linked to the USB connector (see below).
Quick Charge
Quick Charge, developed by Qualcomm, utilizes a protocol that typically relies D+
and D-
pins of USB Type-A or Type-C connectors. This also means that those communication lines are not available for actual USB communication when Quick Charge is used.
So :
- You’ll only need a simple USB connector with classical
GND
,D+
,D-
,VBUS
lines. A Type-A connector will work fine. Which is good. - You won’t be able to communicate through USB while using this Quick Charge trick. Which is sad.
*
(img credit Simon Eugster on wikipedia )
Power Delivery
On the other hand, Power Delivery (PD) is an open standard established by the USB Implementers Forum (USB-IF). It operates using the USB Type-C connector, which supports a versatile array of functions beyond charging, such as data transfer and video output. PD can negotiate power delivery between devices, allowing for a range of voltages and currents, through the additional USB wires/lines (. This flexibility makes it suitable for various devices, from smartphones to laptops and beyond.
So :
- You’ll need a Type-C connector and proper routing of very small line. Good luck with that. (but please let me know if you do)
- You’ll be able to communicate and power your board while using PD. Which would be definitely great.
*
(img credit Chindi.ap on wikipedia )
Conclusion
This - very - small board allows me to get - almost - any voltage using very minimalistic hardware and works on most smart power supply. Playing around with my different chargers let me know more about their real (and sometimes surprising) characteristics. When all I need is 12V
, I now can get it easily on - almost? - any charger (even external batteries).
This gives me food for thought about my box of “chargers I keep just in case” I need a specific voltage…
Is it about to become old XX’s century stuffs?
Files
Kicad 8 projects and Arduino code : QC_Fab.zip