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

Committer:
cedes
Date:
Wed Jun 09 07:47:00 2010 +0000
Revision:
0:8bd0ebc5cbb0

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cedes 0:8bd0ebc5cbb0 1 #include "mbed.h"
cedes 0:8bd0ebc5cbb0 2
cedes 0:8bd0ebc5cbb0 3 DigitalOut myled1(LED1);
cedes 0:8bd0ebc5cbb0 4 DigitalOut myled2(LED2);
cedes 0:8bd0ebc5cbb0 5 DigitalOut myled3(LED3);
cedes 0:8bd0ebc5cbb0 6 DigitalOut myled4(LED4);
cedes 0:8bd0ebc5cbb0 7
cedes 0:8bd0ebc5cbb0 8 DigitalOut outGND1(p21);
cedes 0:8bd0ebc5cbb0 9 PwmOut fmclck6(p22);
cedes 0:8bd0ebc5cbb0 10 PwmOut fmclck5(p23);
cedes 0:8bd0ebc5cbb0 11 DigitalOut outGND2(p24);
cedes 0:8bd0ebc5cbb0 12 PwmOut fmclck4(p25);
cedes 0:8bd0ebc5cbb0 13
cedes 0:8bd0ebc5cbb0 14 #define PLL0CFG_Val 0x00027
cedes 0:8bd0ebc5cbb0 15 #define PLL1_SETUP 0
cedes 0:8bd0ebc5cbb0 16 #define CCLKCFG_Val 5
cedes 0:8bd0ebc5cbb0 17 #define WAIT_SEC_BEFORE_START 5.0
cedes 0:8bd0ebc5cbb0 18
cedes 0:8bd0ebc5cbb0 19 int main() {
cedes 0:8bd0ebc5cbb0 20 // Wait a bit before changing the clock. Who knows, perhaps
cedes 0:8bd0ebc5cbb0 21 // it is needed to connect to the device
cedes 0:8bd0ebc5cbb0 22 myled1 = 1;
cedes 0:8bd0ebc5cbb0 23 wait(WAIT_SEC_BEFORE_START/4.0);
cedes 0:8bd0ebc5cbb0 24 myled1 = 0;
cedes 0:8bd0ebc5cbb0 25 myled2 = 1;
cedes 0:8bd0ebc5cbb0 26 wait(WAIT_SEC_BEFORE_START/4.0);
cedes 0:8bd0ebc5cbb0 27 myled2 = 0;
cedes 0:8bd0ebc5cbb0 28 myled3 = 1;
cedes 0:8bd0ebc5cbb0 29 wait(WAIT_SEC_BEFORE_START/4.0);
cedes 0:8bd0ebc5cbb0 30 myled3 = 0;
cedes 0:8bd0ebc5cbb0 31 myled4 = 1;
cedes 0:8bd0ebc5cbb0 32 wait(WAIT_SEC_BEFORE_START/4.0);
cedes 0:8bd0ebc5cbb0 33 myled1 = 1;
cedes 0:8bd0ebc5cbb0 34 myled2 = 1;
cedes 0:8bd0ebc5cbb0 35 myled3 = 1;
cedes 0:8bd0ebc5cbb0 36 myled4 = 1;
cedes 0:8bd0ebc5cbb0 37
cedes 0:8bd0ebc5cbb0 38
cedes 0:8bd0ebc5cbb0 39
cedes 0:8bd0ebc5cbb0 40 // The following sequence must be followed step by step in order to have PLL0 initialized
cedes 0:8bd0ebc5cbb0 41 // and running:
cedes 0:8bd0ebc5cbb0 42
cedes 0:8bd0ebc5cbb0 43 // 1. Disconnect PLL0 with one feed sequence if PLL0 is already connected.
cedes 0:8bd0ebc5cbb0 44 LPC_SC->PLL0CON &= ~0x02; /* PLL0 Disconnect */
cedes 0:8bd0ebc5cbb0 45 LPC_SC->PLL0FEED = 0xAA;
cedes 0:8bd0ebc5cbb0 46 LPC_SC->PLL0FEED = 0x55;
cedes 0:8bd0ebc5cbb0 47
cedes 0:8bd0ebc5cbb0 48 // 2. Disable PLL0 with one feed sequence.
cedes 0:8bd0ebc5cbb0 49 LPC_SC->PLL0CON &= ~0x01; /* PLL0 Disable */
cedes 0:8bd0ebc5cbb0 50 LPC_SC->PLL0FEED = 0xAA;
cedes 0:8bd0ebc5cbb0 51 LPC_SC->PLL0FEED = 0x55;
cedes 0:8bd0ebc5cbb0 52
cedes 0:8bd0ebc5cbb0 53 // 3. Change the CPU Clock Divider setting to speed up operation without PLL0, if desired.
cedes 0:8bd0ebc5cbb0 54 // LPC_SC->CCLKCFG = 2; /* Setup Clock Divider "2 + 1 = 3 DIVIDER" */
cedes 0:8bd0ebc5cbb0 55
cedes 0:8bd0ebc5cbb0 56 // 4. Write to the Clock Source Selection Control register to change the clock source if
cedes 0:8bd0ebc5cbb0 57 // needed.
cedes 0:8bd0ebc5cbb0 58 LPC_SC->CLKSRCSEL = 0x00000001; /* Select Clock Source for PLL0 */
cedes 0:8bd0ebc5cbb0 59
cedes 0:8bd0ebc5cbb0 60 // 5. Write to the PLL0CFG and make it effective with one feed sequence. The PLL0CFG
cedes 0:8bd0ebc5cbb0 61 // can only be updated when PLL0 is disabled.
cedes 0:8bd0ebc5cbb0 62 LPC_SC->PLL0CFG = 0x00000013; /* configure PLL0, N = 1, M = 20 (0x13 + 1) */
cedes 0:8bd0ebc5cbb0 63 LPC_SC->PLL0FEED = 0xAA;
cedes 0:8bd0ebc5cbb0 64 LPC_SC->PLL0FEED = 0x55;
cedes 0:8bd0ebc5cbb0 65
cedes 0:8bd0ebc5cbb0 66 // 6. Enable PLL0 with one feed sequence.
cedes 0:8bd0ebc5cbb0 67 LPC_SC->PLL0CON |= 0x01; /* PLL0 Enable */
cedes 0:8bd0ebc5cbb0 68 LPC_SC->PLL0FEED = 0xAA;
cedes 0:8bd0ebc5cbb0 69 LPC_SC->PLL0FEED = 0x55;
cedes 0:8bd0ebc5cbb0 70
cedes 0:8bd0ebc5cbb0 71 // 7. Change the CPU Clock Divider setting for the operation with PLL0. It is critical to do
cedes 0:8bd0ebc5cbb0 72 // this before connecting PLL0.
cedes 0:8bd0ebc5cbb0 73 LPC_SC->CCLKCFG = 5; /* Setup Clock Divider "5 + 1 = 6 DIVIDER" */
cedes 0:8bd0ebc5cbb0 74
cedes 0:8bd0ebc5cbb0 75 // 8. Wait for PLL0 to achieve lock by monitoring the PLOCK0 bit in the PLL0STAT register,
cedes 0:8bd0ebc5cbb0 76 // or using the PLOCK0 interrupt, or wait for a fixed time when the input clock to PLL0 is
cedes 0:8bd0ebc5cbb0 77 // slow (i.e. 32 kHz). The value of PLOCK0 may not be stable when the PLL reference
cedes 0:8bd0ebc5cbb0 78 // frequency (FREF, the frequency of REFCLK, which is equal to the PLL input
cedes 0:8bd0ebc5cbb0 79 // frequency divided by the pre-divider value) is less than 100 kHz or greater than
cedes 0:8bd0ebc5cbb0 80 // 20 MHz. In these cases, the PLL may be assumed to be stable after a start-up time
cedes 0:8bd0ebc5cbb0 81 // has passed. This time is 500 μs when FREF is greater than 400 kHz and 200 / FREF
cedes 0:8bd0ebc5cbb0 82 // seconds when FREF is less than 400 kHz.
cedes 0:8bd0ebc5cbb0 83 while (!(LPC_SC->PLL0STAT & (1<<26))); /* Wait for PLOCK0 */
cedes 0:8bd0ebc5cbb0 84
cedes 0:8bd0ebc5cbb0 85 // 9. Connect PLL0 with one feed sequence.
cedes 0:8bd0ebc5cbb0 86 LPC_SC->PLL0CON |= 0x02; /* PLL0 Connect */
cedes 0:8bd0ebc5cbb0 87 LPC_SC->PLL0FEED = 0xAA;
cedes 0:8bd0ebc5cbb0 88 LPC_SC->PLL0FEED = 0x55;
cedes 0:8bd0ebc5cbb0 89
cedes 0:8bd0ebc5cbb0 90 // It is very important not to merge any steps above. For example, do not update the
cedes 0:8bd0ebc5cbb0 91 // PLL0CFG and enable PLL0 simultaneously with the same feed sequence.
cedes 0:8bd0ebc5cbb0 92
cedes 0:8bd0ebc5cbb0 93
cedes 0:8bd0ebc5cbb0 94
cedes 0:8bd0ebc5cbb0 95 // set PWM
cedes 0:8bd0ebc5cbb0 96 outGND1 = 0; // Just to have a GND near to the PWMs
cedes 0:8bd0ebc5cbb0 97 outGND2 = 0; // Just to have a GND near to the PWMs
cedes 0:8bd0ebc5cbb0 98 LPC_PWM1->TCR = (1 << 1); // Reset counter, disable PWM
cedes 0:8bd0ebc5cbb0 99 LPC_SC->PCLKSEL0 &= ~(0x3 << 12);
cedes 0:8bd0ebc5cbb0 100 LPC_SC->PCLKSEL0 |= (1 << 12); // Set peripheral clock divider to /1, i.e. system clock
cedes 0:8bd0ebc5cbb0 101
cedes 0:8bd0ebc5cbb0 102 LPC_PWM1->PCR |= 0x002C; // Double edge PWM for PWM2,3,5
cedes 0:8bd0ebc5cbb0 103
cedes 0:8bd0ebc5cbb0 104 LPC_PWM1->MR0 = 3; // Match Register 0 is shared period counter for all PWM1
cedes 0:8bd0ebc5cbb0 105
cedes 0:8bd0ebc5cbb0 106 LPC_PWM1->MR1 = 0; // so Match Register 0
cedes 0:8bd0ebc5cbb0 107 LPC_PWM1->MR2 = 2; // so Match Register 1
cedes 0:8bd0ebc5cbb0 108 LPC_PWM1->MR3 = 0; // so Match Register 2
cedes 0:8bd0ebc5cbb0 109 LPC_PWM1->MR4 = 1; // so Match Register 3
cedes 0:8bd0ebc5cbb0 110 LPC_PWM1->MR5 = 3; // so Match Register 3
cedes 0:8bd0ebc5cbb0 111
cedes 0:8bd0ebc5cbb0 112 LPC_PWM1->LER |= 1; // Start updating at next period start
cedes 0:8bd0ebc5cbb0 113 LPC_PWM1->TCR = (1 << 0) || (1 << 3); // Enable counter and PWM
cedes 0:8bd0ebc5cbb0 114
cedes 0:8bd0ebc5cbb0 115 while(1);
cedes 0:8bd0ebc5cbb0 116 }