47
47
#include "app_util_platform.h"
48
48
#include "nrf_drv_pwm.h"
49
49
50
+
51
+ #define MAX_PWM_PERIOD_US (0x7FFF << 3) // -> 7FFF (1_us/16) * 128
52
+ #define MAX_PWM_PERIOD_MS ((MAX_PWM_PERIOD_US / 1000) + 1) // approximations advance
53
+ #define MAX_PWM_PERIOD_S ((MAX_PWM_PERIOD_US / 1000000) + 1) // approximations advance
54
+
50
55
#define PWM_INSTANCE_COUNT 3
51
56
57
+ ///> instances of nRF52 PWM driver
52
58
static nrf_drv_pwm_t m_pwm_driver [PWM_INSTANCE_COUNT ] =
53
- {
54
- NRF_DRV_PWM_INSTANCE (0 ),
55
- NRF_DRV_PWM_INSTANCE (1 ),
56
- NRF_DRV_PWM_INSTANCE (2 )
57
- };
59
+ {
60
+ NRF_DRV_PWM_INSTANCE (0 ),
61
+ NRF_DRV_PWM_INSTANCE (1 ),
62
+ NRF_DRV_PWM_INSTANCE (2 )
63
+ };
58
64
59
65
typedef struct
60
66
{
61
67
uint32_t period_us ;
62
68
uint32_t duty_us ;
63
69
float duty ;
64
- } pwm_signal_t ;
70
+ } pwm_signal_t ; /// PWM signal description type
65
71
66
72
typedef struct
67
73
{
68
74
nrf_drv_pwm_t * p_pwm_driver ;
69
75
pwm_signal_t signal ;
70
- } pwm_t ;
76
+ volatile nrf_pwm_values_common_t seq_values [1 ];
77
+ } pwm_t ; /// internal PWM instance support type
71
78
72
79
static pwm_t m_pwm [PWM_INSTANCE_COUNT ] =
73
80
{
74
81
{.p_pwm_driver = NULL },
75
82
{.p_pwm_driver = NULL },
76
83
{.p_pwm_driver = NULL }
77
- };
84
+ }; /// Array of internal PWM instances.
78
85
79
86
typedef struct
80
87
{
81
- uint16_t period ;
82
- uint16_t duty ;
88
+ uint16_t period_hwu ;
89
+ uint16_t duty_hwu ;
83
90
nrf_pwm_clk_t pwm_clk ;
84
- } pulsewidth_set_t ;
91
+ } pulsewidth_set_t ; /// helper type for timing calculations
85
92
86
93
87
- static void internal_pwmout_exe (pwmout_t * obj );
94
+ static void internal_pwmout_exe (pwmout_t * obj , bool new_period );
88
95
89
96
void pwmout_init (pwmout_t * obj , PinName pin )
90
97
{
@@ -95,17 +102,17 @@ void pwmout_init(pwmout_t *obj, PinName pin)
95
102
if (m_pwm [i ].p_pwm_driver == NULL ) // a driver instance not assigned to the obj?
96
103
{
97
104
obj -> pin = pin ;
98
- /// @todo obj->pwm_name =
105
+
99
106
obj -> pwm_channel = i ;
100
107
101
108
m_pwm [i ].p_pwm_driver = & m_pwm_driver [i ];
102
- m_pwm [i ].signal .period_us = 100000 ; // 0.02 s
103
- m_pwm [i ].signal .duty_us = 50000 ;
109
+ m_pwm [i ].signal .period_us = 200000 ; // 0.02 s
110
+ m_pwm [i ].signal .duty_us = 100000 ;
104
111
m_pwm [i ].signal .duty = (0.5 );
105
112
106
113
obj -> pwm_struct = & m_pwm [i ];
107
114
108
- internal_pwmout_exe (obj );
115
+ internal_pwmout_exe (obj , true );
109
116
110
117
break ;
111
118
}
@@ -119,7 +126,6 @@ void pwmout_free(pwmout_t *obj)
119
126
nrf_drv_pwm_uninit ( (nrf_drv_pwm_t * ) obj -> pwm_struct );
120
127
121
128
m_pwm [obj -> pwm_channel ].p_pwm_driver = NULL ;
122
- /// @todo release gpio
123
129
}
124
130
125
131
void pwmout_write (pwmout_t * obj , float percent )
@@ -152,54 +158,112 @@ float pwmout_read(pwmout_t *obj)
152
158
153
159
void pwmout_period (pwmout_t * obj , float seconds )
154
160
{
155
- // @todo saturation
161
+ // raught saturation < 0, quasi-max>
162
+ if (seconds > MAX_PWM_PERIOD_S )
163
+ {
164
+ seconds = MAX_PWM_PERIOD_S ;
165
+ }
166
+ else if (seconds < 0 )
167
+ {
168
+ seconds = 0 ; // f. pwmout_period_us will set period to min. value
169
+ }
170
+
156
171
int us = seconds * 1000000 ;
157
172
158
173
pwmout_period_us (obj , us );
159
174
}
160
175
161
176
void pwmout_period_ms (pwmout_t * obj , int ms )
162
177
{
178
+ // reught saturation < 0, quasi-max>
179
+ if (ms > MAX_PWM_PERIOD_MS )
180
+ {
181
+ ms = MAX_PWM_PERIOD_MS ;
182
+ }
183
+ else if (ms < 0 )
184
+ {
185
+ ms = 0 ; // f. pwmout_period_us will set period to min. value
186
+ }
187
+
163
188
int us = ms * 1000 ;
164
189
165
190
pwmout_period_us (obj , us );
166
191
}
167
192
193
+
168
194
void pwmout_period_us (pwmout_t * obj , int us )
169
195
{
170
196
pwm_signal_t * p_pwm_signal = & (((pwm_t * )obj -> pwm_struct )-> signal );
171
197
198
+ // saturation <1, real-max>
199
+ if (us > MAX_PWM_PERIOD_US )
200
+ {
201
+ us = MAX_PWM_PERIOD_US ;
202
+ }
203
+ else if (us < 1 )
204
+ {
205
+ us = 1 ;
206
+ }
207
+
172
208
p_pwm_signal -> duty_us = (int )((float )us * p_pwm_signal -> duty );
173
209
174
210
p_pwm_signal -> period_us = us ;
175
211
176
- internal_pwmout_exe (obj );
212
+ internal_pwmout_exe (obj , true );
177
213
}
178
214
179
215
void pwmout_pulsewidth (pwmout_t * obj , float seconds )
180
216
{
181
- // @todo saturation
217
+ // raught saturation < 0, quasi-max>
218
+ if (seconds > MAX_PWM_PERIOD_S )
219
+ {
220
+ seconds = MAX_PWM_PERIOD_S ;
221
+ }
222
+ else if (seconds < 0 )
223
+ {
224
+ seconds = 0 ;
225
+ }
226
+
182
227
int us = seconds * 1000000 ;
183
228
184
229
pwmout_pulsewidth_us (obj ,us );
185
230
}
186
231
187
232
void pwmout_pulsewidth_ms (pwmout_t * obj , int ms )
188
233
{
189
- // @todo saturation
234
+ // raught saturation < 0, quasi-max>
235
+ if (ms > MAX_PWM_PERIOD_MS )
236
+ {
237
+ ms = MAX_PWM_PERIOD_MS ;
238
+ }
239
+ else if (ms < 0 )
240
+ {
241
+ ms = 0 ;
242
+ }
243
+
190
244
int us = ms * 1000 ;
191
245
192
- pwmout_pulsewidth_us (obj ,us );
246
+ pwmout_pulsewidth_us (obj , us );
193
247
}
194
248
195
249
void pwmout_pulsewidth_us (pwmout_t * obj , int us )
196
250
{
197
- // @todo saturation
251
+ // saturation <0, real-max>
252
+ if (us > MAX_PWM_PERIOD_US )
253
+ {
254
+ us = MAX_PWM_PERIOD_US ;
255
+ }
256
+ else if (us < 0 )
257
+ {
258
+ us = 0 ;
259
+ }
260
+
198
261
pwm_signal_t * p_pwm_signal = & (((pwm_t * )obj -> pwm_struct )-> signal );
199
262
200
263
p_pwm_signal -> duty_us = us ;
264
+ p_pwm_signal -> duty = us / p_pwm_signal -> period_us ;
201
265
202
- internal_pwmout_exe (obj );
266
+ internal_pwmout_exe (obj , false );
203
267
}
204
268
205
269
@@ -209,15 +273,15 @@ void pwmout_pulsewidth_us(pwmout_t *obj, int us)
209
273
210
274
static ret_code_t pulsewidth_us_set_get (int period_us , int duty_us , pulsewidth_set_t * const p_settings )
211
275
{
212
- uint16_t div ;
276
+ uint16_t div ;
213
277
nrf_pwm_clk_t pwm_clk = NRF_PWM_CLK_16MHz ;
214
278
215
279
for (div = 1 ; div <= 128 ; div <<= 1 )
216
280
{
217
281
if (0x7FFF >= period_us )
218
282
{
219
- p_settings -> period = period_us ; // unit [us * div]
220
- p_settings -> duty = duty_us ; // unit [us * div]
283
+ p_settings -> period_hwu = period_us ; // unit [us/16 * div]
284
+ p_settings -> duty_hwu = duty_us ; // unit [us/16 * div]
221
285
p_settings -> pwm_clk = pwm_clk ;
222
286
223
287
return NRF_SUCCESS ;
@@ -231,63 +295,59 @@ static ret_code_t pulsewidth_us_set_get(int period_us, int duty_us, pulsewidth_s
231
295
return NRF_ERROR_INVALID_PARAM ;
232
296
}
233
297
234
- static volatile nrf_pwm_values_common_t seq_values [1 ];
235
-
236
- static nrf_pwm_sequence_t const seq =
237
- {
238
- .values .p_common = seq_values ,
239
- .length = NRF_PWM_VALUES_LENGTH (seq_values ),
240
- .repeats = 0 ,
241
- .end_delay = 0
242
- };
243
298
244
- static void internal_pwmout_exe (pwmout_t * obj )
299
+ static void internal_pwmout_exe (pwmout_t * obj , bool new_period )
245
300
{
246
- pulsewidth_set_t pulsewidth_set ;
247
- pwm_signal_t * p_pwm_signal ;
248
- nrf_drv_pwm_t * p_pwm_driver ;
249
- ret_code_t ret_code ;
301
+ pulsewidth_set_t pulsewidth_set ;
302
+ pwm_signal_t * p_pwm_signal ;
303
+ nrf_drv_pwm_t * p_pwm_driver ;
304
+ ret_code_t ret_code ;
250
305
251
306
p_pwm_signal = & (((pwm_t * )obj -> pwm_struct )-> signal );
252
307
253
308
if (NRF_SUCCESS == pulsewidth_us_set_get (p_pwm_signal -> period_us * 16 ,
254
309
p_pwm_signal -> duty_us * 16 ,
255
310
& pulsewidth_set ))
256
311
{
257
- //@todo apply pulsewidth_set
258
312
p_pwm_driver = (((pwm_t * )obj -> pwm_struct )-> p_pwm_driver );
259
313
260
- nrf_drv_pwm_config_t config0 =
314
+ nrf_pwm_sequence_t seq =
261
315
{
262
- .output_pins =
263
- {
264
- obj -> pin , // channel 0
265
- NRF_DRV_PWM_PIN_NOT_USED , // channel 1
266
- NRF_DRV_PWM_PIN_NOT_USED , // channel 2
267
- NRF_DRV_PWM_PIN_NOT_USED , // channel 3
268
- },
269
- .irq_priority = APP_IRQ_PRIORITY_LOW ,
270
- .base_clock = pulsewidth_set .pwm_clk ,
271
- .count_mode = NRF_PWM_MODE_UP ,
272
- .top_value = pulsewidth_set .period ,
273
- .load_mode = NRF_PWM_LOAD_COMMON ,
274
- .step_mode = NRF_PWM_STEP_AUTO
316
+ .values .p_common = (nrf_pwm_values_common_t * ) (((pwm_t * )obj -> pwm_struct )-> seq_values ),
317
+ .length = 1 ,
318
+ .repeats = 0 ,
319
+ .end_delay = 0
275
320
};
276
321
322
+ (((pwm_t * )obj -> pwm_struct )-> seq_values )[0 ] = pulsewidth_set .duty_hwu | 0x8000 ;
277
323
278
- //printf("clock = %d, top = %d\r\n", pulsewidth_set.pwm_clk, pulsewidth_set.period);
279
-
280
- nrf_drv_pwm_uninit (p_pwm_driver );
281
-
282
- ret_code = nrf_drv_pwm_init ( p_pwm_driver , & config0 , NULL );
283
-
284
- MBED_ASSERT (ret_code == NRF_SUCCESS ); // assert if free instance was not found.
324
+ if (new_period )
325
+ {
326
+ nrf_drv_pwm_config_t config0 =
327
+ {
328
+ .output_pins =
329
+ {
330
+ obj -> pin | NRF_DRV_PWM_PIN_INVERTED , // channel 0
331
+ NRF_DRV_PWM_PIN_NOT_USED , // channel 1
332
+ NRF_DRV_PWM_PIN_NOT_USED , // channel 2
333
+ NRF_DRV_PWM_PIN_NOT_USED , // channel 3
334
+ },
335
+ .irq_priority = APP_IRQ_PRIORITY_LOW ,
336
+ .base_clock = pulsewidth_set .pwm_clk ,
337
+ .count_mode = NRF_PWM_MODE_UP ,
338
+ .top_value = pulsewidth_set .period_hwu ,
339
+ .load_mode = NRF_PWM_LOAD_COMMON ,
340
+ .step_mode = NRF_PWM_STEP_AUTO
341
+ };
342
+
343
+ nrf_drv_pwm_uninit (p_pwm_driver );
285
344
286
- seq_values [ 0 ] = pulsewidth_set . duty ;
345
+ ret_code = nrf_drv_pwm_init ( p_pwm_driver , & config0 , NULL ) ;
287
346
288
- nrf_drv_pwm_simple_playback (p_pwm_driver , & seq , 0 , NRF_DRV_PWM_FLAG_LOOP );
347
+ MBED_ASSERT (ret_code == NRF_SUCCESS ); // assert if free instance was not found.
348
+ }
289
349
290
-
350
+ nrf_drv_pwm_simple_playback ( p_pwm_driver , & seq , 0 , NRF_DRV_PWM_FLAG_LOOP );
291
351
}
292
352
else
293
353
{
0 commit comments