A concept for how to generate 2 synchronous PWM signals with independent duty cycle, and a synchronous interrupt for trigger ADC conversion. This is targeting PWM-ADC-BEMF velocity control of a brushed DC motor. Due to limitations in the routing of the mbed board, and the design of the peripherals in the LPC17xx MCU, the PWM's are synthesized with a combination of timer matches and software handling to shape the signal. Code is untested for functionality. Testing with a scope for correct function is critical.

Dependencies:   mbed

Committer:
apullin
Date:
Wed Feb 24 09:26:33 2016 +0000
Revision:
0:eeb86d8390aa
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
apullin 0:eeb86d8390aa 1 #include "mbed.h"
apullin 0:eeb86d8390aa 2
apullin 0:eeb86d8390aa 3 void SetupTimer0(void);
apullin 0:eeb86d8390aa 4 void Timer0_IRQHandler(void);
apullin 0:eeb86d8390aa 5 void SetupTimer1(void);
apullin 0:eeb86d8390aa 6 void Timer1_IRQHandler(void);
apullin 0:eeb86d8390aa 7 void StartTimers(void);
apullin 0:eeb86d8390aa 8
apullin 0:eeb86d8390aa 9 DigitalOut PWMA(LED1);
apullin 0:eeb86d8390aa 10 DigitalOut PWMB(LED2);
apullin 0:eeb86d8390aa 11 DigitalOut PWMC(LED3);
apullin 0:eeb86d8390aa 12 DigitalOut PWMD(LED4);
apullin 0:eeb86d8390aa 13
apullin 0:eeb86d8390aa 14 int main() {
apullin 0:eeb86d8390aa 15
apullin 0:eeb86d8390aa 16 uint32_t temp = LPC_SC->PCLKSEL0;
apullin 0:eeb86d8390aa 17 temp = temp & ~(1 << 2); //clear PCLK_TIMER0 bits
apullin 0:eeb86d8390aa 18 temp = temp | (0b01 << 2); // PCLK_TIMER0 = 0b01 = CCLK
apullin 0:eeb86d8390aa 19 temp = temp & ~(1 << 4); //clear PCLK_TIMER1 bits
apullin 0:eeb86d8390aa 20 temp = temp | (0b01 << 4); // PCLK_TIMER1 = 0b01 = CCLK
apullin 0:eeb86d8390aa 21
apullin 0:eeb86d8390aa 22 //SetupTimerPCLK(); //TODO
apullin 0:eeb86d8390aa 23
apullin 0:eeb86d8390aa 24 SetupTimer0();
apullin 0:eeb86d8390aa 25 SetupTimer1();
apullin 0:eeb86d8390aa 26 //SetupADC(); //TODO
apullin 0:eeb86d8390aa 27
apullin 0:eeb86d8390aa 28 StartTimers();
apullin 0:eeb86d8390aa 29
apullin 0:eeb86d8390aa 30 while(1) {
apullin 0:eeb86d8390aa 31 // myled2 = 1;
apullin 0:eeb86d8390aa 32 // wait(0.2);
apullin 0:eeb86d8390aa 33 // myled2 = 0;
apullin 0:eeb86d8390aa 34 // wait(0.2);
apullin 0:eeb86d8390aa 35 }
apullin 0:eeb86d8390aa 36
apullin 0:eeb86d8390aa 37 //Timer0 -> Limit = PWM period
apullin 0:eeb86d8390aa 38 // MR0 = DCA (software set)
apullin 0:eeb86d8390aa 39 // MR1 = DCB (software set)
apullin 0:eeb86d8390aa 40 // MR2 = Software ADC trigger
apullin 0:eeb86d8390aa 41 //Timer1 -> Limit = PWM period (same as Timer0.Limit)
apullin 0:eeb86d8390aa 42 // MR0 = DCC (software set)
apullin 0:eeb86d8390aa 43 // MR1 = DCD (software set)
apullin 0:eeb86d8390aa 44 }
apullin 0:eeb86d8390aa 45
apullin 0:eeb86d8390aa 46 //Pseudocode:
apullin 0:eeb86d8390aa 47 /*
apullin 0:eeb86d8390aa 48 Timer0 ISR{
apullin 0:eeb86d8390aa 49 if ISR source is LIMIT:
apullin 0:eeb86d8390aa 50 if MR0 = 0: DCA to LOW
apullin 0:eeb86d8390aa 51 else: : DCA to HIGH
apullin 0:eeb86d8390aa 52 if MR1 = 0: DCB to LOW
apullin 0:eeb86d8390aa 53 else: : DCB to HIGH
apullin 0:eeb86d8390aa 54
apullin 0:eeb86d8390aa 55 if ISR source is MR0:
apullin 0:eeb86d8390aa 56 DCA to LOW
apullin 0:eeb86d8390aa 57
apullin 0:eeb86d8390aa 58 if ISR source is MR1:
apullin 0:eeb86d8390aa 59 DCB to LOW
apullin 0:eeb86d8390aa 60
apullin 0:eeb86d8390aa 61 if ISR source is MR2:
apullin 0:eeb86d8390aa 62 Start ADC sample & convert
apullin 0:eeb86d8390aa 63
apullin 0:eeb86d8390aa 64 clear Timer0 IF
apullin 0:eeb86d8390aa 65 }
apullin 0:eeb86d8390aa 66
apullin 0:eeb86d8390aa 67 Timer1 ISR{
apullin 0:eeb86d8390aa 68 if ISR source is LIMIT:
apullin 0:eeb86d8390aa 69 if MR0 = 0: DCC to LOW
apullin 0:eeb86d8390aa 70 else: : DCC to HIGH
apullin 0:eeb86d8390aa 71 if MR1 = 0: DCD to LOW
apullin 0:eeb86d8390aa 72 else: : DCD to HIGH
apullin 0:eeb86d8390aa 73
apullin 0:eeb86d8390aa 74 if ISR source is MR0:
apullin 0:eeb86d8390aa 75 DCC to LOW
apullin 0:eeb86d8390aa 76
apullin 0:eeb86d8390aa 77 if ISR source is MR1:
apullin 0:eeb86d8390aa 78 DCD to LOW
apullin 0:eeb86d8390aa 79
apullin 0:eeb86d8390aa 80 clear Timer1 IF
apullin 0:eeb86d8390aa 81 }
apullin 0:eeb86d8390aa 82
apullin 0:eeb86d8390aa 83 ADC ISR{
apullin 0:eeb86d8390aa 84 if ISR source is conversion done:
apullin 0:eeb86d8390aa 85 copy data from ADC buffer to ZOH variable
apullin 0:eeb86d8390aa 86
apullin 0:eeb86d8390aa 87 clear ADC IF
apullin 0:eeb86d8390aa 88 }
apullin 0:eeb86d8390aa 89 */
apullin 0:eeb86d8390aa 90
apullin 0:eeb86d8390aa 91 void SetupTimer1(void)
apullin 0:eeb86d8390aa 92 {
apullin 0:eeb86d8390aa 93 LPC_SC->PCONP |= 1 << 2; // Power on Timer`
apullin 0:eeb86d8390aa 94 LPC_TIM1->TCR = 0x2; // Reset and set to timer mode
apullin 0:eeb86d8390aa 95 LPC_TIM1->CTCR = 0x0;
apullin 0:eeb86d8390aa 96 LPC_TIM1->PR = 0; // No prescale
apullin 0:eeb86d8390aa 97 LPC_TIM1->MR0 = 3000; // PWM period ; TODO: check on scope
apullin 0:eeb86d8390aa 98 LPC_TIM1->MR1 = 0; //DCC
apullin 0:eeb86d8390aa 99 LPC_TIM1->MR2 = 0; //DCD
apullin 0:eeb86d8390aa 100 LPC_TIM1->MCR = (1<<0) //MR0 interrupt - PWM end of period
apullin 0:eeb86d8390aa 101 & (1<<1) //MR0 resets timer - PWM period
apullin 0:eeb86d8390aa 102 & (1<<3) //MR1 interrupt - PWM DCC falling edge
apullin 0:eeb86d8390aa 103 & (1<<6); //MR2 interrupt - PWM DCD falling edge
apullin 0:eeb86d8390aa 104
apullin 0:eeb86d8390aa 105 // Enable the ISR vector
apullin 0:eeb86d8390aa 106 NVIC_SetVector (TIMER1_IRQn, (uint32_t)&Timer1_IRQHandler);
apullin 0:eeb86d8390aa 107 NVIC_EnableIRQ(TIMER1_IRQn);
apullin 0:eeb86d8390aa 108 }
apullin 0:eeb86d8390aa 109
apullin 0:eeb86d8390aa 110
apullin 0:eeb86d8390aa 111 void SetupTimer0(void)
apullin 0:eeb86d8390aa 112 {
apullin 0:eeb86d8390aa 113 LPC_SC-> PCONP |= 1 << 1; // Power on Timer0
apullin 0:eeb86d8390aa 114 LPC_TIM0->TCR = 0x2; // Reset and set to timer mode
apullin 0:eeb86d8390aa 115 LPC_TIM0->CTCR = 0x0;
apullin 0:eeb86d8390aa 116 LPC_TIM0->PR = 0; // No prescale
apullin 0:eeb86d8390aa 117 LPC_TIM1->MR0 = 3000; // PWM period
apullin 0:eeb86d8390aa 118 LPC_TIM1->MR3 = 2950; //ADC trigger point ; TODO: check on scope
apullin 0:eeb86d8390aa 119 LPC_TIM1->MR1 = 0; //DCA
apullin 0:eeb86d8390aa 120 LPC_TIM1->MR2 = 0; //DCB
apullin 0:eeb86d8390aa 121 LPC_TIM0->MCR = (1<<0) //MR0 interrupt - PWM end of period
apullin 0:eeb86d8390aa 122 & (1<<1) //MR0 resets timer - PWM period
apullin 0:eeb86d8390aa 123 & (1<<3) //MR1 interrupt - PWM DCA falling edge
apullin 0:eeb86d8390aa 124 & (1<<6); //MR2 interrupt - PWM DCB falling edge
apullin 0:eeb86d8390aa 125 //& (1<<9); //MR3 interrupt - PWM ADC trigger - doesn't use interrupt; TODO: check on scope with INT enabled
apullin 0:eeb86d8390aa 126
apullin 0:eeb86d8390aa 127 // Enable the ISR vector
apullin 0:eeb86d8390aa 128 NVIC_SetVector (TIMER0_IRQn, (uint32_t)&Timer0_IRQHandler);
apullin 0:eeb86d8390aa 129 NVIC_EnableIRQ(TIMER0_IRQn);
apullin 0:eeb86d8390aa 130 }
apullin 0:eeb86d8390aa 131
apullin 0:eeb86d8390aa 132 void StartTimers(void){
apullin 0:eeb86d8390aa 133 LPC_TIM0->TCR = 1; // Enable Timer0
apullin 0:eeb86d8390aa 134 LPC_TIM1->TCR = 1; // Enable Timer0
apullin 0:eeb86d8390aa 135 }
apullin 0:eeb86d8390aa 136
apullin 0:eeb86d8390aa 137 #define TIM0_IRQ_MR0 (1<<0)
apullin 0:eeb86d8390aa 138 #define TIM0_IRQ_MR1 (1<<1)
apullin 0:eeb86d8390aa 139 #define TIM0_IRQ_MR2 (1<<2)
apullin 0:eeb86d8390aa 140 #define TIM0_IRQ_MR3 (1<<3)
apullin 0:eeb86d8390aa 141
apullin 0:eeb86d8390aa 142 #define TIM1_IRQ_MR0 (1<<0)
apullin 0:eeb86d8390aa 143 #define TIM1_IRQ_MR1 (1<<1)
apullin 0:eeb86d8390aa 144 #define TIM1_IRQ_MR2 (1<<2)
apullin 0:eeb86d8390aa 145 #define TIM1_IRQ_MR3 (1<<3)
apullin 0:eeb86d8390aa 146
apullin 0:eeb86d8390aa 147 void Timer0_IRQHandler(void)
apullin 0:eeb86d8390aa 148 {
apullin 0:eeb86d8390aa 149 //uint32_t ir = LPC_TIM0->IR;
apullin 0:eeb86d8390aa 150
apullin 0:eeb86d8390aa 151 if(LPC_TIM0->IR & TIM0_IRQ_MR0){ //PWM period end/start
apullin 0:eeb86d8390aa 152 if(LPC_TIM0->MR1 > 0){
apullin 0:eeb86d8390aa 153 PWMA = 1;
apullin 0:eeb86d8390aa 154 } else{
apullin 0:eeb86d8390aa 155 PWMA = 0;
apullin 0:eeb86d8390aa 156 }
apullin 0:eeb86d8390aa 157
apullin 0:eeb86d8390aa 158 if(LPC_TIM0->MR2 > 0){
apullin 0:eeb86d8390aa 159 PWMB = 1;
apullin 0:eeb86d8390aa 160 } else{
apullin 0:eeb86d8390aa 161 PWMB = 0;
apullin 0:eeb86d8390aa 162 }
apullin 0:eeb86d8390aa 163
apullin 0:eeb86d8390aa 164 LPC_TIM0->IR &= ~(1 << 0); //clear MR0 interrupt flag
apullin 0:eeb86d8390aa 165 }
apullin 0:eeb86d8390aa 166
apullin 0:eeb86d8390aa 167 if(LPC_TIM0->IR & TIM0_IRQ_MR1){ //PWMA expire
apullin 0:eeb86d8390aa 168 PWMA = 0;
apullin 0:eeb86d8390aa 169 LPC_TIM0->IR &= ~(1 << 1); //clear MR1 interrupt flag
apullin 0:eeb86d8390aa 170 }
apullin 0:eeb86d8390aa 171
apullin 0:eeb86d8390aa 172 if(LPC_TIM0->IR & TIM0_IRQ_MR2){ //PWMB expire
apullin 0:eeb86d8390aa 173 PWMB = 0;
apullin 0:eeb86d8390aa 174 LPC_TIM0->IR &= ~(1 << 2); //clear MR2 interrupt flag
apullin 0:eeb86d8390aa 175 }
apullin 0:eeb86d8390aa 176
apullin 0:eeb86d8390aa 177 //ADC triggering should be done automatically by the peripherals, when MAT0.3 is hit.
apullin 0:eeb86d8390aa 178 //This interrupt is not used, except for debugging and testing.
apullin 0:eeb86d8390aa 179 //if(LPC_TIM0->IR & TIM0_IRQ_MR2){ //ADC trigger
apullin 0:eeb86d8390aa 180 // //Software ADC start here
apullin 0:eeb86d8390aa 181 // LPC_TIM0->IR &= ~(1 << 3); //clear MR3 interrupt flag
apullin 0:eeb86d8390aa 182 //}
apullin 0:eeb86d8390aa 183
apullin 0:eeb86d8390aa 184 }
apullin 0:eeb86d8390aa 185
apullin 0:eeb86d8390aa 186 void Timer1_IRQHandler(void)
apullin 0:eeb86d8390aa 187 {
apullin 0:eeb86d8390aa 188 if(LPC_TIM1->IR & TIM1_IRQ_MR0){ //PWM period end/start
apullin 0:eeb86d8390aa 189 if(LPC_TIM1->MR1 > 0){
apullin 0:eeb86d8390aa 190 PWMC = 1;
apullin 0:eeb86d8390aa 191 } else{
apullin 0:eeb86d8390aa 192 PWMC = 0;
apullin 0:eeb86d8390aa 193 }
apullin 0:eeb86d8390aa 194
apullin 0:eeb86d8390aa 195 if(LPC_TIM1->MR2 > 0){
apullin 0:eeb86d8390aa 196 PWMD = 1;
apullin 0:eeb86d8390aa 197 } else{
apullin 0:eeb86d8390aa 198 PWMD = 0;
apullin 0:eeb86d8390aa 199 }
apullin 0:eeb86d8390aa 200
apullin 0:eeb86d8390aa 201 LPC_TIM1->IR &= ~(1 << 0); //clear MR0 interrupt flag
apullin 0:eeb86d8390aa 202 }
apullin 0:eeb86d8390aa 203
apullin 0:eeb86d8390aa 204 if(LPC_TIM1->IR & TIM1_IRQ_MR1){ //PWMA expire
apullin 0:eeb86d8390aa 205 PWMC = 0;
apullin 0:eeb86d8390aa 206 LPC_TIM1->IR &= ~(1 << 1); //clear MR1 interrupt flag
apullin 0:eeb86d8390aa 207 }
apullin 0:eeb86d8390aa 208
apullin 0:eeb86d8390aa 209 if(LPC_TIM1->IR & TIM1_IRQ_MR2){ //PWMB expire
apullin 0:eeb86d8390aa 210 PWMD = 0;
apullin 0:eeb86d8390aa 211 LPC_TIM1->IR &= ~(1 << 2); //clear MR2 interrupt flag
apullin 0:eeb86d8390aa 212 }
apullin 0:eeb86d8390aa 213 }