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_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
![doxygen](doxygen.png)