Fast 20MHz PWM, with double edge controlled PWMs (90° Phase shifted). CPU clock had to be adjusted to 80MHz (PLL-controlled). Done by accessing the registers directrly.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 
00003 DigitalOut myled1(LED1);
00004 DigitalOut myled2(LED2);
00005 DigitalOut myled3(LED3);
00006 DigitalOut myled4(LED4);
00007 
00008 DigitalOut  outGND1(p21);
00009 PwmOut      fmclck6(p22);
00010 PwmOut      fmclck5(p23);
00011 DigitalOut  outGND2(p24);
00012 PwmOut      fmclck4(p25);
00013 
00014 #define PLL0CFG_Val     0x00027
00015 #define PLL1_SETUP      0
00016 #define CCLKCFG_Val     5
00017 #define WAIT_SEC_BEFORE_START   5.0
00018 
00019 int main() {
00020     // Wait a bit before changing the clock. Who knows, perhaps
00021     // it is needed to connect to the device
00022     myled1 = 1;
00023     wait(WAIT_SEC_BEFORE_START/4.0);
00024     myled1 = 0;
00025     myled2 = 1;
00026     wait(WAIT_SEC_BEFORE_START/4.0);
00027     myled2 = 0;
00028     myled3 = 1;
00029     wait(WAIT_SEC_BEFORE_START/4.0);
00030     myled3 = 0;
00031     myled4 = 1;
00032     wait(WAIT_SEC_BEFORE_START/4.0);
00033     myled1 = 1;
00034     myled2 = 1;
00035     myled3 = 1;
00036     myled4 = 1;
00037     
00038 
00039 
00040     // The following sequence must be followed step by step in order to have PLL0 initialized
00041     // and running:
00042 
00043     // 1. Disconnect PLL0 with one feed sequence if PLL0 is already connected.
00044     LPC_SC->PLL0CON  &= ~0x02;              /* PLL0 Disconnect */
00045     LPC_SC->PLL0FEED  = 0xAA;
00046     LPC_SC->PLL0FEED  = 0x55;
00047 
00048     // 2. Disable PLL0 with one feed sequence.
00049     LPC_SC->PLL0CON  &= ~0x01;              /* PLL0 Disable */
00050     LPC_SC->PLL0FEED  = 0xAA;
00051     LPC_SC->PLL0FEED  = 0x55;
00052 
00053     // 3. Change the CPU Clock Divider setting to speed up operation without PLL0, if desired.
00054 //    LPC_SC->CCLKCFG   = 2;                /* Setup Clock Divider "2 + 1 = 3 DIVIDER"  */
00055     
00056     // 4. Write to the Clock Source Selection Control register to change the clock source if
00057     // needed.
00058     LPC_SC->CLKSRCSEL = 0x00000001;         /* Select Clock Source for PLL0       */
00059     
00060     // 5. Write to the PLL0CFG and make it effective with one feed sequence. The PLL0CFG
00061     // can only be updated when PLL0 is disabled.
00062     LPC_SC->PLL0CFG   = 0x00000013;         /* configure PLL0, N = 1, M = 20 (0x13 + 1) */
00063     LPC_SC->PLL0FEED  = 0xAA;
00064     LPC_SC->PLL0FEED  = 0x55;
00065     
00066     // 6. Enable PLL0 with one feed sequence.
00067     LPC_SC->PLL0CON  |= 0x01;               /* PLL0 Enable */
00068     LPC_SC->PLL0FEED  = 0xAA;
00069     LPC_SC->PLL0FEED  = 0x55;
00070     
00071     // 7. Change the CPU Clock Divider setting for the operation with PLL0. It is critical to do
00072     // this before connecting PLL0.
00073     LPC_SC->CCLKCFG   = 5;                  /* Setup Clock Divider "5 + 1 = 6 DIVIDER"  */
00074     
00075     // 8. Wait for PLL0 to achieve lock by monitoring the PLOCK0 bit in the PLL0STAT register,
00076     // or using the PLOCK0 interrupt, or wait for a fixed time when the input clock to PLL0 is
00077     // slow (i.e. 32 kHz). The value of PLOCK0 may not be stable when the PLL reference
00078     // frequency (FREF, the frequency of REFCLK, which is equal to the PLL input
00079     // frequency divided by the pre-divider value) is less than 100 kHz or greater than
00080     // 20 MHz. In these cases, the PLL may be assumed to be stable after a start-up time
00081     // has passed. This time is 500 μs when FREF is greater than 400 kHz and 200 / FREF
00082     // seconds when FREF is less than 400 kHz.
00083     while (!(LPC_SC->PLL0STAT & (1<<26)));  /* Wait for PLOCK0 */
00084     
00085     // 9. Connect PLL0 with one feed sequence.
00086     LPC_SC->PLL0CON  |= 0x02;               /* PLL0 Connect */
00087     LPC_SC->PLL0FEED  = 0xAA;
00088     LPC_SC->PLL0FEED  = 0x55;
00089     
00090     // It is very important not to merge any steps above. For example, do not update the
00091     // PLL0CFG and enable PLL0 simultaneously with the same feed sequence.
00092 
00093 
00094 
00095     // set PWM
00096     outGND1 = 0;                            // Just to have a GND near to the PWMs
00097     outGND2 = 0;                            // Just to have a GND near to the PWMs
00098     LPC_PWM1->TCR = (1 << 1);               // Reset counter, disable PWM
00099     LPC_SC->PCLKSEL0 &= ~(0x3 << 12);
00100     LPC_SC->PCLKSEL0 |= (1 << 12);          // Set peripheral clock divider to /1, i.e. system clock
00101 
00102     LPC_PWM1->PCR |= 0x002C;                // Double edge PWM for PWM2,3,5
00103 
00104     LPC_PWM1->MR0 = 3;                      // Match Register 0 is shared period counter for all PWM1
00105 
00106     LPC_PWM1->MR1 = 0;                      // so Match Register 0
00107     LPC_PWM1->MR2 = 2;                      // so Match Register 1
00108     LPC_PWM1->MR3 = 0;                      // so Match Register 2
00109     LPC_PWM1->MR4 = 1;                      // so Match Register 3
00110     LPC_PWM1->MR5 = 3;                      // so Match Register 3
00111 
00112     LPC_PWM1->LER |= 1;                     // Start updating at next period start
00113     LPC_PWM1->TCR = (1 << 0) || (1 << 3);   // Enable counter and PWM
00114 
00115     while(1);
00116 }