To get a 100kHz PWM signal using the examples given in the linked topic, just change the REG_PWM_CPRD0 register from 2100 to 840 and the REG_PWM_CDTY0 register from 1050 to 420.
REG_PWM_CPRD0 = 840; // Set the PWM frequency 84MHz/100kHz = 840
REG_PWM_CDTY0 = 420; // Set the PWM duty cycle 50% (840/2=420)
To get a 100kHz PWM signal using the examples given in the linked topic, just change the REG_PWM_CPRD0 register from 2100 to 840 and the REG_PWM_CDTY0 register from 1050 to 420.
REG_PWM_CPRD0 = 840; // Set the PWM frequency 84MHz/100kHz = 840
REG_PWM_CDTY0 = 420; // Set the PWM duty cycle 50% (840/2=420)[/code]
Thanks MartinL, your change is good the problem i have is that i don't have a know i have to increase and than decrease the PWM
, I have used delayMicroseconds() but it isn't a nice Signal and to Slow with 80 uS between the first and the next increase.
// Output a 1000kHz PWM waveform at a resolution of 11-bits on pin DAC1 (PWML0)
void setup() {
// PWM Set-up on pin: DAC1
REG_PMC_PCER1 |= PMC_PCER1_PID36; // Enable PWM
REG_PIOB_ABSR |= PIO_ABSR_P16; // Set PWM pin perhipheral type A or B, in this case B
REG_PIOB_PDR |= PIO_PDR_P16; // Set PWM pin to an output
REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1); // Set the PWM clock rate to 84MHz (84MHz/1)
REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA; // Enable single slope PWM and set the clock source as CLKA
REG_PWM_CPRD0 = 840; // Set the PWM frequency 84MHz/100kHz = 840
REG_PWM_CDTY0 = 0; // Set the PWM duty cycle 50% (840/2=420)
REG_PWM_ENA = PWM_ENA_CHID0; // Enable the PWM channel
}
void loop() {
delayMicroseconds(10);
REG_PWM_CDTY0 = 100;
delayMicroseconds(10);
REG_PWM_CDTY0 = 300;
delayMicroseconds(10);
REG_PWM_CDTY0 = 500;
delayMicroseconds(10);
REG_PWM_CDTY0 = 800;
delayMicroseconds(10);
REG_PWM_CDTY0 = 500;
delayMicroseconds(10);
REG_PWM_CDTY0 = 300;
delayMicroseconds(10);
REG_PWM_CDTY0 = 100;
delayMicroseconds(10);
REG_PWM_CDTY0 = 0;
}
If you're changing the duty cycle, use the buffered duty cycle register, this will update the PWM only on the next timer cycle and avoids glitches appearing on your waveform.
REG_PWM_CDTYUPD0 = 420; // Set the PWM duty cycle 50% (840/2=420)
okay the Signalform is now really good but still to slow with 80 uS between the first and the next increase.
#include <DueTimer.h>
boolean a = true;
int i = 0;
// Output a 1000kHz PWM waveform at a resolution of 11-bits on pin DAC1 (PWML0)
void setup() {
// PWM Set-up on pin: DAC1
REG_PMC_PCER1 |= PMC_PCER1_PID36; // Enable PWM
REG_PIOB_ABSR |= PIO_ABSR_P16; // Set PWM pin perhipheral type A or B, in this case B
REG_PIOB_PDR |= PIO_PDR_P16; // Set PWM pin to an output
REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1); // Set the PWM clock rate to 84MHz (84MHz/1)
REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA; // Enable single slope PWM and set the clock source as CLKA
REG_PWM_CPRD0 = 800; // Set the PWM frequency 84MHz/100kHz = 840
REG_PWM_CDTY0 = 0; // Set the PWM duty cycle 50% (840/2=420)
REG_PWM_ENA = PWM_ENA_CHID0; // Enable the PWM channel
Timer1.attachInterrupt(isr);
Timer1.start(10);
}
void loop() {
}
void isr()
{
if (a==true)
{ i=i+200;
REG_PWM_CDTYUPD0 = i;
if(i==800)
{
a=false;
}
}
if (a==false)
{ i=i-200;
REG_PWM_CDTYUPD0 = i;
if(i==0)
{a=true;}
}
}
If you're aiming to change the duty cycle every PWM timer period? Then you could try enabling either the PWM compare match or compare update interrupts, (update interrupt is commented out in the code below).
The compare match interrupt occurs whenever the counter matches the duty cycle register's value, while the compare update interrupt occurs whenever the counter matches the period register (at the end of the cycle). The interrupts call the PWM controller's PWM_Handler() interrupt service routine (ISR).
// Output a 100kHz PWM waveform at a resolution of 11-bits on pin DAC1 (PWML0)
void setup() {
// PWM Set-up on pin: DAC1
REG_PMC_PCER1 |= PMC_PCER1_PID36; // Enable PWM
REG_PIOB_ABSR |= PIO_ABSR_P16; // Set PWM pin perhipheral type A or B, in this case B
REG_PIOB_PDR |= PIO_PDR_P16; // Set PWM pin to an output
REG_PWM_CLK = PWM_CLK_PREA(0) | PWM_CLK_DIVA(1); // Set the PWM clock rate to 84MHz (84MHz/1)
REG_PWM_CMR0 = PWM_CMR_CPRE_CLKA; // Enable single slope PWM and set the clock source as CLKA
REG_PWM_CPRD0 = 840; // Set the PWM frequency 84MHz/100kHz = 840
REG_PWM_CDTY0 = 0; // Set the PWM duty cycle 0%
REG_PWM_IER2 = PWM_IER2_CMPM0; // Enable interrupt for comparison match channel 0
//REG_PWM_IER2 = PWM_IER2_CMPU0; // Enable interrupt for comparison update channel 0
REG_PWM_ENA = PWM_ENA_CHID0; // Enable the PWM channel
}
loop (){}
void PWM_Handler() // ISR Handler for the PWM controller
{
if (REG_PWM_ISR2 & PWM_ISR2_CMPM0) // Check if the comparison match channel 0 interrupt has been triggered
{
// Add your code here...
}
/*if (REG_PWM_ISR2 & PWM_ISR2_CMPU0) // Check if the comparison update channel 0 interrupt has been triggered
{
// Add your code here...
}*/
}
The PWM_Handler() is the interrupt service routine for the PWM controller. This function is called everytime an enabled PWM controller interrupt is triggered. The PWM controller's PWM Interrupt Enable Register 2 (REG_PWM_IER2) on page 1019 of the datasheet can control which interrupts are enabled.
If the Comparison Match Channel 0 bit (CMPM0) bit is set, the PWM_Handler() function is called on every rising edge of the PWM pulse. Conversely, when the Comparison Update Chanel 0 bit (CMPU0) is set the PWM_Handler() function is called on the falling edge at the end of the cycle.
On entering the PWM_Handler() function we need to test for which interrupt has been triggered. We do this by bitwise ANDing our interrupt of interest with the PWM Interrupt Status Register:
if (REG_PWM_ISR2 & PWM_ISR2_CMPM0) // Check if the comparison match channel 0 interrupt has been triggered
{
// Add your code here...
}
Reading the REG_PWM_ISR2 register automatically clears the interrupt flags.
As you're using the buffered duty cycle update register (REG_PWM_CDTYUPD0), that buffers the duty cycle and only updates the PWM output on the next timer cycle; it's therefore possible to trigger the PWM_Handler() function to load duty cycle update register with a new value on the current timer cycle, ready to be output on the next. This way you avoid having to synchronize your PWM controller with the TC timer (or timer library).
The definition for the PWM_Handler() function can be found in the "sam3x8e.h" file located (on my Windows machine at least) at:
Also in this directory you'll find the "instance" and "component" directories. In these there's a "pwm.h" file that contains the PWM Controller's definitions for its registers and their bitfields. This is also where the register definitions for all the other Due's peripheral registers are held.
The step you mention on page 988 of the SAM3X datasheet is to do with synchronizing the PWM channels to each other and won't really affect you unless you're planning on using more than one channel.