1 /*******************************************************************************
2 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Except as contained in this notice, the name of Maxim Integrated
23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
24 * Products, Inc. Branding Policy.
26 * The mere transfer of this software does not imply any licenses
27 * of trade secrets, proprietary technology, copyrights, patents,
28 * trademarks, maskwork rights, or any other form of intellectual
29 * property whatsoever. Maxim Integrated Products, Inc. retains all
31 *******************************************************************************
34 #include "mbed_assert.h"
36 #include "pwmout_api.h"
38 #include "ioman_regs.h"
39 #include "clkman_regs.h"
40 #include "PeripheralPins.h"
42 //******************************************************************************
43 void pwmout_init(pwmout_t
* obj
, PinName pin
)
45 // Make sure the pin is free for GPIO use
46 unsigned int port
= (unsigned int)pin
>> PORT_SHIFT
;
47 unsigned int port_pin
= (unsigned int)pin
& ~(0xFFFFFFFF << PORT_SHIFT
);
48 MBED_ASSERT(MXC_GPIO
->free
[port
] & (0x1 << port_pin
));
51 PinMap pwm
= PinMap_PWM
[0];
53 // Check if there is a pulse train already active on this port
54 int pin_func
= (MXC_GPIO
->func_sel
[port
] & (0xF << (port_pin
*4))) >> (port_pin
*4);
55 if((pin_func
> 0) && (pin_func
< 4)) {
56 // Search through PinMap_PWM to find the active PT
57 while(pwm
.pin
!= (PinName
)NC
) {
58 if((pwm
.pin
== pin
) && (pwm
.function
== pin_func
)) {
61 pwm
= PinMap_PWM
[++i
];
65 // Search through PinMap_PWM to find an available PT
67 while(pwm
.pin
!= (PinName
)NC
&& (i
> -1)) {
68 pwm
= PinMap_PWM
[i
++];
70 // Check each instance of PT
72 // Check to see if this PT instance is already in use
73 if((((mxc_pt_regs_t
*)pwm
.peripheral
)->rate_length
&
74 MXC_F_PT_RATE_LENGTH_MODE
)) {
79 // If all instances are in use, overwrite the last
80 pwm
= PinMap_PWM
[++i
];
82 pwm
= PinMap_PWM
[--i
];
92 // Make sure we found an available PWM generator
93 MBED_ASSERT(pwm
.pin
!= (PinName
)NC
);
95 // Disable all pwm output
99 MXC_CLKMAN
->clk_ctrl_2_pt
= MXC_E_CLKMAN_CLK_SCALE_ENABLED
;
101 // Set the drive mode to normal
102 MXC_SET_FIELD(&MXC_GPIO
->out_mode
[port
], (0x7 << (port_pin
*4)), (MXC_V_GPIO_OUT_MODE_NORMAL_DRIVE
<< (port_pin
*4)));
104 // Set the obj pointer to the propper PWM instance
105 obj
->pwm
= (mxc_pt_regs_t
*)pwm
.peripheral
;
107 // Initialize object period and pulse width
109 obj
->pulse_width
= -1;
111 // Disable the output
112 obj
->pwm
->train
= 0x0;
113 obj
->pwm
->rate_length
= 0x0;
116 pin_mode(pin
, (PinMode
)PullNone
);
117 pin_function(pin
, pwm
.function
);
119 // default to 20ms: standard for servos, and fine for e.g. brightness control
120 pwmout_period_us(obj
, 20000);
121 pwmout_write (obj
, 0);
123 // Enable the global pwm
124 MXC_PTG
->ctrl
= MXC_F_PT_CTRL_ENABLE_ALL
;
127 //******************************************************************************
128 void pwmout_free(pwmout_t
* obj
)
130 // Set the registers to the reset value
132 obj
->pwm
->rate_length
= 0x08000000;
135 //******************************************************************************
136 static void pwmout_update(pwmout_t
* obj
)
138 // Calculate and set the divider ratio
139 int div
= (obj
->period
* (SystemCoreClock
/1000000))/32;
143 MXC_SET_FIELD(&obj
->pwm
->rate_length
, MXC_F_PT_RATE_LENGTH_RATE_CONTROL
, div
);
145 // Change the duty cycle to adjust the pulse width
146 obj
->pwm
->train
= (0xFFFFFFFF << (32-((32*obj
->pulse_width
)/obj
->period
)));
150 //******************************************************************************
151 void pwmout_write(pwmout_t
* obj
, float percent
)
153 // Saturate percent if outside of range
156 } else if(percent
> 1.0) {
160 // Resize the pulse width to set the duty cycle
161 pwmout_pulsewidth_us(obj
, (int)(percent
*obj
->period
));
164 //******************************************************************************
165 float pwmout_read(pwmout_t
* obj
)
167 // Check for when pulsewidth or period equals 0
168 if((obj
->pulse_width
== 0) || (obj
->period
== 0)){
172 // Return the duty cycle
173 return ((float)obj
->pulse_width
/ (float)obj
->period
);
176 //******************************************************************************
177 void pwmout_period(pwmout_t
* obj
, float seconds
)
179 pwmout_period_us(obj
, (int)(seconds
* 1000000.0));
182 //******************************************************************************
183 void pwmout_period_ms(pwmout_t
* obj
, int ms
)
185 pwmout_period_us(obj
, ms
*1000);
188 //******************************************************************************
189 void pwmout_period_us(pwmout_t
* obj
, int us
)
191 // Check the range of the period
192 MBED_ASSERT((us
>= 0) && (us
<= (int)(SystemCoreClock
/32)));
194 // Set pulse width to half the period if uninitialized
195 if(obj
->pulse_width
== -1){
196 obj
->pulse_width
= us
/2;
202 // Update the registers
206 //******************************************************************************
207 void pwmout_pulsewidth(pwmout_t
* obj
, float seconds
)
209 pwmout_pulsewidth_us(obj
, (int)(seconds
* 1000000.0));
212 //******************************************************************************
213 void pwmout_pulsewidth_ms(pwmout_t
* obj
, int ms
)
215 pwmout_pulsewidth_us(obj
, ms
*1000);
218 //******************************************************************************
219 void pwmout_pulsewidth_us(pwmout_t
* obj
, int us
)
221 // Check the range of the pulsewidth
222 MBED_ASSERT((us
>= 0) && (us
<= (int)(SystemCoreClock
/32)));
224 // Initialize period to double the pulsewidth if uninitialized
225 if(obj
->period
== -1){
229 // Save the pulsewidth
230 obj
->pulse_width
= us
;
232 // Update the register