Skip to content

Instantly share code, notes, and snippets.

@jeremyblow
Last active June 16, 2018 01:08
Show Gist options
  • Save jeremyblow/e68c4b5af63c8a2b4aed08ab6e8e623c to your computer and use it in GitHub Desktop.
Save jeremyblow/e68c4b5af63c8a2b4aed08ab6e8e623c to your computer and use it in GitHub Desktop.
ATmega328p 20kHz PWM for control of Delta THB1748BG
void setup() {
// Core clock runs at 16MHz, three different timers can divide this freq
// by using a prescalar factor. Different PWM modes are available for each
// timer. We are using Fast PWM, which has the counter count from 0 to TOP.
// Thus, timer frequency would be 16MHz / prescalar / TOP count. The output
// turns on when the timer is at 0, and turns off when reaches the compare
// register value. As the compare register approaches TOP, the duty cycle
// approaches 100%. Since 0 is included in the high state, the effective
// counts in the high state will be the register value + 1.
//
// Timer to pin pairs:
// OC0A 6
// OC0B 5 * use
// OC1A 9
// OC1B 10 * use
// OC2A 11
// OC2B 3 * use
// Note: Timer 0 will affect functions using user time e.g. millis() and
// delay(). We will be using A to set TOP, so we can only use B in each
// pair.
// Set data direction to output for relevant pins
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
pinMode(10, OUTPUT);
// Reset existing configuration and counters
TCCR0A = 0;
TCCR0B = 0;
TCCR1A = 0;
TCCR1B = 0;
TCCR2A = 0;
TCCR2B = 0;
TCNT0 = 0;
TCNT1 = 0;
TCNT2 = 0;
// Set waveform generation mode bits WGM to FAST PWM using OCRnA for TOP.
// Timer 0 & 2:
// Mode WGMn2 WGMn1 WGMn0 TOP Description
// 3 0 1 1 0xFF Fast PWM
// 7 1 1 1 OCRnA Fast PWM
// Timer 1:
// Mode WGM13 WGM12 WGM11 WGM10 TOP Description
// 5 0 1 0 1 0xFF Fast PWM, 8bit
// 15 1 1 1 1 OCRnA Fast PWM
//
// Set COMnA/B to 10 provides non-inverted PWM to outputs A and B
// COMnA1 COMnA0 Description
// 0 0 OCnA disabled
// 0 1 WMGn2 = 0: Normal, WGMn2 = 1: Toggle OCnA on Match
// 1 0 Non-inverted mode
// 1 1 Inverted mode
// COMnB1 COMnB0 Description
// 0 0 OCnB disabled
// 0 1 Reserved
// 1 0 Non-inverted mode
// 1 1 Inverted mode
//
// Prescalar is a 3 bit value stored in last three LSB of the register
// as CSn0, CSn1, CSn2. Timer 0/1 and 2 have different value mappings for these
// three bits:
// Timer 0 - 001:1, 010:8, 011:64, 100:256, 101:1024
// Timer 1 - 001:1, 010:8, 011:64, 100:256, 101:1024
// Timer 2 - 001:1, 010:8, 011:32, 100:64, 101:128, 110:256, 111:1024
//
// Note: _BV() is a macro function defined in avr-libc which performs
// _BV(x) (1 << x).
//
// To achieve 20kHz, we solve for a reasonable prescalar that will give
// us a high enough count to fit the level of precision desired, e.g. if
// we wanted a 100 point control scale:
// 16000000 / n / 100 = 20000
// n = 16000000 / 100 / 20000
// n = 8
// Prescalar 8 is the same for all Timers: 010 or CSn1
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
TCCR0B = _BV(WGM02) | _BV(CS01);
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS21);
// Use OCRnA to set TOP limit for all timers (99 has a count of 100)
OCR0A = 99;
OCR1A = 99;
OCR2A = 99;
// Set starting compare registers to ~5% duty cycle (you may use OCRnB directly, also).
analogWrite(3, 5);
analogWrite(5, 5);
analogWrite(10, 5);
// References:
// * pg. 94, 95, 99, 100, 104
// http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf
// * http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
// * https://sites.google.com/site/qeewiki/books/avr-guide/pwm-on-the-atmega328
}
void loop() {
// Control goes here
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment