Skip to content

Commit 9f33787

Browse files
committed
PWM for nRF52 full debuged.
1 parent 7798651 commit 9f33787

File tree

1 file changed

+126
-66
lines changed
  • hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832

1 file changed

+126
-66
lines changed

hal/targets/hal/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/pwmout_api.c

Lines changed: 126 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -47,44 +47,51 @@
4747
#include "app_util_platform.h"
4848
#include "nrf_drv_pwm.h"
4949

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+
5055
#define PWM_INSTANCE_COUNT 3
5156

57+
///> instances of nRF52 PWM driver
5258
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+
};
5864

5965
typedef struct
6066
{
6167
uint32_t period_us;
6268
uint32_t duty_us;
6369
float duty;
64-
} pwm_signal_t;
70+
} pwm_signal_t; /// PWM signal description type
6571

6672
typedef struct
6773
{
6874
nrf_drv_pwm_t * p_pwm_driver;
6975
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
7178

7279
static pwm_t m_pwm[PWM_INSTANCE_COUNT] =
7380
{
7481
{.p_pwm_driver = NULL},
7582
{.p_pwm_driver = NULL},
7683
{.p_pwm_driver = NULL}
77-
};
84+
}; /// Array of internal PWM instances.
7885

7986
typedef struct
8087
{
81-
uint16_t period;
82-
uint16_t duty;
88+
uint16_t period_hwu;
89+
uint16_t duty_hwu;
8390
nrf_pwm_clk_t pwm_clk;
84-
} pulsewidth_set_t;
91+
} pulsewidth_set_t; /// helper type for timing calculations
8592

8693

87-
static void internal_pwmout_exe(pwmout_t *obj);
94+
static void internal_pwmout_exe(pwmout_t *obj, bool new_period);
8895

8996
void pwmout_init(pwmout_t *obj, PinName pin)
9097
{
@@ -95,17 +102,17 @@ void pwmout_init(pwmout_t *obj, PinName pin)
95102
if (m_pwm[i].p_pwm_driver == NULL) // a driver instance not assigned to the obj?
96103
{
97104
obj->pin = pin;
98-
/// @todo obj->pwm_name =
105+
99106
obj->pwm_channel = i;
100107

101108
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;
104111
m_pwm[i].signal.duty = (0.5);
105112

106113
obj->pwm_struct = &m_pwm[i];
107114

108-
internal_pwmout_exe(obj);
115+
internal_pwmout_exe(obj, true);
109116

110117
break;
111118
}
@@ -119,7 +126,6 @@ void pwmout_free(pwmout_t *obj)
119126
nrf_drv_pwm_uninit( (nrf_drv_pwm_t*) obj->pwm_struct );
120127

121128
m_pwm[obj->pwm_channel].p_pwm_driver = NULL;
122-
/// @todo release gpio
123129
}
124130

125131
void pwmout_write(pwmout_t *obj, float percent)
@@ -152,54 +158,112 @@ float pwmout_read(pwmout_t *obj)
152158

153159
void pwmout_period(pwmout_t *obj, float seconds)
154160
{
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+
156171
int us = seconds * 1000000;
157172

158173
pwmout_period_us(obj, us);
159174
}
160175

161176
void pwmout_period_ms(pwmout_t *obj, int ms)
162177
{
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+
163188
int us = ms * 1000;
164189

165190
pwmout_period_us(obj, us);
166191
}
167192

193+
168194
void pwmout_period_us(pwmout_t *obj, int us)
169195
{
170196
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
171197

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+
172208
p_pwm_signal->duty_us = (int)((float)us * p_pwm_signal->duty);
173209

174210
p_pwm_signal->period_us = us;
175211

176-
internal_pwmout_exe(obj);
212+
internal_pwmout_exe(obj, true);
177213
}
178214

179215
void pwmout_pulsewidth(pwmout_t *obj, float seconds)
180216
{
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+
182227
int us = seconds * 1000000;
183228

184229
pwmout_pulsewidth_us(obj,us);
185230
}
186231

187232
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
188233
{
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+
190244
int us = ms * 1000;
191245

192-
pwmout_pulsewidth_us(obj,us);
246+
pwmout_pulsewidth_us(obj, us);
193247
}
194248

195249
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
196250
{
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+
198261
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
199262

200263
p_pwm_signal->duty_us = us;
264+
p_pwm_signal->duty = us / p_pwm_signal->period_us;
201265

202-
internal_pwmout_exe(obj);
266+
internal_pwmout_exe(obj, false);
203267
}
204268

205269

@@ -209,15 +273,15 @@ void pwmout_pulsewidth_us(pwmout_t *obj, int us)
209273

210274
static ret_code_t pulsewidth_us_set_get(int period_us, int duty_us, pulsewidth_set_t * const p_settings)
211275
{
212-
uint16_t div;
276+
uint16_t div;
213277
nrf_pwm_clk_t pwm_clk = NRF_PWM_CLK_16MHz;
214278

215279
for(div = 1; div <= 128 ; div <<= 1)
216280
{
217281
if (0x7FFF >= period_us)
218282
{
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]
221285
p_settings->pwm_clk = pwm_clk;
222286

223287
return NRF_SUCCESS;
@@ -231,63 +295,59 @@ static ret_code_t pulsewidth_us_set_get(int period_us, int duty_us, pulsewidth_s
231295
return NRF_ERROR_INVALID_PARAM;
232296
}
233297

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-
};
243298

244-
static void internal_pwmout_exe(pwmout_t *obj)
299+
static void internal_pwmout_exe(pwmout_t *obj, bool new_period)
245300
{
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;
250305

251306
p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
252307

253308
if (NRF_SUCCESS == pulsewidth_us_set_get(p_pwm_signal->period_us * 16,
254309
p_pwm_signal->duty_us * 16,
255310
&pulsewidth_set))
256311
{
257-
//@todo apply pulsewidth_set
258312
p_pwm_driver = (((pwm_t*)obj->pwm_struct)->p_pwm_driver);
259313

260-
nrf_drv_pwm_config_t config0 =
314+
nrf_pwm_sequence_t seq =
261315
{
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
275320
};
276321

322+
(((pwm_t*)obj->pwm_struct)->seq_values)[0] = pulsewidth_set.duty_hwu | 0x8000;
277323

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);
285344

286-
seq_values[0] = pulsewidth_set.duty;
345+
ret_code = nrf_drv_pwm_init( p_pwm_driver, &config0, NULL);
287346

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+
}
289349

290-
350+
nrf_drv_pwm_simple_playback(p_pwm_driver, &seq, 0, NRF_DRV_PWM_FLAG_LOOP);
291351
}
292352
else
293353
{

0 commit comments

Comments
 (0)