# Development of buck-converter on STM32F334: principle of operation, calculations, prototyping

In my last two articles, I talked about the power module and the control board based on the STM32F334R8T6 microcontroller, which were created specifically for implementing control systems for power converters and electric drives. An example of a DC /AC converter was also considered, which was a demonstration, not a complete construction. Now it's time to do something simple, but useful, and most importantly complete. 3r31196.
3r31196.
Most of the issues related to the project and power electronics are related to specific topologies: someone is interested in knowing the PFC control algorithm, someone wants to learn how to build a half-bridge LLC, but the most popular topology is undoubtedly buck. After all, a buck converter (also known as a buck converter) is the main one for most interesting projects: it is a driver for LED luminaires, an MPPT controller base for solar panels, chargers and much more. 3r31196.
3r31196.
There is a lot of information on the buck in the network, including datasheets, but it is scattered and I personally haven’t met any material that describes in detail the process of creating a digital-controlled buck converter. It's time to fix it. There is practically no mathematics, an explanation “on the fingers”, so it will be interesting to anyone who is somehow connected with electronics. 3r31196.
3r31196.
3r31199. 3r31196.
3r31199. 3r31196.
3r31184. Introduction 3r31185. 3r31196.
First you need to understand what we want to get in the end and what kind of introductory we have. The buck topology is downward, that is, it allows you to build a downward voltage converter. As you will see below, the voltage at the output of the buck-converter is almost linearly dependent on the input voltage, so you need to add feedback. Today I will talk about simple voltage feedback (voltage mode), which is the most obvious and will allow you to understand the principle of operation, while this feedback will be enough for you to accomplish most tasks. 3r31196.
3r31196.
At the end of the article we will get a working stabilized voltage source in the “synchronous buck” topology, operating at a sufficiently high frequency with digital control, implemented on the STM32F334R8T6 with the use of High Resolution PWM (HRPWM). The input voltage range is 15 60V, the output voltage is 12V, the maximum output current is 2A. 3r31196.
3r31196.
3r31184. Chapter 1. The principle of the topology of the buck
3r31196.
I will begin to tell from the very basics and will gradually improve our converter, since “Synchronous buck” is an improved version with increased efficiency and control complexity. The basic topology, which you probably used, is as follows: 3r31196.
3r31196.
3r31196.
3r31196.
This topology is used in low-power voltage converters, for example, to power digital circuits and other low-power devices. The dc /dc downgrades that you use in your devices are most likely implemented on microchips for this topology. An example of such a 3r350 chip. LMR16006 3r31199. . 3r31196.
3r31196.
The principle of operation of this circuit is very simple, the PWM signal is sent to the VT1 transistor, the work itself is divided into 2 stages, which alternate one after another: 3r31196.
3r31196.

Stage of energy storage in the LC circuit. 3r31099. At this stage, the transistor VT1 is open and the current flows through the transistor to the load, simultaneously accumulating energy in the inductance coil and output capacitance: 3r31196.
3r31196.
3r3645.
Stage of discharge. 3r31099. At this stage, the transistor VT1 closes and the most interesting begins. A choke is such a thing that accumulates energy if a potential is applied to it (open VT1) and gives it away if the potential is gone (VT1 is closed). At the same time, he seeks not only to give energy, but to preserve the value of the current and its direction, therefore, to use this property, you need to add a diode VD1 to close the circuit, because the current flows only in a closed circuit: 3r31196.
3r31196.
3r3645.
3r31196.
When I got acquainted with this topology at 6-7m class, I didn’t understand right away why the diode does not conduct current at the 1st stage, now it seems trivial, but I think it is worth mentioning. When VT1 is open, a + VIN potential is applied to the cathode of the VD1 diode, for example, + 20V, and a ground potential is applied to the diode anode. In order for the current to flow through the diode it should be exactly the opposite: the potential at the anode must be greater than the potential at the cathode, therefore, in a buck, the diode is “closed” at the energy storage stage. At the stage of discharge, the diode already closes the circuit, the potential + VIN does not act on its cathode and does not “lock” it. I hope clearly explained. 3r31196.
3r31196.
Then you should have a question: “And what voltage will be at the output, if we applied to the input 20V?”. As always, everything is simple:

3r31196.
3r31196.
3r31196.
As can be seen from the formula, the output voltage linearly depends on the duty cycle (duty) of the PWM signal, which we apply to the VT1 transistor. If someone does not know or has forgotten the “duty ratio” is the ratio of the time that the transistor is in the open state to the period duration. This ratio can take a value from 0 to 1 or from 0 to 100%. Then we will operate with this particular figure when controlling the converter, but for understanding the essence let's substitute this relation into the formula: 3r31196.
3r31196.
3r3102. 3r31196.
3r31196.
The frequency of the buck-converter value is constant and is selected when designing, during operation it does not change, and therefore the period (T) is constant. It turns out that the output voltage directly depends on two physical quantities:

3r31196.

from the time at which we open the upper transistor (VT1) - the longer it is open, the more energy accumulates in the LC filter and, accordingly, the higher the output voltage; 3r3645.
from the input voltage, for example, if we fixed the filling to 50% and change the Vin from 20 to 40V, then the output voltage will also vary from 10 to 20V. 3r3645.
3r31196.
I think you have started to see the general picture and the principle of work, let's fix it now and look at the real oscillograms and check this ratio in practice. I have assembled a buck model, which is loaded with a 10 W LED. I used 3 oscilloscope channels, which are included in the following points: 3r31196.
3r31196.
3r31196.
3r31196.
[b] Test No 1 - The input voltage (Vin) is constant 20V, the duty ratio
changes. 3r31196.
3r31196.

Vin = 20V, D = 25%, Vout = D * Vin = ??? * 20V = 5V

3r31196.
3r3144. 3r3645.
Vin = 20V, D = 50%, Vout = D * Vin = 0.5 * 20V = 10V

3r31196.
3r3152. 3r3645.
3r31196.
As you can see on the oscillograms, the relation between the output voltage and the fill factor is correct. Of course, this was an “idealized” experiment; in reality, the voltage at the input is not stable and floats in a fairly wide range. Let's now see what will be the dependence on the input voltage with a fixed filling. 3r31196.
3r31196.
Test No 2 - The input voltage (Vin) changes, the fill factor is constant and is equal to 50% 3r31196.
3r31196.

Vin = 15V, D = 50%, Vout = D * Vin = 0.5 * 15V = 7.5V

3r31196.
3r? 3175. 3r3645.
Vin = 20V, D = 50%, Vout = D * Vin = 0.5 * 20V = 10V

3r31196.
3r3183. 3r3645.
Vin = 30V, D = 50%, Vout = D * Vin = 0.5 * 30V = 15V

3r31196.
3r3191. 3r3645.
3r31196.
Now we are convinced in practice that the output voltage also linearly depends on the input voltage with a fixed fill factor. Understand how to stabilize the output? The principle of stabilization is simple as the formula itself - Vout is equal to 12V and a constant, we can change the fill factor using a microcontroller, so if Vin increases, then the output voltage increases and at this point we decrease the fill factor (duty) again until 12V. Accordingly, with a decrease in Vin, we begin to increase the fill factor until, again, the voltage Vout becomes 12V. 3r31196.
3r31196.
What else would you like to pay attention to in the theoretical section Oh, yes! Surely you wonder how PWM with an amplitude of 20V after the transistor eventually turned into a constant voltage with scanty pulsations? Indeed, if we put the red oscilloscope probe at the source of the transistor VT? the green probe after the LC filter, we will see the following picture: 3r31196.
3r31196.
3r31196.
3r31196.
You can see how the LC filter "lubricates" the alternating voltage to a constant, and the thing is that the energy stored in the inductance and capacitance cannot be instantly consumed, hence the voltage cannot instantly change. We get that at the moment when the PWM before the choke is 0V, the output voltage is provided by the energy stored in the filter, which does not dissolve instantly and is enough to maintain the voltage at the time of closing VT1. This is all on the fingers of course, if it is interesting to go deeper, then as always I advise you to start the book 3r31098. B.Yu. Semenova “Power electronics: from simple to complex”
, there is a whole chapter on the buck (chopper). 3r31196.
3r31196.

### Fight for efficiency

3r31196.
As I wrote a little earlier - it was a basic version of the topology. Its main disadvantage is high losses on the blocking diode. What current in the simple systems working on MK and CPLD? Usually within 1A, sometimes 2A, if there is some TFT display. In this case, the loss even when using a Schottky diode will be 0.4V * 2A = 0.8W. In principle, it is tolerable, it is possible to dissipate so much on the SMA /SMB package without any problems, although at a voltage of 3.3V and 2A a loss of 0.8V is still 12% efficiency! 3r31196.
3r31196.
Now imagine a case where the current is 20A. It could be an MPPT controller, a large FPGA power system and much more. In this case, the loss will be 0.4V * 20A = 8 W! What does it mean? For example, in the case of MPPT, you will have less energy stored in the battery, in the case of powering the FPGA it will be an additional 8 W of heat that needs to be dissipated somewhere and in both cases it is undoubtedly a loss of overall efficiency. What can be done? And let's replace the VD1 diode with another N-channel Mosfet and get the following scheme: 3r31196.
3r31196.
3r31196.
3r31196.
Now the transistor VT2 acts as a diode, that is, conducts a current when VT1 is closed. The diode, which was in the basic version did not require control, but now we have to pay for an improvement in performance with an additional control channel with a PWM signal. 3r31196.
3r31196.
First, let's calculate how much we have reduced losses. The resistance of the channel of the modern mosfet is a few mΩ. As an example, let's take a transistor from my power module I told about in my last articles - 3r-3237. IPP083N10N5AKSA1 3r31199. with channel resistance 8.3 mΩ. We get static losses equal to ??? * 20A * 20A = ??? W. Of course, there will also be dynamic losses, which with an adequately designed driver will be no more than 20%, that is, the total losses will be 4 watts. We get that the transition from the usual buck-to synchronous allows halving the losses on the diode. 3r31196.
3r31196.
Let us now analyze the complicated management. As we already understood, the blocking diode conducted the current when VT1 was closed. From this it follows that VT2 must be closed when VT1 is open and, accordingly, VT2 is open when VT1 is closed. If it is simpler, the transistors work alternately: or one is open or the other, if both transistors open, a through-current will occur, since they are closed between themselves VIN and GND. Let's see what the signal should be, where the “yellow channel” is a VT1 transistor and the “green channel” is a VT2 transistor: 3r31196.
3r31196.
3r31196.
3r31196.
As you can see, if the logical channel “1” is set in the yellow channel (on VT1), then at that time a logical “0” should be set in the green channel (on VT2). We obtain that VT1 pumps energy into the LC filter, and VT2 closes the circuit at the stage of discharge. 3r31196.
3r31196.
There is another point about which you have already heard or read above - 3r31098. pass-through current 3r31099. . The fact is that a real, not an ideal transistor (mosfet) has a certain capacity at the gate, that is, in reality, it does not instantly go from log.0 to log.? and the energy in the transistor does not dissolve instantly, resulting in transistors for a short time at the moment of switching may both be open. This can lead in the best case to increased losses, which means heating up and in the worst case to the woman, since Through current is a common short circuit (short circuit). To avoid this, between turning off one transistor and turning on the other one introduces a delay, or so-called dead-time. It looks like this:

3r31196.
3r31196.
3r31196.
I think you noticed that there is a small space on the signal switching edge. I installed it obviously large (about 3%) so that you can see it, in reality it is much smaller. In general, dead-time (further dt) is set as short as possible, but at the same time sufficient for the transistors to close. It can be calculated, or it can be chosen empirically, I personally think that this and that option is normal, but bearded Jedi will surely tell you: “It is necessary to consider it necessary, but to model it better!”. This is certainly correct, but decide for yourself - if you are not too lazy to model in LTspice, taking into account the parasitic inductances and capacitances of conductors and components. 3r31196.
3r31196.
For the stand in this article, I set the dt to ~ 100 ns (in fact, 104). My module allows you to install it significantly less, because the driver is very harshly applied, but surely many of you will assemble your layout without my module, which means there is very likelysnot will blow. I’ll leave dt with a margin so that they don’t bahn because of the snot, and if you have a normal layout on the board, you can reduce it yourself - in the chapter on the code you will see how, but for now we’re really looking at dt: 3r31196.
3r31196.
3r31196.
3r31196.
Here you can see that dt lasts 2.5 divisions and each division is 40 ns - it means the duration is ~ 100 ns as it was intended. I hope you understand why dt is needed, how long it should be, and how the buck topology converter works in general. If you do not understand, then as usual questions in the comments, HP and the mail are accepted, while I seem to be answering everything. 3r31196.
3r31196.
3r31184. Chapter 2. The calculation of the main components 3r31185. 3r31196.
In this part of the article, I will show how to quickly and simply calculate the main power components for a synchronous buck-converter, namely: choke, input and output capacitors, transistors. 3r31196.
3r31196.
Let me remind you the introductory dаta: 3r31196.
3r31196.

Input voltage: 15 30V

Output voltage: 12V

Rated output current: 2A

Switching frequency: 100 kHz 3r3-33645.
3r31196.
Output voltage 12V is selected because As a load, I plan to use a 12V 20W LED, which is at hand and is a very visual load. Anticipating the questions of the “experts” in the comments - yes, I am aware that the LED needs current stabilization, but we do a voltage regulator and the LED is just a load. 3r31196.
3r31196.
The input voltage is chosen from the bald, you can do 15 60V, so if you are interested in a different range, you can calculate the value of the components for it. A rated current of 2A is chosen to obtain an output power of 12V * 2A = 24 W, that is, slightly more than is needed for the LED. The LED itself at 12V consumes about ??? 1.9A. 3r31196.
3r31196.
The most interesting parameter remained - the operating frequency of the converter. What should it be? Here you have to answer yourself, in my case it is 100 kHz. The choice is based on two theses: 3r31196.
3r31196.

Increasing the frequency leads to a decrease in the required inductance of the choke, the input and output capacitors. Simply put, as the frequency increases, the size of the device decreases. With decreasing frequency, dimensions increase. 3r3645.
Reducing the frequency leads to an increase in efficiency, because dynamic losses when switching transistors are reduced. Increasing the frequency increases the dynamic component of the transistors and accordingly reduces the efficiency. 3r3645.
3r31196.
Now I will not discuss the choice of frequency, just accept that 100 kHz. After I show the calculation method, we will return to this question, because the formulas will more clearly show the dependence of the denominations of the main components of the operating frequency. 3r31196.
3r31196.
Step 1. Select transistors 3–3–31099. 3r31196.
3r31196.
We will be mainly interested in 3 parameters: maximum drain-source voltage, channel resistance in the open state and gate capacitance. The entire potential of the voltage source (Vin) is applied to the transistor, and there are also spikes at the moment of switching. You have 2 options: take the transistor VT1 and VT2 with a voltage margin or the story RC snubber at VT2. In my case, there are 100V transistors on the power module, and with an input 30V, this is a huge voltage margin, even 60V was enough to do without snubber and protect the transistor from breakdown. 3r31196.
3r31196.
Channel resistance - here the less, the better, but there is one BUT. When the channel resistance decreases, we reduce static losses (I 2 * R), but the technology is such that the shutter capacity increases, and this leads to an increase in dynamic losses. You have to find a middle ground between the "channel resistance" and "gate capacity". For voltages up to 100V, I advise you to pay attention to Infineon's OptiMOS series transistors, you can already look at high voltages for parametric search or even towards IGBT transistors. The latter are also supported by my power module and do not require any changes in the driver. 3r31196.
3r31196.
Step 2. Calculate the inductance of the choke 3r3-1099. 3r31196.
3r31196.
It is necessary to calculate the minimum value of inductance, which will allow our dc /dc converter to operate in continuous current mode (L 3r31116. Min [/sub] ):

3r31196.
3r31196.
3r31196.
In terms of variables, I think everything is clear, except - k 3r31116. ind 3r31117. . These are permissible ripple currents in the choke, usually choose the value of 20 50%, but I almost always set 30%. The smaller the ripple of current, the farther we will be from the saturation limit of the core on which the choke is wound, but as can be seen from the formula, we will need a large inductance of the choke. 3r31196.
3r31196.
Now we calculate the minimum value of inductance, which is needed for my input data, ripple, I will lay 30% as already written above: 3r31196.
3r31196.
3r33385. 3r31196.
3r31196.
It should be understood that this is the minimum inductance required for operation of a buck converter in the mode of inseparable currents, but again there is a nuance. In the process of increasing the current acting in the winding, the permeability of the core and the inductance of the choke WITHOUT current and With the current are slightly different, somewhat different for different materials. In order to avoid a situation when with an increase in the current in the inductor, the inductance decreased below L 3r31116. min [/sub] and dc /dc did not go into the discontinuous current mode, it is necessary to slightly increase the inductance, that is, add a couple of extra turns during the winding. Increasing the inductance by 10-15% will be enough for the material Kool Mu, and my choke will be on it. 3r31196.
3r31196.
[b] Step 3. Calculate and manufacture the throttle
3r31196.
3r31196.
I wanted to describe this procedure in the “prototyping” section, but then the inductance calculation stage would have remained less clear to you, and probably missed the interesting pictures, so I’ll describe everything here. For the manufacture of the throttle, I will take the throttle R26 /14/11 (R is a ring and the figures are dimensions) from the material Kool Mu with a permeability of 6? download the documentation on it and you can buy it here - 3r3402. Lapcos 3r31199. . 3r31196.
3r31196.
3r3408. 3r31196.
3r31196.
Now you need to count how many turns and what wire you need to wind. Let's start with the number of turns perhaps. The documentation on the core has such a convenient parameter - A L which is 75 nH /revolution 3r3r1118. 2 [/sup] . Here carefully - the turns in the square! To find the inductance of the core, you must multiply A L on the number of turns per square. Hence the formula for finding the number of turns looks like this:

3r31196.
3r33434. 3r31196.
3r31196.
In order to obtain the minimum required inductance, it is necessary to wind 40 turns, but as we have already discussed, it is necessary to slightly increase the inductance, say, throw +3 turns. We take the ring and wind 43 turns, we get the following choke:

3r31196.
3r33434. 3r31196.
3r31196.
Now for the sake of interest let's calculate what inductance should be:

3r31196.
3r31196.
3r31196.
And for reliability, we check the inductance of the choke with tweezers:

3r31196.
3r33450. 3r31196.
3r31196.
137 μH, great! The results agreed, the error was within ± 8% for A L . Here it is worth noting - if you do not have the ability to measure inductance, then do not buy cores for aliexpress, in ChiD, complex, electronic engineer and other “eatery” - there is a chance to get a core from another material or not that permeability, but with proper labeling verified. Without the ability to measure inductance, you cannot test A 3r31116. L [/sub] and you will be able to suffer a lot in search of the cause of the "babakh" of your converter. 3r31196.
3r31196.
Then a reasonable question will appear - “will we have enough of the core and its dimensions? Maybe it was necessary more? ". For the material Kool Mu, the magnetic induction limit is 0.5 T, in practice it is better not to climb over the threshold above ??? T without obvious need. It turns out that the winding wound on the core does not have to create an induction at each point of the core more than ??? T, so check: 3r31196.
3r31196.
3r31196.
3r31196.
As you can see, the value of magnetic induction ??? T is much lower than the limit 0.5 T. Two conclusions can be drawn from this: firstly, the throttle will not go into saturation, and secondly, the core is very large and powerfully take a ring of a significantly smaller size. I took the ring R26 simply because I have a whole box of them, there is no other secret meaning here. 3r31196.
3r31196.
It remains to determine what wire size to take for the choke. Firstly, I strongly advise you not to take a wire with a diameter of more than 1 1.2 mm at such high frequencies, since The skin effect already has a significant effect and reduces the effective cross section. Secondly, the current density in the wire must be selected based on the conditions of cooling and power. At low power (up to 10-20 W), you can safely lay the current density of 8. 10 A /mm 2 even without blowing air flow. At capacities up to several kilowatts, it is better to lay the current density in the range of 5 6 A /mm 2 , and with powers from 10 kW and further, it will be reasonable to reduce the current density to 3 4 A /mm 3r31118. 2 [/sup] . 3r31196.
3r31196.
I had a varnished wire with a diameter of 0.8 mm on hand. Its cross section is respectively ~ 0.5 mm 2 . At a current of 2A, we obtain a current density in the winding of about 4 A /mm 2 . I could use a wire and half the cross section, but my core is big enough, so the wire of a larger cross section got in without problems. When you optimize your device, you will have to first read and then buy the wire of the desired cross section, then you will be able to get the optimal dimensions of the choke. 3r31196.
3r31196.
Step 4. Calculate the output capacitor 3r31196.
3r31196.
At this stage, as in the case of inductance, we will consider the minimum value of the capacitance, which must be installed in the LC filter at the output of the buck converter. Accordingly, if you install more, it will be better and then you will see why. Calculate capacity:

3r31196.
3r31196.
3r31196.
Of course, the capacity must also be set with a certain margin, especially if you use only ceramics at the outlet, since its capacity is greatly reduced depending on the voltage applied to it. You should also pay attention to the dependence on pulsations - the variable V pulse 3r31117. . This is the maximum value of the ripple at the output, that is, ideally with a capacity of 147.8 microfarads, the amplitude of the pulsations will be 0.2 V, that is, the output voltage will float in the range of 11.9 12.1 V. Want to reduce ripple? Then reduce them in the formula and the value of the resulting capacity will increase accordingly, of course, you will not get a laboratory power supply simply by increasing the output capacity. It is also necessary to take into account the need for a low ESR, for this purpose, 1-2 electrolytes are usually put in parallel and in parallel they are hung with ceramics a few microfarads with the X7R dielectric is desirable. If the budget allows, then it is possible to replace the electrolytic capacitor with polymer tantalum (as in a GPU), and so ceramics are not needed, they have an ESR and so little. 3r31196.
3r31196.
[b] Arguments about the working frequency 3-???. 3r31196.
3r31196.
Now, as I said, let us return to the question of choosing the operating frequency of the converter. Let me divide the conclusions into several thoughts: 3r3r11196.
3r31196.

As you can see in the formula, the frequency appears, the higher the operating frequency, the lower the inductance value of the choke will be required and the smaller the number of turns will have to be wound - we save on copper and simplify the manufacture of coiled goods 3r336455.
In the formula for calculating the magnetic induction there is an inductance and the number of turns, however, as you remember, the inductance has a quadratic dependence on the turns, which means that if the number of turns decreases 2 times, the inductance decreases 4 times. It follows from this that with an increase in the frequency, the inductance and the value of magnetic induction decrease, which means that a smaller core can be used, that is, we reduce the dimensions of 3r33645.
Now let's look at the formula of the output capacitance, everything is also obvious here - it depends linearly on the inductance, that is, the smaller the inductance, the smaller the capacitance needed. Dimensions are reduced! 3r3645.
Now for the bad The frequency increases, which means that the dynamic losses of transistors increase, and this obviously leads to a decrease in the overall efficiency. For any significant power, a reasonable frequency limit for a buck converter on mosfet s is 200 kHz and lower. Want more power (hundreds of watts) and a huge frequency? Welcome to the world of GaN transistors or resonant topologies 3r3363645.
3r31196.
I think from these theses it became clear to you what the switching frequency affects, now you need to independently learn how to find the "middle ground" between losses on transistors and the size of the device. In one of the following articles I will teach you how to optimize the working frequency for maximum efficiency, the main thing is not to forget that I was going to do it. 3r31196.
3r31196.
3r31184. Chapter 3. We collect the layout of the buck converter
3r31196.
So, the most tedious, but important, part is over, now the hardware and code will go. Let's put together a model on which we will implement theoretical calculations. To do this, you need two modules about which I told in previous articles: 3r35050. power module
and 3r33552. control module on the STM32F334 3r31199. . You can also collect a half-bridge from any IR2110 waste trap yourself on the breadboard, and use any MK: STM32-Discovery, LaunchPad, Arduino as control and simply adapt the operation logic and code to your favorite MK, nothing will be difficult if You understood from the first two chapters how the buck converter works. 3r31196.
3r31196.
Now let's make our buck-diagram more “realistic” by adding the nominal values ​​of all components to it and correctly reflect the number of capacitors, as well but what part can my power module realize? 3r31196.
3r31196.
3r? 3562. 3r33535. 3r31199. 3r31196.
3r31196.
As can be seen from the diagram, the module already contains a half-bridge (two transistors) for the implementation of a synchronous buck and an input capacitor, by the way, the module stands with a huge margin - there are 3 electrolytes of 1000 µF each and 100V, which is enough to build a buck for 500 -800 watts. It remains for us to add a choke, which we have already manufactured and output capacitors, the latter, too, by the way, with a margin, since I found only 4700 microfarads of 25V for low voltage, but they are some Chinese, so I decided to pair a couple of them. In fact, 470 microfarads of one is enough there, but I simply didn’t have such little things in the hatchet. It turns out such a construction:

3r31196.
3r33573. 3r31196.
3r31196.
As previously mentioned, a high power 20W LED is used as a load. I don’t know how much he shines, and it’s not very interesting, but at 12V he consumes just 21 22 W, which my buck converter is designed for. The LED itself smeared KPT-8 and screwed it to the radiator, of course it is not enough, but it lasts 5-7 minutes of operation without problems (heats up to +40 50 3r31118. O [/sup] C), and I don’t need more. We connect from the control module 2 signals HRPWM, GND and through the divider we catch the output of the buck to the ADC, as a result we have the following stand: 3r31196.
3r31196.
3r33584. 3r31196.
3r31196.
3r31184. Chapter 4. We write software and run the converter 3r31185. 3r31196.
Now we have everything we need to start writing code and liven up our buck converter. First, let's look at the pin-out for the STM32F334R8T6 microcontroller, which is in the control module: 3r31196.
3r31196.
3r3-3597. 3r31196.
3r31196.
Now we understand what microcontroller pins will be used. On the module itself, I will need only 1 of 5 channels to control the power section; we will use channel “A”. This channel, like the others, has 2 high-precision PWM outputs (HRPWM), 1 error input (do not use it), GND for combining the ground of the boards, and 2 ADC channels (we will use only one for voltage). 3r31196.
3r31196.
[b] A little about HRPWM 3r31099. 3r31196.
3r31196.
In the open spaces of the Russian-speaking segment of the Internet, I practically did not encounter any training materials on HRPWM and did not meet at all materials about working with HRPWM based on STM32 microcontrollers, and this is a very useful periphery. 3r31196.
3r31196.
In this article I will not delve into the theory of this periphery, so I will describe the essence. HRPWM or High Resolution PWM is a PWM module that is familiar to us, which has a higher resolution setting of the duty ratio and, in addition, usually has more flexible settings. 3r31196.
3r31196.
3r3620. 3r31199. 3r31196.
3r31196.

The microcontroller STM32F334R8T6 has 10 HRPWM channels, which are combined into 5 groups of 2 channels. These 2 channels within the group can work both independently and form a complementary pair - the last one we need; 3r3645.
Inside the complementary pair between 2 PWM signals, you can set the hardware dead-time to protect against the through current; 3r3645.
All 10 channels are clocked from one timer - Master timer, thanks to which they are all synchronized with each other and you do not have to manually configure the chain of timers. It is enough to turn on the master and timers A E for clocked by it; 3r3645.
The frequency on the HRPWM is doubled, that is, with a core frequency of 72 MHz, HRPWM goes 144 MHz after the additional multiplier (x2) with PLL. This makes it possible to control the converters at a frequency of hundreds of kHz; 3r3645.
Many settings for PWM control, for example, besides the possibility to bind PWM generation to the beginning and end of the period, there are 4 more configurable events (comp) that allow you to translate PWM to 0 or 1 at any time of the period other than the beginning /end of the period; 3r3645.
There are modes for specific topologies, for example, the push-pull mode, which allows for multiple push-pull topologies. 3r3645.
3r31196.
And this is only a small part of the features, on the HRPWM device diagram you can still see the possibility of synchronization with a bunch of events, DACs, comparators built into the MC, and alongside this flowchart there are many more documented possibilities. 3r31196.
3r31196.
There remains the last question that needs to be addressed - “why is this PWM high-bit?”. To do this, consider a simple example. Imagine that you decided to use the MK without HRPWM, say STM32F103C8T? which also operates at 72 MHz. We need to control the half bridge at a frequency of 70 kHz, which step of regulation we can get: 7?00?000 /1025 steps = 7?243 Hz. Yeah, we have 1025 steps and when adjusting we can change the output voltage with a theoretical step of 1/1025 = ~ 0.1%. Now we take STM32F33? with a clocking frequency of 144 MHz and a timer shift depth of 32 bits, we get the equivalent frequency of 144 MHz * 32 = ??? GHz. For those who are frightened and questioned in the figure:

3r31196.
3r3658. 3r31196.
3r31196.
No, this is not the operating frequency, this is the equivalent frequency. What does this give us? We take the equivalent frequency of ?60?00?000 Hz /7?300 Hz = 6?535 steps. Now we can adjust the voltage (or current) at the output in 1/??? increments = ~ ???%, that is, 100 times more accurate! 3r31196.
3r31196.
And now let's do it - the frequency is 700 kHz, which is normal for a multi-phase buck, for example. F103 will have ??? Hz /??? Hz = 102 steps, which allows at best to get a regulation of 1%, but this is 1% for duty, that is, in reality, with so many steps you will have voltage to float at the output as if stabilizing and no special. Whereas for F334 the number of steps will be approximately 650? which still allows building a very accurate voltage or current regulator. We get that the resolution (step) of the setting of the duty ratio is much higher /more often than that of a conventional MK with a standard PWM module inside. 3r31196.
3r31196.
[b] Setting the clock system 3r31099. 3r31196.
3r31196.
As a development environment in this article, I used TrueSTUDIO, for it is free, not as miserable as Keil or IAR yes yes tell me about his wonderful debugger , cross-platform and perhaps the best solution for beginners and not only. At the end of the article there will be an archive with the project for this particular IDE. I will not tell you how to create and customize a project, just leave a link to the video, where everything is shown in detail - watch . 3r31196.
3r31196.
After the project has been created and the LED has flashed, it is necessary to adjust the clocking system, namely from 8 MHz, raise the frequency to 72 MHz and feed it to the core, and then adjust the divider to reduce the frequency applied to the ADC: 3r31196.
3r31196.
3r? 31124. 3r3ir31125. void StartInitClock (void) {
RCC-> CR | = RCC_CR_HSEON; //Enable HSE
while (! (RCC-> CR & RCC_CR_HSERDY));
FLASH-> ACR | = FLASH_ACR_LATENCY_1;
RCC-> CFGR | = RCC_CFGR_PLLMUL9; //PLL mult x9
RCC-> CFGR | = RCC_CFGR_PLLSRC; //Source HSE 3r3-31206. RCC-> CFGR2 | = RCC_CFGR2_ADCPRE12_DIV10; //ADC source AHB /10 3r3-31206.
RCC-> CR | = RCC_CR_PLLON;
while ((RCC-> CR & RCC_CR_PLLRDY) == 0) {} 3r3-31206.
RCC-> CFGR & = ~ RCC_CFGR_SW;
RCC-> CFGR | = RCC_CFGR_SW_PLL; //Select source SYSCLK = PLL
while ((RCC-> CFGR & RCC_CFGR_SWS)! = RCC_CFGR_SWS_1) {} //Wait PLL 3r-31206.
}
3r31143. 3r31144. 3r31196.
It's all just think, the algorithm is as follows: 3r31149. switches to external quartz (HSE) -> wait for the transition to complete and set the ready flag -> feed the PLL signal from the crystal -> multiply 8 MHz by 9 -> 72 MHz divide by 10 for the ADC clock -> turn on PLL -> we wait for it to turn on and set the ready flag -> feed on the system bus and the core signal from the PLL -> wait for the switch to complete -> ready. 3r31150. 3r31196.
3r31196.
[b] Configure the HRPWM
3r31196.
3r31196.
Here everything is somewhat more complicated. This module has a lot of functionality, a lot of settings and the amount of documentation is very large, but this is a minus and at the same time a plus - you have to pay for flexibility. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. RCC-> CFGR3 | = RCC_CFGR3_HRTIM1SW_PLL;
RCC-> APB2ENR | = RCC_APB2ENR_HRTIM1EN;
3r31143. 3r31144. 3r31196.
It is necessary to indicate that HRTIM is clocked from the PLL, the multiplier x2 is already on by default. Then we just turn on clocking for HRTIM, here the first feature - as we understand the timer clocked by PLL, but turned on for APB2. This is not entirely logical, but in a file with CMSIS it is easy to search or in the documentation. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. RCC-> AHBENR | = RCC_AHBENR_GPIOAEN;
GPIOA-> MODER & = ~ GPIO_MODER_MODER8;
GPIOA-> MODER | = GPIO_MODER_MODER8_1; //Alternative PP
GPIOA-> OSPEEDR | = GPIO_OSPEEDER_OSPEEDR8; //Very high speed
GPIOA-> MODER & = ~ GPIO_MODER_MODER9;
GPIOA-> MODER | = GPIO_MODER_MODER9_1;
GPIOA-> OSPEEDR | = GPIO_OSPEEDER_OSPEEDR9;
GPIOA-> AFR[1]| = 0xDD; //PA8 and PA9 - AF13 3r3-31206. 3r31143. 3r31144. 3r31196.
PA8 and PA9 is the output of Timer A, which on my module goes to channel No. ? which you can see on the diagram and pin-out. Legs are configured as a push-pull with an alternative function, the number of the function itself for both legs is the 13th. It is also important to tune to the maximum GPIO frequency, otherwise it will be an incomprehensible blockage of the front and the fall of the signal, which is extremely critical for power electronics. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. HRTIM1-> sCommonRegs.DLLCR | = HRTIM_DLLCR_CAL | HRTIM_DLLCR_CALEN;
while ((HRTIM1-> sCommonRegs.ISR & HRTIM_ISR_DLLRDY) == RESET);
3r31143. 3r31144. 3r31196.
Before you start, you need to calibrate the timer, because it works with minimal delays, then just wait for the ready flag. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. HRTIM1-> sTimerxRegs[0].PERxR = PeriodTimerA; //Period for timer A
HRTIM1-> sTimerxRegs[0].CMP1xR = 0; //Duty for timer A
3r31143. 3r31144. 3r31196.
That went flexibility. Firstly, we can set our own frequency for each timer A E, then we simply record the period of our PWM. Secondly, by default we have PIMA alignment at the beginning of the period, that is, the signal goes to log.1 at the beginning of the new period, and now we need to choose when it returns to log.? in this case by comparator No. ? that is I ask in it the essence of the fill factor (duty). 3r31196.
3r31196.
For example, you can translate PWM not at the beginning of the period, but by comparator # ? but return to log.0 by comparator # 2 and thus move the phase by hardware. 3r31196.
3r31196.
HRTIM1-> sTimerxRegs[0].OUTxR | = HRTIM_OUTR_DTEN;
//Tdtg = ??? ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTPRSC_0 | HRTIM_DTR_DTPRSC_1;
//Deadtime rising = 15 * Ttg = 104 ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTR_0 | HRTIM_DTR_DTR_1 | HRTIM_DTR_DTR_2 | HRTIM_DTR_DTR_3;
//Deadtime falling = 15 * Ttg = 104 ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTF_0 | HRTIM_DTR_DTF_1 | HRTIM_DTR_DTF_2 | HRTIM_DTR_DTF_3;
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTFSLK | HRTIM_DTR_DTRSLK;
3r31143. 3r31144. 3r31196.
At this stage we include the dead-time and set it up, in principle there are all formulas in the comments, they can also be found in the reference manual. DT with a duration of ~ 100 ms you have already seen on the oscillogram in the theoretical chapter of this article. Dead time can be set separately on the front and on the decline of the signal. By the way,[0]- this is Timer A, respectively,[1]- this is Timer B and so on. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. //Samples in the middle of ON time
HRTIM1-> sTimerxRegs[0].CMP2xR = PeriodTimerA /10;
//ADC trigger 1 update: Timer A
//ADC trigger 1 timer A compare 2
3r31143. 3r31144. 3r31196.
For me it was not the most obvious point. Essentially, I want to make it so that at 10% of the duration of the Timer A period, an event is generated that would trigger the ADC conversion and measure the feedback signal. Why 10%? Just ideally, the measurement should not fall at the time of the transition of PIM from 0 to 1 or vice versa, because At this moment, transients and disturbances occur in the power section, and we do not need to measure them. Therefore, in my case, 10% is optimal, since at 12V output and 30V input voltage of the duty cycle (duty) does not fall to 10% and the switching time of the transistor does not exactly coincide with the measurement of the ADC. 3r31196.
3r31196.
Now you need to look at the event communication system between HRTIM and the ADC: 3r31196.
3r31196.
3r31196.
3r31196.
In the first line, we choose when exactly the comparator will work, in my case it is 10% of the period of timer A. Next, we select a specific trigger in the ADC, which MK will contact, 1 or 3 is available. Now it simply indicates which event will send a signal to the ADC, in my case it is comparator # 2. 3r31196.
3r31196.
3r? 31124. 3r3ir31125. //Enable output PWM for TA1 and TA2 3r3-31206. HRTIM1-> sCommonRegs.OENR | = HRTIM_OENR_TA1OEN | HRTIM_OENR_TA2OEN;
//Continuous mode
HRTIM1-> sTimerxRegs[0].TIMxCR | = HRTIM_TIMCR_CONT;
//Period for master timer
HRTIM1-> sMasterRegs.MPER = 65000;
//Enable counter for Master and timer A
HRTIM1-> sMasterRegs.MCR | = HRTIM_MCR_MCEN | HRTIM_MCR_TACEN;
3r31143. 3r31144. 3r31196.
And the final chord! We allow HRTIM to output signals from Timer A to our GPIO. Now we select the mode, it is infinite (I have it), and it happens that the timer has been turned on for 1 period and after that it must be started again. Next, set the period for the Master timer and turn it on with the last step, it starts clocking the channel timers and the PWM signal appears at the output. 3r31196.
3r31196.
It was a setup function, it remains to make a function that will set the fill factor (duty), and we will work with it when creating the regulator: 3r31196.
3r31196.
3r? 31124. 3r3ir31125. void SetDutyTimerA (uint16_t duty) {3r-31206. HRTIM1-> sTimerxRegs[0].CMP1xR = duty;
}
3r31143. 3r31144. 3r31196.
3r33878.
Listing the settings feature and setting the fill factor 3r31099. 3r3881. 3r? 31124. 3r3ir31125. //f = 102.4 kHz
#define PeriodTimerA ((uint16_t) 45000)
void InitHRPWM (void) {
RCC-> CFGR3 | = RCC_CFGR3_HRTIM1SW_PLL;
RCC-> APB2ENR | = RCC_APB2ENR_HRTIM1EN;
/************************************************
. * Setting GPIO
************************************************ /
RCC-> AHBENR | = RCC_AHBENR_GPIOAEN;
//Alternative PP
GPIOA-> MODER & = ~ GPIO_MODER_MODER8;
GPIOA-> MODER | = GPIO_MODER_MODER8_1;
//Very high speed
GPIOA-> OSPEEDR | = GPIO_OSPEEDER_OSPEEDR8;
GPIOA-> MODER & = ~ GPIO_MODER_MODER9;
GPIOA-> MODER | = GPIO_MODER_MODER9_1;
GPIOA-> OSPEEDR | = GPIO_OSPEEDER_OSPEEDR9;
//PA8 and PA9 - AF13 3r3-31206. GPIOA-> AFR[1]| = 0xDD;
/************************************************
. * Setting timer A
************************************************ /
HRTIM1-> sCommonRegs.DLLCR | = HRTIM_DLLCR_CAL | HRTIM_DLLCR_CALEN;
while ((HRTIM1-> sCommonRegs.ISR & HRTIM_ISR_DLLRDY) == RESET);
//Period for timer A
HRTIM1-> sTimerxRegs[0].PERxR = PeriodTimerA;
//Duty for timer A
HRTIM1-> sTimerxRegs[0].CMP1xR = 0;
HRTIM1-> sTimerxRegs[0].OUTxR | = HRTIM_OUTR_DTEN;
//Tdtg = ??? ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTPRSC_0 | HRTIM_DTR_DTPRSC_1;
//Deadtime rising = 15 * Ttg = 104 ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTR_0 | HRTIM_DTR_DTR_1 | HRTIM_DTR_DTR_2 | HRTIM_DTR_DTR_3;
//Deadtime falling = 15 * Ttg = 104 ns
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTF_0 | HRTIM_DTR_DTF_1 | HRTIM_DTR_DTF_2 | HRTIM_DTR_DTF_3;
HRTIM1-> sTimerxRegs[0].DTxR | = HRTIM_DTR_DTFSLK | HRTIM_DTR_DTRSLK;
//Event forces the output to the active state for TA1
HRTIM1-> sTimerxRegs[0].SETx1R | = HRTIM_SET1R_PER;
//Event forces for TA1
HRTIM1-> sTimerxRegs[0].RSTx1R | = HRTIM_RST1R_CMP1;
/************************************************
. * ADC trigger intialization (with CMP2 event)
************************************************* /
.
//Samples in the middle of ON time
HRTIM1-> sTimerxRegs[0].CMP2xR = PeriodTimerA /10;
//ADC trigger 1 update: Timer A
//ADC trigger 1 timer A compare 2
/************************************************
. * HRTIM start
************************************************ /
//Enable output PWM for TA1 and TA2 3r3-31206. HRTIM1-> sCommonRegs.OENR | = HRTIM_OENR_TA1OEN | HRTIM_OENR_TA2OEN;
//Continuous mode
HRTIM1-> sTimerxRegs[0].TIMxCR | = HRTIM_TIMCR_CONT;
//Period for master timer
HRTIM1-> sMasterRegs.MPER = 65000;
//Enable counter for Master and timer A
HRTIM1-> sMasterRegs.MCR | = HRTIM_MCR_MCEN | HRTIM_MCR_TACEN;
}
void SetDutyTimerA (uint16_t duty) {3r-31206.
HRTIM1-> sTimerxRegs[0].CMP1xR = duty;
}
3r31143. 3r31144. 3r31196.
3r31196.
Now let's find out if we are going the right way. In function 3r31149. main [/i] We initialize the HRTIM setting and set the duty cycle, say 22500. With an input voltage of 20V and a period of 4500? our fill factor will be 50% and the output will be about 10V. This is not enough to blow up the LED to full, but it should catch fire and we will understand if the power part is working, is everything good with dt and so on. I started everything from the first time:

3r31196.
3r31155. 3r31156. 3r31157. 3r3998. 3r31159.
3r31196.
3r31196.
You can see that all previous theoretical calculations have been confirmed. With a fixed duty cycle (duty) of 50%, the output voltage was simply divided into 2: 20V -> 10V, 22V -> 11V, 18V -> 9V. Now let's make sure that the output voltage is stable and does not depend on the input, that is, we add feedback. 3r31196.
3r31196.
3r31196.
About ADC in STM32 a lot has already been written to me, I elaborated only on setting up a trigger tied to the HRTIM comparator. I will briefly tell you about the rest of the ADC settings. We look at the initialization function:

3r31196.
3r? 31124. 3r3ir31125. void InitBasicADC (void) {
RCC-> AHBENR | = RCC_AHBENR_GPIOCEN;
/************************************************
. * Calibration
************************************************ /
Delay (10);
/************************************************
. * Select event trigger and channel
************************************************ /
//Enable start conversion external trigger
//Length regular ADC channel = 1
/************************************************
************************************************ /
Delay (10);
}
3r31143. 3r31144. 3r31196.
I use the regular channel mode, I have only one channel and it is selected in the register 3r31149. SQR1 [/i] . Enabled the ADC number ? namely, its input IN? it is fast and can work at the maximum sampling frequency, but not this time. The sampling rate is equal to the PWM frequency, since 1 period = 1 sample, in principle, this is more than enough. 3r31196.
3r31196.
We also register CFGR 3r31150. you need to select an event that will trigger the conversion, that is, Event 7 3r31150. Why him? We look in RM:

3r31196.
3r31085. 3r31196.
3r31196.
Trigger 1 from the HRPWM module comes to Event 7 for our ADC No. ? which in this case works as a slave, it is controlled from the HRPWM module. I think now it is clear how to connect 2 modules, in principle, the algorithm is similar for any periphery and any timer, the name of the register will be different. 3r31196.
3r31196.
Upon reaching the period counter, the master timer will start the conversion, which after about 15 cycles (how many exactly look at RM-e) will cause an interrupt and you can pick up the result. It is in this interruption that we organize the control algorithm. Yes, it’s better not to do something massively inside the interrupt, it’s better to set the flag and transfer the execution further, but I allow myself this simplification, because in this case my controller is not particularly loaded and it will be able to calculate and exit the interrupt with 146% probability the emergence of a new one. 3r31196.
3r31196.
[b] A little about the management of 3r31099. 3r31196.
3r31196.
Imagine that you entered the bathroom and decided to wash your hands in the sink. You slightly open the water, touch with your hand, cold? Add more hot water, warmer? Good! Add more hot water? Almost what you want? Good! Add more hot water, try with your hand, burn it? Come on, now let us down a little hot. Good? And so indefinitely you will turn the tap until the water temperature is perfect. This is the easiest regulator! 3r31196.
3r31196.
Only here, it is not the amount of hot water that is regulated, but the fill factor of the PIM. Instead of a hand, we have an ADC with measured result. It remains only to implement the logic. We consider that we should issue an ADC at 12V at the output, and then with the help of condition 3r31149. if
make our controller maintain this value by changing the duty cycle (duty). 3r31196.
3r31196.
To begin with, let's hang a voltage divider at the output to reduce 12V to 2-2.5V, for example, since The ADC can measure from 0 to + 3.3V and if you apply 12V, the microcontroller will burn simply. Therefore, I will put a divider with nominal values ​​of 10 kΩ and 2 kΩ, which will give a division factor of 6 and, accordingly, our + 12V will turn into + 2V. Our ADC will produce the result: adcResult = (V [sub] Out /k) /V 3r3r16116. ref 3r31117. * 2 12 = (12V /6) /3.3 * 4095 = 2481. Now we write the code for the interrupt handler: 3r31196.
3r31196.
3r? 31124. 3r3ir31125. void ADC1_2_IRQHandler (void) {3r-31206.
dutyControl = dutyControl - 10;
}
else
{
dutyControl = dutyControl + 10;
}
SetDutyTimerA (dutyControl);
}
3r31143. 3r31144. 3r31196.
The first thing after getting into the interrupt handler is to reset the flag of the interrupt itself, otherwise the second time you will not get into it. Then we read the result and save it as a variable adcResult . Now, knowing the voltage at the output, you need to make an adjustment to the value of the fill factor for PWM, I realized this simply through the condition 3r31149. if
. In each PWM period, we measure, increase or decrease the fill factor and set the result for the next period. Everything is simple, fast and visible essence. We look at the result of the work:

3r31196.
3r31155. 3r31156. 3r31157. 3r31158. 3r31159.
3r31196.
3r31196.
As you can see, everything works and when the input voltage changes, the output itself remains stable at 12V. Strongly attentive can notice small needles skipping, then you just need to hang up the X7R ceramics at the output of 1-10 microfarads and they will leave, I'm just too lazy to look for it and solder it. Now the oscillogram itself, so as not to spoil the eyes:

3r31196.
3r31171. 3r31196.
3r31196.
Here you can see how the output voltage rises. The fact is that due to the control algorithm, the filling must reach values ​​from 0 to 1?00? for example, a thousand periods are needed, or approximately 10 ms. It suits me because soft-start, if you want to shorten the rise time, then just complicate the algorithm and add +100? not +1? and the closer you get to the specified 12V, the less regulation step you take until you reach +10 . In general, in terms of management, you can do a lot of things, so you have a field for experiments. 3r31196.
3r31196.
Another interesting point is the oscillations at the moment of shutdown, such an "accordion". The fact is that after turning off the power, my digital part continues to work from another power supply unit and it tries to keep the desired value at the output. Where does energy come from? Yes, from the input capacitor, these are the ones that are 1000 µF each, as many as 3 pieces, this is an interesting phenomenon. 3r31196.
3r31196.
3r31184. Conclusion 3r31185. 3r31196.
The article came out is not small, but you wanted everything and immediately say, let's get a finished piece of metal - you will get it. I hope you enjoy the article, tried to make it more likely not scientific, but popular science, so that the material was available to people with different levels of knowledge and experience. Perhaps in the future I will analyze similarly other topologies like boost, full bridge and others. 3r31196.
3r31196.
By the way, this article and code will serve for the new MPPT controller at 20A, which I am designing. Now I wait for a payment from 3r31192. PCBway
which, in fact, volunteered to sponsor my open projects with printed circuit boards, the source code for MPPT will also be open to all my modules. 3r31196.
3r31196.
Most importantly forgot! Keep the project with the code for TrueSTDIO -
RAR 3r31199. .
+ 0 -