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@0:13e0b9ea312f, 2013-09-15 (annotated)
- Committer:
- flash_ahaa
- Date:
- Sun Sep 15 22:20:47 2013 +0000
- Revision:
- 0:13e0b9ea312f
- Child:
- 1:381bd99d10a4
PwmDAC is a library to run more than one PWM channel and channel updates at the same time.
; E.g. for RGB animations or as a PWM lowpass with active filters. Maximum PWM frequency is 48MHz. Writen for mbed LPC1768.
;
; Not tested 09/16/2013
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
flash_ahaa | 0:13e0b9ea312f | 1 | #include "PwmDAC.h" |
flash_ahaa | 0:13e0b9ea312f | 2 | #include "mbed.h" |
flash_ahaa | 0:13e0b9ea312f | 3 | |
flash_ahaa | 0:13e0b9ea312f | 4 | void PwmDAC::init() { |
flash_ahaa | 0:13e0b9ea312f | 5 | _allActive = true; |
flash_ahaa | 0:13e0b9ea312f | 6 | _resolution = 255; |
flash_ahaa | 0:13e0b9ea312f | 7 | _frequency = (double) SYS_CLK / _resolution; |
flash_ahaa | 0:13e0b9ea312f | 8 | _period = 1 / _frequency; |
flash_ahaa | 0:13e0b9ea312f | 9 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 10 | _pulsewidth[i] = 0.0; |
flash_ahaa | 0:13e0b9ea312f | 11 | _duty[i] = 0.0; |
flash_ahaa | 0:13e0b9ea312f | 12 | _steps[i] = 0; |
flash_ahaa | 0:13e0b9ea312f | 13 | } |
flash_ahaa | 0:13e0b9ea312f | 14 | |
flash_ahaa | 0:13e0b9ea312f | 15 | LPC_SC->PCONP |= (1 << 6); // Bit 6 -> 1 == Poweron PWM1 |
flash_ahaa | 0:13e0b9ea312f | 16 | LPC_SC->PCLKSEL0 |= (1 << 12); // Bit 13/12 -> 0/1 == Full clock 96MHz |
flash_ahaa | 0:13e0b9ea312f | 17 | LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10); |
flash_ahaa | 0:13e0b9ea312f | 18 | // PWM on ch. 1-6 p26 p25 p24 p23 p22 p21 |
flash_ahaa | 0:13e0b9ea312f | 19 | LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10); |
flash_ahaa | 0:13e0b9ea312f | 20 | // no pull up/ down p26 p25 p24 p23 p22 p21 |
flash_ahaa | 0:13e0b9ea312f | 21 | // 0 - pull up enabled |
flash_ahaa | 0:13e0b9ea312f | 22 | // 1 - repeater mode enabled |
flash_ahaa | 0:13e0b9ea312f | 23 | // 2 - no pull up/down |
flash_ahaa | 0:13e0b9ea312f | 24 | // 3 - pull down enabled |
flash_ahaa | 0:13e0b9ea312f | 25 | |
flash_ahaa | 0:13e0b9ea312f | 26 | LPC_PWM1->MCR = 2; // no reset, stop or interrupt on timer compare match |
flash_ahaa | 0:13e0b9ea312f | 27 | // only TC reset on match with MR0 == new period of pwm cycle |
flash_ahaa | 0:13e0b9ea312f | 28 | LPC_PWM1->CTCR |= (0 << 0); // PWM used in timer mode |
flash_ahaa | 0:13e0b9ea312f | 29 | LPC_PWM1->PCR = 0; // all channels are single edge controlled, outputs disable |
flash_ahaa | 0:13e0b9ea312f | 30 | LPC_PWM1->PCR |= (0x3F << 9); // Bit 14:9 -> 1 PWM outputs ch. 1-6 enabled |
flash_ahaa | 0:13e0b9ea312f | 31 | LPC_PWM1->PR = 0; // no prescaling for PWM1 TC |
flash_ahaa | 0:13e0b9ea312f | 32 | |
flash_ahaa | 0:13e0b9ea312f | 33 | MR[0] = &LPC_PWM1->MR0; |
flash_ahaa | 0:13e0b9ea312f | 34 | MR[1] = &LPC_PWM1->MR1; |
flash_ahaa | 0:13e0b9ea312f | 35 | MR[2] = &LPC_PWM1->MR2; |
flash_ahaa | 0:13e0b9ea312f | 36 | MR[3] = &LPC_PWM1->MR3; |
flash_ahaa | 0:13e0b9ea312f | 37 | MR[4] = &LPC_PWM1->MR4; |
flash_ahaa | 0:13e0b9ea312f | 38 | MR[5] = &LPC_PWM1->MR5; |
flash_ahaa | 0:13e0b9ea312f | 39 | MR[6] = &LPC_PWM1->MR6; |
flash_ahaa | 0:13e0b9ea312f | 40 | |
flash_ahaa | 0:13e0b9ea312f | 41 | *MR[0] = _resolution; // period of 1 PWM cycle |
flash_ahaa | 0:13e0b9ea312f | 42 | LPC_PWM1->LER |= (1 << 0); // update shadowregister, set cycle to output |
flash_ahaa | 0:13e0b9ea312f | 43 | |
flash_ahaa | 0:13e0b9ea312f | 44 | for(int i = 1; i < 7; i++) { // update ch. 1-6 |
flash_ahaa | 0:13e0b9ea312f | 45 | *MR[i] = 0; |
flash_ahaa | 0:13e0b9ea312f | 46 | LPC_PWM1->LER |= (1 << i); |
flash_ahaa | 0:13e0b9ea312f | 47 | } |
flash_ahaa | 0:13e0b9ea312f | 48 | |
flash_ahaa | 0:13e0b9ea312f | 49 | LPC_PWM1->TCR |= (1 << 3) | (1 << 0); // enable PWM and Timer (PWM unit) |
flash_ahaa | 0:13e0b9ea312f | 50 | // ==> output update from MR1-6 are load and |
flash_ahaa | 0:13e0b9ea312f | 51 | // enabled with LPC_PWM1->LER Bit 6:1 set to "1" |
flash_ahaa | 0:13e0b9ea312f | 52 | |
flash_ahaa | 0:13e0b9ea312f | 53 | } |
flash_ahaa | 0:13e0b9ea312f | 54 | |
flash_ahaa | 0:13e0b9ea312f | 55 | void PwmDAC::deactivate(unsigned int ch) { |
flash_ahaa | 0:13e0b9ea312f | 56 | if(ch < 6) { |
flash_ahaa | 0:13e0b9ea312f | 57 | LPC_PINCON->PINSEL4 &= ~(1 << (ch + ch)); |
flash_ahaa | 0:13e0b9ea312f | 58 | LPC_PINCON->PINMODE4 |= (3 << (ch + ch)); |
flash_ahaa | 0:13e0b9ea312f | 59 | } |
flash_ahaa | 0:13e0b9ea312f | 60 | else {// deactivate all |
flash_ahaa | 0:13e0b9ea312f | 61 | LPC_PINCON->PINSEL4 &= 0xFFFFFB00; |
flash_ahaa | 0:13e0b9ea312f | 62 | // PWM on ch. 0-5 p26 p25 p24 p23 p22 p21 |
flash_ahaa | 0:13e0b9ea312f | 63 | LPC_PINCON->PINMODE4 |= (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 10); |
flash_ahaa | 0:13e0b9ea312f | 64 | } |
flash_ahaa | 0:13e0b9ea312f | 65 | _allActive = false; |
flash_ahaa | 0:13e0b9ea312f | 66 | } |
flash_ahaa | 0:13e0b9ea312f | 67 | |
flash_ahaa | 0:13e0b9ea312f | 68 | void PwmDAC::activate(unsigned int ch) { |
flash_ahaa | 0:13e0b9ea312f | 69 | if(ch < 6) { |
flash_ahaa | 0:13e0b9ea312f | 70 | LPC_PINCON->PINSEL4 |= (1 << (ch + ch)); |
flash_ahaa | 0:13e0b9ea312f | 71 | LPC_PINCON->PINMODE4 |= (2 << (ch + ch)); |
flash_ahaa | 0:13e0b9ea312f | 72 | _allActive = false; |
flash_ahaa | 0:13e0b9ea312f | 73 | } |
flash_ahaa | 0:13e0b9ea312f | 74 | else {// activate all |
flash_ahaa | 0:13e0b9ea312f | 75 | LPC_PINCON->PINSEL4 |= (1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 8) | (1 << 10); |
flash_ahaa | 0:13e0b9ea312f | 76 | // PWM on ch. 0-5 p26 p25 p24 p23 p22 p21 |
flash_ahaa | 0:13e0b9ea312f | 77 | LPC_PINCON->PINMODE4 |= (2 << 0) | (2 << 2) | (2 << 4) | (2 << 6) | (2 << 8) | (2 << 10); |
flash_ahaa | 0:13e0b9ea312f | 78 | _allActive = true; |
flash_ahaa | 0:13e0b9ea312f | 79 | } |
flash_ahaa | 0:13e0b9ea312f | 80 | } |
flash_ahaa | 0:13e0b9ea312f | 81 | |
flash_ahaa | 0:13e0b9ea312f | 82 | void PwmDAC::setFrequency(double frequency) { |
flash_ahaa | 0:13e0b9ea312f | 83 | _frequency = frequency; |
flash_ahaa | 0:13e0b9ea312f | 84 | _period = 1/frequency; |
flash_ahaa | 0:13e0b9ea312f | 85 | _resolution = (uint32_t) ((double) SYS_CLK / frequency); |
flash_ahaa | 0:13e0b9ea312f | 86 | |
flash_ahaa | 0:13e0b9ea312f | 87 | *MR[0] = _resolution; // period of 1 PWM cycle |
flash_ahaa | 0:13e0b9ea312f | 88 | LPC_PWM1->LER |= (1 << 0); // update shadowregister, set cycle to output |
flash_ahaa | 0:13e0b9ea312f | 89 | } |
flash_ahaa | 0:13e0b9ea312f | 90 | |
flash_ahaa | 0:13e0b9ea312f | 91 | void PwmDAC::setPeriod(double seconds) { |
flash_ahaa | 0:13e0b9ea312f | 92 | _frequency = 1/seconds; |
flash_ahaa | 0:13e0b9ea312f | 93 | _period = seconds; |
flash_ahaa | 0:13e0b9ea312f | 94 | _resolution = (uint32_t) ((double) SYS_CLK * seconds); |
flash_ahaa | 0:13e0b9ea312f | 95 | |
flash_ahaa | 0:13e0b9ea312f | 96 | *MR[0] = _resolution; // period of 1 PWM cycle |
flash_ahaa | 0:13e0b9ea312f | 97 | LPC_PWM1->LER |= (1 << 0); // update shadowregister, set cycle to output |
flash_ahaa | 0:13e0b9ea312f | 98 | } |
flash_ahaa | 0:13e0b9ea312f | 99 | |
flash_ahaa | 0:13e0b9ea312f | 100 | void PwmDAC::setResolution(uint32_t resolution) { |
flash_ahaa | 0:13e0b9ea312f | 101 | _resolution = resolution; |
flash_ahaa | 0:13e0b9ea312f | 102 | _frequency = (double) SYS_CLK / resolution; |
flash_ahaa | 0:13e0b9ea312f | 103 | _period = 1 / _frequency; |
flash_ahaa | 0:13e0b9ea312f | 104 | |
flash_ahaa | 0:13e0b9ea312f | 105 | *MR[0] = _resolution; // period of 1 PWM cycle |
flash_ahaa | 0:13e0b9ea312f | 106 | LPC_PWM1->LER |= (1 << 0); // update shadowregister, set cycle to output |
flash_ahaa | 0:13e0b9ea312f | 107 | } |
flash_ahaa | 0:13e0b9ea312f | 108 | |
flash_ahaa | 0:13e0b9ea312f | 109 | void PwmDAC::updateDuty(double duty[]) { |
flash_ahaa | 0:13e0b9ea312f | 110 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 111 | if(duty[i] <= 100.0) { |
flash_ahaa | 0:13e0b9ea312f | 112 | _duty[i] = duty[i]; |
flash_ahaa | 0:13e0b9ea312f | 113 | _pulsewidth[i] = duty[i] / 100.0 * _period; |
flash_ahaa | 0:13e0b9ea312f | 114 | _steps[i] = (uint32_t) ((double) SYS_CLK * _pulsewidth[i]); |
flash_ahaa | 0:13e0b9ea312f | 115 | *MR[i+1] = _steps[i]; |
flash_ahaa | 0:13e0b9ea312f | 116 | LPC_PWM1->LER |= (1 << (i+1)); |
flash_ahaa | 0:13e0b9ea312f | 117 | } |
flash_ahaa | 0:13e0b9ea312f | 118 | } |
flash_ahaa | 0:13e0b9ea312f | 119 | } |
flash_ahaa | 0:13e0b9ea312f | 120 | |
flash_ahaa | 0:13e0b9ea312f | 121 | void PwmDAC::updatePulsewidth(double pulsewidth[]) { |
flash_ahaa | 0:13e0b9ea312f | 122 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 123 | if(pulsewidth[i] <= _period) { |
flash_ahaa | 0:13e0b9ea312f | 124 | _duty[i] = pulsewidth[i] / _period; |
flash_ahaa | 0:13e0b9ea312f | 125 | _pulsewidth[i] = pulsewidth[i]; |
flash_ahaa | 0:13e0b9ea312f | 126 | _steps[i] = (uint32_t) ((double) SYS_CLK * pulsewidth[i]); |
flash_ahaa | 0:13e0b9ea312f | 127 | *MR[i+1] = _steps[i]; |
flash_ahaa | 0:13e0b9ea312f | 128 | LPC_PWM1->LER |= (1 << (i+1)); |
flash_ahaa | 0:13e0b9ea312f | 129 | } |
flash_ahaa | 0:13e0b9ea312f | 130 | } |
flash_ahaa | 0:13e0b9ea312f | 131 | } |
flash_ahaa | 0:13e0b9ea312f | 132 | |
flash_ahaa | 0:13e0b9ea312f | 133 | void PwmDAC::updateSteps(uint32_t steps[]) { |
flash_ahaa | 0:13e0b9ea312f | 134 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 135 | if(steps[i] <= _resolution) { |
flash_ahaa | 0:13e0b9ea312f | 136 | _duty[i] = (double) steps[i] / _resolution; |
flash_ahaa | 0:13e0b9ea312f | 137 | _pulsewidth[i] = _duty[i] * _period; |
flash_ahaa | 0:13e0b9ea312f | 138 | _steps[i] = steps[i]; |
flash_ahaa | 0:13e0b9ea312f | 139 | *MR[i+1] = steps[i]; |
flash_ahaa | 0:13e0b9ea312f | 140 | LPC_PWM1->LER |= (1 << (i+1)); |
flash_ahaa | 0:13e0b9ea312f | 141 | } |
flash_ahaa | 0:13e0b9ea312f | 142 | } |
flash_ahaa | 0:13e0b9ea312f | 143 | } |
flash_ahaa | 0:13e0b9ea312f | 144 | |
flash_ahaa | 0:13e0b9ea312f | 145 | void PwmDAC::stop() { |
flash_ahaa | 0:13e0b9ea312f | 146 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 147 | *MR[i+1] = 0; |
flash_ahaa | 0:13e0b9ea312f | 148 | LPC_PWM1->LER |= (1 << (i+1)); |
flash_ahaa | 0:13e0b9ea312f | 149 | } |
flash_ahaa | 0:13e0b9ea312f | 150 | } |
flash_ahaa | 0:13e0b9ea312f | 151 | |
flash_ahaa | 0:13e0b9ea312f | 152 | void PwmDAC::start() { |
flash_ahaa | 0:13e0b9ea312f | 153 | for(int i = 0; i < 6; i++) { |
flash_ahaa | 0:13e0b9ea312f | 154 | *MR[i+1] = _steps[i]; |
flash_ahaa | 0:13e0b9ea312f | 155 | LPC_PWM1->LER |= (1 << (i+1)); |
flash_ahaa | 0:13e0b9ea312f | 156 | } |
flash_ahaa | 0:13e0b9ea312f | 157 | } |