I have a requirement to read (get the value of) the duty cycle of a previously assigned PWM pin in the arduino to forward back to a pi.
I would like to "query" the arduino for this value and not measure it externally.
In my setup, the arduino receives json commands from a serially connected pi that tells the arduino to "set" a duty cycle value on the output PWM pin. In order to conserve space, the function that does this has local and hence volatile variables (as the function is reused) and once the command is actioned the assigned duty cycle of the pin is forgotten.
At a later time, the pi "asks" the arduino via a json message for each of the arduino pin's statuses and the arduino is to send the values back.
To avoid storing the duty cycle value of each pin in a local array and updating it each time (for example) is there a way to "ask the arduino" for this duty cycle value through either a pin query command, via the PORT registers, or some other way?
I don't really want to set up interrupts on the arduino to work it out or measure from another input pin as I only want to configure and "change & query" pin state from the connected pi.
I also prefer not to hold "old" values as variables in the pi, but always query the arduino for the true value each time it is needed.
Is the setting of the pin's duty cycle held in an arduino register somewhere...or is it lost forever once the analogWrite command is executed?
Apologies if this question has already been asked and thank you for any pointers. This project is still in its infancy...
Not in a single register. For the AT... controllers the duty cycle can be calculated from TOP and OCR values and the timer mode. The mode is stored in the TCCR registers of the timer and is common to all channels of that timer. Also TOP is common to all channels and, depending on mode, can be fixed or stored in ICR or OCRA. Finally the duty cycle is TOP/OCR [*100%]
And your RAM is already in use down the last few bytes?
How many PWM-channels do you have?
I guess it can't be much more than 8
So we are talking about 8 bytes which you could use to always update whenever you set the PWM-pin to a new dutycycle and make these variables global.
If you are really in the situation of just having 6 bytes of RAM left
I would consider either finding places in your code that to save RAM at other places or choosing a microcontroller with enough RAM to do it.
My first guess is to not use JSON but a much simpler data-exchange-protocol
If you use 16 channels with d16bit duty-cycles we are still talking about just 32 bytes.
I will investigate the registers you have hi-lighted and see if this will provide what I want to achieve. It looks promising so I am extremely grateful for your reply.
The pi is running homebridge and is the "brain" and the arduino will provide the "muscle/sensors". All service types are defined and managed in the pi homebridge plugin and the arduino has no idea what it is doing. It just gets/sets things connected to each pin. All analog input scaling factors etc., will be done in the config definition in the homebridge plugin in the pi. The pi and arduino are connected via the USB port.
The homekit protocol supports both config, get, set and state change and this is why I would like to read the value of the PWM Duty Cycle in the cases of the current brightness/hue/colour characteristic of a light, or the "tilt" characteristic of window slats amongst other things.
I am using json messages so that I can also connect to the arduino via its web server/ethernet/wifi /serial port, interface easily with node-red to the arduino and make it more of a "universal" I/O json compliant device with a simple json messaging syntax. That is, it doesn't need to be connected to homebridge. Its just a black box that sends/receives standard formatted json messages.
You are right, I do have memory to work with. I was just hoping to "ask" the arduino directly "what it is currently doing with each pin?", not "what did I tell you to do earlier?" so that the response is more valid and always current.
The three replies that I have received from you, Delta_G and Dr Diettrich now give me a couple of solid options to investigate and I really appreciate all of your thoughts and insights.
What makes you think using a variable to save the last setting applied won't be "valid and always current"? The duty cycle is setting is only changed when you set it with and analogWrite(). So it makes zero sense to think that that value and the value saved in the variable can get out of synch.
On the other hand, on the AVRs, the low-level OCRnx PWM registers are not changed when you send an analogWrite(pin,0) or an analogWrite(pin,255) because the code shortcuts and calls digitalWrite(pin,xx) instead.
void receiveData() {
myJSONString .....
..
myDutyCylce = extractDutyCycle(myJSONString); // <<== this is the ONE and ONLY line of code that SETS the value
analogWrite(Ch1,myDutyCylce);
you can execute as many read / print / send variable myDutyCycle whereever you want in your code
As long as there is a
ONE and ONLY
place where you assign the value
you can be sure that printing / sending the value delivers the momentary actual value.