@@ -54,10 +54,10 @@ HardwarePWM* HwPWMx[] =
54
54
};
55
55
56
56
#if CFG_DEBUG
57
- bool can_stringify_token (uintptr_t token)
57
+ bool can_stringify_token (uint32_t token)
58
58
{
59
59
uint8_t * t = (uint8_t *)&token;
60
- for (size_t i = 0 ; i < sizeof (uintptr_t ); ++i, ++t)
60
+ for (size_t i = 0 ; i < sizeof (uint32_t ); ++i, ++t)
61
61
{
62
62
uint8_t x = *t;
63
63
if ((x < 0x20 ) || (x > 0x7E )) return false ;
@@ -71,14 +71,12 @@ void HardwarePWM::DebugOutput(Stream& logger)
71
71
logger.printf (" HwPWM Debug:" );
72
72
for (size_t i = 0 ; i < count; i++) {
73
73
HardwarePWM const * pwm = HwPWMx[i];
74
- uintptr_t token = pwm->_owner_token ;
74
+ uint32_t token = pwm->_owner_token ;
75
75
logger.printf (" || %d:" , i);
76
76
if (can_stringify_token (token)) {
77
77
uint8_t * t = (uint8_t *)(&token);
78
- static_assert (sizeof (uintptr_t ) == 4 );
79
78
logger.printf (" \" %c%c%c%c\" " , t[0 ], t[1 ], t[2 ], t[3 ] );
80
79
} else {
81
- static_assert (sizeof (uintptr_t ) == 4 );
82
80
logger.printf (" %08x" , token);
83
81
}
84
82
for (size_t j = 0 ; j < MAX_CHANNELS; j++) {
@@ -96,76 +94,6 @@ void HardwarePWM::DebugOutput(Stream& logger)
96
94
void HardwarePWM::DebugOutput (Stream& logger) {}
97
95
#endif // CFG_DEBUG
98
96
99
- // returns true ONLY when (1) no PWM channel has a pin, and (2) the owner token is nullptr
100
- bool HardwarePWM::takeOwnership (uintptr_t token)
101
- {
102
- bool notInIsr = !isInISR ();
103
- if (token == 0 ) {
104
- if (notInIsr) {
105
- LOG_LV1 (" HwPWM" , " zero / nullptr is not a valid ownership token (attempted use in takeOwnership)" );
106
- }
107
- return false ; // cannot take ownership with nullptr
108
- }
109
- if (token == this ->_owner_token ) {
110
- if (notInIsr) {
111
- LOG_LV1 (" HwPWM" , " failing to acquire ownership because already owned by requesting token (cannot take ownership twice)" );
112
- }
113
- }
114
- if (this ->_owner_token != 0 ) {
115
- return false ;
116
- }
117
- if (this ->usedChannelCount () != 0 ) {
118
- return false ;
119
- }
120
- if (this ->enabled ()) {
121
- return false ;
122
- }
123
- // TODO: warn, but do not fail, if taking ownership with IRQs already enabled
124
- // NVIC_GetActive
125
-
126
- // Use C++11 atomic CAS operation
127
- uintptr_t newValue = 0U ;
128
- return this ->_owner_token .compare_exchange_strong (newValue, token);
129
- }
130
- // returns true ONLY when (1) no PWM channel has a pin attached, and (2) the owner token matches
131
- bool HardwarePWM::releaseOwnership (uintptr_t token)
132
- {
133
- bool notInIsr = !isInISR ();
134
- if (token == 0 ) {
135
- if (notInIsr) {
136
- LOG_LV1 (" HwPWM" , " zero / nullptr is not a valid ownership token (attempted use in releaseOwnership)" );
137
- }
138
- return false ;
139
- }
140
- if (!this ->isOwner (token)) {
141
- if (notInIsr) {
142
- LOG_LV1 (" HwPWM" , " attempt to release ownership when not the current owner" );
143
- }
144
- return false ;
145
- }
146
- if (this ->usedChannelCount () != 0 ) {
147
- if (notInIsr) {
148
- LOG_LV1 (" HwPWM" , " attempt to release ownership when at least on channel is still connected" );
149
- }
150
- return false ;
151
- }
152
- if (this ->enabled ()) {
153
- if (notInIsr) {
154
- LOG_LV1 (" HwPWM" , " attempt to release ownership when PWM peripheral is still enabled" );
155
- }
156
- return false ; // if it's enabled, do not allow ownership to be released, even with no pins in use
157
- }
158
- // TODO: warn, but do not fail, if releasing ownership with IRQs enabled
159
- // NVIC_GetActive
160
-
161
- // Use C++11 atomic CAS operation
162
- bool result = this ->_owner_token .compare_exchange_strong (token, 0U );
163
- if (!result) {
164
- LOG_LV1 (" HwPWM" , " race condition resulted in failure to acquire ownership" );
165
- }
166
- return result;
167
- }
168
-
169
97
HardwarePWM::HardwarePWM (NRF_PWM_Type* pwm) :
170
98
_pwm(pwm)
171
99
{
@@ -179,6 +107,38 @@ HardwarePWM::HardwarePWM(NRF_PWM_Type* pwm) :
179
107
_pwm->PSEL .OUT [1 ] = 0xFFFFFFFFUL ;
180
108
}
181
109
110
+ void HardwarePWM::begin (void )
111
+ {
112
+ // Initialize Registers
113
+ _pwm->MODE = PWM_MODE_UPDOWN_Up;
114
+ _pwm->COUNTERTOP = _max_value; // default is 255 (8 bit), can be configured before begin()
115
+ _pwm->PRESCALER = _clock_div;
116
+ _pwm->DECODER = PWM_DECODER_LOAD_Individual;
117
+ _pwm->LOOP = 0 ;
118
+
119
+ _pwm->SEQ [0 ].PTR = (uint32_t ) _seq0;
120
+ _pwm->SEQ [0 ].CNT = MAX_CHANNELS; // default mode is Individual --> count must be 4
121
+ _pwm->SEQ [0 ].REFRESH = 0 ;
122
+ _pwm->SEQ [0 ].ENDDELAY = 0 ;
123
+
124
+ _pwm->SEQ [1 ].PTR = 0 ;
125
+ _pwm->SEQ [1 ].CNT = 0 ;
126
+ _pwm->SEQ [1 ].REFRESH = 0 ;
127
+ _pwm->SEQ [1 ].ENDDELAY = 0 ;
128
+
129
+ _pwm->ENABLE = 1 ;
130
+ }
131
+
132
+ void HardwarePWM::stop (void )
133
+ {
134
+ _pwm->ENABLE = 0 ;
135
+ }
136
+
137
+ bool HardwarePWM::enabled (void )
138
+ {
139
+ return _pwm->ENABLE ;
140
+ }
141
+
182
142
void HardwarePWM::setResolution (uint8_t bitnum)
183
143
{
184
144
setMaxValue ( bit (min8 (bitnum, 15 )) -1 );
@@ -196,6 +156,25 @@ void HardwarePWM::setClockDiv(uint8_t div)
196
156
_pwm->PRESCALER = _clock_div;
197
157
}
198
158
159
+ void HardwarePWM::_set_psel (int ch, uint32_t value)
160
+ {
161
+ // Must disable before changing PSEL
162
+ if ( enabled () )
163
+ {
164
+ _pwm->ENABLE = 0 ;
165
+ _pwm->PSEL .OUT [ch] = value;
166
+ _seq0[ch] = 0 ;
167
+ _pwm->ENABLE = 1 ;
168
+
169
+ // re-start sequence
170
+ if ( usedChannelCount () ) _pwm->TASKS_SEQSTART [0 ] = 1 ;
171
+ }else
172
+ {
173
+ _pwm->PSEL .OUT [ch] = value;
174
+ _seq0[ch] = 0 ;
175
+ }
176
+ }
177
+
199
178
/* *
200
179
* Add pin to this group.
201
180
* @param pin Pin to add
@@ -222,17 +201,7 @@ bool HardwarePWM::addPin(uint8_t pin)
222
201
pinMode (pin, OUTPUT);
223
202
digitalWrite (pin, LOW);
224
203
225
- // Must disable before changing PSEL
226
- if ( enabled () )
227
- {
228
- _pwm->ENABLE = 0 ;
229
- _pwm->PSEL .OUT [ch] = g_ADigitalPinMap[pin];
230
- _pwm->ENABLE = 1 ;
231
- _start ();
232
- }else
233
- {
234
- _pwm->PSEL .OUT [ch] = g_ADigitalPinMap[pin];
235
- }
204
+ _set_psel (ch, g_ADigitalPinMap[pin]);
236
205
237
206
return true ;
238
207
}
@@ -242,70 +211,21 @@ bool HardwarePWM::removePin(uint8_t pin)
242
211
int ch = pin2channel (pin);
243
212
VERIFY ( ch >= 0 );
244
213
245
- bool const en = enabled ();
246
-
247
- // Must disable before changing PSEL
248
- if ( en ) _pwm->ENABLE = 0 ;
249
-
250
- _pwm->PSEL .OUT [ch] = 0xFFFFFFFFUL ;
251
- _seq0[ch] = 0 ;
252
-
253
- if ( en ) _pwm->ENABLE = 1 ;
254
-
214
+ _set_psel (ch, 0xFFFFFFFFUL );
255
215
return true ;
256
216
}
257
217
258
- bool HardwarePWM::enabled (void )
259
- {
260
- return _pwm->ENABLE ;
261
- }
262
-
263
- void HardwarePWM::begin (void )
264
- {
265
- // Initialize Registers
266
- _pwm->MODE = PWM_MODE_UPDOWN_Up;
267
- _pwm->COUNTERTOP = _max_value; // default is 255 (8 bit), can be configured before begin()
268
- _pwm->PRESCALER = _clock_div;
269
- _pwm->DECODER = PWM_DECODER_LOAD_Individual;
270
- _pwm->LOOP = 0 ;
271
-
272
- _pwm->SEQ [0 ].PTR = (uint32_t ) _seq0;
273
- _pwm->SEQ [0 ].CNT = MAX_CHANNELS; // default mode is Individual --> count must be 4
274
- _pwm->SEQ [0 ].REFRESH = 0 ;
275
- _pwm->SEQ [0 ].ENDDELAY = 0 ;
276
-
277
- _pwm->SEQ [1 ].PTR = 0 ;
278
- _pwm->SEQ [1 ].CNT = 0 ;
279
- _pwm->SEQ [1 ].REFRESH = 0 ;
280
- _pwm->SEQ [1 ].ENDDELAY = 0 ;
281
-
282
- _pwm->ENABLE = 1 ;
283
- }
284
-
285
- void HardwarePWM::_start (void )
286
- {
287
- // update sequence count (depending on mode)
288
- // _pwm->SEQ[0].CNT = MAX_CHANNELS;
289
-
290
- // start sequence
291
- _pwm->TASKS_SEQSTART [0 ] = 1 ;
292
- }
293
-
294
- void HardwarePWM::stop (void )
295
- {
296
- _pwm->ENABLE = 0 ;
297
- }
298
-
299
- bool HardwarePWM::writeChannel (uint8_t ch, uint16_t value, bool inverted )
218
+ bool HardwarePWM::writeChannel (uint8_t ch, uint16_t value, bool inverted)
300
219
{
301
220
VERIFY ( ch < MAX_CHANNELS );
302
221
303
222
_seq0[ch] = value | (inverted ? 0 : bit (15 ));
304
223
305
- // Start PWM if not already
224
+ // Initialize PWM if not already
306
225
if ( !enabled () ) begin ();
307
226
308
- _start ();
227
+ // start sequence
228
+ _pwm->TASKS_SEQSTART [0 ] = 1 ;
309
229
310
230
return true ;
311
231
}
@@ -350,3 +270,55 @@ uint8_t HardwarePWM::freeChannelCount(void) const
350
270
return MAX_CHANNELS - usedChannelCount ();
351
271
}
352
272
273
+ // returns true ONLY when (1) no PWM channel has a pin, and (2) the owner token is nullptr
274
+ bool HardwarePWM::takeOwnership (uint32_t token)
275
+ {
276
+ bool const thread_mode = !isInISR ();
277
+
278
+ if (token == 0 ) {
279
+ if (thread_mode) LOG_LV1 (" HwPWM" , " zero is not a valid ownership token (attempted use in takeOwnership)" );
280
+ return false ;
281
+ }
282
+
283
+ if (token == this ->_owner_token ) {
284
+ if (thread_mode) LOG_LV1 (" HwPWM" , " failing to acquire ownership because already owned by requesting token (cannot take ownership twice)" );
285
+ return false ;
286
+ }
287
+
288
+ if ( this ->_owner_token != 0 ) return false ;
289
+ if ( this ->usedChannelCount () != 0 ) return false ;
290
+ if ( this ->enabled () ) return false ;
291
+
292
+ // Use C++11 atomic CAS operation
293
+ uint32_t expectedValue = 0U ;
294
+ return this ->_owner_token .compare_exchange_strong (expectedValue, token);
295
+ }
296
+
297
+ // returns true ONLY when (1) no PWM channel has a pin attached, and (2) the owner token matches
298
+ bool HardwarePWM::releaseOwnership (uint32_t token)
299
+ {
300
+ bool const thread_mode = !isInISR ();
301
+
302
+ if (token == 0 ) {
303
+ if (thread_mode) LOG_LV1 (" HwPWM" , " zero is not a valid ownership token (attempted use in releaseOwnership)" );
304
+ return false ;
305
+ }
306
+
307
+ if (!this ->isOwner (token)) {
308
+ if (thread_mode) LOG_LV1 (" HwPWM" , " attempt to release ownership when not the current owner" );
309
+ return false ;
310
+ }
311
+
312
+ if (this ->usedChannelCount () != 0 ) {
313
+ if (thread_mode) LOG_LV1 (" HwPWM" , " attempt to release ownership when at least on channel is still connected" );
314
+ return false ;
315
+ }
316
+
317
+ if (this ->enabled ()) {
318
+ if (thread_mode) LOG_LV1 (" HwPWM" , " attempt to release ownership when PWM peripheral is still enabled" );
319
+ return false ; // if it's enabled, do not allow ownership to be released, even with no pins in use
320
+ }
321
+
322
+ // Use C++11 atomic CAS operation
323
+ return this ->_owner_token .compare_exchange_strong (token, 0U );
324
+ }
0 commit comments