I’ve been writing a program to have the PRU on my BBB manage a switched-mode power converter.
I want to make sure that if something goes wrong in the host program the power converter is shutdown gracefully, so I have implemented a simple “watch dog timer” scheme.
The idea is that the host program is constantly setting an address in shared memory to 0 in a loop. The PRU is also constantly incrementing that same address. If the host loop stops, the value at the address climbs above a maximum and the PRU knows that the host program has gone away.
As I think this scheme through, I realize that there is a large likelihood that the host program and the PRU will try to operate on this shared memory address at the same time!
So far my program has not appeared to suffer any ill effects, but I guess I’m just interested in how this is handled by the am335x and if I ought to aware of possible gotchas!
The memory writes should be atomic but the read modify write will not be. This will cause you to loose some sets to zero when the PRU reads the memory location, ARM sets it to zero then the PRU writes back the incremented value. It would be good to have the increment rate and clear rate such that if they conflict once that they won’t both happen at the same time at the next set to zero.
Thanks for the explanation.
As you might imagine, the pru is incrementing at a very well controlled frequency. The host program on the other hand I have very little control of timing (hence the need for the pru!) So from the host side, I’m just zeroing the memory address inside a “while” loop that runs a bunch of other stuff as well (mainly fprintfs and printfs.) Since I have no control of how long these operations take, I just figure that they happen when they happen, and I figure that it is really unlikely that I will see 2 zero writes from the host get clobbered in a row. At the moment I have my watch dog time set to 25, so I think this wont be a problem.
BUT… you say that the read-modfiy-write sequence will not be atomic? This is the part of the setup that is run by the PRU. If this is not atomic, am I correct in understanding that my PRU program loop will no longer run on a predictable frequency? I suppose I can tolerate timing chaos of 20-30ns, but not much more than that… and I would prefer to have my PRU loop running very regularly!
Have I understood you correctly?
Each of the memory writes will be atomic, but since you have two things
writing to the same memory location, the PRU might miss one of the ARM
code writes (or the ARM might miss the PRU write, depending on exactly
what you're doing). It's generally safer to have only one process write
each memory location and use an appropriate handshake mechanism.
This is "real-time 101", and there are a *LOT* of different ways to
handle synchronization, but one example of what you could do is:
* PRU updates a value (ie: adds one, changes a pointer to data, etc.)
* ARM reads the value and notices it changed (by comparing it to the
last value read)
* ARM core does whatever is needed, then writes a new value into a
*DIFFERENT* spot in the PRU memory. This could be the same value
written by the PRU or some other value, depending on what you're doing
* The PRU monitors the second memory location (written by the ARM) and
when it changes, the PRU knows the ARM has completed it's task.
* ...wait for the PRU to trigger the process again...
There are many lock-free semaphore, fifo, and synchronization mechanisms
you can use to safely communicate between the two asynchronous CPUs
(ARM+PRU). Google a bit and/or provide more application details if the
above mechanism doesn't sound like what you need.
Atomic is the operation completes as one indivisible operation. The
read modify write isn't since another operation can happen on the
memory location between the read and write. Atomic doesn't state anything
about how long it takes.
I thought I had seen documentation on what happens with conflicts on
accessing the PRU memory but I can't find it now. I think any additional
delay will be well under your limit.