Is there an inverse function like int analogReadWrite(uint8_t pin){} that would read and return the appropriate timer's OCnx?
My use-case is to simulate a device attached to a PWM, and I'd like to read back the PWM value without modifying the controlling code
/*
FadeWOD & analogWriteRead, adapted from
https://www.arduino.cc/en/Tutorial/BuiltInExamples/Fade
https://github.com/arduino/arduino-examples/blob/main/examples/01.Basics/Fade/Fade.ino
Simulation at https://wokwi.com/arduino/projects/323945277471851092
Forum https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774
Arduino CC0-1.0
DaveX 2022-02-18 CC SA
This example shows how to fade an LED on pin 9 using the analogWrite()
function without blocking.
The analogWrite() function uses PWM, so if you want to change the pin you're
using, be sure to use another PWM capable pin. On most Arduino, the PWM pins
are identified with a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Fade
*/
int led = 9; // the PWM pin the LED is attached to
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup() {
// declare pin 9 to be an output:
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
// non-blocking wrapper
const unsigned long adjustInterval = 30;
static unsigned long lastAdjust = 0;
if ( millis() - lastAdjust > adjustInterval) {
lastAdjust += adjustInterval;
// set the brightness of pin 9:
analogWrite(led, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= 255) {
fadeAmount = -fadeAmount;
}
// wait for 30 milliseconds to see the dimming effect
//delay(30); // handled by adjustInterval
// ***************
// This `analogWriteRead(pin);` functionality is what I'm looking for:
// Serial.println(analogWriteRead(9));
// ***************
} // end of millis() adjustInterval code
}
Is there handy function that reads the PWM value that has been written with analogWrite(pin,val); ?
int analogWriteReadUnoPin9PWM(){
// based on 9 = OC1A from
// https://upload.wikimedia.org/wikipedia/commons/c/c9/Pinout_of_ARDUINO_Board_and_ATMega328PU.svg
return OCR1A;
}
Wouldn’t analogReadWrite (nice name!) just be returning what you “analogWrote}” a few kind back?
Or have a linear relation to another number you need?
And if it is in a separate place you need that number, I see that I would have to modify the code, but you could set a global variable at the time and place of the analogWrite.
I guess I’m hacking away at my code so much alla time I think nothing of strewing all kindsa changes around.
In this case, perhaps creating a function to do all the analogWriting, then calling that function everywhere you were doing ananlogWrite would let you have code that read the same, more or less, and a localized ability to change just what and all happens with every analaogWrite.
/*
FadeWOD & analogWriteRead, adapted from
https://www.arduino.cc/en/Tutorial/BuiltInExamples/Fade
https://github.com/arduino/arduino-examples/blob/main/examples/01.Basics/Fade/Fade.ino
Simulation at https://wokwi.com/arduino/projects/323945277471851092
Forum https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774
Arduino CC0-1.0
DaveX 2022-02-18 CC SA
This example shows how to fade an LED on pin 9 using the analogWrite()
function without blocking.
The analogWrite() function uses PWM, so if you want to change the pin you're
using, be sure to use another PWM capable pin. On most Arduino, the PWM pins
are identified with a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Fade
*/
int led = 9; // the PWM pin the LED is attached to
int brightness = 0; // how bright the LED is
int oldBrightness;
int fadeAmount = 5; // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup()
{
// declare pin 9 to be an output:
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop()
{
// non-blocking wrapper
const unsigned long adjustInterval = 30;
static unsigned long lastAdjust = 0;
if ( millis() - lastAdjust > adjustInterval)
{
lastAdjust += adjustInterval;
// remember and set the brightness of pin 9:
oldBrightness = brightness;
analogWrite(led, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= 255)
{
fadeAmount = -fadeAmount;
}
// wait for 30 milliseconds to see the dimming effect
//delay(30); // handled by adjustInterval
// ***************
// This `analogWriteRead(pin);` functionality is what I'm looking for:
Serial.println(oldBrightness);
// ***************
} // end of millis() adjustInterval code
}
Or, even better, this:
/*
FadeWOD & analogWriteRead, adapted from
https://www.arduino.cc/en/Tutorial/BuiltInExamples/Fade
https://github.com/arduino/arduino-examples/blob/main/examples/01.Basics/Fade/Fade.ino
Simulation at https://wokwi.com/arduino/projects/323945277471851092
Forum https://forum.arduino.cc/t/what-is-the-inverse-of-analogwrite-pin-val/960774
Arduino CC0-1.0
DaveX 2022-02-18 CC SA
This example shows how to fade an LED on pin 9 using the analogWrite()
function without blocking.
The analogWrite() function uses PWM, so if you want to change the pin you're
using, be sure to use another PWM capable pin. On most Arduino, the PWM pins
are identified with a "~" sign, like ~3, ~5, ~6, ~9, ~10 and ~11.
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Fade
*/
int led = 9; // the PWM pin the LED is attached to
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
// the setup routine runs once when you press reset:
void setup()
{
// declare pin 9 to be an output:
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop()
{
// non-blocking wrapper
const unsigned long adjustInterval = 30;
static unsigned long lastAdjust = 0;
if ( millis() - lastAdjust > adjustInterval)
{
lastAdjust += adjustInterval;
// remember and set the brightness of pin 9:
Serial.println(brightness);
analogWrite(led, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= 255)
{
fadeAmount = -fadeAmount;
}
} // end of millis() adjustInterval code
}
OK, so you want to have a function that you can stick into the original code, in your example at the end of the free running unblocked loop() that can read back the value the rest of the (otherwise unmolested not changed) program analogWrote.
I see the point, no need to go into it, no fear of otherwise wrecking it accidentally.
Reading back the register looks like the only solution, and that depends on the origin author using analogWrite in a plain vanilla fashion OR combing through to see how it might not be. Plain.
Awkward is in the mind of the beholder. I think it is clever and beautiful.
Just don’t know how ‘xactly to do that, registers and stuff you knw, ppl make a career of it.
In case anyone wonders, the wokwi runs on a simulation of the chip, so all the registers are there and operate with fidelity to the real world.
I looked at that code and if I was at the big rig would dare take a stab at it but I see @johnwasser over there who is the one to cut this butter like a torch.
That’s for sure the kind of thing you’d need to do to make a general solution for plain usage of anslogWrite for you anslogReadWrite.
Hacking up the stock analogWrite wasn't too bad with find&replace:
int analogWriteRead(uint8_t pin)
{
// This reads what has been written
int val ;
switch (digitalPinToTimer(pin))
{
// XXX fix needed for atmega8
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
case TIMER0A:
val = OCR0; // get pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A:
val = OCR0A; // get pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0B1)
case TIMER0B:
val = OCR0B; // get pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
val = OCR1A; // get pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:
val = OCR1B; // get pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1C1)
case TIMER1C:
val = OCR1C; // get pwm duty
break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2:
val = OCR2; // get pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A:
val = OCR2A; // get pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B:
val = OCR2B; // get pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A:
val = OCR3A; // get pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
val = OCR3B; // get pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C:
val = OCR3C; // get pwm duty
break;
#endif
#if defined(TCCR4A)
case TIMER4A:
val = OCR4A; // get pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
val = OCR4B; // get pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C:
val = OCR4C; // get pwm duty
break;
#endif
#if defined(TCCR4C) && defined(COM4D1)
case TIMER4D:
val = OCR4D; // get pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5A1)
case TIMER5A:
val = OCR5A; // get pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5B1)
case TIMER5B:
val = OCR5B; // get pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5C1)
case TIMER5C:
val = OCR5C; // get pwm duty
break;
#endif
case NOT_ON_TIMER:
default:
val = digitalRead(pin) ? 255 : 0;
}
return val;
}
Thanks. It does have the same effect for this code, but I was looking to leave the the code mostly untouched an add some instrumentation for monitoring the code's IO in a corner of the unblocked loop()
This is way out of my wheelhouse, but the 328p data sheet (page 116 and 117 of my old version) recommends disabling interrupts when reading OCRxx. I'm not seeing that in these code samples. Any reasons why?
For example, analogWrite(pin,127);analogWrite(pin,0); would leave the OCRnx register with 127, but would turn off the TCCRnx & bit(COMnx1) bit so the pin is controlled by the PORTx:bit
one would have to detect whether TCCR1A & bit(COM1A1); is set and if so, then the OCR1A is controlling the pin, but if not, then the pin is controlled by digitalWrite and you have to dig up something like *portOutputRegister(digitalPinToPort(pin))&digitalPintoBitMask(pin)?255:0;
Maybe:
...
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
if (TCCRA1 & bit(COM1A1) { // pin is OC1A
val = OCR1A; // get pwm duty
} else { // pin not controlled PWM OC1A, but by output port instead
//val = *portOutputRegister(digitalPinToPort(pin))&digitalPinToBitMask(pin)?255:0;
digitalRead(pin)*255;
}
break;
#endif
...