24
24
#include "pinmap.h"
25
25
#include "PeripheralPins.h"
26
26
#include "device_peripherals.h"
27
+ #include "sleepmodes.h"
27
28
28
29
#include "em_cmu.h"
29
30
#include "em_gpio.h"
30
31
#include "em_timer.h"
31
32
32
- static int clockfreq ;
33
- static int prescaler_div ;
33
+ static int pwm_clockfreq ;
34
+ static int pwm_prescaler_div ;
35
+
36
+ uint32_t pwmout_get_channel_route (pwmout_t * obj ) {
37
+ MBED_ASSERT (obj -> channel != (PWMName ) NC );
38
+
39
+ switch (obj -> channel ) {
40
+ case PWM_CH0 :
41
+ return TIMER_ROUTE_CC0PEN ;
42
+ break ;
43
+ case PWM_CH1 :
44
+ return TIMER_ROUTE_CC1PEN ;
45
+ break ;
46
+ case PWM_CH2 :
47
+ return TIMER_ROUTE_CC2PEN ;
48
+ break ;
49
+ default :
50
+ return 0 ;
51
+ }
52
+ }
34
53
35
- uint8_t pwmout_get_index (pwmout_t * obj )
54
+ void pwmout_enable_pins (pwmout_t * obj , uint8_t enable )
36
55
{
37
- return 0 ;
56
+ if (enable ) {
57
+ pin_mode (obj -> pin , PushPull );
58
+ } else {
59
+ // TODO_LP return PinMode to the previous state
60
+ pin_mode (obj -> pin , Disabled );
61
+ }
38
62
}
39
63
40
- void pwmout_preinit (pwmout_t * obj , PinName pin )
64
+ void pwmout_enable (pwmout_t * obj , uint8_t enable )
41
65
{
42
- obj -> channel = (PWMName ) pinmap_peripheral (pin , PinMap_PWM );
43
- obj -> pin = pin ;
44
- MBED_ASSERT (obj -> channel != (PWMName ) NC );
66
+ /* Start with default CC (Compare/Capture) channel parameters */
67
+ TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT ;
68
+ if (enable ) {
69
+ /* Set mode to PWM */
70
+ timerCCInit .mode = timerCCModePWM ;
71
+ }
72
+
73
+ /* Configure CC channel */
74
+ TIMER_InitCC (PWM_TIMER , obj -> channel , & timerCCInit );
45
75
}
46
76
47
77
void pwmout_init (pwmout_t * obj , PinName pin )
48
78
{
49
- pwmout_preinit (obj , pin );
79
+ obj -> channel = (PWMName ) pinmap_peripheral (pin , PinMap_PWM );
80
+ obj -> pin = pin ;
81
+ MBED_ASSERT (obj -> channel != (PWMName ) NC );
50
82
51
- /* Enable correct channel */
52
- switch (obj -> channel ) {
53
- case PWM_CH0 :
54
- PWM_TIMER -> ROUTE |= TIMER_ROUTE_CC0PEN ;
55
- break ;
56
- case PWM_CH1 :
57
- PWM_TIMER -> ROUTE |= TIMER_ROUTE_CC1PEN ;
58
- break ;
59
- case PWM_CH2 :
60
- PWM_TIMER -> ROUTE |= TIMER_ROUTE_CC2PEN ;
61
- break ;
83
+ /* Turn on clock */
84
+ CMU_ClockEnable (PWM_TIMER_CLOCK , true);
62
85
63
- }
86
+ /* Turn on timer */
87
+ if (!(PWM_TIMER -> STATUS & TIMER_STATUS_RUNNING )) {
88
+ TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT ;
89
+ TIMER_Init (PWM_TIMER , & timerInit );
90
+ }
91
+
92
+ /* Enable correct channel */
93
+ uint32_t routeloc = pwmout_get_channel_route (obj );
94
+ if (PWM_TIMER -> ROUTE & routeloc ) {
95
+ //This channel was already in use
96
+ //TODO: gracefully handle this case
97
+ } else {
98
+ //This channel was unused up to now
99
+ PWM_TIMER -> ROUTE |= routeloc ;
100
+ blockSleepMode (EM1 );
101
+
102
+ //TODO: check if any channel was up already, then don't re-init timer
103
+ pwmout_enable (obj , true);
104
+ pwmout_enable_pins (obj , true);
105
+ }
64
106
65
107
/* Route correct channel to location 1 */
108
+ PWM_TIMER -> ROUTE &= ~_TIMER_ROUTE_LOCATION_MASK ;
66
109
PWM_TIMER -> ROUTE |= PWM_ROUTE ;
67
110
68
111
/*HFPER is the default clock we will use. It has a frequency of 14MHz*/
69
- clockfreq = REFERENCE_FREQUENCY ;
112
+ pwm_clockfreq = REFERENCE_FREQUENCY ;
70
113
71
114
/* Set default 20ms frequency and 0ms pulse width */
72
115
pwmout_period (obj , 0.02 );
73
116
}
74
117
75
- void pwmout_enable_pins (pwmout_t * obj , uint8_t enable )
76
- {
77
- if (enable ) {
78
- pin_mode (obj -> pin , PushPull );
79
- } else {
80
- // TODO_LP return PinMode to the previous state
81
- pin_mode (obj -> pin , Disabled );
82
- }
118
+ void pwmout_free (pwmout_t * obj ) {
119
+ uint32_t routeloc = pwmout_get_channel_route (obj );
120
+ if (PWM_TIMER -> ROUTE & routeloc ) {
121
+ //This channel was in use, so disable
122
+ PWM_TIMER -> ROUTE &= ~routeloc ;
123
+ pwmout_enable_pins (obj , false);
124
+ unblockSleepMode (EM1 );
125
+
126
+ //TODO: check if all channels are down, then switch off timer
127
+ } else {
128
+ //This channel was disabled already
129
+ }
83
130
}
84
131
85
- void pwmout_enable (pwmout_t * obj , uint8_t enable )
86
- {
87
- TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT ;
88
-
89
- if (enable ) {
90
- /* Start with default CC (Compare/Capture) channel parameters */
91
- TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT ;
92
-
93
- /* Set mode to PWM */
94
- timerCCInit .mode = timerCCModePWM ;
95
-
96
- /* Configure CC channel */
97
- TIMER_InitCC (PWM_TIMER , obj -> channel , & timerCCInit );
98
- TIMER_Init (PWM_TIMER , & timerInit );
99
- } else {
100
- timerInit .enable = false;
101
- TIMER_Init (PWM_TIMER , & timerInit );
102
- }
103
- }
104
-
105
-
106
132
void pwmout_write (pwmout_t * obj , float value )
107
133
{
108
134
if (value < 0.0f ) {
@@ -111,7 +137,7 @@ void pwmout_write(pwmout_t *obj, float value)
111
137
value = 1 ;
112
138
}
113
139
114
- float pulse_period_in_s = obj -> period_cycles / (float ) clockfreq ;
140
+ float pulse_period_in_s = obj -> period_cycles / (float ) pwm_clockfreq ;
115
141
pwmout_pulsewidth (obj , value * pulse_period_in_s );
116
142
}
117
143
@@ -127,17 +153,17 @@ void pwmout_period(pwmout_t *obj, float seconds)
127
153
// This gives us max resolution for a given period
128
154
129
155
//The value of the top register if prescaler is set to 0
130
- int cycles = clockfreq * seconds ;
131
- prescaler_div = 0 ;
156
+ int cycles = pwm_clockfreq * seconds ;
157
+ pwm_prescaler_div = 0 ;
132
158
133
159
//The top register is only 16 bits, so we keep dividing till we are below 0xFFFF
134
160
while (cycles > 0xFFFF ) {
135
161
cycles /= 2 ;
136
- prescaler_div ++ ;
162
+ pwm_prescaler_div ++ ;
137
163
138
- //Max prescaler_div supported is 10
139
- if (prescaler_div > 10 ) {
140
- prescaler_div = 10 ;
164
+ //Max pwm_prescaler_div supported is 10
165
+ if (pwm_prescaler_div > 10 ) {
166
+ pwm_prescaler_div = 10 ;
141
167
cycles = 0xFFFF ; //Set it to max possible value;
142
168
break ;
143
169
}
@@ -146,7 +172,7 @@ void pwmout_period(pwmout_t *obj, float seconds)
146
172
obj -> period_cycles = cycles ;
147
173
148
174
//Set prescaler
149
- PWM_TIMER -> CTRL = (PWM_TIMER -> CTRL & ~_TIMER_CTRL_PRESC_MASK ) | (prescaler_div << _TIMER_CTRL_PRESC_SHIFT );
175
+ PWM_TIMER -> CTRL = (PWM_TIMER -> CTRL & ~_TIMER_CTRL_PRESC_MASK ) | (pwm_prescaler_div << _TIMER_CTRL_PRESC_SHIFT );
150
176
151
177
/* Set Top Value, which controls the PWM period */
152
178
TIMER_TopSet (PWM_TIMER , obj -> period_cycles );
@@ -164,7 +190,7 @@ void pwmout_period_us(pwmout_t *obj, int us)
164
190
165
191
void pwmout_pulsewidth (pwmout_t * obj , float seconds )
166
192
{
167
- obj -> width_cycles = clockfreq * seconds ;
193
+ obj -> width_cycles = pwm_clockfreq * seconds ;
168
194
TIMER_CompareBufSet (PWM_TIMER , obj -> channel , obj -> width_cycles );
169
195
}
170
196
0 commit comments