PwmDAC is a library to run more the one PWM channel and channel updates at the time. Maximum PWM frequency is 48MHz. You can use for in example for rgb applications or as a multi channel dac with connected active lowpass. Written for mbed LPC1768. Not completly tested. I will upload my results as soon as possible. Although some deeper informations and LTSpice simulations

Dependents:   DiscoTech filter_implement

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PwmDAC.cpp Source File

PwmDAC.cpp

00001 #include "PwmDAC.h"
00002 #include "mbed.h"
00003 
00004 void PwmDAC::init() {
00005     _allActive = true;
00006     _resolution = 255;
00007     _frequency = (double) SYS_CLK / _resolution;
00008     _period = 1 / _frequency;
00009     for(int i = 0; i < 6; i++) {
00010         _pulsewidth[i] = 0.0;
00011         _duty[i] = 0.0;
00012         _steps[i] = 0;
00013     }
00014       
00015     LPC_SC->PCONP |= (1 << 6);                                              // Bit 6 -> 1 == Poweron PWM1
00016     LPC_SC->PCLKSEL0 |= (1 << 12);                                          // Bit 13/12 -> 0/1 == Full clock 96MHz
00017     LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10);
00018     // PWM on ch. 1-6        p26        p25        p24         p23       p22         p21
00019     LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10);
00020     // no pull up/ down      p26        p25        p24         p23       p22         p21
00021     // 0 - pull up enabled
00022     // 1 - repeater mode enabled
00023     // 2 - no pull up/down
00024     // 3 - pull down enabled
00025     
00026     LPC_PWM1->MCR = 2;                                                      // no reset, stop or interrupt on timer compare match
00027                                                                             // only TC reset on match with MR0 == new period of pwm cycle
00028     LPC_PWM1->CTCR |= (0 << 0);                                             // PWM used in timer mode
00029     LPC_PWM1->PCR = 0;                                                      // all channels are single edge controlled, outputs disable
00030     LPC_PWM1->PCR |= (0x3F << 9);                                           // Bit 14:9 -> 1 PWM outputs ch. 1-6 enabled               
00031     LPC_PWM1->PR = 0;                                                       // no prescaling for PWM1 TC
00032 
00033     MR[0] = &LPC_PWM1->MR0;
00034     MR[1] = &LPC_PWM1->MR1;
00035     MR[2] = &LPC_PWM1->MR2;
00036     MR[3] = &LPC_PWM1->MR3;
00037     MR[4] = &LPC_PWM1->MR4;
00038     MR[5] = &LPC_PWM1->MR5;
00039     MR[6] = &LPC_PWM1->MR6;
00040     
00041     *MR[0] = _resolution;                                                   // period of 1 PWM cycle
00042     LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
00043     
00044     for(int i = 1; i < 7; i++) {                                            // update ch. 1-6
00045         *MR[i] = 0;
00046     }
00047     LPC_PWM1->LER |= (0x3F << 1);
00048         
00049     LPC_PWM1->TCR |= (1 << 3) | (1 << 0);                                   // enable PWM and Timer (PWM unit)
00050                                                                             // ==> output update from MR1-6 are load and
00051                                                                             // enabled with LPC_PWM1->LER Bit 6:1 set to "1"
00052 
00053 }
00054 
00055 void PwmDAC::deactivate(unsigned int ch) {
00056     if(ch < 6) {
00057         LPC_PINCON->PINSEL4 &= ~(1 << (ch + ch));
00058         LPC_PINCON->PINMODE4 |= (3 << (ch + ch));
00059     }
00060     else {// deactivate all
00061         LPC_PINCON->PINSEL4 &= 0xFFFFFB00;
00062         // PWM on ch. 0-5        p26        p25        p24         p23       p22         p21
00063         LPC_PINCON->PINMODE4 |= (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 10);        
00064     }
00065     _allActive = false;
00066 }
00067 
00068 void PwmDAC::activate(unsigned int ch) {
00069     if(ch < 6) {
00070         LPC_PINCON->PINSEL4 |= (1 << (ch + ch));
00071         LPC_PINCON->PINMODE4 |= (2 << (ch + ch));
00072         _allActive = false;
00073     }
00074     else {// activate all
00075         LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10);
00076         // PWM on ch. 0-5        p26        p25        p24         p23       p22         p21
00077         LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10);
00078         _allActive = true;
00079     }
00080 }
00081 
00082 void PwmDAC::setFrequency(double frequency) {
00083     _frequency = frequency;
00084     _period = 1/frequency;
00085     _resolution = (uint32_t) ((double) SYS_CLK / frequency);
00086     
00087     *MR[0] = _resolution;                                                   // period of 1 PWM cycle
00088     LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
00089 }
00090 
00091 void PwmDAC::setPeriod(double seconds) {
00092     _frequency = 1/seconds;
00093     _period = seconds;
00094     _resolution = (uint32_t) ((double) SYS_CLK * seconds);
00095     
00096     *MR[0] = _resolution;                                                   // period of 1 PWM cycle
00097     LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
00098 }
00099 
00100 void PwmDAC::setResolution(uint32_t resolution) {
00101     _resolution = resolution;
00102     _frequency = (double) SYS_CLK / resolution;
00103     _period = 1 / _frequency;
00104 
00105     *MR[0] = _resolution;                                                   // period of 1 PWM cycle
00106     LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
00107 }
00108 
00109 void PwmDAC::updateDuty(double duty[]) {
00110     for(int i = 0; i < 6; i++) {
00111         if(duty[i] <= 100.0) {
00112             _duty[i] = duty[i];
00113             _pulsewidth[i] = duty[i] / 100.0 * _period;
00114             _steps[i] = (uint32_t) ((double) SYS_CLK * _pulsewidth[i]);
00115             *MR[i+1] = _steps[i];
00116         }
00117     }
00118     LPC_PWM1->LER |= (0x3F << 1);    
00119 }
00120 
00121 void PwmDAC::updatePulsewidth(double pulsewidth[]) {
00122     for(int i = 0; i < 6; i++) {
00123         if(pulsewidth[i] <= _period) {
00124             _duty[i] = pulsewidth[i] / _period;
00125             _pulsewidth[i] = pulsewidth[i];
00126             _steps[i] = (uint32_t) ((double) SYS_CLK * pulsewidth[i]);
00127             *MR[i+1] = _steps[i];
00128         }
00129     }
00130     LPC_PWM1->LER |= (0x3F << 1);
00131 }
00132     
00133 void PwmDAC::updateSteps(uint32_t steps[]) {
00134     for(int i = 0; i < 6; i++) {
00135         if(steps[i] <= _resolution) {
00136             _duty[i] = (double) steps[i] / _resolution;
00137             _pulsewidth[i] = _duty[i] * _period;
00138             _steps[i] = steps[i];
00139             *MR[i+1] = steps[i];
00140         }
00141     }
00142     LPC_PWM1->LER |= (0x3F << 1);    
00143 }
00144 
00145 void PwmDAC::stop() {
00146     for(int i = 0; i < 6; i++) {
00147         *MR[i+1] = 0;
00148     }    
00149     LPC_PWM1->LER |= (0x3F << 1);
00150 }
00151 
00152 void PwmDAC::start() {
00153     for(int i = 0; i < 6; i++) {
00154         *MR[i+1] = _steps[i];
00155     }
00156     LPC_PWM1->LER |= (0x3F << 1);   
00157 }