]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11UXX/pwmout_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[max/tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC11UXX / pwmout_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "mbed_assert.h"
17 #include "pwmout_api.h"
18 #include "cmsis.h"
19 #include "pinmap.h"
20 #include "PeripheralPins.h" // For the Peripheral to Pin Definitions found in the individual Target's Platform
21
22 #define TCR_CNT_EN       0x00000001
23 #define TCR_RESET        0x00000002
24
25 typedef struct {
26     uint8_t timer;
27     uint8_t mr;
28 } timer_mr;
29
30 static timer_mr pwm_timer_map[11] = {
31     {0, 0}, {0, 1}, {0, 2},
32     {1, 0}, {1, 1},
33     {2, 0}, {2, 1}, {2, 2},
34     {3, 0}, {3, 1}, {3, 2},
35 };
36
37 static LPC_CTxxBx_Type *Timers[4] = {
38     LPC_CT16B0, LPC_CT16B1,
39     LPC_CT32B0, LPC_CT32B1
40 };
41
42 void pwmout_init(pwmout_t* obj, PinName pin) {
43     // determine the channel
44     PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
45     MBED_ASSERT(pwm != (PWMName)NC);
46
47     obj->pwm = pwm;
48     
49     // Timer registers
50     timer_mr tid = pwm_timer_map[pwm];
51     LPC_CTxxBx_Type *timer = Timers[tid.timer];
52     
53     // Disable timer
54     timer->TCR = 0;
55     
56     // Power the correspondent timer
57     LPC_SYSCON->SYSAHBCLKCTRL |= 1 << (tid.timer + 7);
58     
59     /* Enable PWM function */
60     timer->PWMC = (1 << 3)|(1 << 2)|(1 << 1)|(1 << 0);
61     
62     /* Reset Functionality on MR3 controlling the PWM period */
63     timer->MCR = 1 << 10;
64     
65     // default to 20ms: standard for servos, and fine for e.g. brightness control
66     pwmout_period_ms(obj, 20);
67     pwmout_write    (obj, 0);
68     
69     // Wire pinout
70     pinmap_pinout(pin, PinMap_PWM);
71 }
72
73 void pwmout_free(pwmout_t* obj) {
74     // [TODO]
75 }
76
77 void pwmout_write(pwmout_t* obj, float value) {
78     if (value < 0.0f) {
79         value = 0.0;
80     } else if (value > 1.0f) {
81         value = 1.0;
82     }
83     
84     timer_mr tid = pwm_timer_map[obj->pwm];
85     LPC_CTxxBx_Type *timer = Timers[tid.timer];
86     uint32_t t_off = timer->MR3 - (uint32_t)((float)(timer->MR3) * value);
87     
88     timer->MR[tid.mr] = t_off;
89 }
90
91 float pwmout_read(pwmout_t* obj) {
92     timer_mr tid = pwm_timer_map[obj->pwm];
93     LPC_CTxxBx_Type *timer = Timers[tid.timer];
94     
95     float v = (float)(timer->MR3 - timer->MR[tid.mr]) / (float)(timer->MR3);
96     return (v > 1.0f) ? (1.0f) : (v);
97 }
98
99 void pwmout_period(pwmout_t* obj, float seconds) {
100     pwmout_period_us(obj, seconds * 1000000.0f);
101 }
102
103 void pwmout_period_ms(pwmout_t* obj, int ms) {
104     pwmout_period_us(obj, ms * 1000);
105 }
106
107 // Set the PWM period, keeping the duty cycle the same.
108 void pwmout_period_us(pwmout_t* obj, int us) {
109     int i = 0;
110     uint32_t period_ticks = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000);
111     
112     timer_mr tid = pwm_timer_map[obj->pwm];
113     LPC_CTxxBx_Type *timer = Timers[tid.timer];
114     uint32_t old_period_ticks = timer->MR3;
115
116     // for 16bit timer, set prescaler to avoid overflow
117     if (timer == LPC_CT16B0 || timer == LPC_CT16B1) {
118         uint16_t high_period_ticks = period_ticks >> 16;
119         timer->PR = high_period_ticks;
120         period_ticks /= (high_period_ticks + 1);
121     }
122     
123     timer->TCR = TCR_RESET;
124     timer->MR3 = period_ticks;
125     
126     // Scale the pulse width to preserve the duty ratio
127     if (old_period_ticks > 0) {
128         for (i=0; i<3; i++) {
129             uint32_t t_off = period_ticks - (uint32_t)(((uint64_t)timer->MR[i] * (uint64_t)period_ticks) / (uint64_t)old_period_ticks);
130             timer->MR[i] = t_off;
131         }
132     }
133     timer->TCR = TCR_CNT_EN;
134 }
135
136 void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
137     pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
138 }
139
140 void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
141     pwmout_pulsewidth_us(obj, ms * 1000);
142 }
143
144 void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
145     timer_mr tid = pwm_timer_map[obj->pwm];
146     LPC_CTxxBx_Type *timer = Timers[tid.timer];
147     uint32_t t_on = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000 / (timer->PR + 1));
148     
149     timer->TCR = TCR_RESET;
150     if (t_on > timer->MR3) {
151         pwmout_period_us(obj, us);
152         t_on = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000 / (timer->PR + 1));
153     }
154     uint32_t t_off = timer->MR3 - t_on;
155     timer->MR[tid.mr] = t_off;
156     timer->TCR = TCR_CNT_EN;
157 }