07-22-2020 03:57 AM
Hello all,
I would like to ask for some advice in this topic. My application has different while loops running at different amount of ticks. One loop reads grid voltage through analog signals at 400 ticks and a different while loop performs the control of an inverter at 200 ticks. Which method would be better to send voltage signals from read loop to control loop? At the moment I use registers but I am having some trouble. Would global variables or memory items be better?
Thank you.
Solved! Go to Solution.
07-22-2020 04:26 AM
It very much depends if you need any synchronization between these tasks. At these speeds (I assume your 400 ticks means you run this in a non-SCTL loop with the tick timer VI) you aren’t so much concerned about single cycle delays so anything should work, even global variables (shudder), but it’s important for you to understand if these loops can run totally asynchronously and if a delay between when you write the value and when it is read in the other loop is a problem. Globals, Locals and memory do not allow you to control synchronization. The fabric makes sure that read and write access are protected from each other so your read loop never reads partial values. But this protection takes resources and time and can cause the read loop to miss updates if it doesn’t run considerably slower than the write loop. That does not have to be a problem but it could be one of the reason for your “strange” trouble.
Registers allow synchronization but you do need to utilize the according handshake signals for that to work. It also would mean that your voltage read loop (with the write register) actually should be slower or at most the same speed than your control loop, otherwise you overrun the register write. In the control loop you have to use the “output ready” signal to see if your value is valid and your control algorithm needs to process the new value or do an iteration of doing nothing or maybe just updating the output value with a new calculated instantaneous value based on the previous signal trend and the loop interval.
07-23-2020 01:10 AM
Thank you for the advice! I will try to implement what you suggested. Just one doubt. If the read register or read memory is faster than the write register or write memory (lets say twice faster), I will have the same value twice or it will read 0 when. I will try to explain by an example:
Lets say I write the voltage at 400 ticks in a register or memory with following values: 400V - 500V- 400V ...
When I read this register or memory at 200 ticks, I will have available these values 400V - 400V - 500V - 500V - 400V - 400V or these 400V - 0V- 500V - 0V - 400V - 0V.
Thank you in advance.
07-23-2020 02:38 AM
For Memory you will have read the same value twice (no guarantee that it will be always exactly twice as there is no synchronization between the loops and you could occasionally read the same value only once but also three times).
For registers you get an output ready boolean that tells you if the read value is a new value. I never have attempted to see if the read value is the same as the previous one but simply use the output ready indicator to process the new value or skip updating the current value in the control loop for this iteration.
07-23-2020 06:17 AM
@rolfk wrote:
For Memory you will have read the same value twice (no guarantee that it will be always exactly twice as there is no synchronization between the loops and you could occasionally read the same value only once but also three times).
For registers you get an output ready boolean that tells you if the read value is a new value. I never have attempted to see if the read value is the same as the previous one but simply use the output ready indicator to process the new value or skip updating the current value in the control loop for this iteration.
Don't you mean "Handshake Items"?
On the FPGA, it's important to bear in mind that the clock domain crossing mechanism can have considerable overhead depending on how the two clock domains relate to each other. It may be that if you send from a 40MHz loop to an 80MHz loop, that only every second or third value is received due to synchronisation overhead. You need to observe what the result is for your case. Handshake Items expose this mechanism, Registers don't even though they use the exact same synchronisation in the background.
BlockRAM can be used in two clock domains at the same time, but if you do this you must make sure you don't read and write to the same address simultaneously. That can be difficult to guarantee.
07-23-2020 10:14 AM - edited 07-23-2020 10:32 AM
You could be right about the item names! I’m mot in the position currently to start up LabVIEW and check the exact naming, instead sitting at the swimming pool and looking over the Mediterranean at 30 deg Celsius with a cool drink in front of me.
As to making sure to not access memory from read and write at the same time I usually solve that with a handshake register in which I write the base address of a new data frame after all frame values have been written. The read loop waits until the handshake arrives and then reads the entire frame in a single cycle loop and writing it in a DMA FIFO. Why the memory you may ask?
First it serves as memory buffer storing up to 512 frames, second it helps me demultiplexing the non-sequential order of the AI channels into the logical channel order. The read loop also receives the maximum amplitude of each frame of 64 or more channels and compares it to a threshold value. Only when the threshold has been reached will the read loop start to read up to 500 frames before and stream them through the DMA FIFO and up to 500 frames after the latest threshold exceeding. Reduces the data nevccessarey to process in RT tremendously and also the storage needed to save the data in the end!
07-23-2020 10:46 AM
Aw man. I could use a cool drink here in the office. 30°C is the only thing in common right now.... Jealous.
I'm a big fan of Block RAM also, we use it extensively across clock domains.
07-29-2021 10:26 AM
To get info: Functions > Programming > Data Storage & Transfer > VI-Defined FIFO,
then right-click it to select Data Storage & Transfer Palette again and get FIFO Method. Connect them, then choose a Read or a Write for the Method, right-click the Method and select Help. The Help contains "You can use FIFOs to transfer data among multiple clock domains", and the "transfer" is a link - click it.
The help will then show info about methods that can be used for the data transfer.
A Block Memory FIFO (look its properties when creating it), or a Hanshake Item can be used for a lossless data transfer between parallel loops, even in different clock domains. They are similar, except that FIFO can keep more data queued (the Handshake just one item), is more configurable, and does not demand a Single-Cycle Timed Loop (SCTL).
Both Handshake and FIFO can tell the reader if it gets a new data.
If your loops aren't SCTL ones, you can put an SCTL inside, and wire a True constant to their Stops, so they will execute once, but it will be enough to write/read the data. In such a case they can use the same clock domain, so the data will be transferred within one clock domain.
Yet another issue is synchronization between these loops - if the reader loop has a period of 200 ticks, the data may spent in the FIFO/Handshake from 0 to 199 ticks from being ready to being read (if the writer loop period is exactly 2x longer, the delay will be stable). Seems some synchronization method may be to use a dummy data: the writer would write a real data, wait 200 ticks, write a dummy data, and the reader would just wait for a data, without using a Loop Timer.