I'm currently trying to control fans via PWM. My first attempt was with the Nano 33 IoT and it worked on the first attempts by configuring the registers accordingly.
Now I wanted to implement the same feature on the DUE but got really strange results for which I have no explanation.
I've tried two different approaches.
Here's the first one where I measured 25kHz on the output but experienced the following behavior:
Duty 0 : Meter reports 0% dutycycle. Fan spins quite fast at this stage. When running this cycle on the Nano 33 IoT the fan runs very slow at its absolute minimum capability.
Duty 1680: Meter reports 50% dutycycle. Fan spins on around half the speed
Duty 3360: Meter reports 0%. Fan spins as fast as on duty 0.
I've selected Pins 40 and 41 as they are configurable on PWM channel 3 which shouldn't come in conflict with other stuff.
I need to control a display LED driver at 1kHz on another pin so this is why I need to select pins on other channels where possible.
void setup() {
Serial.begin(115200);
PMC->PMC_PCER1 |= PMC_PCER1_PID36;
PWM->PWM_DIS = PWM_DIS_CHID3; // Disable PWM channel 3
//PC8 = D40 = PIOC, P8
PMC->PMC_PCER0 |= PMC_PCER0_PID11;
PIOC->PIO_PDR |= PIO_PDR_P8;
PIOC->PIO_ABSR |= PIO_ABSR_P8;
//PC9 = D41 = PIOC, P9
PIOC->PIO_PDR |= PIO_PDR_P9;
PIOC->PIO_ABSR |= PIO_ABSR_P9;
// Set registers for PWM channel 3
PWM->PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1); // Set the PWM clock rate to 84MHz (84MHz/1). Divide by 1
PWM->PWM_CH_NUM[3].PWM_CMR = PWM_CMR_CPRE_CLKA;
PWM->PWM_CH_NUM[3].PWM_CPRD = 3360; //84MHz / 3360 = 25kHz
PWM->PWM_CH_NUM[3].PWM_CDTY = 1680; //50%
PWM->PWM_ENA = PWM_ENA_CHID3; // Enable PWM channel 3 again
}
void loop()
{
PWM->PWM_CH_NUM[3].PWM_CDTY = 0;
Serial.println(0);
delay(5000);
PWM->PWM_CH_NUM[3].PWM_CDTY = 1680;
Serial.println(1680);
delay(5000);
PWM->PWM_CH_NUM[3].PWM_CDTY = 3360;
Serial.println(3360);
delay(5000);
}
Alright so this didn't work and so I hopped on the net to find a different approach which utilizes the same methods as the core framework. This time I tried pins 6 and 7 and also pin 5 with different frequencies to understand what goes wrong.
The following example is an edited version of "Bob Cousins" approach.
This time I wanted to know when the dutycycle produces a 0% output.
// --------------------------------------------
//
// Hardware PWM with different frequencies demo
//
// Bob Cousins, August 2014
// --------------------------------------------
int dutyCycle = 0;
void setup() {
Serial.begin(115200);
// put your setup code here, to run once:
pinMode (6, OUTPUT);
pinMode (7, OUTPUT);
pinMode (5, OUTPUT);
// call analogWrite first to allow Arduino to initialise
analogWrite (6, 128);
analogWrite (7, 128);
analogWrite (5, 128);
// set clka to 1kHz, clkb to 25kHz
PWMC_ConfigureClocks (255 * 1000, 255 * 25000, VARIANT_MCK);
// set channel 6 to use clkb
PWMC_ConfigureChannel (PWM, 6, PWM_CMR_CPRE_CLKB, 0, 0);
PWMC_ConfigureChannel (PWM, 7, PWM_CMR_CPRE_CLKB, 0, 0);
// Note: need to re-enable channel after doing Configure
PWMC_EnableChannel (PWM, 6);
PWMC_EnableChannel (PWM, 7);
// set channel 5 to use clka
PWMC_ConfigureChannel (PWM, 5, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_EnableChannel (PWM, 5);
}
void loop() {
//Increase cycle
dutyCycle += 1;
analogWrite (6, dutyCycle);
analogWrite (7, dutyCycle);
analogWrite (5, dutyCycle);
Serial.print("Duty:");
Serial.println(dutyCycle);
//Start over if max value has been reached
if (dutyCycle >= 255)
{
dutyCycle = 0;
}
delay(100);
}
Guess what? I've got the exact same result across all pins - even D5. Around a value of 240 the fan jumps back to normal speed and the output reads 0% duty on the meter.
What am I doing wrong? I can't seem to find an explanation...