Skeleton program for Federico's 4YP project.
Dependencies: WebSocketClient WiflyInterface mbed messages
Fork of IoT_Ex by
pwm.cpp
00001 // ************** 00002 // * iQ_PWM.cpp * 00003 // ************** 00004 // 00005 // Created: 2015/03/19 00006 // By: Damien Frost 00007 00008 #include "math.h" 00009 #include "mbed.h" 00010 #include "globals.h " 00011 #include "pwm.h" 00012 #include "ADC.h " 00013 #include "Commands.h " 00014 00015 #define DEBUG 00016 #define INFOMESSAGES 00017 #define WARNMESSAGES 00018 #define ERRMESSAGES 00019 #define FUNCNAME "PWM" 00020 #include "messages.h" 00021 00022 00023 // Configures the PWM for use, using an initial duty cycle and period in us. 00024 void ConfigurePWM(float duty_us, float period_us){ 00025 unsigned int value; 00026 float newVal; 00027 00028 // Ensure power is turned on 00029 // Grabbed from lines 54-57 of analogin_api.h, modified for PWM 00030 // This turns on the clock to Ports A, B, and C 00031 RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; 00032 // This turns on the clock to the Time 1: 00033 RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; 00034 00035 // Set the GPIO Ports properly: 00036 // PWM1 is connected to PA_8 00037 // PWM1N is connected to PA_7 00038 00039 // Set the PWM outputs to general output pins: 00040 // This sets the PA_7 and PA_8 pins to Alternate Function Pins 00041 value = 0x8000 + 0x20000; 00042 GPIOA->MODER |= value; 00043 00044 // Set the PWM outputs to high speed: 00045 value = 0xC000 + 0x30000; 00046 GPIOA->OSPEEDR |= value; 00047 00048 // Set PWM as outputs to the pins: 00049 value = GPIOA->AFR[1]; 00050 // Reset the lowest four bits: 00051 value &= 0xFFFFFFF0; 00052 // Configure PA_8 to AF: 00053 value |= 0x1; 00054 GPIOA->AFR[1] = value; 00055 00056 value = GPIOA->AFR[0]; 00057 // Reset the the 4 MSB: 00058 value &= 0x0FFFFFFF; 00059 // Configure PA_7 to AF: 00060 value |= 0x10000000; 00061 GPIOA->AFR[0] = value; 00062 00063 // Set pull down resistors to PWM outputs: 00064 value = GPIOA->PUPDR; 00065 // Clear the bits: 00066 value &= ~(GPIO_PUPDR_PUPDR7 | GPIO_PUPDR_PUPDR8); 00067 // Set to pull down: 00068 value |= GPIO_PUPDR_PUPDR7_1 | GPIO_PUPDR_PUPDR8_1; 00069 // Set the register: 00070 GPIOA ->PUPDR = value; 00071 00072 // Set the prescale value to 1: 00073 TIM1->PSC = 0; 00074 00075 // *** TIM1 control register 1: TIMx_CR1 *** 00076 value = 0; 00077 // [9:8] Set CKD bits to zero for clock division of 1 00078 // [7] TIMx_ARR register is buffered, set the ARPE bit to 1: 00079 value |= TIM_CR1_ARPE; 00080 // [6:5] Set CMS bits to zero for edge aligned mode 00081 // [6:5] Set CMS bits to 10 for Center Aligned mode 2, up down mode with flags set when counter reaches the top. 00082 //value |= TIM_CR1_CMS_1; 00083 // [4] Set DIR bit to zero for upcounting 00084 // [3] Set OPM bit to zero so that the counter is not stopped at update event 00085 // [2] Set URS bit to zero so that anything can create an interrupt 00086 // [1] Set UDIS bit to zero to generate an update event 00087 // [0] Set the CEN bit to zero to disable the counter 00088 // * Set the TIMx_CR1 Register: * 00089 TIM1->CR1 |= value; 00090 00091 // *** TIM1 control register 2: TIMx_CR2 *** 00092 value = 0; 00093 // [14] Set OIS4 bit to zero, the idle state of OC4 output 00094 // [13] Set OIS3N bit to zero, the idle state of OC3N output 00095 // [12] Set OIS3 bit to zero, the idle state of OC3 output 00096 // [11] Set OIS2N bit to zero, the idle state of OC2N output 00097 // [10] Set OIS2 bit to zero, the idle state of OC2 output 00098 // [9] Set OIS1N bit to zero, the idle state of OC1N output 00099 // [8] Set OIS1 bit to zero, the idle state of OC1 output 00100 // [7] Set TI1S bit to zero, connecting only CH1 pin to TI1 input 00101 // [6:4] Set to 111: The OC4REF signal is used as trigger output (TRGO) 00102 // value |= TIM_CR2_MMS_2 | TIM_CR2_MMS_1 | TIM_CR2_MMS_0; 00103 //value |= TIM_CR2_MMS_1 | TIM_CR2_MMS_0; 00104 // [3] Set CCDS bit to zero, request sent when CCx event occurs 00105 // [2] Set CCUS bit to 1, capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on TRGI 00106 //value |= 0x4; 00107 // [0] Set CCPC bit to 1, CCxE, CCxNE and OCxM are update on a commutation event, or rising edge on TRGI 00108 //value |= 0x1; 00109 // * Set the TIMx_CR2 Register: * 00110 TIM1->CR2 = value; 00111 00112 // *** TIM1 Auto Reload Register: ARR *** 00113 value = 0; 00114 // [15:0] Set ARR bits to the frequency to be loaded in: 00115 newVal = ceil(period_us/PWMSTEP_US); 00116 value = (unsigned int) newVal; 00117 // * Set the TIMx_ARR Register: 00118 TIM1->ARR = value; 00119 00120 // *** TIM1 capture/compare register 1: CCR1 *** 00121 value = 0; 00122 // [15:0] Set the capture compare value to the duty cycle: 00123 newVal = ceil(duty_us/PWMSTEP_US); 00124 value = (unsigned int) newVal; 00125 // * Set the TIMx_CCR1 Register: 00126 TIM1->CCR1 = value; 00127 00128 // *** TIM1 capture/compare register 4: CCR4 *** 00129 value = 0; 00130 // [15:0] Set the capture compare value to the value at which the PWM interrupt should be triggered: 00131 newVal = 0; 00132 value = (unsigned int) newVal; 00133 // * Set the TIMx_CCR4 Register: 00134 TIM1->CCR4 = 0; 00135 00136 // *** TIM1 capture/compare mode register 2: CCMR2 00137 value = 0; 00138 // [15] Set OC4CE bit to 0, OC4Ref is not affected by the ETRF input 00139 // [14-12] Set the OC4M bits to '110', PWM mode 1, which is what we want I think. 00140 value |= TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1; 00141 // [11] Set the OC4PE bit to 1, meaning read/write operations to the preload event require an update event. 00142 value |= TIM_CCMR2_OC4PE; 00143 // [10] Set the OC4FE bit to 0, the output compare fast enable is disabled 00144 // [9:8] Set the CC4S bits to 0, the channel is configured as an output. 00145 // * Set the TIMx_CCMR2 Register: * 00146 TIM1->CCMR2 = value; 00147 00148 // *** TIM1 capture/compare mode register 1: CCMR1 00149 value = 0; 00150 // [7] Set OC1CE bit to 0, OC1Ref is not affected by the ETRF input 00151 // [6-4] Set the OC1M bits to '110', PWM mode 1, which is what we want I think. 00152 value |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; 00153 // [3] Set the OC1PE bit to 1, meaning read/write operations to the preload event require an update event. 00154 value |= TIM_CCMR1_OC1PE; 00155 // [2] Set the OC1FE bit to 0, the output compare fast enable is disabled 00156 // [1:0] Set the CC1S bits to 0, the channel is configured as an output. 00157 // * Set the TIMx_CCMR1 Register: * 00158 TIM1->CCMR1 = value; 00159 00160 // *** TIM1 capture/compare enable register: CCER 00161 value = 0; 00162 // [15:4] - Don't care: 00163 // [3] Set CC1NP bit to 1 for active low. ( 00164 value |= TIM_CCER_CC1NP; 00165 // [2] Set CC1NE bit to 0, to de-activate the OC1N signal 00166 // value |= 0x4; 00167 // [1] Set the CC1P bit to 1 for active low. 00168 value |= TIM_CCER_CC1P; 00169 // [0] Set the CC1E bit to 1, to de-activate the OC1 signal 00170 // value |= 0x1; 00171 // * Set the TIM1_CCER Register: * 00172 TIM1->CCER = value; 00173 00174 // *** TIM1 break and dead-time register: BDTR 00175 value = 0; 00176 // [15] Set MOE bit to 1 to enable the OC and OCN outputs 00177 value |= 0x8000; 00178 // [11] Set the OSSR bit such that the ouputs are forced to their idle mode when not running 00179 //value |= TIM_BDTR_OSSR; 00180 // [10] Set OSSI bit such that the outputs are forced to their idle mode when MOE = 0 00181 value |= TIM_BDTR_OSSI; 00182 // * Set the TIM1_BDTR register: 00183 TIM1->BDTR = value; 00184 00185 // *** TIM1 DMA/Interrupt enable register: DIER 00186 value = 0; 00187 // [2] Set the CC1IE bit to 1, to trigger an interrupt when counter 1 has a match - which should be half way through the duty cycle. 00188 value |= TIM_DIER_CC4IE; 00189 // Set the TIM1_DIER register: 00190 TIM1->DIER |= value; 00191 00192 // Set the UG bit in the EGR register to kick things off: 00193 value = 3; 00194 TIM1->EGR = value; 00195 00196 // Print a message saying you are done: 00197 INFO("PWM configuration complete!"); 00198 00199 #ifdef DEBUG_PWM 00200 // Debugging Code: 00201 DBG("TIM1 Registers:"); 00202 DBG("The CCMR1 Register reads: %d", TIM1->CCMR1); 00203 DBG("The CR1 Register reads: %d", TIM1->CR1); 00204 DBG("The CR2 Register reads: %d", TIM1->CR2); 00205 DBG("The ARR Register reads: %d", TIM1->ARR); 00206 DBG("The CCR1 Register reads: %d", TIM1->CCR1); 00207 DBG("The CCER Register reads: %d", TIM1->CCER); 00208 DBG("The BDTR Register reads: %d", TIM1->BDTR); 00209 DBG("The EGR Register reads: %d", TIM1->EGR); 00210 DBG("The SMCR Register reads: %d", TIM1->SMCR); 00211 DBG("The PSC Register reads: %d", TIM1->PSC); 00212 DBG("The GPIOA Registers:\n\r"); 00213 DBG("The MODER Register reads: %d", GPIOA->MODER); 00214 DBG("The OSPEEDR Register reads: %d", GPIOA->OSPEEDR); 00215 DBG("The AFR[0] Register reads: %d", GPIOA->AFR[0]); 00216 DBG("The AFR[1] Register reads: %d", GPIOA->AFR[1]); 00217 DBG("Clock Registers:"); 00218 DBG("The CFGR Register reads: %d", RCC->CFGR); 00219 00220 #endif 00221 00222 INFO("TIM1 Interrupt Priority: %d", NVIC_GetPriority(TIM1_CC_IRQn)); 00223 INFO("UART1 Interrupt Priority: %d", NVIC_GetPriority(USART1_IRQn)); 00224 INFO("UART2 Interrupt Priority: %d", NVIC_GetPriority(USART2_IRQn)); 00225 INFO("UART6 Interrupt Priority: %d", NVIC_GetPriority(USART6_IRQn)); 00226 00227 // Configure the interrupt: 00228 NVIC_SetVector(TIM1_CC_IRQn, (uint32_t)&TIM1_CC_IRQHandler); 00229 NVIC_SetPriority(TIM1_CC_IRQn, PWMHIGHPRIORITY); 00230 NVIC_EnableIRQ(TIM1_CC_IRQn); 00231 00232 00233 00234 return; 00235 } 00236 00237 void TIM1_CC_IRQHandler(void){ 00238 00239 // States of the PWM module: 00240 /* 00241 #define PWMST_SETUPCONV 0 00242 #define PWMST_STARTCONV 1 00243 #define PWMST_RUNSCSKDC 2 00244 #define PWMST_CALCNEWPH 3 00245 #define PWMST_SETNEWPH 4 00246 #define PWMST_SHIFT 5 00247 #define PWMST_SAMPLECHTROUGH 6 00248 #define PWMST_WAITSAMPLETROUGH 7 00249 #define PWMST_WAIT 8 00250 #define PWMST_SAMPLECHHILL 9 00251 #define PWMST_WAITSAMPLEHILL 10 00252 #define PWMST_MAXST 11 00253 */ 00254 00255 if(((TIM1->SR & TIM_SR_CC4IF) > 0)&&(IotStatus.CheckFlag(SS_PWMOVERRUNFLAG) == false)){ 00256 // Block any other interrupts from occuring: 00257 IotStatus.SetFlag(SS_PWMOVERRUNFLAG); 00258 00259 db = 1; 00260 00261 // Sample the ADCs: 00262 VoltageMeasurement = VoltageSensor.read(); 00263 CurrentMeasurement = CurrentSensor.read(); 00264 db = 0; 00265 // Set battery model inputs: 00266 00267 00268 // Set a debug pin high: 00269 db = 1; // Probe this pin to see how long the battery model algorithm takes to run. 00270 00271 // Run battery model here: 00272 00273 00274 // Clear the debug pin: 00275 db = 0; 00276 00277 // Read battery model outputs: 00278 00279 00280 00281 // Clear the flag: 00282 IotStatus.ClearFlag(SS_PWMOVERRUNFLAG); 00283 TIM1->SR &= (~TIM_SR_CC4IF); 00284 } 00285 00286 00287 return; 00288 } 00289 00290 00291 00292 00293 00294 // Set a new duty cycle: 00295 float SetDuty_us(float duty_us){ 00296 unsigned int value; 00297 float newVal; 00298 float temp = (duty_us/PwmPeriod_us); 00299 00300 newVal = ceil(duty_us/PWMSTEP_US); 00301 value = (unsigned int) newVal; 00302 // Disable the Update Event: 00303 SETUDIS; 00304 // * Set the TIMx_CCR1 Register: 00305 TIM1->CCR1 = value; 00306 // Set the CCR4 Register to the maximum value minus CH4SHIFT. This ensures the high speed ADC is in sync with the PWM module. 00307 TIM1->CCR4 = 0; 00308 // Re-enable the update event 00309 CLEARUDIS; 00310 return temp*PwmPeriod_us; 00311 } 00312 00313 00314 // Turns on and off the PWM: 00315 void TurnOnPWM(bool trueForOn){ 00316 if(trueForOn){ 00317 // Enable the outputs: 00318 DBG("Enabling outputs..."); 00319 TIM1->CCER |= TIM_CCER_CC1E | TIM_CCER_CC1NE; 00320 // Turn on the gating: 00321 DBG("Turning on gating...:"); 00322 TIM1->CR1 |= TIM_CR1_CEN; 00323 DBG("PWM on."); 00324 00325 }else{ 00326 // Turn off the gating: 00327 TIM1->CR1 &= ~TIM_CR1_CEN; 00328 // Disable the outputs: 00329 TIM1->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC1NE); 00330 } 00331 return; 00332 } 00333 00334 00335 00336 void SetPWMPeriodAndDuty(int pwmper){ 00337 // This functions sets the PWM period by first disabling updates to the PWM module 00338 // It also scales the duty cycle register, so the duty cycle is the SAME. 00339 00340 // Disable the UEV event in the PWM module: 00341 SETUDIS; 00342 // Set the new period: 00343 TIM1->ARR = (unsigned int)(PwmPeriod_us/PWMSTEP_US); 00344 // Set the new duty cycle: 00345 TIM1->CCR1 = ((unsigned int)(Duty_us/PwmPeriod_us * TIM1->ARR)); 00346 // Set the CCR4 Register to the maximum value minus CH4SHIFT. This ensures the high speed ADC is in sync with the PWM module. 00347 TIM1->CCR4 = 0; 00348 // Re-enable the UEV event: 00349 CLEARUDIS; 00350 // Done! 00351 return; 00352 } 00353 00354 void SetPWMPeriodAndDuty_us(float period){ 00355 // This functions sets the PWM period by first disabling updates to the PWM module 00356 // It also scales the duty cycle register, so the duty cycle is the SAME. 00357 float PwmSteps = ((float)period/(float)PWMSTEP_US); 00358 00359 // Disable the UEV event in the PWM module: 00360 SETUDIS; 00361 // Set the new period: 00362 if(PwmSteps > PWMARRMAX){ 00363 PwmSteps = PWMARRMAX; 00364 WARN("Maximum PWM Period Reached."); 00365 } 00366 TIM1->ARR = (unsigned int)(PwmSteps); 00367 DBG("TIM1->ARR: %d", TIM1->ARR); 00368 DBG("period: %.3f", period); 00369 DBG("PWMSTEP: %.3f", (float) PWMSTEP_US); 00370 // Set the new duty cycle: 00371 TIM1->CCR1 = ((unsigned int)(Duty_us/period * TIM1->ARR)); 00372 // Set the CCR4 Register to the maximum value minus CH4SHIFT. This ensures the high speed ADC is in sync with the PWM module. 00373 TIM1->CCR4 = 0; 00374 // Re-enable the UEV event: 00375 CLEARUDIS; 00376 // Done! 00377 return; 00378 } 00379 00380
Generated on Tue Jul 12 2022 21:32:12 by 1.7.2