FPGA: PID controller (VHDL newbie) - Page 1
Forum section: electronics / general

author: Yansi
author_rank: Super Contributor
timestamp: April 17, 2020, 10:50:48 pm
content: Hello, it's me again with my FPGA adventures, learning VHDL by practicing it.Today I have tried to implement a PSD controller (just PS to be specific). Being bit more knowledgeable I have gone straight to the incremental form to spare myself the pain experienced by many others. PS controller difference equation should be:y(n) = y(n-1) + A0*x(n) + A1*x(n-1)where the transformed coefficients shall beA0 = Kp + KiA1 = KpI have tried to implement it using just my own ideas cobbling together some state machine, that should go through the equation step by step. But that failed miserably, making the horrendous mess you can see attached. Very resource hungry and very ineffective. After seeing what my original code has synthesized to, I have realized it would be better to start from scratch and think a bit more before writing some code, rather than doing it the other way round.After bit of paper + pencil + brain time, I came up with this circuit idea below. The idea is to have a 16bit precision input/output controller, with an internal 32bit accumulator. Following the equation mentioned above, it seems to me, the whole PS controller can be calculated in just two multiply-accumulate steps, using the same 32bit adder and the same 16x16 multiply, just by multiplexing the inputs to the multiplier.That way I think I can get the best resource usage and a sensible implementation that will probably also work. Also, it would be handy to add intermediate registers around the multiplier to speed stuff up, but those were omitted for clarity (and I do not need that much speed anyway).The register on the left side is the z-1representing thex(n-1)term.The whole then shall be controlled by a simple state machine: Either idle (waiting to trigger the calculation), or then in the two states of calculating the two products ofA0*x(n)andA1*x(n-1).The question is, is this a sensible approach or not and why?I have tried at first to find a suitable beginner tutorial, but I only mostly find it implemented in the most ugly way that could compete with my original one.//EDIT: Ugly typos.

author: hamster_nz
author_rank: Super Contributor
timestamp: April 18, 2020, 12:29:40 am
content: I think you might be better off using two multipliers, as that way you can use different 'scale factors' for the A0 and A1 constants, and on their products. It also avoids the need for MUXs and an FSM.You can also run at half the clock rate for the same throughput...In most FPGAs the DSP blocks are set up for cascading of operands and products, which could be leveraged if highest performance is needed.

author: BrianHG
author_rank: Super Contributor
timestamp: April 18, 2020, 01:18:45 am
content: VHDL(It just means I really wanted to help, but I only know System Verilog)

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 10:08:30 am
content: Quote from: BrianHG on April 18, 2020, 01:18:45 amWell I did not ask for code... yet!So it's fine, just asking about the generic principles, I can probably then cobble some code together and make another useless logic mess.Quote from: hamster_nz on April 18, 2020, 12:29:40 amI have the smallest Cyclone IV FPGA of them all and am afraid I would run out of resources, if I'd be using too much logic hungry design. hence my question if it is sensible to optimize like this. Different scale factors for A0 and A1 are rarely required - at least from my experience working with SW on a different platform. The scale is applied by scaling the input/output of the controller function.So considering the same scale factor and resource usage constraint, does the above make sense? Little FSM to control it will probably not add much logic. (At least thats what I think now)

author: OwO
author_rank: Super Contributor
timestamp: April 18, 2020, 10:24:04 am
content: Yes, your general approach is sound: drawing a diagram before writing code, utilizing basic building blocks (mux, flipflop, arithmetic units, etc), and understanding how they map to FPGA resources.I haven't seen your code so I can't comment on that, but I do recommend putting enough detail into your diagrams so that the code is basically a mirror image of the diagram. For example, if there are pipeline registers, it changes the logic and overall timing, so it's best to leave those on the diagram.EDIT: I also recommend drawing timing diagrams to clarify the operation of the circuit and so you have something to check against when troubleshooting simulations or logic analyzer waveforms.Wouldn't it be possible to omit mux2? Since when it comes time to calculate A1*x(n) the input has already moved to the next value; if you need to handle non-continuous data you could add a clock enable term to all flipflops but this comes at a performance penalty. mux1 can also be omitted by using a shift register ring, but the mux approach is also cheap because the inputs are constant.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 12:02:30 pm
content: Quote from: Yansi on April 17, 2020, 10:50:48 pmIMHO you are making the classic mistake to think in terms of logic. Also in many cases you won't need the D part from PID so let's just look at the PI part.In VHDL you can write this (with all signals defined as integer types):error <= setpoint - input;integrator <= integrator + error * ki;output <= integrator + kp * error;and the synthesizer will map it onto FPGA logic (whether it has built-in multipliers / adders) or not. If you have a specific FPGA as a target then make sure to read the synthesizer manual on how calculations are mapped on hardware. It is possible that you can get a better resource usage by writing the equations in a certain way. You can probably add the D part yourself.Now onto the interesting part of implementing a PID controller using fixed point math; you'll have to very carefully think about having enough resolution and catching overflow conditions. You'll likely want to limit the range of the integrator so it doesn't wrap around (remember the integrator's main purpose is to take care of DC offset in the control loop). A good idea is to create a test bench and simulate your PID controller to see if you have enough resolution. I think 16 bits may not be enough so if the building blocks only support 16 bit then you'll need to cascade them; let the synthesizer handle that for you. Another interesting excersize is to write the equations in various ways and see how that affects the implementation (speed and resource wise). That knowledge can be universally applied to future projects instead of going the tedious hand crafting route every time.Now someone will probably chime in and say that writing equations is never going to get the best performance yadda yadda yadda yadda. But you can't go around hand-optimising large FPGA designs. It is like writing an entire microcontroller application in assembler instead of C. VHDL synthesizers are much more capable than people seem to think. You can achieve the resource sharing through the synthesizer as well if you rewrite the PID controller as a statemachine. But read the synthesizer manual on how to achieve that.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 12:30:54 pm
content: Whats wrong about thinking in terms of logic, if designing a logic circuit is exactly what I am doing?Your suggestion ofQuoteis exactly what leads to a mess*. Please read carefully, as I have said clearly, the derivative (Kd) is not used and I am also using the proper DSP-friendly form of a PS controller in the incremental form, where you do not need to care about some overflowing sum.There is nothing that can overflow in the PS controller equation in incremental form, if all one does is to just use a saturated addition for the accumulator. Saturated add function is easy to implement, using just some combinatorial logic from the upper bits and a MUX, that swaps output for a maximum positive / minimum negative value. I got that already working, see below:* Likely requiring one more 32bit register for the integrator and uses 2 multipliers instead of one. And also one more 32bit adder. That is already way too many more resources used.

author: mikerj
author_rank: Super Contributor
timestamp: April 18, 2020, 12:43:10 pm
content: Quote from: Yansi on April 18, 2020, 12:30:54 pmKp has nothing to do with the derivative, it's the gain for the proportional term.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 12:46:31 pm
content: Kd, of course. That is a typo there.//corrected, thanks for pointing that out.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 01:09:31 pm
content: Quote from: Yansi on April 18, 2020, 12:30:54 pmIt is local optimalisation. Local optimisation is a slow process which in the end is limited by how efficient a certain approach can be implemented. It is better to start with a more efficient method at a higher level. Just read the synthesizer manual to see how you can infer resource sharing and go from there to look for a PI loop implementation which fits best on that. Also, don't look at the intermediate output from the synthesizer but at what is actually going into the FPGA. The synthesizer may produce a lot of extra logic so the solution may seem sub-optimal but all unused logic will be optimised away at a later stage.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 01:23:56 pm
content: But I do not understand how does writing "a mess" at first help me to reach more optimal (in terms of resources used) solution?I have no doubts that the synthesizer can do some clever tricks and what not, but I think the code you have suggested will not or could not ever optimize to something like I have drawn on the paper, which to me seems like a pretty good solution to not waste resources.Or am I missing something there?(I will now try to put down some code to try sythesize my circuit from the paper drawing.)

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 01:27:45 pm
content: You have to start somewhere and that is the synthesizer manual and see what they write in there about resource sharing. From there re-write equations to steer the synthesizer towards an optimal solution.I'm also not sure whether your DSP friendly solution is the best option. Usually there is a factor of 100 to 1000 between Kp and Ki. Combining them into one multiplication factor seems like a sure way to loose resolution. Having a seperate integrator (which can be bit-shifted for free) looks like a better plan to me in order to reduce the number of bits needed while keeping resolution high. If you want to share the multiplier you can calculate the integrator (a 32 bit register) in the first cycle and then add the top 16 bits from the integrator with the multiplication of kp * error in the second cycle. In the end the amount of logic you need is the same. But this kind of optimisation really starts by determining the minimum number of bits you need to achieve the required accuracy.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 01:43:46 pm
content: I come from the motor control / power electronics world and I admit I have never stumbled upon a place I would need separate scales for those two. But being rather young there may be a lot to see yet, no doubts. We have always scaled just the whole input/output of the controller.Sure, 16 bits fixed-point PI controller is not much resolution. 100 : 1 scale is just 7 bits difference, leaving still 7 bits of precision. Also, no precision is lost, as the accumulator is not truncated and full multiplication accuracy is kept there.I will probably modify it for 32 bits later, but I need something simple that works first. Using a 32x32 multiply would eat 4 of the 18bit multipliers per single operation. Using your approach of "mess code first", I would need 2 of those 32x32 multipliers per controller, meaning 8 HW multipliers per controller. The FPGA only has 15 of them and I need 6 controllers total. That does not fit well, hence it got me thinking about improving my approach to begin with.Sure I can make a 4-stage pipelined multiply to use just a single 16bit multiplier to do a full 32x32 multiply in 4 steps. But that is too much trouble for a VHDL beginner. Even though I know some tricks how to improve things, I have a lot of troubles fighting with VHDL syntax, types and what not now, so trying to do simple steps first.What you have suggested was essentially what I have started with, now trying to improve it.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 02:03:21 pm
content: You need a maximum of 2 multipliers per PI controller if you keep the data paths at 18 bit. So 6 controllers would need 12 HW multipliers. I'm not too familier with the Cyclone FPGAs but I assume each HW multiplier has an accumulator as well. That accumulator would be very useful as an integrator.So something like this with all signals as 18 bit signed numbers except for the integrator (which I assume would have at least 36 bits):error <= input - setpoint;integrator <= integrator + ki * error;mul_add <= error * kp + integrator(35 downto 18);output <= mul_add(35 downto 18);This should synthesize into using 2 HW multipliers per PI controller. The value for ki is divided by 262144 for free.You can play with speed versus amount of logic by placing the lines 'error <= input - setpoint;' and / or 'output <= mul_add(35 downto 18);' outside a clocked process.

author: OwO
author_rank: Super Contributor
timestamp: April 18, 2020, 02:14:49 pm
content: Number of multipliers you would use is entirely set by the maximum sample rate you need to handle. If this is something like 1Msps, use a single 18x18 multiplier and multiplex it, and you can get away with writing behavioral code because the whole thing would only need to run at 48MHz for 6 channels. The dataflow methodology and heavy pipelining is what I do to hit 350MHz on the slowest speed grade Artix.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 02:19:19 pm
content: 32x32 multiply (or 36x36) requires four 16x16 (or 18x18) HW multipliers.No accumulators after the multiplier. Just optional registers on both inputs or the output. Cyclone IV is quite simple FPGA I guess. Already investigated in the device handbook.OwO: I need to run all controllers at like 10kHz rate or what, so I could happily multiplex just one to do all the work. A bit funny to use FPGA for this, but there's other HW I need that I can't get or emulate using a generic MCU.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 02:20:56 pm
content: Quote from: OwO on April 18, 2020, 02:14:49 pmThat is also an option. And a really development time effective approach would be to use a small soft-core like the Picoblaze from Ken Chapman which takes care of the sequencing part using some software.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 02:21:52 pm
content: Quote from: Yansi on April 18, 2020, 02:19:19 pmYes, but do you need 32 bit multiplications? In the end your multiplications don't need to exceed the bit width of the output signal. What is the resolution of the output signal? And I think there are some optimisations possible as well.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 03:25:20 pm
content: I find it highly unrealistic to try bother with any kind of obscure softcore CPU architecture as an FPGA beginner. :-/Not that sure what width of multiply is really needed. But the other logic supposed to be fed the output from the controller now can accept up to 24 bits. Could be little less, little more. Not finished with it yet either.It seems that using the approach of "think first - code later" is much better - to no surprise. It was easy to pursue the sythesizer to produce the thing below.Now if I'd fill in the missing structure on the B input of the multiplier, I'd have a complete PS controller. Even surprised it required less code to write, than my original version, that synthesized to the garbage I wasn't even sure it worked properly.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 03:41:49 pm
content: Quote from: Yansi on April 18, 2020, 03:25:20 pmYou should look into it. The Picoblaze is an extremely simple and yet powerful solution to avoid having to code complex statemachines in VHDL. I have used it in several designs; it could be a good fit for your protect if you want to pipeline the multipliers. Another option is to use a programmable statemachine but the Picoblaze is probably easier.

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 18, 2020, 04:50:25 pm
content: Just a couple thoughts:- I think the "hardest" part (if you consider that "hard") here will be to avoid overflows/underflows using fixed-point arithmetic (which I assume here), rather than figuring out how to implement it efficiently; I don't completely disagree with nctnico with this (but I think his naive implementation is probably not dealing with overflows right to begin with?) As many often say, as long as the result fits your requirements in terms of speed and area, it's not necessary to optimize it further unless it's done for just its own sake (and, why not.)- Pipelining will get you a lot more ROI in terms of speed improvements than any other technique IMO for this,- Regarding using a CPU soft core, I do agree that it would make it much more difficult especially if you've never used one before. And looks overkill to me for just a PID.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 05:00:44 pm
content: Quote from: SiliconWizard on April 18, 2020, 04:50:25 pmYou are definitely wrong here. Try to figure out the logic and statemachines needed to pipe all the multiplications through one multiplier for 6 channels. It is much easier to implement sequential logic using software than hardware. The Picoblaze was officialle called 'Ken Chapman's Programmable State Machine' and it is just that. It has 4 (IIRC) simple instructions. In case of a PID controller the program can loop over 6 sets of input, setpoint, ki, kp, integrator and output registers. The data itself doesn't flow through the Picoblaze; the Picoblaze only controls the multiplexers to select the input for the multiplier / adder and where to store the result. Sure this approach doesn't get the highest throughput but it is extremely time efficient to develop. The Picoblaze (or something similar) is something which belongs in every FPGA / ASIC designer's toolbox.

author: Yansi
author_rank: Super Contributor
timestamp: April 18, 2020, 05:34:19 pm
content: Just wanted to note, that Picoblaze is a product for Xilinx and seems intended to be used only by Xilinx users. I am not sure if it is legal to be used on other vendors FPGAs. Altera (Intel) seems to have some sort of NIOS softCPU.Regarding the fixedpoint overflow: As I've already stated, only a saturating adder is required. Already implemented that and verified it working.The current state machine to control the PS controlel is extremely simple three state one. Waiting in idle, then stepping through the other two steps. No other conditions anywhere. Dead easy.Adding a top level FSM to multiplex through 6 set of inputs and outputs would also be likely straightforward.(And I almost doubt a simple 8bit softCPU would be even capable of computing 6 PS controllers at any half-decent rate)

author: filssavi
author_rank: Frequent Contributor
timestamp: April 18, 2020, 06:14:12 pm
content: Unless you are planning to run the PID at 100/200 MHz ( which in motor control I doubt you want) soft core is the way to go, only one multiplier/ adder needed , don’t bother with micro optimising the architecture, as it is a waste of time (unless you want to learn to do that, in that case optimise away)

author: SiliconWizard
author_rank: Super Contributor
timestamp: April 18, 2020, 06:18:01 pm
content: Quote from: Yansi on April 18, 2020, 05:34:19 pmThat's right. It's free to use... on Xilinx products only.https://en.wikipedia.org/wiki/PicoBlazeQuote from: Yansi on April 18, 2020, 05:34:19 pmIt's certain it wouldn't be able to reach the same frequencies and would eat up more resources.Since you pretty much have it all figured out, I can't see what it would bring to the table.

author: nctnico
author_rank: Super Contributor
timestamp: April 18, 2020, 07:35:02 pm
content: Quote from: Yansi on April 18, 2020, 05:34:19 pmGood point. Picoblaze is highly optimized for Xilinx anyway (it is a true work of art) but for non-Xilinx use there is a functionally identical portable version called 'Pacoblaze'. NIOS is a full blown CPU core which is much more complicated (and overkill for a relatively simple statemachine).In my projects I create a way to change the Picoblaze program externally (so I don't need to go through the FPGA compilation process) and debug it's firmware. For small FPGA projects which compile in seconds it doesn't matter much but when the compilation starts to take serious time then it can be a fast way to develop.

author: filssavi
author_rank: Frequent Contributor
timestamp: April 18, 2020, 09:48:42 pm
content: Quote from: SiliconWizard on April 18, 2020, 06:18:01 pmThe statement is true, but it completely misses the point, I see very very few instances where a digital PID controller working at such extreme frequencies can be actually usefull in real life (other than as a d**k measuring context), so the frequency advantage while technically true is not applicableAs for the resources, modern FPGA’s are so large that using a tiny soft core or two is not that much of an issueEDIT: on the resources side, calling the processing unit a soft core is also very generous, as for most type of non adaptive controllers including Not only PIDs but much more advanced stuff you can really get by without even having loops and jumps, as you are executing mostly just a series of math operations chained together, this also simplified the control unit design greatly (that means you will have to write your own assembler/compiler though as I think adapting LLVM to such a strange architecture would be quite strange

author: Bassman59
author_rank: Super Contributor
timestamp: April 19, 2020, 04:00:55 am
content: Quote from: nctnico on April 18, 2020, 07:35:02 pmIt's "highly optimized for Xilinx" because by writing it as instantiations of Xilinx primitives makes it impossible to directly port to other manufacturers' devices. (Or even newer Xilinx devices. Last time I used a PicoBlaze I was doing Spartan 3AN designs, so ...). That was the intent. The line about how doing so is for best performance is bullshit.

author: nctnico
author_rank: Super Contributor
timestamp: April 19, 2020, 11:01:52 am
content: Quote from: Bassman59 on April 19, 2020, 04:00:55 amYou are not getting my points: Picoblaze is a very neat example of hand crafting primitives into something functional. That is why I wrote 'highly optimised'. Secondly I'm not writing about performance as in throughput (I litteraly wrote you won't get the highest throughput) but using a simple softcore (programmable statemachine) like Picoblaze / Pacoblaze can greatly reduce development time. Especially when synthesizing / building a new FPGA binary takes an hour or more.

author: hamster_nz
author_rank: Super Contributor
timestamp: April 19, 2020, 10:12:15 pm
content: It seems to make sense to me to do PID in HDL with an FPGA if you need very low fixed, predictable latency.When you introduce software on a soft-core CPU the control loop latency can change based on inputs. Aside from jumps in the code path, CPU instructions like division can take a different number of cycles, and then there might be interrupts...Implementing the PID in HDL and also using the CPU for command and control seems a good idea to me.