analogWrite not working on PIN 6/9

Hi,

I am getting started with writing programs for Adruino. I was successfully able to implement the LED-hello-world of putting together an LED, a 220 Ohm resistor on a bread board and wiring it to my UNO Q.

The circuit looks like the following.

I have tuned on the LED for using digitalWrite on both pins 6 and 9. However, analogWrite works on neither.

Here is my code.

void setup() {
  pinMode(9, OUTPUT);

}

int delta = 5;
int brightness = 0;

void loop() {

  brightness += delta;
  
  if (brightness <= 0 || brightness >= 255) {
    delta = -delta;
  }

  analogWrite(9, brightness);
  delay(30);
}

Any pointer on what is possibly going wrong here would be really helpful.

The project is pretty simple, there's no reason why it shouldn't work.
Using Wokwi it works perfectly, the LED turns on and off gradually so either you have a faulty LED or some other type of hardware problem (e.g. defective breadboard or contacts inserted incorrectly or in the wrong hole...).

Hey @funkymonk89

Please remove the pinMode line from the setup and check again.

Let me know!

Cheers.

Why? The default mode for pins is "INPUT", but since we need to use it to drive a led it is an OUTPUT...

Hi @docdoc

analogWrite behaves differently, and, at the moment, it doesn’t work if the pin is configured as a digital output, which pinMode(PIN, OUTPUT) does.

Cheers.

Forgive me, but I still don't understand. Are you telling me that the call to analogWrite() doesn't work if the pin is declared OUTPUT (which should be a requirement), despite the fact that it defaults to INPUT? I've never heard of this, so I'm curious. Can you tell me where you read it?

@docdoc
This is not an Uno, but Uno Q

Try the following AI generated untested sketch for UNOQ:

// LED connected to pin 9 (PWM pin)

void setup() {
  pinMode(9, OUTPUT);
}

void loop() {
  // Increase brightness from 0 to 255
  for (int brightness = 0; brightness <= 255; brightness++) {
    analogWrite(9, brightness);   // write PWM value
    delay(10);                    // small delay
  }

  // Decrease brightness from 255 to 0
  for (int brightness = 255; brightness >= 0; brightness--) {
    analogWrite(9, brightness);
    delay(10);
  }
}

Sorry, you're right, I was misled by the schematic image in the first post.

Works like a charm! Thanks manchuino!

Just out of curiosity and to try to understand: is this a "feature" or a "bug" in the UNO Q platform/compiler? Because in my opinion, it makes no sense for it to behave differently from other Arduino boards.

I do not explicitly include pinMode(PWMPin, OUTPUT) in the sketch as the PWMPin is already configured as OUTPUT in the analogWrite() function itself.

`void analogWrite(uint8_t pin, uint8_t value)
{
    if (value > 255) value = 255;

    switch(pin) {
        case 3: // OC2B, Timer2
            DDRD |= (1 << 3);       // set pin as output
            TCCR2A |= (1 << COM2B1) | (1 << WGM20) | (1 << WGM21); // Fast PWM
            TCCR2B |= (1 << CS20);  // no prescaler
            OCR2B = value;          // set duty cycle
            break;

        case 11: // OC2A, Timer2
            DDRB |= (1 << 3);       // set pin as output (PB3)
            TCCR2A |= (1 << COM2A1) | (1 << WGM20) | (1 << WGM21);
            TCCR2B |= (1 << CS20);
            OCR2A = value;
            break;

        case 5: // OC0B, Timer0
            DDRD |= (1 << 5);  //DPin-5 as output
            TCCR0A |= (1 << COM0B1) | (1 << WGM00) | (1 << WGM01);
            TCCR0B |= (1 << CS00);
            OCR0B = value;
            break;

        case 6: // OC0A, Timer0
            DDRD |= (1 << 6);  //DPin-6 as output
            TCCR0A |= (1 << COM0A1) | (1 << WGM00) | (1 << WGM01);
            TCCR0B |= (1 << CS00);
            OCR0A = value;
            break;

        case 9: // OC1A, Timer1
            DDRB |= (1 << 1);  //DPin-9 as output
            TCCR1A |= (1 << COM1A1) | (1 << WGM10) | (1 << WGM11);
            TCCR1B |= (1 << CS10);
            OCR1A = value;
            break;

        case 10: // OC1B, Timer1
            DDRB |= (1 << 2);    //DPin-10 as output
            TCCR1A |= (1 << COM1B1) | (1 << WGM10) | (1 << WGM11);
            TCCR1B |= (1 << CS10);
            OCR1B = value;
            break;

        default:
            // Invalid pin for PWM
            break;
    }
}`

Thanks. So, since this behavior seems different from other Arduinos, can you confirm that it's a specific behavior of the UNO Q (and that in my opinion it's an unacceptable "asymmetry")?
And in any case, why does using pinMode(PWMPin, OUTPUT) prevent correct operation?

for UNOQ 

and NOT 

for UNOR3 or MEGA.

Yes, @GolamMostafa, thank you but I already know we're talking about UNO Q.

I'm just asking/wondering why on UNO Q using pinMode() prevents analogWrite() from working, as it has no reason at all in my opinion, and it appears to me to be something that violates the uniformity of behavior of Arduino boards.

Some comments made by AI are given below. Check if they make sense.

:four: Why this only happens on UNO-Q

  • Standard Arduino UNO cores handle analogWrite() so that manual pinMode() usually doesn’t break PWM.
  • Some “Uno-Q” cores or clones have slightly different Wiring.c / core implementation, where:
    • pinMode() resets the timer’s COMnx bits.
    • analogWrite() does not reconfigure the COMnx bits if called after pinMode().

So, the root cause is core implementation differences, not the hardware itself.

pinMode(9, OUTPUT);

I believe pinMode(9, OUTPUT); prevents analogWrite() from working because pinMode() is for configuring a pin as digital IO rather Analog. I speculate that the digital block for a given pin must be in a high impedance state for the analog circuit to have any effect on the pin. When pinMode(9, OUTPUT); is used the digital block will overwrite the analog circuit.
I suspect this has not come up on other Arduino boards you have used simply because earlier Uno boards do not have true digital to analog converters. PWM is a digital function that uses duty-cycle to provide an time averaged effect similar to analog but look quite different on an oscilloscope.
I believe I have used the Arduino IDE with non Arduino boards that have an anolog output which would be configured the same way the Uno Q is. I do not think this is something new or unique to the Uno Q.

Ok, that's what I was worried about. And this confirms my revulsion for the UNO Q (or, rather, for this Qualcomm "invasion" of a decade-old Arduino ecosystem) as an "anomaly" that I don't consider positive. Personal opinion, of course.

Probably, but for me it's yet another confirmation that the Q's "core" is not correct. I hope they do something to ensure that the UNO Q's basic behavior and functionality are always consistent with the rest of the boards.

PWM signal is essentially a digital signal with "varying duty cycle" and NOT a "slowly varying DC signal" (aka analog signal). So, use of pinMode(9, OUTPUT) is fully justified.

If we look into #12 for the implementation of analogwrite() function, the following line is there, which is the register level code of pinMode(9, OUTPUT).

`DDRB |= (1 << 1);  //DPin-9 (PB1/OC1A) as output `

In the above code, the Bit-1 of Data Direction Register of Port-B is made HIGH so that the direction of the correesponding DPin-9 is output.

Can the above be said straightway? For example:

When we do bit manipulation of TC1 registers of UNOR3 to generate Fast Mode PWM signal, we need to reset TCCR1A = 0 and TCCR1B = 0 first; otherwise, the codes do not generate the signal. It is because the init() function (executed before setup()) might have put some non-zero values into some bits of TCCR1A and TCCR1B registers, which have pevented our newly created codes from working.

void init()
{
        // this needs to be called before setup() or some functions won't
        // work there
        sei();
        
        // on the ATmega168, timer 0 is also used for fast hardware pwm
        // (using phase-correct PWM would mean that timer 0 overflowed half as often
        // resulting in different millis() behavior on the ATmega8 and ATmega168)
        sbi(TCCR0A, WGM01);
        sbi(TCCR0A, WGM00);

        // set timer 0 prescale factor to 64
        // this combination is for the standard 168/328/1280/2560
        sbi(TCCR0B, CS01);
        sbi(TCCR0B, CS00);

        // enable timer 0 overflow interrupt
        sbi(TIMSK0, TOIE0);

        // timers 1 and 2 are used for phase-correct hardware pwm
        // this is better for motors as it ensures an even waveform
        // note, however, that fast pwm mode can achieve a frequency of up
        // 8 MHz (with a 16 MHz clock) at 50% duty cycle

        TCCR1B = 0;

        // set timer 1 prescale factor to 64
        sbi(TCCR1B, CS11);
        sbi(TCCR1B, CS10);

        // put timer 1 in 8-bit phase correct pwm mode
        sbi(TCCR1A, WGM10);

        // set timer 2 prescale factor to 64
        sbi(TCCR2B, CS22);

        // configure timer 2 for phase correct pwm (8-bit)
        sbi(TCCR2A, WGM20);

        // set a2d prescale factor to 128
        // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
        // XXX: this will not work properly for other clock speeds, and
        // this code should use F_CPU to determine the prescale factor.
        sbi(ADCSRA, ADPS2);
        sbi(ADCSRA, ADPS1);
        sbi(ADCSRA, ADPS0);

        // enable a2d conversions
        sbi(ADCSRA, ADEN);

        // the bootloader connects pins 0 and 1 to the USART; disconnect them
        // here so they can be used as normal digital i/o; they will be
        // reconnected in Serial.begin()
        UCSR0B = 0;

}