Hi All
I am trying to get a high frequency (8MHz) PWM signal from pin 9 on a Nano IOT board. I have narrowed down a bigger problem I am having to a too slow clockspeed on this pin from a library I am using.
code from library:
inline void Tlc5948::startBuiltinGsclk() {
// On Arduino Nano
// timer 0 -> A: 6 B: 5
// timer 1 -> A: 9 B: 10 * using this timer
// timer 2 -> A: 3 B: 11
// From https://withinspecifications.30ohm.com/2014/02/20/Fast-PWM-on-AtMega328/
// and atmega328p datasheet
// To set appropriate mode for PWM we need three settings enabled:
// TCCRXA - PWM mode + output CLEAR invert/non-invert
// Fast Pwm Mode(counts up and resets to 0, and changes output on OCR0X val)
// \- We do this by settings WGM0[1:0] in TCCR0A to 1 and WGM02 TCCR0B to 1
// \- WGM02 in TCCR0B also specifies that reset to 0 happens at OCR0A value
// \- and not at TOP (255 for timer 0, 65536 for timer 1)
// set COM0X1 bits to 1
// \- sets output to clear on match and start from BOTTOM (non-inverting)
ICR1 = 1; // according to datasheet this works well for static duty as TOP
// using 1 as TOP gives 1 bit resolution but 8Mhz max frequency
// enable A and B, using OCR1A TOP
//TCCRXA = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
//enable just A, using ICR1 as TOP (leave WGM10 as 0)
TCCR1A = _BV(COM1A1) | _BV(WGM11);
// TCCRXB - Timer control Reg b
// controls: clock prescaler (and upper bits of WGM)
// for timer1: CS0[2:0] = 001 -> prescaler = 1 (produces 8Mhz signal)
// note: WGM02 = 1 -> set Fast PWM mode
// other prescalers: 010 -> prescaler = 8 (produces 1Mhz signal, cleaner than the 8Mhz)
// Using _BV(CS11) produces slower 1Mhz signal, but it's cleaner than the 8Mhz one
// this signal can be used if the ESPWM mode
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
OCR1A = 0;
}
This stuff really messes with my head, so any help is greatly appreciated. I am hoping for a basic setup and loop program similar to below, but works and explains what it does.
Thank you
Thank you for pointing that out. I don't need PWM, I just need 8MHz. It is for the GSClk, or greyscale clock. The chip that connects to this wire counts a bunch of them, and does its own greyscaling based on it. I just need to provide it with this signal greater than 1MHz, and less than 33MHz. I am still lost trying to get any to work, even the example code is not working. No errors, just no output
// Number to count to with PWM (TOP value). Frequency can be calculated by
// freq = GCLK4_freq / (TCC0_prescaler * (1 + TOP_value))
// With TOP of 47, we get a 1 MHz square wave in this example
//freq = 48 / (1 * (1+top))
//freq out should be 8
//8 = 48 / (1 * (1+top))
//8 * (1 + top) = 48
//1 + top = 6
//top = 5
uint32_t period = 6 - 1;
void startClk(){
// Because we are using TCC0, limit period to 24 bits
period = ( period < 0x00ffffff ) ? period : 0x00ffffff;
// Enable and configure generic clock generator 4
GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC | // Improve duty cycle
GCLK_GENCTRL_GENEN | // Enable generic clock gen
GCLK_GENCTRL_SRC_DFLL48M | // Select 48MHz as source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Set clock divider of 1 to generic clock generator 4
GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) | // Divide 48 MHz by 1
GCLK_GENDIV_ID(4); // Apply to GCLK4 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Enable GCLK4 and connect it to TCC0 and TCC1
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | // Enable generic clock
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0/1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Divide counter by 1 giving 48 MHz (20.83 ns) on each TCC0 tick
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV1_Val);
// Use "Normal PWM" (single-slope PWM): count up to PER, match on CC[n]
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_NPWM; // Select NPWM as waveform
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
// Set the period (the number to count to (TOP) before resetting timer)
TCC0->PER.reg = period;
while (TCC0->SYNCBUSY.bit.PER);
// Set PWM signal to output 50% duty cycle
// n for CC[n] is determined by n = x % 4 where x is from WO[x]
TCC0->CC[2].reg = period / 2;
while (TCC0->SYNCBUSY.bit.CC2);
// Configure PA20 (D9 on Arduino Nano) to be output
PORT->Group[PORTA].DIRSET.reg = PORT_PA20; // Set pin as output
PORT->Group[PORTA].OUTCLR.reg = PORT_PA20; // Set pin to low
// Enable the port multiplexer for PA18
PORT->Group[PORTA].PINCFG[20].reg |= PORT_PINCFG_PMUXEN;
// Connect TCC0 timer to PA18. Function F is TCC0/WO[2] for PA18.
// Odd pin num (2*n + 1): use PMUXO
// Even pin num (2*n): use PMUXE
PORT->Group[PORTA].PMUX[10].reg = PORT_PMUX_PMUXE_F;
// Enable output (start PWM)
TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
}
void setup() {
startClk();
}
void loop() {
// Do nothing
}