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 /* To have a PWM where we can change both the period and the duty cycle, 00025 * we need an entire timer. With the following conventions: 00026 * * MR3 is used for the PWM period 00027 * * MR0, MR1, MR2 are used for the duty cycle 00028 */ 00029 static const PinMap PinMap_PWM[] = { 00030 /* CT16B0 */ 00031 {P0_8 , PWM_1, 2}, {P1_13, PWM_1, 2}, /* MR0 */ 00032 {P0_9 , PWM_2, 2}, {P1_14, PWM_2, 2}, /* MR1 */ 00033 {P0_10, PWM_3, 3}, {P1_15, PWM_3, 2}, /* MR2 */ 00034 00035 /* CT16B1 */ 00036 {P0_21, PWM_4, 1}, /* MR0 */ 00037 {P0_22, PWM_5, 2}, {P1_23, PWM_5, 1}, /* MR1 */ 00038 00039 /* CT32B0 */ 00040 {P0_18, PWM_6, 2}, {P1_24, PWM_6, 1}, /* MR0 */ 00041 {P0_19, PWM_7, 2}, {P1_25, PWM_7, 1}, /* MR1 */ 00042 {P0_1 , PWM_8, 2}, {P1_26, PWM_8, 1}, /* MR2 */ 00043 00044 /* CT32B1 */ 00045 {P0_13, PWM_9 , 3}, {P1_0, PWM_9 , 1}, /* MR0 */ 00046 {P0_14, PWM_10, 3}, {P1_1, PWM_10, 1}, /* MR1 */ 00047 {P0_15, PWM_11, 3}, {P1_2, PWM_11, 1}, /* MR2 */ 00048 00049 {NC, NC, 0} 00050 }; 00051 00052 typedef struct { 00053 uint8_t timer; 00054 uint8_t mr; 00055 } timer_mr; 00056 00057 static timer_mr pwm_timer_map[11] = { 00058 {0, 0}, {0, 1}, {0, 2}, 00059 {1, 0}, {1, 1}, 00060 {2, 0}, {2, 1}, {2, 2}, 00061 {3, 0}, {3, 1}, {3, 2}, 00062 }; 00063 00064 static LPC_CTxxBx_Type *Timers[4] = { 00065 LPC_CT16B0, LPC_CT16B1, 00066 LPC_CT32B0, LPC_CT32B1 00067 }; 00068 00069 static unsigned int pwm_clock_mhz; 00070 00071 void pwmout_init(pwmout_t* obj, PinName pin) { 00072 // determine the channel 00073 PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); 00074 if (pwm == (uint32_t)NC) 00075 error("PwmOut pin mapping failed"); 00076 00077 obj->pwm = pwm; 00078 00079 // Timer registers 00080 timer_mr tid = pwm_timer_map[pwm]; 00081 LPC_CTxxBx_Type *timer = Timers[tid.timer]; 00082 00083 // Disable timer 00084 timer->TCR = 0; 00085 00086 // Power the correspondent timer 00087 LPC_SYSCON->SYSAHBCLKCTRL |= 1 << (tid.timer + 7); 00088 00089 /* Enable PWM function */ 00090 timer->PWMC = (1 << 3)|(1 << 2)|(1 << 1)|(1 << 0); 00091 00092 /* Reset Functionality on MR3 controlling the PWM period */ 00093 timer->MCR = 1 << 10; 00094 00095 pwm_clock_mhz = SystemCoreClock / 1000000; 00096 00097 // default to 20ms: standard for servos, and fine for e.g. brightness control 00098 pwmout_period_ms(obj, 20); 00099 pwmout_write (obj, 0); 00100 00101 // Wire pinout 00102 pinmap_pinout(pin, PinMap_PWM); 00103 } 00104 00105 void pwmout_free(pwmout_t* obj) { 00106 // [TODO] 00107 } 00108 00109 void pwmout_write(pwmout_t* obj, float value) { 00110 if (value < 0.0f) { 00111 value = 0.0; 00112 } else if (value > 1.0f) { 00113 value = 1.0; 00114 } 00115 00116 timer_mr tid = pwm_timer_map[obj->pwm]; 00117 LPC_CTxxBx_Type *timer = Timers[tid.timer]; 00118 uint32_t t_off = timer->MR3 - (uint32_t)((float)(timer->MR3 ) * value); 00119 00120 timer->TCR = TCR_RESET; 00121 timer->MR [tid.mr] = t_off; 00122 timer->TCR = TCR_CNT_EN; 00123 } 00124 00125 float pwmout_read(pwmout_t* obj) { 00126 timer_mr tid = pwm_timer_map[obj->pwm]; 00127 LPC_CTxxBx_Type *timer = Timers[tid.timer]; 00128 00129 float v = (float)(timer->MR3 - timer->MR [tid.mr]) / (float)(timer->MR3 ); 00130 return (v > 1.0f) ? (1.0f) : (v); 00131 } 00132 00133 void pwmout_period(pwmout_t* obj, float seconds) { 00134 pwmout_period_us(obj, seconds * 1000000.0f); 00135 } 00136 00137 void pwmout_period_ms(pwmout_t* obj, int ms) { 00138 pwmout_period_us(obj, ms * 1000); 00139 } 00140 00141 // Set the PWM period, keeping the duty cycle the same. 00142 void pwmout_period_us(pwmout_t* obj, int us) { 00143 int i = 0; 00144 uint32_t period_ticks = pwm_clock_mhz * us; 00145 00146 timer_mr tid = pwm_timer_map[obj->pwm]; 00147 LPC_CTxxBx_Type *timer = Timers[tid.timer]; 00148 uint32_t old_period_ticks = timer->MR3 ; 00149 00150 timer->TCR = TCR_RESET; 00151 timer->MR3 = period_ticks; 00152 00153 // Scale the pulse width to preserve the duty ratio 00154 if (old_period_ticks > 0) { 00155 for (i=0; i<3; i++) { 00156 uint32_t t_off = period_ticks - (uint32_t)(((uint64_t)timer->MR [i] * (uint64_t)period_ticks) / (uint64_t)old_period_ticks); 00157 timer->MR [i] = t_off; 00158 } 00159 } 00160 timer->TCR = TCR_CNT_EN; 00161 } 00162 00163 void pwmout_pulsewidth(pwmout_t* obj, float seconds) { 00164 pwmout_pulsewidth_us(obj, seconds * 1000000.0f); 00165 } 00166 00167 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { 00168 pwmout_pulsewidth_us(obj, ms * 1000); 00169 } 00170 00171 void pwmout_pulsewidth_us(pwmout_t* obj, int us) { 00172 uint32_t t_on = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000); 00173 timer_mr tid = pwm_timer_map[obj->pwm]; 00174 LPC_CTxxBx_Type *timer = Timers[tid.timer]; 00175 00176 timer->TCR = TCR_RESET; 00177 if (t_on > timer->MR3 ) { 00178 pwmout_period_us(obj, us); 00179 } 00180 uint32_t t_off = timer->MR3 - t_on; 00181 timer->MR [tid.mr] = t_off; 00182 timer->TCR = TCR_CNT_EN; 00183 }
Generated on Tue Jul 12 2022 13:47:01 by 1.7.2