Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-src by
pwmout_api.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include "pwmout_api.h" 00017 #include "cmsis.h" 00018 #include "pinmap.h" 00019 #include "error.h" 00020 00021 #define TCR_CNT_EN 0x00000001 00022 #define TCR_RESET 0x00000002 00023 00024 // PORT ID, PWM ID, Pin function 00025 static const PinMap PinMap_PWM[] = { 00026 {P1_2, PWM0_1, 3}, 00027 {P1_3, PWM0_2, 3}, 00028 {P1_5, PWM0_3, 3}, 00029 {P1_6, PWM0_4, 3}, 00030 {P1_7, PWM0_5, 3}, 00031 {P1_11, PWM0_6, 3}, 00032 {P1_18, PWM1_1, 2}, 00033 {P1_20, PWM1_2, 2}, 00034 {P1_21, PWM1_3, 2}, 00035 {P1_23, PWM1_4, 2}, 00036 {P1_24, PWM1_5, 2}, 00037 {P1_26, PWM1_6, 2}, 00038 {P2_0, PWM1_1, 1}, 00039 {P2_1, PWM1_2, 1}, 00040 {P2_2, PWM1_3, 1}, 00041 {P2_3, PWM1_4, 1}, 00042 {P2_4, PWM1_5, 1}, 00043 {P2_5, PWM1_6, 1}, 00044 {P3_16, PWM0_1, 2}, 00045 {P3_17, PWM0_2, 2}, 00046 {P3_18, PWM0_3, 2}, 00047 {P3_19, PWM0_4, 2}, 00048 {P3_20, PWM0_5, 2}, 00049 {P3_21, PWM0_6, 2}, 00050 {P3_24, PWM1_1, 2}, 00051 {P3_25, PWM1_2, 2}, 00052 {P3_26, PWM1_3, 2}, 00053 {P3_27, PWM1_4, 2}, 00054 {P3_28, PWM1_5, 2}, 00055 {P3_29, PWM1_6, 2}, 00056 {NC, NC, 0} 00057 }; 00058 00059 static const uint32_t PWM_mr_offset[7] = { 00060 0x18, 0x1C, 0x20, 0x24, 0x40, 0x44, 0x48 00061 }; 00062 00063 #define TCR_PWM_EN 0x00000008 00064 static unsigned int pwm_clock_mhz; 00065 00066 void pwmout_init(pwmout_t* obj, PinName pin) { 00067 // determine the channel 00068 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); 00069 if (pwm == (uint32_t)NC) 00070 error("PwmOut pin mapping failed"); 00071 00072 obj->channel = pwm; 00073 obj->pwm = LPC_PWM0; 00074 00075 if (obj->channel > 6) { // PWM1 is used if pwm > 6 00076 obj->channel -= 6; 00077 obj->pwm = LPC_PWM1; 00078 } 00079 00080 obj->MR = (__IO uint32_t *)((uint32_t)obj->pwm + PWM_mr_offset[obj->channel]); 00081 00082 // ensure the power is on 00083 if (obj->pwm == LPC_PWM0) { 00084 LPC_SC->PCONP |= 1 << 5; 00085 } else { 00086 LPC_SC->PCONP |= 1 << 6; 00087 } 00088 00089 obj->pwm->PR = 0; // no pre-scale 00090 00091 // ensure single PWM mode 00092 obj->pwm->MCR = 1 << 1; // reset TC on match 0 00093 00094 // enable the specific PWM output 00095 obj->pwm->PCR |= 1 << (8 + obj->channel); 00096 00097 pwm_clock_mhz = PeripheralClock / 1000000; 00098 00099 // default to 20ms: standard for servos, and fine for e.g. brightness control 00100 pwmout_period_ms(obj, 20); 00101 pwmout_write (obj, 0); 00102 00103 // Wire pinout 00104 pinmap_pinout(pin, PinMap_PWM); 00105 } 00106 00107 void pwmout_free(pwmout_t* obj) { 00108 // [TODO] 00109 } 00110 00111 void pwmout_write(pwmout_t* obj, float value) { 00112 if (value < 0.0f) { 00113 value = 0.0; 00114 } else if (value > 1.0f) { 00115 value = 1.0; 00116 } 00117 00118 // set channel match to percentage 00119 uint32_t v = (uint32_t)((float)(obj->pwm->MR0) * value); 00120 00121 // workaround for PWM1[1] - Never make it equal MR0, else we get 1 cycle dropout 00122 if (v == obj->pwm->MR0) { 00123 v++; 00124 } 00125 00126 *obj->MR = v; 00127 00128 // accept on next period start 00129 obj->pwm->LER |= 1 << obj->channel; 00130 } 00131 00132 float pwmout_read(pwmout_t* obj) { 00133 float v = (float)(*obj->MR) / (float)(obj->pwm->MR0); 00134 return (v > 1.0f) ? (1.0f) : (v); 00135 } 00136 00137 void pwmout_period(pwmout_t* obj, float seconds) { 00138 pwmout_period_us(obj, seconds * 1000000.0f); 00139 } 00140 00141 void pwmout_period_ms(pwmout_t* obj, int ms) { 00142 pwmout_period_us(obj, ms * 1000); 00143 } 00144 00145 // Set the PWM period, keeping the duty cycle the same. 00146 void pwmout_period_us(pwmout_t* obj, int us) { 00147 // calculate number of ticks 00148 uint32_t ticks = pwm_clock_mhz * us; 00149 00150 // set reset 00151 obj->pwm->TCR = TCR_RESET; 00152 00153 // set the global match register 00154 obj->pwm->MR0 = ticks; 00155 00156 // Scale the pulse width to preserve the duty ratio 00157 if (obj->pwm->MR0 > 0) { 00158 *obj->MR = (*obj->MR * ticks) / obj->pwm->MR0; 00159 } 00160 00161 // set the channel latch to update value at next period start 00162 obj->pwm->LER |= 1 << 0; 00163 00164 // enable counter and pwm, clear reset 00165 obj->pwm->TCR = TCR_CNT_EN | TCR_PWM_EN; 00166 } 00167 00168 void pwmout_pulsewidth(pwmout_t* obj, float seconds) { 00169 pwmout_pulsewidth_us(obj, seconds * 1000000.0f); 00170 } 00171 00172 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { 00173 pwmout_pulsewidth_us(obj, ms * 1000); 00174 } 00175 00176 void pwmout_pulsewidth_us(pwmout_t* obj, int us) { 00177 // calculate number of ticks 00178 uint32_t v = pwm_clock_mhz * us; 00179 00180 // workaround for PWM1[1] - Never make it equal MR0, else we get 1 cycle dropout 00181 if (v == obj->pwm->MR0) { 00182 v++; 00183 } 00184 00185 // set the match register value 00186 *obj->MR = v; 00187 00188 // set the channel latch to update value at next period start 00189 obj->pwm->LER |= 1 << obj->channel; 00190 }
Generated on Tue Jul 12 2022 13:47:01 by
1.7.2
