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

PwmDAC.cpp

Committer:
flash_ahaa
Date:
2013-09-21
Revision:
1:381bd99d10a4
Parent:
0:13e0b9ea312f

File content as of revision 1:381bd99d10a4:

#include "PwmDAC.h"
#include "mbed.h"

void PwmDAC::init() {
    _allActive = true;
    _resolution = 255;
    _frequency = (double) SYS_CLK / _resolution;
    _period = 1 / _frequency;
    for(int i = 0; i < 6; i++) {
        _pulsewidth[i] = 0.0;
        _duty[i] = 0.0;
        _steps[i] = 0;
    }
      
    LPC_SC->PCONP |= (1 << 6);                                              // Bit 6 -> 1 == Poweron PWM1
    LPC_SC->PCLKSEL0 |= (1 << 12);                                          // Bit 13/12 -> 0/1 == Full clock 96MHz
    LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10);
    // PWM on ch. 1-6        p26        p25        p24         p23       p22         p21
    LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10);
    // no pull up/ down      p26        p25        p24         p23       p22         p21
    // 0 - pull up enabled
    // 1 - repeater mode enabled
    // 2 - no pull up/down
    // 3 - pull down enabled
    
    LPC_PWM1->MCR = 2;                                                      // no reset, stop or interrupt on timer compare match
                                                                            // only TC reset on match with MR0 == new period of pwm cycle
    LPC_PWM1->CTCR |= (0 << 0);                                             // PWM used in timer mode
    LPC_PWM1->PCR = 0;                                                      // all channels are single edge controlled, outputs disable
    LPC_PWM1->PCR |= (0x3F << 9);                                           // Bit 14:9 -> 1 PWM outputs ch. 1-6 enabled               
    LPC_PWM1->PR = 0;                                                       // no prescaling for PWM1 TC

    MR[0] = &LPC_PWM1->MR0;
    MR[1] = &LPC_PWM1->MR1;
    MR[2] = &LPC_PWM1->MR2;
    MR[3] = &LPC_PWM1->MR3;
    MR[4] = &LPC_PWM1->MR4;
    MR[5] = &LPC_PWM1->MR5;
    MR[6] = &LPC_PWM1->MR6;
    
    *MR[0] = _resolution;                                                   // period of 1 PWM cycle
    LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
    
    for(int i = 1; i < 7; i++) {                                            // update ch. 1-6
        *MR[i] = 0;
    }
    LPC_PWM1->LER |= (0x3F << 1);
        
    LPC_PWM1->TCR |= (1 << 3) | (1 << 0);                                   // enable PWM and Timer (PWM unit)
                                                                            // ==> output update from MR1-6 are load and
                                                                            // enabled with LPC_PWM1->LER Bit 6:1 set to "1"

}

void PwmDAC::deactivate(unsigned int ch) {
    if(ch < 6) {
        LPC_PINCON->PINSEL4 &= ~(1 << (ch + ch));
        LPC_PINCON->PINMODE4 |= (3 << (ch + ch));
    }
    else {// deactivate all
        LPC_PINCON->PINSEL4 &= 0xFFFFFB00;
        // PWM on ch. 0-5        p26        p25        p24         p23       p22         p21
        LPC_PINCON->PINMODE4 |= (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 10);        
    }
    _allActive = false;
}

void PwmDAC::activate(unsigned int ch) {
    if(ch < 6) {
        LPC_PINCON->PINSEL4 |= (1 << (ch + ch));
        LPC_PINCON->PINMODE4 |= (2 << (ch + ch));
        _allActive = false;
    }
    else {// activate all
        LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10);
        // PWM on ch. 0-5        p26        p25        p24         p23       p22         p21
        LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10);
        _allActive = true;
    }
}

void PwmDAC::setFrequency(double frequency) {
    _frequency = frequency;
    _period = 1/frequency;
    _resolution = (uint32_t) ((double) SYS_CLK / frequency);
    
    *MR[0] = _resolution;                                                   // period of 1 PWM cycle
    LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
}

void PwmDAC::setPeriod(double seconds) {
    _frequency = 1/seconds;
    _period = seconds;
    _resolution = (uint32_t) ((double) SYS_CLK * seconds);
    
    *MR[0] = _resolution;                                                   // period of 1 PWM cycle
    LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
}

void PwmDAC::setResolution(uint32_t resolution) {
    _resolution = resolution;
    _frequency = (double) SYS_CLK / resolution;
    _period = 1 / _frequency;

    *MR[0] = _resolution;                                                   // period of 1 PWM cycle
    LPC_PWM1->LER |= (1 << 0);                                              // update shadowregister, set cycle to output
}

void PwmDAC::updateDuty(double duty[]) {
    for(int i = 0; i < 6; i++) {
        if(duty[i] <= 100.0) {
            _duty[i] = duty[i];
            _pulsewidth[i] = duty[i] / 100.0 * _period;
            _steps[i] = (uint32_t) ((double) SYS_CLK * _pulsewidth[i]);
            *MR[i+1] = _steps[i];
        }
    }
    LPC_PWM1->LER |= (0x3F << 1);    
}

void PwmDAC::updatePulsewidth(double pulsewidth[]) {
    for(int i = 0; i < 6; i++) {
        if(pulsewidth[i] <= _period) {
            _duty[i] = pulsewidth[i] / _period;
            _pulsewidth[i] = pulsewidth[i];
            _steps[i] = (uint32_t) ((double) SYS_CLK * pulsewidth[i]);
            *MR[i+1] = _steps[i];
        }
    }
    LPC_PWM1->LER |= (0x3F << 1);
}
    
void PwmDAC::updateSteps(uint32_t steps[]) {
    for(int i = 0; i < 6; i++) {
        if(steps[i] <= _resolution) {
            _duty[i] = (double) steps[i] / _resolution;
            _pulsewidth[i] = _duty[i] * _period;
            _steps[i] = steps[i];
            *MR[i+1] = steps[i];
        }
    }
    LPC_PWM1->LER |= (0x3F << 1);    
}

void PwmDAC::stop() {
    for(int i = 0; i < 6; i++) {
        *MR[i+1] = 0;
    }    
    LPC_PWM1->LER |= (0x3F << 1);
}

void PwmDAC::start() {
    for(int i = 0; i < 6; i++) {
        *MR[i+1] = _steps[i];
    }
    LPC_PWM1->LER |= (0x3F << 1);   
}