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
Diff: PwmDAC.cpp
- Revision:
- 0:13e0b9ea312f
- Child:
- 1:381bd99d10a4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PwmDAC.cpp Sun Sep 15 22:20:47 2013 +0000 @@ -0,0 +1,157 @@ +#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 |= (1 << i); + } + + 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 |= (1 << (i+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 |= (1 << (i+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 |= (1 << (i+1)); + } + } +} + +void PwmDAC::stop() { + for(int i = 0; i < 6; i++) { + *MR[i+1] = 0; + LPC_PWM1->LER |= (1 << (i+1)); + } +} + +void PwmDAC::start() { + for(int i = 0; i < 6; i++) { + *MR[i+1] = _steps[i]; + LPC_PWM1->LER |= (1 << (i+1)); + } +} \ No newline at end of file