A sketch for the Clock pin and the Data pin (I took as an example for the Data pin output 101010.....). Note that the 26 samples of the Data pin are output only once in this example, whereas the clock pin runs at 50% duty cycle forever:
/*******************************************************************************************/
/* Synchro channel PWMH0 ONLY with PDC DMA trigger on Compare for the Data pin */
/* PWM channel 1 50% duty cycle for the clock pin */
/*******************************************************************************************/
// Pin 35 (PC3)is the data pin
// Pin 37 (PC5)is the clock pin
#define BufferSize (26) // Sample number (a power of 2 is better)
#define PERIOD_VALUE (17) // For 4.94 MHz
#define NbCh (1) // Only channel 0 ---> Number of channels = 1
#define DUTY_BUFFER_LENGTH (BufferSize * NbCh) // Half words
uint16_t Duty_Buffer[DUTY_BUFFER_LENGTH];
uint16_t Duty_Buffer_Null[DUTY_BUFFER_LENGTH];
uint16_t Buffer_Duty[BufferSize];
void setup () {
PMC->PMC_PCER1 |= PMC_PCER1_PID36; // PWM controller power ON
PWM->PWM_CLK = PWM_CLK_PREA(0b0000) | PWM_CLK_DIVA(1); // Set the PWM clock rate for 84 MHz/1
/***************** Data pin programming *********************/
// PWMH0 on PC3, peripheral type B
PIOC->PIO_PDR |= PIO_PDR_P3; // Set PWM pin to a peripheral
PIOC->PIO_ABSR |= PIO_PC3B_PWMH0; // Set PWM pin peripheral type B for PWMH1 (Arduino pin 35)
// Set synchro channels list : Channel 0
PWM->PWM_DIS = PWM_DIS_CHID0;
PWM->PWM_SCM = PWM_SCM_SYNC0 | // Add SYNCx accordingly, at least SYNC0
PWM_SCM_UPDM_MODE2; //Automatic write of duty-cycle update registers by the PDC DMA
// Set the PWM Reference channel 0 i.e. : Clock/Frequency/Alignment
PWM->PWM_CH_NUM[0].PWM_CMR = PWM_CMR_CPRE_CLKA; // The period is left aligned, clock source as CLKA on channel 0
PWM->PWM_CH_NUM[0].PWM_CPRD = PERIOD_VALUE; // Set the PWM frequency (84MHz/1)/PERIOD_VALUE Hz
// Fill duty cycle buffer for channels 0, x, y ...
// Buffer_Duty is a buffer of Half Words(H_W) composed of N lines which structure model for each duty cycle update is :
// [ H_W: First synchro channel 0 duty cycle **Mandatory** ]/[ H_W: Second synchro channel duty cycle ] ... and so on
for (int i = 0; i < BufferSize / 2; i++) // Data pin output example: Buffer = 10101010 ....
{
Buffer_Duty[2 * i] = 4095;
Buffer_Duty[2 * i + 1] = 0;
}
for (int i = 0; i < DUTY_BUFFER_LENGTH ; i++)
{
Duty_Buffer_Null[i] = 0;
}
for (int i = 0; i < DUTY_BUFFER_LENGTH ; i++) // Data pin output example: Buffer = 10101010 ....
{
Duty_Buffer[i] = Buffer_Duty[i];
}
PWM->PWM_TPR = (uint32_t)Duty_Buffer; // FIRST DMA buffer
PWM->PWM_TCR = DUTY_BUFFER_LENGTH; // Number of Half words
PWM->PWM_TNPR = (uint32_t)Duty_Buffer_Null; // Next DMA buffer
PWM->PWM_TNCR = DUTY_BUFFER_LENGTH;
PWM->PWM_PTCR = PWM_PTCR_TXTEN; // Enable PDC Transmit channel request
// Set Interrupt events
PWM->PWM_IER2 = PWM_IER2_WRDY; //Write Ready for Synchronous Channels Update Interrupt Enable
NVIC_EnableIRQ(PWM_IRQn);
/*************************************************************************/
/******************* Clock pin programming ***********/
PIOC->PIO_PDR |= PIO_PDR_P5; // Set PWM pin to a peripheral
PIOC->PIO_ABSR |= PIO_PC5B_PWMH1; // Set PWM pin peripheral type B for PWMH1 (Arduino pin 37)
PWM->PWM_DIS = PWM_DIS_CHID1;
PWM->PWM_CH_NUM[1].PWM_CMR = PWM_CMR_CPRE_CLKA; // The period is left aligned, clock source as CLKA on channel 1
PWM->PWM_CH_NUM[1].PWM_CPRD = PERIOD_VALUE; // Set the PWM frequency 84 MHz/PWM_CPRD = 4.94 MHz
PWM->PWM_CH_NUM[1].PWM_CDTY = (uint8_t)(PERIOD_VALUE/2); // Set the PWM duty cycle = (CPRD/CDTY) * 100 %
/***********************************************************/
PWM->PWM_ENA = PWM_ENA_CHID0 | // Enable PWM channel 0 and channel 1 at the same time
PWM_ENA_CHID1;
}
void loop() {
}
void PWM_Handler() { // move PDC DMA pointers to next buffer
PWM->PWM_ISR2; // Clear status register
PWM->PWM_TNPR = (uint32_t)Duty_Buffer_Null;
PWM->PWM_TNCR = DUTY_BUFFER_LENGTH;
}