1 /* mbed Microcontroller Library
2 * Copyright (c) 2006-2015 ARM Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "mbed_assert.h"
17 #include "pwmout_api.h"
21 #include "PeripheralPins.h"
23 static float pwm_clock
= 0;
25 void pwmout_init(pwmout_t
* obj
, PinName pin
) {
26 // determine the channel
27 PWMName pwm
= (PWMName
)pinmap_peripheral(pin
, PinMap_PWM
);
28 MBED_ASSERT(pwm
!= (PWMName
)NC
);
31 float clkval
= SystemCoreClock
/ 1000000.0f
;
41 unsigned int ftm_n
= (pwm
>> TPM_SHIFT
);
42 unsigned int ch_n
= (pwm
& 0xFF);
44 SIM
->SCGC6
|= 1 << (SIM_SCGC6_FTM0_SHIFT
+ ftm_n
);
46 FTM_Type
*ftm
= (FTM_Type
*)(FTM0_BASE
+ 0x1000 * ftm_n
);
47 ftm
->CONF
|= FTM_CONF_BDMMODE(3);
48 ftm
->SC
= FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv
); // (clock)MHz / clkdiv ~= (0.75)MHz
49 ftm
->CONTROLS
[ch_n
].CnSC
= (FTM_CnSC_MSB_MASK
| FTM_CnSC_ELSB_MASK
); /* No Interrupts; High True pulses on Edge Aligned PWM */
50 ftm
->MODE
= FTM_MODE_FTMEN_MASK
;
51 ftm
->SYNC
= FTM_SYNC_CNTMIN_MASK
;
52 ftm
->SYNCONF
= FTM_SYNCONF_SYNCMODE_MASK
| FTM_SYNCONF_SWSOC_MASK
| FTM_SYNCONF_SWWRBUF_MASK
;
54 //Without SYNCEN set CnV does not seem to update
55 ftm
->COMBINE
= FTM_COMBINE_SYNCEN0_MASK
| FTM_COMBINE_SYNCEN1_MASK
| FTM_COMBINE_SYNCEN2_MASK
| FTM_COMBINE_SYNCEN3_MASK
;
57 obj
->CnV
= &ftm
->CONTROLS
[ch_n
].CnV
;
59 obj
->SYNC
= &ftm
->SYNC
;
61 // default to 20ms: standard for servos, and fine for e.g. brightness control
62 pwmout_period_ms(obj
, 20);
63 pwmout_write(obj
, 0.0);
66 pinmap_pinout(pin
, PinMap_PWM
);
69 void pwmout_free(pwmout_t
* obj
) {}
71 void pwmout_write(pwmout_t
* obj
, float value
) {
74 } else if (value
> 1.0) {
78 while(*obj
->SYNC
& FTM_SYNC_SWSYNC_MASK
);
79 *obj
->CnV
= (uint32_t)((float)(*obj
->MOD
+ 1) * value
);
80 *obj
->SYNC
|= FTM_SYNC_SWSYNC_MASK
;
83 float pwmout_read(pwmout_t
* obj
) {
84 while(*obj
->SYNC
& FTM_SYNC_SWSYNC_MASK
);
85 float v
= (float)(*obj
->CnV
) / (float)(*obj
->MOD
+ 1);
86 return (v
> 1.0) ? (1.0) : (v
);
89 void pwmout_period(pwmout_t
* obj
, float seconds
) {
90 pwmout_period_us(obj
, seconds
* 1000000.0f
);
93 void pwmout_period_ms(pwmout_t
* obj
, int ms
) {
94 pwmout_period_us(obj
, ms
* 1000);
97 // Set the PWM period, keeping the duty cycle the same.
98 void pwmout_period_us(pwmout_t
* obj
, int us
) {
99 float dc
= pwmout_read(obj
);
100 *obj
->MOD
= (uint32_t)(pwm_clock
* (float)us
) - 1;
101 *obj
->SYNC
|= FTM_SYNC_SWSYNC_MASK
;
102 pwmout_write(obj
, dc
);
105 void pwmout_pulsewidth(pwmout_t
* obj
, float seconds
) {
106 pwmout_pulsewidth_us(obj
, seconds
* 1000000.0f
);
109 void pwmout_pulsewidth_ms(pwmout_t
* obj
, int ms
) {
110 pwmout_pulsewidth_us(obj
, ms
* 1000);
113 void pwmout_pulsewidth_us(pwmout_t
* obj
, int us
) {
114 *obj
->CnV
= (uint32_t)(pwm_clock
* (float)us
);
115 *obj
->SYNC
|= FTM_SYNC_SWSYNC_MASK
;