What I need is to control two steppermotors. Varying the PWM frequency independent from each other, from around 20 Hz up to around 320-640 Hz. Being able to stop them (DC= 0).
I tried using the turbo_PWM library, but was getting a little anoid by the long start up time of around 18 sec. Else the library seems to be working OK.
So I decided to shift from using the turbo_PWM library, and instead to set up things directly via the registers. Lot of coding ex. and info of doing so, in the forum, especially thanks to you MartinL.
But it seems the problem also accurse when using the registers directly. Only way to be sure it works is by using PERB (and CCB?). If not using PERB it will start right away, but making different errors after some sec/ stopping PWM (all 0/1 in). then sometimes start again.
The sketch is shifting between 3 frequencies, reading the result in on digitalread 14.
All the // is from the different things I tried when testing.
// declare variables **********************************************
#define DIR 5 //
#define STEP 8 //
#define SLEEP 6 //
#define DIR2 2
#define STEP2 7 //
#define SLEEP2 3
#define SD_CS 10
unsigned long testTime;
int testState;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
for (int i= 0; i<= 5; i++) {
delay(1000);
Serial.print("Serial init sec");
Serial.println(i);
}
Serial.println("Debug");
pinMode(DIR2, OUTPUT);
digitalWrite(DIR2, LOW);
pinMode(STEP2, OUTPUT);
digitalWrite(STEP2, LOW);
pinMode(SLEEP2, OUTPUT);
digitalWrite(SLEEP2, LOW); // sleep
pinMode(DIR, OUTPUT);
digitalWrite(DIR, LOW); //
pinMode(STEP, OUTPUT);
digitalWrite(STEP, LOW);
pinMode(SLEEP, OUTPUT);
digitalWrite(SLEEP, LOW); // sleep
// 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 64 giving ..
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER(TCC_CTRLA_PRESCALER_DIV64_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 = 6000;
while (TCC0->SYNCBUSY.bit.PER);
//TCC0->PERB.reg = 6000;
//while (TCC0->SYNCBUSY.bit.PERB);
// 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 = 6000 / 2;
//while (TCC0->SYNCBUSY.bit.CC2);
TCC0->CCB[2].reg = 6000 / 2;
while (TCC0->SYNCBUSY.bit.CCB2);
// Configure PA18 ( ) to be output
PORT->Group[PORTA].DIRSET.reg = PORT_PA18; // Set pin as output
PORT->Group[PORTA].OUTCLR.reg = PORT_PA18; // Set pin to low
// Enable the port multiplexer for PA18
PORT->Group[PORTA].PINCFG[18].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[9].reg = PORT_PMUX_PMUXE_F;
// Enable output (start PWM)
TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
while (TCC0->SYNCBUSY.bit.ENABLE);
analogReadResolution(12);
Serial.println("Debug 2");
delay(1000);
testState= 0;
testTime= millis()+500;
Serial.println("start state 0 f= 124");
}
void loop() {
// put your main code here, to run repeatedly:
// 14999 = 50 Hz
// 7499 = 100 Hz
switch(testState) {
case 0: // running 124 Hz, shifting to 62
if (millis()> testTime) {
testTime= millis()+500;
testState++;
Serial.println("skift til state 1, frekvens 62");
TCC0->PER.reg = 12000;
while (TCC0->SYNCBUSY.bit.PER);
//TCC0->PERB.reg = 12000;
//while (TCC0->SYNCBUSY.bit.PERB);
// 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 = 12000 / 2;
//while (TCC0->SYNCBUSY.bit.CC2);
TCC0->CCB[2].reg = 12000 / 2;
while (TCC0->SYNCBUSY.bit.CCB2);
// Enable output (start PWM)
//TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
//while (TCC0->SYNCBUSY.bit.ENABLE);
}
break;
case 1: // running 62 Hz, skift til 42
if (millis()> testTime) {
testTime= millis()+500;
testState= 2;
Serial.println("skift til state 2, frekevns 42");
//TCC0->CTRLBSET.reg = TCC_CTRLBSET_LUPD; // Set the Lock Update bit
// while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
TCC0->PER.reg = 18000;
while (TCC0->SYNCBUSY.bit.PER);
//TCC0->PERB.reg = 18000;
//while (TCC0->SYNCBUSY.bit.PERB);
// 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 = 18000 / 2;
//while (TCC0->SYNCBUSY.bit.CC2);
TCC0->CCB[2].reg = 18000 / 2;
while (TCC0->SYNCBUSY.bit.CCB2);
//TCC0->CTRLBCLR.reg = TCC_CTRLBCLR_LUPD; // Clear the Lock Update bit
// while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
// Enable output (start PWM)
//TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
//while (TCC0->SYNCBUSY.bit.ENABLE);
}
break;
case 2: // running 42 Hz, skift til 124
if (millis()> testTime) {
testTime= millis()+500;
testState= 0;
Serial.println("skift til state 0, frekevns 124");
//TCC0->CTRLBSET.reg = TCC_CTRLBSET_LUPD; // Set the Lock Update bit
// while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
TCC0->PER.reg = 6000;
while (TCC0->SYNCBUSY.bit.PER);
//TCC0->PERB.reg = 6000;
//while (TCC0->SYNCBUSY.bit.PERB);
// 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 = 6000 / 2;
//while (TCC0->SYNCBUSY.bit.CC2);
TCC0->CCB[2].reg = 6000 / 2;
while (TCC0->SYNCBUSY.bit.CCB2);
//TCC0->CTRLBCLR.reg = TCC_CTRLBCLR_LUPD; // Clear the Lock Update bit
// while (TCC0->SYNCBUSY.bit.CTRLB); // Wait for synchronization
// Enable output (start PWM)
//TCC0->CTRLA.reg |= (TCC_CTRLA_ENABLE);
//while (TCC0->SYNCBUSY.bit.ENABLE);
}
break;
}
delay(2);
Serial.println(digitalRead(14)); // reading the PWM in again
}