fix for mbed lib issue 3 (i2c problem) see also https://mbed.org/users/mbed_official/code/mbed/issues/3 affected implementations: LPC812, LPC11U24, LPC1768, LPC2368, LPC4088
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_18, PWM_1, 2}, 00027 {P1_20, PWM_2, 2}, 00028 {P1_21, PWM_3, 2}, 00029 {P1_23, PWM_4, 2}, 00030 {P1_24, PWM_5, 2}, 00031 {P1_26, PWM_6, 2}, 00032 {P2_0 , PWM_1, 1}, 00033 {P2_1 , PWM_2, 1}, 00034 {P2_2 , PWM_3, 1}, 00035 {P2_3 , PWM_4, 1}, 00036 {P2_4 , PWM_5, 1}, 00037 {P2_5 , PWM_6, 1}, 00038 {P3_25, PWM_2, 3}, 00039 {P3_26, PWM_3, 3}, 00040 {NC, NC, 0} 00041 }; 00042 00043 __IO uint32_t *PWM_MATCH[] = { 00044 &(LPC_PWM1->MR0), 00045 &(LPC_PWM1->MR1), 00046 &(LPC_PWM1->MR2), 00047 &(LPC_PWM1->MR3), 00048 &(LPC_PWM1->MR4), 00049 &(LPC_PWM1->MR5), 00050 &(LPC_PWM1->MR6) 00051 }; 00052 00053 #define TCR_PWM_EN 0x00000008 00054 00055 static unsigned int pwm_clock_mhz; 00056 00057 void pwmout_init(pwmout_t* obj, PinName pin) { 00058 // determine the channel 00059 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); 00060 if (pwm == (uint32_t)NC) 00061 error("PwmOut pin mapping failed"); 00062 00063 obj->pwm = pwm; 00064 obj->MR = PWM_MATCH[pwm]; 00065 00066 // ensure the power is on 00067 LPC_SC->PCONP |= 1 << 6; 00068 00069 // ensure clock to /4 00070 LPC_SC->PCLKSEL0 &= ~(0x3 << 12); // pclk = /4 00071 LPC_PWM1->PR = 0; // no pre-scale 00072 00073 // ensure single PWM mode 00074 LPC_PWM1->MCR = 1 << 1; // reset TC on match 0 00075 00076 // enable the specific PWM output 00077 LPC_PWM1->PCR |= 1 << (8 + pwm); 00078 00079 pwm_clock_mhz = SystemCoreClock / 4000000; 00080 00081 // default to 20ms: standard for servos, and fine for e.g. brightness control 00082 pwmout_period_ms(obj, 20); 00083 pwmout_write (obj, 0); 00084 00085 // Wire pinout 00086 pinmap_pinout(pin, PinMap_PWM); 00087 } 00088 00089 void pwmout_free(pwmout_t* obj) { 00090 // [TODO] 00091 } 00092 00093 void pwmout_write(pwmout_t* obj, float value) { 00094 if (value < 0.0f) { 00095 value = 0.0; 00096 } else if (value > 1.0f) { 00097 value = 1.0; 00098 } 00099 00100 // set channel match to percentage 00101 uint32_t v = (uint32_t)((float)(LPC_PWM1->MR0) * value); 00102 00103 // workaround for PWM1[1] - Never make it equal MR0, else we get 1 cycle dropout 00104 if (v == LPC_PWM1->MR0) { 00105 v++; 00106 } 00107 00108 *obj->MR = v; 00109 00110 // accept on next period start 00111 LPC_PWM1->LER |= 1 << obj->pwm; 00112 } 00113 00114 float pwmout_read(pwmout_t* obj) { 00115 float v = (float)(*obj->MR) / (float)(LPC_PWM1->MR0); 00116 return (v > 1.0f) ? (1.0f) : (v); 00117 } 00118 00119 void pwmout_period(pwmout_t* obj, float seconds) { 00120 pwmout_period_us(obj, seconds * 1000000.0f); 00121 } 00122 00123 void pwmout_period_ms(pwmout_t* obj, int ms) { 00124 pwmout_period_us(obj, ms * 1000); 00125 } 00126 00127 // Set the PWM period, keeping the duty cycle the same. 00128 void pwmout_period_us(pwmout_t* obj, int us) { 00129 // calculate number of ticks 00130 uint32_t ticks = pwm_clock_mhz * us; 00131 00132 // set reset 00133 LPC_PWM1->TCR = TCR_RESET; 00134 00135 // set the global match register 00136 LPC_PWM1->MR0 = ticks; 00137 00138 // Scale the pulse width to preserve the duty ratio 00139 if (LPC_PWM1->MR0 > 0) { 00140 *obj->MR = (*obj->MR * ticks) / LPC_PWM1->MR0; 00141 } 00142 00143 // set the channel latch to update value at next period start 00144 LPC_PWM1->LER |= 1 << 0; 00145 00146 // enable counter and pwm, clear reset 00147 LPC_PWM1->TCR = TCR_CNT_EN | TCR_PWM_EN; 00148 } 00149 00150 void pwmout_pulsewidth(pwmout_t* obj, float seconds) { 00151 pwmout_pulsewidth_us(obj, seconds * 1000000.0f); 00152 } 00153 00154 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { 00155 pwmout_pulsewidth_us(obj, ms * 1000); 00156 } 00157 00158 void pwmout_pulsewidth_us(pwmout_t* obj, int us) { 00159 // calculate number of ticks 00160 uint32_t v = pwm_clock_mhz * us; 00161 00162 // workaround for PWM1[1] - Never make it equal MR0, else we get 1 cycle dropout 00163 if (v == LPC_PWM1->MR0) { 00164 v++; 00165 } 00166 00167 // set the match register value 00168 *obj->MR = v; 00169 00170 // set the channel latch to update value at next period start 00171 LPC_PWM1->LER |= 1 << obj->pwm; 00172 }
Generated on Tue Jul 12 2022 13:47:01 by 1.7.2