added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Committer:
JojoS
Date:
Sat Sep 10 15:32:04 2016 +0000
Revision:
147:ba84b7dc41a7
Parent:
144:ef7eb2e8f9f7
added prescaler for 16 bit timers (solution as in LPC11xx), default prescaler 31 for max 28 ms period time

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /***************************************************************************//**
<> 144:ef7eb2e8f9f7 2 * @file pwmout_api.c
<> 144:ef7eb2e8f9f7 3 *******************************************************************************
<> 144:ef7eb2e8f9f7 4 * @section License
<> 144:ef7eb2e8f9f7 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
<> 144:ef7eb2e8f9f7 6 *******************************************************************************
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * SPDX-License-Identifier: Apache-2.0
<> 144:ef7eb2e8f9f7 9 *
<> 144:ef7eb2e8f9f7 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
<> 144:ef7eb2e8f9f7 11 * not use this file except in compliance with the License.
<> 144:ef7eb2e8f9f7 12 * You may obtain a copy of the License at
<> 144:ef7eb2e8f9f7 13 *
<> 144:ef7eb2e8f9f7 14 * http://www.apache.org/licenses/LICENSE-2.0
<> 144:ef7eb2e8f9f7 15 *
<> 144:ef7eb2e8f9f7 16 * Unless required by applicable law or agreed to in writing, software
<> 144:ef7eb2e8f9f7 17 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
<> 144:ef7eb2e8f9f7 18 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 144:ef7eb2e8f9f7 19 * See the License for the specific language governing permissions and
<> 144:ef7eb2e8f9f7 20 * limitations under the License.
<> 144:ef7eb2e8f9f7 21 *
<> 144:ef7eb2e8f9f7 22 ******************************************************************************/
<> 144:ef7eb2e8f9f7 23
<> 144:ef7eb2e8f9f7 24 #include "device.h"
<> 144:ef7eb2e8f9f7 25 #include "clocking.h"
<> 144:ef7eb2e8f9f7 26 #if DEVICE_PWMOUT
<> 144:ef7eb2e8f9f7 27
<> 144:ef7eb2e8f9f7 28 #include "mbed_assert.h"
<> 144:ef7eb2e8f9f7 29 #include "pwmout_api.h"
<> 144:ef7eb2e8f9f7 30 #include "cmsis.h"
<> 144:ef7eb2e8f9f7 31 #include "pinmap.h"
<> 144:ef7eb2e8f9f7 32 #include "PeripheralPins.h"
<> 144:ef7eb2e8f9f7 33 #include "device_peripherals.h"
<> 144:ef7eb2e8f9f7 34 #include "sleepmodes.h"
<> 144:ef7eb2e8f9f7 35
<> 144:ef7eb2e8f9f7 36 #include "em_cmu.h"
<> 144:ef7eb2e8f9f7 37 #include "em_gpio.h"
<> 144:ef7eb2e8f9f7 38 #include "em_timer.h"
<> 144:ef7eb2e8f9f7 39
<> 144:ef7eb2e8f9f7 40 static uint32_t pwm_prescaler_div;
<> 144:ef7eb2e8f9f7 41
<> 144:ef7eb2e8f9f7 42 float pwmout_calculate_duty(uint32_t width_cycles, uint32_t period_cycles);
<> 144:ef7eb2e8f9f7 43 void pwmout_write_channel(uint32_t channel, float value);
<> 144:ef7eb2e8f9f7 44
<> 144:ef7eb2e8f9f7 45 uint32_t pwmout_get_channel_route(uint32_t channel)
<> 144:ef7eb2e8f9f7 46 {
<> 144:ef7eb2e8f9f7 47 MBED_ASSERT(channel != (PWMName) NC);
<> 144:ef7eb2e8f9f7 48
<> 144:ef7eb2e8f9f7 49 switch (channel) {
<> 144:ef7eb2e8f9f7 50 #ifdef TIMER_ROUTEPEN_CC0PEN
<> 144:ef7eb2e8f9f7 51 case PWM_CH0:
<> 144:ef7eb2e8f9f7 52 return TIMER_ROUTEPEN_CC0PEN;
<> 144:ef7eb2e8f9f7 53 break;
<> 144:ef7eb2e8f9f7 54 case PWM_CH1:
<> 144:ef7eb2e8f9f7 55 return TIMER_ROUTEPEN_CC1PEN;
<> 144:ef7eb2e8f9f7 56 break;
<> 144:ef7eb2e8f9f7 57 case PWM_CH2:
<> 144:ef7eb2e8f9f7 58 return TIMER_ROUTEPEN_CC2PEN;
<> 144:ef7eb2e8f9f7 59 break;
<> 144:ef7eb2e8f9f7 60 case PWM_CH3:
<> 144:ef7eb2e8f9f7 61 return TIMER_ROUTEPEN_CC3PEN;
<> 144:ef7eb2e8f9f7 62 break;
<> 144:ef7eb2e8f9f7 63 #else
<> 144:ef7eb2e8f9f7 64 case PWM_CH0:
<> 144:ef7eb2e8f9f7 65 return TIMER_ROUTE_CC0PEN;
<> 144:ef7eb2e8f9f7 66 break;
<> 144:ef7eb2e8f9f7 67 case PWM_CH1:
<> 144:ef7eb2e8f9f7 68 return TIMER_ROUTE_CC1PEN;
<> 144:ef7eb2e8f9f7 69 break;
<> 144:ef7eb2e8f9f7 70 case PWM_CH2:
<> 144:ef7eb2e8f9f7 71 return TIMER_ROUTE_CC2PEN;
<> 144:ef7eb2e8f9f7 72 break;
<> 144:ef7eb2e8f9f7 73 #endif
<> 144:ef7eb2e8f9f7 74 default:
<> 144:ef7eb2e8f9f7 75 return 0;
<> 144:ef7eb2e8f9f7 76 }
<> 144:ef7eb2e8f9f7 77 }
<> 144:ef7eb2e8f9f7 78
<> 144:ef7eb2e8f9f7 79 /*
<> 144:ef7eb2e8f9f7 80 * Disables the route location given. Returns true if it was enabled, false if it wasn't.
<> 144:ef7eb2e8f9f7 81 */
<> 144:ef7eb2e8f9f7 82 bool pwmout_disable_channel_route(uint32_t routeloc) {
<> 144:ef7eb2e8f9f7 83 #ifdef TIMER_ROUTEPEN_CC0PEN
<> 144:ef7eb2e8f9f7 84 if(PWM_TIMER->ROUTEPEN & routeloc) {
<> 144:ef7eb2e8f9f7 85 //This channel was in use, so disable
<> 144:ef7eb2e8f9f7 86 PWM_TIMER->ROUTEPEN &= ~routeloc;
<> 144:ef7eb2e8f9f7 87 return true;
<> 144:ef7eb2e8f9f7 88 }
<> 144:ef7eb2e8f9f7 89 #else
<> 144:ef7eb2e8f9f7 90 if(PWM_TIMER->ROUTE & routeloc) {
<> 144:ef7eb2e8f9f7 91 //This channel was in use, so disable
<> 144:ef7eb2e8f9f7 92 PWM_TIMER->ROUTE &= ~routeloc;
<> 144:ef7eb2e8f9f7 93 return true;
<> 144:ef7eb2e8f9f7 94 }
<> 144:ef7eb2e8f9f7 95 #endif
<> 144:ef7eb2e8f9f7 96 return false;
<> 144:ef7eb2e8f9f7 97 }
<> 144:ef7eb2e8f9f7 98
<> 144:ef7eb2e8f9f7 99 /*
<> 144:ef7eb2e8f9f7 100 * Check if a channel is active
<> 144:ef7eb2e8f9f7 101 */
<> 144:ef7eb2e8f9f7 102 bool pwmout_channel_route_active(uint32_t routeloc) {
<> 144:ef7eb2e8f9f7 103 #ifdef TIMER_ROUTEPEN_CC0PEN
<> 144:ef7eb2e8f9f7 104 if(PWM_TIMER->ROUTEPEN & routeloc) {
<> 144:ef7eb2e8f9f7 105 return true;
<> 144:ef7eb2e8f9f7 106 }
<> 144:ef7eb2e8f9f7 107 #else
<> 144:ef7eb2e8f9f7 108 if(PWM_TIMER->ROUTE & routeloc) {
<> 144:ef7eb2e8f9f7 109 return true;
<> 144:ef7eb2e8f9f7 110 }
<> 144:ef7eb2e8f9f7 111 #endif
<> 144:ef7eb2e8f9f7 112 return false;
<> 144:ef7eb2e8f9f7 113 }
<> 144:ef7eb2e8f9f7 114
<> 144:ef7eb2e8f9f7 115 /*
<> 144:ef7eb2e8f9f7 116 * Set the given route PEN flag
<> 144:ef7eb2e8f9f7 117 */
<> 144:ef7eb2e8f9f7 118 void pwmout_set_channel_route(uint32_t routeloc) {
<> 144:ef7eb2e8f9f7 119 #ifdef TIMER_ROUTEPEN_CC0PEN
<> 144:ef7eb2e8f9f7 120 PWM_TIMER->ROUTEPEN |= routeloc;
<> 144:ef7eb2e8f9f7 121 #else
<> 144:ef7eb2e8f9f7 122 PWM_TIMER->ROUTE |= routeloc;
<> 144:ef7eb2e8f9f7 123 #endif
<> 144:ef7eb2e8f9f7 124 }
<> 144:ef7eb2e8f9f7 125
<> 144:ef7eb2e8f9f7 126 /*
<> 144:ef7eb2e8f9f7 127 * Check if all routes are disabled
<> 144:ef7eb2e8f9f7 128 */
<> 144:ef7eb2e8f9f7 129 bool pwmout_all_inactive(void) {
<> 144:ef7eb2e8f9f7 130 #ifdef TIMER_ROUTEPEN_CC0PEN
<> 144:ef7eb2e8f9f7 131 if(PWM_TIMER->ROUTEPEN == _TIMER_ROUTEPEN_RESETVALUE) {
<> 144:ef7eb2e8f9f7 132 return true;
<> 144:ef7eb2e8f9f7 133 }
<> 144:ef7eb2e8f9f7 134 #else
<> 144:ef7eb2e8f9f7 135 if(PWM_TIMER->ROUTE & (TIMER_ROUTE_CC0PEN | TIMER_ROUTE_CC1PEN | TIMER_ROUTE_CC2PEN)) {
<> 144:ef7eb2e8f9f7 136 return true;
<> 144:ef7eb2e8f9f7 137 }
<> 144:ef7eb2e8f9f7 138 #endif
<> 144:ef7eb2e8f9f7 139 return false;
<> 144:ef7eb2e8f9f7 140 }
<> 144:ef7eb2e8f9f7 141
<> 144:ef7eb2e8f9f7 142 void pwmout_enable_pins(pwmout_t *obj, uint8_t enable)
<> 144:ef7eb2e8f9f7 143 {
<> 144:ef7eb2e8f9f7 144 if (enable) {
<> 144:ef7eb2e8f9f7 145 pin_mode(obj->pin, PushPull);
<> 144:ef7eb2e8f9f7 146 } else {
<> 144:ef7eb2e8f9f7 147 // TODO_LP return PinMode to the previous state
<> 144:ef7eb2e8f9f7 148 pin_mode(obj->pin, Disabled);
<> 144:ef7eb2e8f9f7 149 }
<> 144:ef7eb2e8f9f7 150 }
<> 144:ef7eb2e8f9f7 151
<> 144:ef7eb2e8f9f7 152 void pwmout_enable(pwmout_t *obj, uint8_t enable){
<> 144:ef7eb2e8f9f7 153 if (enable) {
<> 144:ef7eb2e8f9f7 154 // Set mode to PWM
<> 144:ef7eb2e8f9f7 155 PWM_TIMER->CC[obj->channel].CTRL = TIMER_CC_CTRL_MODE_PWM;
<> 144:ef7eb2e8f9f7 156 } else {
<> 144:ef7eb2e8f9f7 157 // Set mode to default (== disabled)
<> 144:ef7eb2e8f9f7 158 PWM_TIMER->CC[obj->channel].CTRL = _TIMER_CC_CTRL_MODE_DEFAULT;
<> 144:ef7eb2e8f9f7 159 }
<> 144:ef7eb2e8f9f7 160 }
<> 144:ef7eb2e8f9f7 161
<> 144:ef7eb2e8f9f7 162 void pwmout_init(pwmout_t *obj, PinName pin)
<> 144:ef7eb2e8f9f7 163 {
<> 144:ef7eb2e8f9f7 164 obj->channel = (PWMName) pinmap_peripheral(pin, PinMap_PWM);
<> 144:ef7eb2e8f9f7 165 obj->pin = pin;
<> 144:ef7eb2e8f9f7 166 MBED_ASSERT(obj->channel != (PWMName) NC);
<> 144:ef7eb2e8f9f7 167
<> 144:ef7eb2e8f9f7 168 /* Turn on clock */
<> 144:ef7eb2e8f9f7 169 CMU_ClockEnable(PWM_TIMER_CLOCK, true);
<> 144:ef7eb2e8f9f7 170
<> 144:ef7eb2e8f9f7 171 /* Turn on timer */
<> 144:ef7eb2e8f9f7 172 if(!(PWM_TIMER->STATUS & TIMER_STATUS_RUNNING)) {
<> 144:ef7eb2e8f9f7 173 TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT;
<> 144:ef7eb2e8f9f7 174 TIMER_Init(PWM_TIMER, &timerInit);
<> 144:ef7eb2e8f9f7 175 }
<> 144:ef7eb2e8f9f7 176
<> 144:ef7eb2e8f9f7 177 // Set route enable
<> 144:ef7eb2e8f9f7 178 if(pwmout_channel_route_active(pwmout_get_channel_route(obj->channel))) {
<> 144:ef7eb2e8f9f7 179 //This channel was already in use
<> 144:ef7eb2e8f9f7 180 //TODO: gracefully handle this case. mbed_error?
<> 144:ef7eb2e8f9f7 181 return;
<> 144:ef7eb2e8f9f7 182 } else {
<> 144:ef7eb2e8f9f7 183 pwmout_set_channel_route(pwmout_get_channel_route(obj->channel));
<> 144:ef7eb2e8f9f7 184 blockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 185 pwmout_enable(obj, true);
<> 144:ef7eb2e8f9f7 186 pwmout_enable_pins(obj, true);
<> 144:ef7eb2e8f9f7 187 }
<> 144:ef7eb2e8f9f7 188
<> 144:ef7eb2e8f9f7 189 // Set route location
<> 144:ef7eb2e8f9f7 190 #ifdef _TIMER_ROUTELOC0_CC0LOC_LOC0
<> 144:ef7eb2e8f9f7 191 switch (obj->channel) {
<> 144:ef7eb2e8f9f7 192 case PWM_CH0:
<> 144:ef7eb2e8f9f7 193 PWM_TIMER->ROUTELOC0 &= ~_TIMER_ROUTELOC0_CC0LOC_MASK;
<> 144:ef7eb2e8f9f7 194 PWM_TIMER->ROUTELOC0 |= pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTELOC0_CC0LOC_SHIFT;
<> 144:ef7eb2e8f9f7 195 break;
<> 144:ef7eb2e8f9f7 196 case PWM_CH1:
<> 144:ef7eb2e8f9f7 197 PWM_TIMER->ROUTELOC0 &= ~_TIMER_ROUTELOC0_CC1LOC_MASK;
<> 144:ef7eb2e8f9f7 198 PWM_TIMER->ROUTELOC0 |= pinmap_find_function(pin,PinMap_PWM)<< _TIMER_ROUTELOC0_CC1LOC_SHIFT;
<> 144:ef7eb2e8f9f7 199 break;
<> 144:ef7eb2e8f9f7 200 case PWM_CH2:
<> 144:ef7eb2e8f9f7 201 PWM_TIMER->ROUTELOC0 &= ~_TIMER_ROUTELOC0_CC2LOC_MASK;
<> 144:ef7eb2e8f9f7 202 PWM_TIMER->ROUTELOC0 |= pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTELOC0_CC2LOC_SHIFT;
<> 144:ef7eb2e8f9f7 203 break;
<> 144:ef7eb2e8f9f7 204 case PWM_CH3:
<> 144:ef7eb2e8f9f7 205 PWM_TIMER->ROUTELOC0 &= ~_TIMER_ROUTELOC0_CC3LOC_MASK;
<> 144:ef7eb2e8f9f7 206 PWM_TIMER->ROUTELOC0 |= pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTELOC0_CC3LOC_SHIFT;
<> 144:ef7eb2e8f9f7 207 break;
<> 144:ef7eb2e8f9f7 208 default:
<> 144:ef7eb2e8f9f7 209 MBED_ASSERT(false);
<> 144:ef7eb2e8f9f7 210 }
<> 144:ef7eb2e8f9f7 211 #else
<> 144:ef7eb2e8f9f7 212 // On P1, the route location is statically defined for the entire timer.
<> 144:ef7eb2e8f9f7 213 PWM_TIMER->ROUTE &= ~_TIMER_ROUTE_LOCATION_MASK;
<> 144:ef7eb2e8f9f7 214 if(pwmout_all_inactive()) {
<> 144:ef7eb2e8f9f7 215 PWM_TIMER->ROUTE |= pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTE_LOCATION_SHIFT;
<> 144:ef7eb2e8f9f7 216 } else {
<> 144:ef7eb2e8f9f7 217 MBED_ASSERT((pinmap_find_function(pin,PinMap_PWM) << _TIMER_ROUTE_LOCATION_SHIFT) == (PWM_TIMER->ROUTE & _TIMER_ROUTE_LOCATION_MASK));
<> 144:ef7eb2e8f9f7 218 }
<> 144:ef7eb2e8f9f7 219 #endif
<> 144:ef7eb2e8f9f7 220
<> 144:ef7eb2e8f9f7 221 // Set default 20ms frequency and 0ms pulse width
<> 144:ef7eb2e8f9f7 222 pwmout_period(obj, 0.02);
<> 144:ef7eb2e8f9f7 223 }
<> 144:ef7eb2e8f9f7 224
<> 144:ef7eb2e8f9f7 225 void pwmout_free(pwmout_t *obj)
<> 144:ef7eb2e8f9f7 226 {
<> 144:ef7eb2e8f9f7 227 if(pwmout_disable_channel_route(pwmout_get_channel_route(obj->channel))) {
<> 144:ef7eb2e8f9f7 228 //Channel was previously enabled, so do housekeeping
<> 144:ef7eb2e8f9f7 229 unblockSleepMode(EM1);
<> 144:ef7eb2e8f9f7 230 } else {
<> 144:ef7eb2e8f9f7 231 //This channel was disabled already
<> 144:ef7eb2e8f9f7 232 }
<> 144:ef7eb2e8f9f7 233
<> 144:ef7eb2e8f9f7 234 pwmout_enable_pins(obj, false);
<> 144:ef7eb2e8f9f7 235
<> 144:ef7eb2e8f9f7 236 if(pwmout_all_inactive()) {
<> 144:ef7eb2e8f9f7 237 //Stop timer
<> 144:ef7eb2e8f9f7 238 PWM_TIMER->CMD = TIMER_CMD_STOP;
<> 144:ef7eb2e8f9f7 239 while(PWM_TIMER->STATUS & TIMER_STATUS_RUNNING);
<> 144:ef7eb2e8f9f7 240
<> 144:ef7eb2e8f9f7 241 //Disable clock
<> 144:ef7eb2e8f9f7 242 CMU_ClockEnable(PWM_TIMER_CLOCK, false);
<> 144:ef7eb2e8f9f7 243 }
<> 144:ef7eb2e8f9f7 244 }
<> 144:ef7eb2e8f9f7 245
<> 144:ef7eb2e8f9f7 246 void pwmout_write(pwmout_t *obj, float value)
<> 144:ef7eb2e8f9f7 247 {
<> 144:ef7eb2e8f9f7 248 pwmout_write_channel(obj->channel, value);
<> 144:ef7eb2e8f9f7 249 }
<> 144:ef7eb2e8f9f7 250
<> 144:ef7eb2e8f9f7 251 void pwmout_write_channel(uint32_t channel, float value) {
<> 144:ef7eb2e8f9f7 252 uint32_t width_cycles = 0;
<> 144:ef7eb2e8f9f7 253 if (value < 0.0f) {
<> 144:ef7eb2e8f9f7 254 width_cycles = 0;
<> 144:ef7eb2e8f9f7 255 } else if (value >= 1.0f) {
<> 144:ef7eb2e8f9f7 256 width_cycles = PWM_TIMER->TOPB + 1;
<> 144:ef7eb2e8f9f7 257 } else {
<> 144:ef7eb2e8f9f7 258 width_cycles = (uint16_t)((float)PWM_TIMER->TOPB * value);
<> 144:ef7eb2e8f9f7 259 }
<> 144:ef7eb2e8f9f7 260
<> 144:ef7eb2e8f9f7 261 TIMER_CompareBufSet(PWM_TIMER, channel, width_cycles);
<> 144:ef7eb2e8f9f7 262 }
<> 144:ef7eb2e8f9f7 263
<> 144:ef7eb2e8f9f7 264 float pwmout_read(pwmout_t *obj)
<> 144:ef7eb2e8f9f7 265 {
<> 144:ef7eb2e8f9f7 266 return pwmout_calculate_duty(TIMER_CaptureGet(PWM_TIMER, obj->channel), TIMER_TopGet(PWM_TIMER));
<> 144:ef7eb2e8f9f7 267 }
<> 144:ef7eb2e8f9f7 268
<> 144:ef7eb2e8f9f7 269 float pwmout_calculate_duty(uint32_t width_cycles, uint32_t period_cycles) {
<> 144:ef7eb2e8f9f7 270 if(width_cycles > period_cycles) {
<> 144:ef7eb2e8f9f7 271 return 1.0f;
<> 144:ef7eb2e8f9f7 272 }
<> 144:ef7eb2e8f9f7 273 else if (width_cycles == 0) {
<> 144:ef7eb2e8f9f7 274 return 0.0f;
<> 144:ef7eb2e8f9f7 275 }
<> 144:ef7eb2e8f9f7 276 else {
<> 144:ef7eb2e8f9f7 277 return (float) width_cycles / (float) period_cycles;
<> 144:ef7eb2e8f9f7 278 }
<> 144:ef7eb2e8f9f7 279 }
<> 144:ef7eb2e8f9f7 280
<> 144:ef7eb2e8f9f7 281 // Set the PWM period, keeping the duty cycle the same.
<> 144:ef7eb2e8f9f7 282 void pwmout_period(pwmout_t *obj, float seconds)
<> 144:ef7eb2e8f9f7 283 {
<> 144:ef7eb2e8f9f7 284 // Find the lowest prescaler divider possible.
<> 144:ef7eb2e8f9f7 285 // This gives us max resolution for a given period
<> 144:ef7eb2e8f9f7 286
<> 144:ef7eb2e8f9f7 287 //The value of the top register if prescaler is set to 0
<> 144:ef7eb2e8f9f7 288 uint32_t cycles = (uint32_t)REFERENCE_FREQUENCY * seconds;
<> 144:ef7eb2e8f9f7 289 pwm_prescaler_div = 0;
<> 144:ef7eb2e8f9f7 290
<> 144:ef7eb2e8f9f7 291 //The top register is only 16 bits, so we keep dividing till we are below 0xFFFF
<> 144:ef7eb2e8f9f7 292 while (cycles > 0xFFFF) {
<> 144:ef7eb2e8f9f7 293 cycles /= 2;
<> 144:ef7eb2e8f9f7 294 pwm_prescaler_div++;
<> 144:ef7eb2e8f9f7 295
<> 144:ef7eb2e8f9f7 296 //Max pwm_prescaler_div supported is 10
<> 144:ef7eb2e8f9f7 297 if (pwm_prescaler_div > 10) {
<> 144:ef7eb2e8f9f7 298 pwm_prescaler_div = 10;
<> 144:ef7eb2e8f9f7 299 cycles = 0xFFFF; //Set it to max possible value;
<> 144:ef7eb2e8f9f7 300 break;
<> 144:ef7eb2e8f9f7 301 }
<> 144:ef7eb2e8f9f7 302 }
<> 144:ef7eb2e8f9f7 303
<> 144:ef7eb2e8f9f7 304 //Check if anything changed
<> 144:ef7eb2e8f9f7 305 if(((PWM_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) == (pwm_prescaler_div << _TIMER_CTRL_PRESC_SHIFT)) && (TIMER_TopGet(PWM_TIMER) == cycles)) return;
<> 144:ef7eb2e8f9f7 306
<> 144:ef7eb2e8f9f7 307 //Save previous period for recalculation of duty cycles
<> 144:ef7eb2e8f9f7 308 uint32_t previous_period_cycles = PWM_TIMER->TOPB;
<> 144:ef7eb2e8f9f7 309
<> 144:ef7eb2e8f9f7 310 //Set prescaler
<> 144:ef7eb2e8f9f7 311 PWM_TIMER->CTRL = (PWM_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (pwm_prescaler_div << _TIMER_CTRL_PRESC_SHIFT);
<> 144:ef7eb2e8f9f7 312
<> 144:ef7eb2e8f9f7 313 //Set Top Value, which controls the PWM period
<> 144:ef7eb2e8f9f7 314 TIMER_TopBufSet(PWM_TIMER, cycles);
<> 144:ef7eb2e8f9f7 315
<> 144:ef7eb2e8f9f7 316 //For each active channel, re-calculate the compare value
<> 144:ef7eb2e8f9f7 317 uint32_t channel = 0;
<> 144:ef7eb2e8f9f7 318 while(pwmout_get_channel_route(channel) != 0) {
<> 144:ef7eb2e8f9f7 319 if(pwmout_channel_route_active(channel)) {
<> 144:ef7eb2e8f9f7 320 //recalc and reset compare value
<> 144:ef7eb2e8f9f7 321 pwmout_write_channel(channel, pwmout_calculate_duty(PWM_TIMER->CC[channel].CCVB, previous_period_cycles));
<> 144:ef7eb2e8f9f7 322 }
<> 144:ef7eb2e8f9f7 323 channel++;
<> 144:ef7eb2e8f9f7 324 }
<> 144:ef7eb2e8f9f7 325 }
<> 144:ef7eb2e8f9f7 326
<> 144:ef7eb2e8f9f7 327 void pwmout_period_ms(pwmout_t *obj, int ms)
<> 144:ef7eb2e8f9f7 328 {
<> 144:ef7eb2e8f9f7 329 pwmout_period(obj, ms / 1000.0f);
<> 144:ef7eb2e8f9f7 330 }
<> 144:ef7eb2e8f9f7 331
<> 144:ef7eb2e8f9f7 332 void pwmout_period_us(pwmout_t *obj, int us)
<> 144:ef7eb2e8f9f7 333 {
<> 144:ef7eb2e8f9f7 334 pwmout_period(obj, us / 1000000.0f);
<> 144:ef7eb2e8f9f7 335 }
<> 144:ef7eb2e8f9f7 336
<> 144:ef7eb2e8f9f7 337 void pwmout_pulsewidth(pwmout_t *obj, float seconds)
<> 144:ef7eb2e8f9f7 338 {
<> 144:ef7eb2e8f9f7 339 uint16_t width_cycles = (uint16_t) (((float) (REFERENCE_FREQUENCY >> pwm_prescaler_div)) * seconds);
<> 144:ef7eb2e8f9f7 340 TIMER_CompareBufSet(PWM_TIMER, obj->channel, width_cycles);
<> 144:ef7eb2e8f9f7 341 }
<> 144:ef7eb2e8f9f7 342
<> 144:ef7eb2e8f9f7 343 void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
<> 144:ef7eb2e8f9f7 344 {
<> 144:ef7eb2e8f9f7 345 uint16_t width_cycles = (uint16_t) ((REFERENCE_FREQUENCY >> pwm_prescaler_div) * ms) / 1000;
<> 144:ef7eb2e8f9f7 346 TIMER_CompareBufSet(PWM_TIMER, obj->channel, width_cycles);
<> 144:ef7eb2e8f9f7 347 }
<> 144:ef7eb2e8f9f7 348
<> 144:ef7eb2e8f9f7 349 void pwmout_pulsewidth_us(pwmout_t *obj, int us)
<> 144:ef7eb2e8f9f7 350 {
<> 144:ef7eb2e8f9f7 351 uint16_t width_cycles = (uint16_t) ((REFERENCE_FREQUENCY >> pwm_prescaler_div) * us) / 1000000;
<> 144:ef7eb2e8f9f7 352 TIMER_CompareBufSet(PWM_TIMER, obj->channel, width_cycles);
<> 144:ef7eb2e8f9f7 353 }
<> 144:ef7eb2e8f9f7 354
<> 144:ef7eb2e8f9f7 355 #endif