Need help with phase correct PWM 10 bit

Hi guys. I’m a rookie who’s doing a project on controlling DC motor (PID controller). I have done some reading and wanted to increase my PWM resolution. Below is what i have for this purpose

float val=0;
void setup() {
pinMode(9,OUTPUT);
TCCR1A=(1<<WGM11)|(1<<WGM10)|(1<<COM1A1)|(0<<COM1A0);
TCCR1B=(0<<WGM13)|(0<<WGM12);
Serial.begin(9600);

}

void loop() {
  val=200;
  OCR1A= val;
  Serial.println(digitalRead(9));

}

In here, I set T/C1 at mode 7 (phase correct PWM 10bit). Personally, I find it quite alright, but my output is a total black out (all zeros). Please, help me to find what I was missing.
Many thanks.
P/s: I have read an example in which _BV() is used; however, at the time, I dont quite understand the command, so I just wrote above lines based on what I understand. Can you guys explain me the difference also? Thanks

Hi,
Where do you output to pin9 to make it change?
What model Arduino?

Tom.... :slight_smile:

Hi Tom,
I’m using UNO r3 with ATmega 328p. What i have posted is the program to test whether or not my PWM setting is accurate. Correct me if I’m wrong, my thinking is: “the output in Serial monitor should be a series of [1 0 0 0 0] continously (since I set ORC1A=200, the duty cycle should be 20%)”.
Do you spot any problem? Thanks

Here’s an example I have that uses mode 14 …

// Set 'TOP' for PWM resolution.  Assumes 16 MHz clock.
// const unsigned int TOP = 0xFFFF; // 16-bit resolution.   244 Hz PWM
// const unsigned int TOP = 0x7FFF; // 15-bit resolution.   488 Hz PWM
// const unsigned int TOP = 0x3FFF; // 14-bit resolution.   976 Hz PWM
// const unsigned int TOP = 0x1FFF; // 13-bit resolution.  1953 Hz PWM
// const unsigned int TOP = 0x0FFF; // 12-bit resolution.  3906 Hz PWM
// const unsigned int TOP = 0x07FF; // 11-bit resolution.  7812 Hz PWM
const unsigned int TOP = 0x03FF; // 10-bit resolution. 15624 Hz PWM

void PWM16Begin() {
  // Stop Timer/Counter1
  TCCR1A = 0;  // Timer/Counter1 Control Register A
  TCCR1B = 0;  // Timer/Counter1 Control Register B
  TIMSK1 = 0;   // Timer/Counter1 Interrupt Mask Register
  TIFR1 = 0;   // Timer/Counter1 Interrupt Flag Register
  ICR1 = TOP;
  OCR1A = 0;  // Default to 0% PWM
  OCR1B = 0;  // Default to 0% PWM

  // Set clock prescale to 1 for maximum PWM frequency
  TCCR1B |= (1 << CS10);

  // Set to Timer/Counter1 to Waveform Generation Mode 14: Fast PWM with TOP set by ICR1
  TCCR1A |= (1 << WGM11);
  TCCR1B |= (1 << WGM13) | (1 << WGM12) ;
}

void PWM16EnableA() {
  // Enable Fast PWM on Pin 9: Set OC1A at BOTTOM and clear OC1A on OCR1A compare
  TCCR1A |= (1 << COM1A1);
  pinMode(9, OUTPUT);
}

void PWM16EnableB() {
  // Enable Fast PWM on Pin 10: Set OC1B at BOTTOM and clear OC1B on OCR1B compare
  TCCR1A |= (1 << COM1B1);
  pinMode(10, OUTPUT);
}

inline void PWM16A(unsigned int PWMValue) {
  OCR1A = constrain(PWMValue, 0, TOP);
}

inline void PWM16B(unsigned int PWMValue) {
  OCR1B = constrain(PWMValue, 0, TOP);
}


void setup() {
  Serial.begin(9600);
  PWM16Begin();

  // On the Arduino UNO T1A is Pin 9 and T1B is Pin 10

  //  PWM16A(0);  // Set initial PWM value for Pin 9
  //  PWM16EnableA();  // Turn PWM on for Pin 9

  PWM16B(0);  // Set initial PWM value for Pin 10
  PWM16EnableB();  // Turn PWM on for Pin 10
}

void loop() {
}

Thank you, dlloyd. But can you confirm my way of checking PWM is correct?

Bear in mind that if you do not set the count (TCNT1) to zero before restarting the timer the first pulse could be a glitch.

can you confirm my way of checking PWM is correct?

Your way is not correct, because using the hardware PWM output overrides the normal port functionality and digitalRead() on that pin will not work. To see the pattern of 1’s and 0’s jumper pin 9 to another one, and read that one.

Your way of setting up the timer is incorrect in that with no prescaler set the timer output is halted.

In here, I set T/C1 at mode 7 (phase correct PWM 10bit).

You are actually setting mode 3 which is 10 bit phase correct.

val should be declared as an int not a float.

If you are going to play around with the timers, I would recommend a good read of the ATmega 328 data sheet. You may find it easier to use the Timer 1 library which is set up for 10 bit PWM.

Here’s your code with the changes to see some serial output.

//float val=0;
int val;
void setup() {
pinMode(9,OUTPUT);
pinMode(4,INPUT);
TCCR1A=(1<<WGM11)|(1<<WGM10)|(1<<COM1A1)|(0<<COM1A0);
TCCR1B=(0<<WGM13)|(0<<WGM12)|1<<CS11 | 1<< CS10;//presecaler 8
Serial.begin(115200);

}

void loop() {
 val=200;
 OCR1A= val;
 Serial.println(digitalRead(4));

}

Thank you @cattledog, it works. It didnt occur to me that I need to set prescaler, I thought it was default at 64 :smiley:

It didnt occur to me that I need to set prescaler, I thought it was default at 64 :smiley:

You are correct, but the syntax you used to set TCCR1B wiped the preset out.

You could use a review of register setting, and the use of = (equals) , |= (or equals), &= (and equals) as well as he straight |(or) and &(and) . Also,The bit shifting of 0 to clear a single register bit may not do what you think it does.