Skip to content

Commit fb4beea

Browse files
authored
Merge pull request #562 from adafruit/followup-496
clean up pwn and analog
2 parents 7993737 + b2c9e54 commit fb4beea

File tree

8 files changed

+373
-319
lines changed

8 files changed

+373
-319
lines changed

.travis.yml.bck

Lines changed: 0 additions & 68 deletions
This file was deleted.

cores/nRF5/HardwarePWM.cpp

Lines changed: 112 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ HardwarePWM* HwPWMx[] =
5454
};
5555

5656
#if CFG_DEBUG
57-
bool can_stringify_token(uintptr_t token)
57+
bool can_stringify_token(uint32_t token)
5858
{
5959
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)
6161
{
6262
uint8_t x = *t;
6363
if ((x < 0x20) || (x > 0x7E)) return false;
@@ -71,14 +71,12 @@ void HardwarePWM::DebugOutput(Stream& logger)
7171
logger.printf("HwPWM Debug:");
7272
for (size_t i = 0; i < count; i++) {
7373
HardwarePWM const * pwm = HwPWMx[i];
74-
uintptr_t token = pwm->_owner_token;
74+
uint32_t token = pwm->_owner_token;
7575
logger.printf(" || %d:", i);
7676
if (can_stringify_token(token)) {
7777
uint8_t * t = (uint8_t*)(&token);
78-
static_assert(sizeof(uintptr_t) == 4);
7978
logger.printf(" \"%c%c%c%c\"", t[0], t[1], t[2], t[3] );
8079
} else {
81-
static_assert(sizeof(uintptr_t) == 4);
8280
logger.printf(" %08x", token);
8381
}
8482
for (size_t j = 0; j < MAX_CHANNELS; j++) {
@@ -96,76 +94,6 @@ void HardwarePWM::DebugOutput(Stream& logger)
9694
void HardwarePWM::DebugOutput(Stream& logger) {}
9795
#endif // CFG_DEBUG
9896

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-
16997
HardwarePWM::HardwarePWM(NRF_PWM_Type* pwm) :
17098
_pwm(pwm)
17199
{
@@ -179,6 +107,38 @@ HardwarePWM::HardwarePWM(NRF_PWM_Type* pwm) :
179107
_pwm->PSEL.OUT[1] = 0xFFFFFFFFUL;
180108
}
181109

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+
182142
void HardwarePWM::setResolution(uint8_t bitnum)
183143
{
184144
setMaxValue( bit(min8(bitnum, 15)) -1 );
@@ -196,6 +156,25 @@ void HardwarePWM::setClockDiv(uint8_t div)
196156
_pwm->PRESCALER = _clock_div;
197157
}
198158

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+
199178
/**
200179
* Add pin to this group.
201180
* @param pin Pin to add
@@ -222,17 +201,7 @@ bool HardwarePWM::addPin(uint8_t pin)
222201
pinMode(pin, OUTPUT);
223202
digitalWrite(pin, LOW);
224203

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]);
236205

237206
return true;
238207
}
@@ -242,70 +211,21 @@ bool HardwarePWM::removePin(uint8_t pin)
242211
int ch = pin2channel(pin);
243212
VERIFY( ch >= 0 );
244213

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);
255215
return true;
256216
}
257217

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)
300219
{
301220
VERIFY( ch < MAX_CHANNELS );
302221

303222
_seq0[ch] = value | (inverted ? 0 : bit(15));
304223

305-
// Start PWM if not already
224+
// Initialize PWM if not already
306225
if ( !enabled() ) begin();
307226

308-
_start();
227+
// start sequence
228+
_pwm->TASKS_SEQSTART[0] = 1;
309229

310230
return true;
311231
}
@@ -350,3 +270,55 @@ uint8_t HardwarePWM::freeChannelCount(void) const
350270
return MAX_CHANNELS - usedChannelCount();
351271
}
352272

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

Comments
 (0)