mbed library sources

Fork of mbed-src by mbed official

Committer:
mbed_official
Date:
Mon Apr 20 10:45:07 2015 +0100
Revision:
516:b3fb5c6901a6
Parent:
480:69aad4cbc07a
Synchronized with git revision 016b9ad9cba789b99acee1102802355338120b29

Full URL: https://github.com/mbedmicro/mbed/commit/016b9ad9cba789b99acee1102802355338120b29/

NXP's HAL - Fix PwmOut period using SCT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 480:69aad4cbc07a 1 /* mbed Microcontroller Library
mbed_official 480:69aad4cbc07a 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 480:69aad4cbc07a 3 *
mbed_official 480:69aad4cbc07a 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 480:69aad4cbc07a 5 * you may not use this file except in compliance with the License.
mbed_official 480:69aad4cbc07a 6 * You may obtain a copy of the License at
mbed_official 480:69aad4cbc07a 7 *
mbed_official 480:69aad4cbc07a 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 480:69aad4cbc07a 9 *
mbed_official 480:69aad4cbc07a 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 480:69aad4cbc07a 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 480:69aad4cbc07a 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 480:69aad4cbc07a 13 * See the License for the specific language governing permissions and
mbed_official 480:69aad4cbc07a 14 * limitations under the License.
mbed_official 480:69aad4cbc07a 15 */
mbed_official 480:69aad4cbc07a 16 #include "mbed_assert.h"
mbed_official 480:69aad4cbc07a 17 #include "pwmout_api.h"
mbed_official 480:69aad4cbc07a 18 #include "cmsis.h"
mbed_official 480:69aad4cbc07a 19 #include "pinmap.h"
mbed_official 480:69aad4cbc07a 20 #include "mbed_error.h"
mbed_official 480:69aad4cbc07a 21
mbed_official 480:69aad4cbc07a 22 // Ported from LPC824 and adapted.
mbed_official 480:69aad4cbc07a 23
mbed_official 480:69aad4cbc07a 24 #if DEVICE_PWMOUT
mbed_official 480:69aad4cbc07a 25
mbed_official 480:69aad4cbc07a 26 #define PWM_IRQn SCT_IRQn
mbed_official 480:69aad4cbc07a 27
mbed_official 480:69aad4cbc07a 28 // Bit flags for used SCT Outputs
mbed_official 480:69aad4cbc07a 29 static unsigned char sct_used = 0;
mbed_official 480:69aad4cbc07a 30 static int sct_inited = 0;
mbed_official 480:69aad4cbc07a 31
mbed_official 480:69aad4cbc07a 32 // Find available output channel
mbed_official 480:69aad4cbc07a 33 // Max number of PWM outputs is 4 on LPC812
mbed_official 480:69aad4cbc07a 34 static int get_available_sct() {
mbed_official 480:69aad4cbc07a 35 int i;
mbed_official 480:69aad4cbc07a 36
mbed_official 480:69aad4cbc07a 37 // Find available output channel 0..3
mbed_official 480:69aad4cbc07a 38 // Also need one Match register per channel
mbed_official 480:69aad4cbc07a 39 for (i = 0; i < CONFIG_SCT_nOU; i++) {
mbed_official 480:69aad4cbc07a 40 // for (i = 0; i < 4; i++) {
mbed_official 480:69aad4cbc07a 41 if ((sct_used & (1 << i)) == 0)
mbed_official 480:69aad4cbc07a 42 return i;
mbed_official 480:69aad4cbc07a 43 }
mbed_official 480:69aad4cbc07a 44 return -1;
mbed_official 480:69aad4cbc07a 45 }
mbed_official 480:69aad4cbc07a 46
mbed_official 480:69aad4cbc07a 47 // Any Port pin may be used for PWM.
mbed_official 480:69aad4cbc07a 48 // Max number of PWM outputs is 4
mbed_official 480:69aad4cbc07a 49 void pwmout_init(pwmout_t* obj, PinName pin) {
mbed_official 480:69aad4cbc07a 50 MBED_ASSERT(pin != (uint32_t)NC);
mbed_official 480:69aad4cbc07a 51
mbed_official 480:69aad4cbc07a 52 int sct_n = get_available_sct();
mbed_official 480:69aad4cbc07a 53 if (sct_n == -1) {
mbed_official 480:69aad4cbc07a 54 error("No available SCT Output");
mbed_official 480:69aad4cbc07a 55 }
mbed_official 480:69aad4cbc07a 56
mbed_official 480:69aad4cbc07a 57 sct_used |= (1 << sct_n);
mbed_official 480:69aad4cbc07a 58
mbed_official 480:69aad4cbc07a 59 obj->pwm = (LPC_SCT_TypeDef*)LPC_SCT;
mbed_official 480:69aad4cbc07a 60 obj->pwm_ch = sct_n;
mbed_official 480:69aad4cbc07a 61
mbed_official 480:69aad4cbc07a 62 LPC_SCT_TypeDef* pwm = obj->pwm;
mbed_official 480:69aad4cbc07a 63
mbed_official 480:69aad4cbc07a 64 // Init SCT on first use
mbed_official 480:69aad4cbc07a 65 if (! sct_inited) {
mbed_official 480:69aad4cbc07a 66 sct_inited = 1;
mbed_official 480:69aad4cbc07a 67
mbed_official 480:69aad4cbc07a 68 // Enable the SCT clock
mbed_official 480:69aad4cbc07a 69 LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8);
mbed_official 480:69aad4cbc07a 70
mbed_official 480:69aad4cbc07a 71 // Clear peripheral reset the SCT:
mbed_official 480:69aad4cbc07a 72 LPC_SYSCON->PRESETCTRL |= (1 << 8);
mbed_official 480:69aad4cbc07a 73
mbed_official 480:69aad4cbc07a 74 // Two 16-bit counters, autolimit (ie reset on Match_0)
mbed_official 516:b3fb5c6901a6 75 //pwm->CONFIG &= ~(0x1);
mbed_official 516:b3fb5c6901a6 76 //pwm->CONFIG |= (1 << 17);
mbed_official 516:b3fb5c6901a6 77 pwm->CONFIG |= ((0x3 << 17) | 0x01);
mbed_official 480:69aad4cbc07a 78
mbed_official 480:69aad4cbc07a 79 // halt and clear the counter
mbed_official 516:b3fb5c6901a6 80 pwm->CTRL_U |= (1 << 2) | (1 << 3);
mbed_official 480:69aad4cbc07a 81
mbed_official 480:69aad4cbc07a 82 // System Clock (30 Mhz) -> Prescaler -> us_ticker (1 MHz)
mbed_official 516:b3fb5c6901a6 83 pwm->CTRL_U &= ~(0x7F << 5);
mbed_official 516:b3fb5c6901a6 84 pwm->CTRL_U |= (((SystemCoreClock/1000000 - 1) & 0x7F) << 5);
mbed_official 480:69aad4cbc07a 85
mbed_official 480:69aad4cbc07a 86 pwm->EVENT[0].CTRL = (1 << 12) | 0; // Event_0 on Match_0
mbed_official 480:69aad4cbc07a 87 pwm->EVENT[0].STATE = 0xFFFFFFFF; // All states
mbed_official 480:69aad4cbc07a 88
mbed_official 480:69aad4cbc07a 89 // unhalt the counter:
mbed_official 480:69aad4cbc07a 90 // - clearing bit 2 of the CTRL register
mbed_official 516:b3fb5c6901a6 91 pwm->CTRL_U &= ~(1 << 2);
mbed_official 480:69aad4cbc07a 92
mbed_official 480:69aad4cbc07a 93 // Not using IRQs
mbed_official 480:69aad4cbc07a 94 //NVIC_SetVector(PWM_IRQn, (uint32_t)pwm_irq_handler);
mbed_official 480:69aad4cbc07a 95 //NVIC_EnableIRQ(PWM_IRQn);
mbed_official 480:69aad4cbc07a 96 }
mbed_official 480:69aad4cbc07a 97
mbed_official 480:69aad4cbc07a 98 // LPC81x has only one SCT and 4 Outputs
mbed_official 480:69aad4cbc07a 99 // LPC82x has only one SCT and 6 Outputs
mbed_official 480:69aad4cbc07a 100 // LPC1549 has 4 SCTs and 16 Outputs
mbed_official 480:69aad4cbc07a 101 switch(sct_n) {
mbed_official 480:69aad4cbc07a 102 case 0:
mbed_official 480:69aad4cbc07a 103 // SCTx_OUT0
mbed_official 480:69aad4cbc07a 104 LPC_SWM->PINASSIGN[6] &= ~0xFF000000;
mbed_official 480:69aad4cbc07a 105 LPC_SWM->PINASSIGN[6] |= (pin << 24);
mbed_official 480:69aad4cbc07a 106 break;
mbed_official 480:69aad4cbc07a 107 case 1:
mbed_official 480:69aad4cbc07a 108 // SCTx_OUT1
mbed_official 480:69aad4cbc07a 109 LPC_SWM->PINASSIGN[7] &= ~0x000000FF;
mbed_official 480:69aad4cbc07a 110 LPC_SWM->PINASSIGN[7] |= (pin);
mbed_official 480:69aad4cbc07a 111 break;
mbed_official 480:69aad4cbc07a 112 case 2:
mbed_official 480:69aad4cbc07a 113 // SCTx_OUT2
mbed_official 480:69aad4cbc07a 114 LPC_SWM->PINASSIGN[7] &= ~0x0000FF00;
mbed_official 480:69aad4cbc07a 115 LPC_SWM->PINASSIGN[7] |= (pin << 8);
mbed_official 480:69aad4cbc07a 116 break;
mbed_official 480:69aad4cbc07a 117 case 3:
mbed_official 480:69aad4cbc07a 118 // SCTx_OUT3
mbed_official 480:69aad4cbc07a 119 LPC_SWM->PINASSIGN[7] &= ~0x00FF0000;
mbed_official 480:69aad4cbc07a 120 LPC_SWM->PINASSIGN[7] |= (pin << 16);
mbed_official 480:69aad4cbc07a 121 break;
mbed_official 480:69aad4cbc07a 122 default:
mbed_official 480:69aad4cbc07a 123 break;
mbed_official 480:69aad4cbc07a 124 }
mbed_official 480:69aad4cbc07a 125
mbed_official 480:69aad4cbc07a 126 pwm->EVENT[sct_n + 1].CTRL = (1 << 12) | (sct_n + 1); // Event_n on Match_n
mbed_official 480:69aad4cbc07a 127 pwm->EVENT[sct_n + 1].STATE = 0xFFFFFFFF; // All states
mbed_official 480:69aad4cbc07a 128
mbed_official 480:69aad4cbc07a 129 pwm->OUT[sct_n].SET = (1 << 0); // All PWM channels are SET on Event_0
mbed_official 480:69aad4cbc07a 130 pwm->OUT[sct_n].CLR = (1 << (sct_n + 1)); // PWM ch is CLRed on Event_(ch+1)
mbed_official 480:69aad4cbc07a 131
mbed_official 480:69aad4cbc07a 132 // default to 20ms: standard for servos, and fine for e.g. brightness control
mbed_official 480:69aad4cbc07a 133 pwmout_period_ms(obj, 20); // 20ms period
mbed_official 480:69aad4cbc07a 134 pwmout_write (obj, 0.0); // 0ms pulsewidth, dutycycle 0
mbed_official 480:69aad4cbc07a 135 }
mbed_official 480:69aad4cbc07a 136
mbed_official 480:69aad4cbc07a 137 void pwmout_free(pwmout_t* obj) {
mbed_official 480:69aad4cbc07a 138 // PWM channel is now free
mbed_official 480:69aad4cbc07a 139 sct_used &= ~(1 << obj->pwm_ch);
mbed_official 480:69aad4cbc07a 140
mbed_official 480:69aad4cbc07a 141 // Disable the SCT clock when all channels free
mbed_official 480:69aad4cbc07a 142 if (sct_used == 0) {
mbed_official 480:69aad4cbc07a 143 LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 8);
mbed_official 480:69aad4cbc07a 144 sct_inited = 0;
mbed_official 480:69aad4cbc07a 145 };
mbed_official 480:69aad4cbc07a 146 }
mbed_official 480:69aad4cbc07a 147
mbed_official 480:69aad4cbc07a 148 // Set new dutycycle (0.0 .. 1.0)
mbed_official 480:69aad4cbc07a 149 void pwmout_write(pwmout_t* obj, float value) {
mbed_official 480:69aad4cbc07a 150 //value is new dutycycle
mbed_official 480:69aad4cbc07a 151 if (value < 0.0f) {
mbed_official 480:69aad4cbc07a 152 value = 0.0;
mbed_official 480:69aad4cbc07a 153 } else if (value > 1.0f) {
mbed_official 480:69aad4cbc07a 154 value = 1.0;
mbed_official 480:69aad4cbc07a 155 }
mbed_official 480:69aad4cbc07a 156
mbed_official 480:69aad4cbc07a 157 // Match_0 is PWM period. Compute new endtime of pulse for current channel
mbed_official 516:b3fb5c6901a6 158 uint32_t t_off = (uint32_t)((float)(obj->pwm->MATCHREL[0].U) * value);
mbed_official 516:b3fb5c6901a6 159 obj->pwm->MATCHREL[(obj->pwm_ch) + 1].U = t_off; // New endtime
mbed_official 480:69aad4cbc07a 160 }
mbed_official 480:69aad4cbc07a 161
mbed_official 480:69aad4cbc07a 162 // Get dutycycle (0.0 .. 1.0)
mbed_official 480:69aad4cbc07a 163 float pwmout_read(pwmout_t* obj) {
mbed_official 516:b3fb5c6901a6 164 uint32_t t_period = obj->pwm->MATCHREL[0].U;
mbed_official 480:69aad4cbc07a 165
mbed_official 480:69aad4cbc07a 166 //Sanity check
mbed_official 480:69aad4cbc07a 167 if (t_period == 0) {
mbed_official 480:69aad4cbc07a 168 return 0.0;
mbed_official 480:69aad4cbc07a 169 };
mbed_official 480:69aad4cbc07a 170
mbed_official 516:b3fb5c6901a6 171 uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch) + 1].U;
mbed_official 480:69aad4cbc07a 172 float v = (float)t_off/(float)t_period;
mbed_official 480:69aad4cbc07a 173 //Sanity check
mbed_official 480:69aad4cbc07a 174 return (v > 1.0f) ? (1.0f) : (v);
mbed_official 480:69aad4cbc07a 175 }
mbed_official 480:69aad4cbc07a 176
mbed_official 480:69aad4cbc07a 177 // Set the PWM period, keeping the duty cycle the same (for this channel only!).
mbed_official 480:69aad4cbc07a 178 void pwmout_period(pwmout_t* obj, float seconds){
mbed_official 480:69aad4cbc07a 179 pwmout_period_us(obj, seconds * 1000000.0f);
mbed_official 480:69aad4cbc07a 180 }
mbed_official 480:69aad4cbc07a 181
mbed_official 480:69aad4cbc07a 182 // Set the PWM period, keeping the duty cycle the same (for this channel only!).
mbed_official 480:69aad4cbc07a 183 void pwmout_period_ms(pwmout_t* obj, int ms) {
mbed_official 480:69aad4cbc07a 184 pwmout_period_us(obj, ms * 1000);
mbed_official 480:69aad4cbc07a 185 }
mbed_official 480:69aad4cbc07a 186
mbed_official 480:69aad4cbc07a 187 // Set the PWM period, keeping the duty cycle the same (for this channel only!).
mbed_official 480:69aad4cbc07a 188 void pwmout_period_us(pwmout_t* obj, int us) {
mbed_official 480:69aad4cbc07a 189
mbed_official 516:b3fb5c6901a6 190 uint32_t t_period = obj->pwm->MATCHREL[0].U; // Current PWM period
mbed_official 516:b3fb5c6901a6 191 obj->pwm->MATCHREL[0].U = (uint32_t)us; // New PWM period
mbed_official 480:69aad4cbc07a 192
mbed_official 480:69aad4cbc07a 193 //Keep the dutycycle for the new PWM period
mbed_official 480:69aad4cbc07a 194 //Should really do this for all active channels!!
mbed_official 480:69aad4cbc07a 195 //This problem exists in all mbed libs.
mbed_official 480:69aad4cbc07a 196
mbed_official 480:69aad4cbc07a 197 //Sanity check
mbed_official 480:69aad4cbc07a 198 if (t_period == 0) {
mbed_official 480:69aad4cbc07a 199 return;
mbed_official 480:69aad4cbc07a 200 // obj->pwm->MATCHREL[(obj->pwm_ch) + 1].L = 0; // New endtime for this channel
mbed_official 480:69aad4cbc07a 201 }
mbed_official 480:69aad4cbc07a 202 else {
mbed_official 516:b3fb5c6901a6 203 uint32_t t_off = obj->pwm->MATCHREL[(obj->pwm_ch) + 1].U;
mbed_official 480:69aad4cbc07a 204 float v = (float)t_off/(float)t_period;
mbed_official 516:b3fb5c6901a6 205 obj->pwm->MATCHREL[(obj->pwm_ch) + 1].U = (uint32_t)((float)us * (float)v); // New endtime for this channel
mbed_official 480:69aad4cbc07a 206 }
mbed_official 480:69aad4cbc07a 207 }
mbed_official 480:69aad4cbc07a 208
mbed_official 480:69aad4cbc07a 209
mbed_official 480:69aad4cbc07a 210 //Set pulsewidth
mbed_official 480:69aad4cbc07a 211 void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
mbed_official 480:69aad4cbc07a 212 pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
mbed_official 480:69aad4cbc07a 213 }
mbed_official 480:69aad4cbc07a 214
mbed_official 480:69aad4cbc07a 215 //Set pulsewidth
mbed_official 480:69aad4cbc07a 216 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms){
mbed_official 480:69aad4cbc07a 217 pwmout_pulsewidth_us(obj, ms * 1000);
mbed_official 480:69aad4cbc07a 218 }
mbed_official 480:69aad4cbc07a 219
mbed_official 480:69aad4cbc07a 220 //Set pulsewidth
mbed_official 480:69aad4cbc07a 221 void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
mbed_official 480:69aad4cbc07a 222
mbed_official 480:69aad4cbc07a 223 //Should add Sanity check to make sure pulsewidth < period!
mbed_official 516:b3fb5c6901a6 224 obj->pwm->MATCHREL[(obj->pwm_ch) + 1].U = (uint32_t)us; // New endtime for this channel
mbed_official 480:69aad4cbc07a 225 }
mbed_official 480:69aad4cbc07a 226
mbed_official 480:69aad4cbc07a 227 #endif