Sparkfun SAMD21 DEV board: I am building a remote control sailboat which will autonomously control itself using PWM servo motors. During development, I would like to take control of this boat when she is misbehaving, and control the her with a standard RC (remote control) receiver. I have two similar PWM signals, one from the SAM21 (pin 2 PWM) and one from the RC receiver (pin 6 INPUT_PULLUP). I have both of these pins working independently. The PWM pin uses some code I found here, written by MartinL, (THANK YOU!) reproduced below with minor changes. The RC signal, I connected, using an input pin which causes an interrupt. In my interrupt handler, I simply change the state of an output pin to mirror the state of the input pin, one line of code (not shown). What I want to do is to route both signals, alternately, to the same pin using a flag I call "PWMfrom" to cause the transfer.
I tried changing the output pin (pin 2) to OUTPUT, and this worked, but I can't seem to get the pin changed back to PWM, without reinitializing 50 lines of start code again. I am sure there is an easier way to do this.
[code]
void PWMsetup() {
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(3) | // Divide the 48MHz clock source by divisor 3: 48MHz/3=16MHz
GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Enable the port multiplexer for the 4 PWM channels: timer TCC0 outputs
const uint8_t CHANNELS = 4;
const uint8_t pwmPins[] = { 2, 5, 10, 12 }; //formerly 2, 5, 6, 7 or 4,3,10,12
for (uint8_t i = 0; i < CHANNELS; i++)
{
PORT->Group[g_APinDescription[pwmPins[i]].ulPort].PINCFG[g_APinDescription[pwmPins[i]].ulPin].bit.PMUXEN = 1;
}
// Connect the TCC0 timer to the port outputs - port pins are paired odd PMUO and even PMUXE
// F & E specify the timers: TCC0, TCC1 and TCC2
//formerly PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;
//formerly PORT->Group[g_APinDescription[6].ulPort].PMUX[g_APinDescription[6].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F;
PORT->Group[g_APinDescription[2].ulPort].PMUX[g_APinDescription[2].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F; //4 for pins 3&4 and 2 for pins 2&5
PORT->Group[g_APinDescription[10].ulPort].PMUX[g_APinDescription[10].ulPin >> 1].reg = PORT_PMUX_PMUXO_F | PORT_PMUX_PMUXE_F; //6 for pins 6&7 and 10 for pins 10&12
// Feed GCLK4 to TCC0 and TCC1
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TCC0 and TCC1
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TCC0_TCC1; // Feed GCLK4 to TCC0 and TCC1
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Dual slope PWM operation: timers countinuously count up to PER register value then down 0
REG_TCC0_WAVE |= TCC_WAVE_POL(0xF) | // Reverse the output polarity on all TCC0 outputs
TCC_WAVE_WAVEGEN_DSBOTTOM; // Setup dual slope PWM on TCC0
while (TCC0->SYNCBUSY.bit.WAVE); // Wait for synchronization
// Each timer counts up to a maximum or TOP value set by the PER register,
// this determines the frequency of the PWM operation:
// 20000 = 50Hz, 10000 = 100Hz, 2500 = 400Hz
REG_TCC0_PER = 20000; // Set the frequency of the PWM on TCC0 to 50Hz
while (TCC0->SYNCBUSY.bit.PER);
// The CCBx register value corresponds to the pulsewidth in microseconds (us)
REG_TCC0_CCB0 = 1500; // TCC0 CCB0 - center the servo on D2
while (TCC0->SYNCBUSY.bit.CCB0);
REG_TCC0_CCB1 = 1500; // TCC0 CCB1 - center the servo on D5
while (TCC0->SYNCBUSY.bit.CCB1);
REG_TCC0_CCB2 = 1500; // TCC0 CCB2 - center the servo on D6
while (TCC0->SYNCBUSY.bit.CCB2);
REG_TCC0_CCB3 = 1500; // TCC0 CCB3 - center the servo on D7
while (TCC0->SYNCBUSY.bit.CCB3);
// Divide the 16MHz signal by 8 giving 2MHz (0.5us) TCC0 timer tick and enable the outputs
REG_TCC0_CTRLA |= TCC_CTRLA_PRESCALER_DIV8 | // Divide GCLK4 by 8
TCC_CTRLA_ENABLE; // Enable the TCC0 output
while (TCC0->SYNCBUSY.bit.ENABLE); // Wait for synchronization
} //PWMsetup()
void PWMloop() {
// called every second
static int servocount = 1500;
if (PWMfrom == CPU) { //let CPU be in control
servocount += 100;
if (servocount > 2000) {
servocount = 1000;
}
//we might be able to use analogWrite() here instead of writing to register.
REG_TCC0_CCB0 = servocount; // TCC0 CCB0 - control the servo on D2
while (TCC0->SYNCBUSY.bit.CCB0);
REG_TCC0_CCB1 = servocount; // TCC0 CCB1 - control the servo on D5
while (TCC0->SYNCBUSY.bit.CCB1);
REG_TCC0_CCB2 = servocount; // TCC0 CCB2 - control the servo on D6
while (TCC0->SYNCBUSY.bit.CCB2);
REG_TCC0_CCB3 = servocount; // TCC0 CCB3 - control the servo on D7
while (TCC0->SYNCBUSY.bit.CCB3);
} else { //let remote be in control
//stop PWM
REG_TCC0_CCB0 = 0; // TCC0 CCB0 - control the servo on D2
while (TCC0->SYNCBUSY.bit.CCB0);
REG_TCC0_CCB1 = servocount; // TCC0 CCB1 - control the servo on D5
while (TCC0->SYNCBUSY.bit.CCB1);
REG_TCC0_CCB2 = servocount; // TCC0 CCB2 - control the servo on D6
while (TCC0->SYNCBUSY.bit.CCB2);
REG_TCC0_CCB3 = servocount; // TCC0 CCB3 - control the servo on D7
while (TCC0->SYNCBUSY.bit.CCB3);
}//if PWMfrom
}
[/code]
You will see I have 4 PWM pins. I want to change them all simultaneously.
Thanks for your help.
Doug