Can't do analogRead() after changing PWM frequency

I am experimenting with using different PWM frequencies for controlling some DC motors. I've discovered that changing the PWM frequency also affects analogRead(), and need to understand what's going on.

For example, I have this code that I'm using to set the PWM frequency for output 10, to 31kHz (this is on a Yun):

TCCR1B = _BV(CS10); TCCR1A = _BV(WGM10); TCCR1A = TCCR1A | _BV(COM1A1) | _BV(COM1B1) | _BV(COM1C1);

This works fine, it sets the PWM frequency as desired, as I verified with an oscilloscope.

Then, later on in my sketch, I am reading from pin A5, using:

int val = analogRead(A5);

This also works fine.

Once having adjusted the PWM frequency as per above, I write to pin 10 using:

OCR1B = x;

where "x" is a value from 1 to 255. This works fine if and only if x is 0. If I write a non-zero value to OCR1B, my reads from A5 become random.

Can anyone explain this? Why can't I do an analogRead() after adjusting the PWM frequency, and is there any way to get this to work?

Thanks.

  • Dave

Here is a sketch that reproduces the problem:

#include <Console.h>

void setup() {
  Bridge.begin();    
  Console.begin();
  while (!Console)
    ;
    
  pinMode(10, OUTPUT);
      
  // set PWM timer to 31kHz
  TCCR1B = _BV(CS10); 
  TCCR1A = _BV(WGM10) | _BV(COM1A1) | _BV(COM1B1) | _BV(COM1C1);  

  OCR1B = 0;
    
  for (int i = 0; i < 50; i++) {
    Console.print(i);
    Console.print(") ");
    Console.println(analogRead(A5));
    
    if (i == 25) {
      Console.println("Writing 50 to port 10");
      OCR1B = 50;
    };
  };
}

void loop() {
  // put your main code here, to run repeatedly:

}

And here is the output of that sketch:

Using username "root".
0) 317
1) 299
2) 333
3) 298
4) 302
5) 295
6) 337
7) 324
8) 302
9) 329
10) 300
11) 334
12) 293
13) 318
14) 297
15) 311
16) 260
17) 326
18) 287
19) 304
20) 313
21) 305
22) 316
23) 296
24) 331
25) 324
Writing 50 to port 10
26) 203
27) 917
28) 270
29) 240
30) 236
31) 237
32) 161
33) 495
34) 263
35) 214
36) 252
37) 234
38) 564
39) 735
40) 214
41) 237
42) 178
43) 569
44) 953
45) 227
46) 159
47) 241
48) 283
49) 1004

So you can see, before the 0CR1B = 50; statement, the analogRead() was returning fairly consistent values. Afterwards, they were random values.

What's on the analog pin? Are you actually reading a sensor, or is it open?

It’s a sensor. It’s a CNY70. I’ve been using it a lot, it’s got a good value coming in. You can see by the 25 consistent readings before I send the PWM output. After the PWM output it goes haywire. It seems to have something to do with the timing of the A/D conversion being affected, but I’m not sure how you’re supposed to do analogRead()s after messing with the timer frequencies. There must be a way.

Maybe analogRead uses that same timer in some way (pure guess on my part), or maybe the high frequency on the PWM pin causes some interference that the analogRead is picking up (another pure guess on my part).

What's the reasoning behind wanting a PWM up in the 10s of kHz compared to the single kHz that it usually has (pure nosiness on my part).

I’m controlling some DC motors. Ideally I would have a linear relationship between voltage applied and motor RPM, and it would also be nice to have the least annoying motor whine. So I’m using the CNY70 attached to a wheel, attached to one of the motors, to measure and graph voltage vs RPM. Playing with different PWM frequencies to find the best choice.

You've got interference from the motors - now you have motor switching currents zinging about all over the place while the ADC is doing a conversion.

You probably have a shared ground wire between motor circuit and sensor circuit, or they are too close together...

The noise is massive, suggesting the sensor circuit is very high impedance or that you have lots of RFI from these motors/drivers.

Mark - would that explain what I’m seeing though? The issue only happens when I have a high PWM frequency. I did some further testing last night, and found that it worked fine up to 900Hz. I guess the real proof would be if I disconnected the motors. I expect I will see the same issue if the motors weren’t even connected.