Can I "read" the duty cycle value of an output pin previously set with a analogWrite command?

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%]

1 Like

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.

best regards Stefan

Thank you very much for your reply!

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.

Plenty to do...

Kind regards and thank you again

Jason

Thanks Stefan,

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.

Thank you

Jason

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.

If you have defined a global variable

byte myDutyCycle;

and have somewhere a receiving-function

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.

best regards Stefan

This thread had a good discussion:

The solution was that using namespaces to save the value was cleaner, more reliable and more portable than reverse-engineering the chip's PWM code.

All the more reason to abandon the fool's errand of trying to work backwards from the register settings.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.