Skip to content

Commit 947d8bb

Browse files
committed
clean up pwn and analog
replace built-in atomic with freeRTOS critical functions
1 parent 7993737 commit 947d8bb

File tree

3 files changed

+99
-115
lines changed

3 files changed

+99
-115
lines changed

cores/nRF5/HardwarePWM.cpp

Lines changed: 69 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,8 @@ void HardwarePWM::DebugOutput(Stream& logger)
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
{
@@ -350,3 +278,72 @@ uint8_t HardwarePWM::freeChannelCount(void) const
350278
return MAX_CHANNELS - usedChannelCount();
351279
}
352280

281+
// returns true ONLY when (1) no PWM channel has a pin, and (2) the owner token is nullptr
282+
bool HardwarePWM::takeOwnership(uintptr_t token)
283+
{
284+
if (token == 0) {
285+
LOG_LV1("HwPWM", "zero / nullptr is not a valid ownership token (attempted use in takeOwnership)");
286+
return false;
287+
}
288+
289+
if (token == this->_owner_token) {
290+
LOG_LV1("HwPWM", "failing to acquire ownership because already owned by requesting token (cannot take ownership twice)");
291+
return false;
292+
}
293+
294+
if (this->_owner_token != 0) return false;
295+
if (this->usedChannelCount() != 0) return false;
296+
if (this->enabled()) return false;
297+
298+
if (isInISR())
299+
{
300+
UBaseType_t intr_status = taskENTER_CRITICAL_FROM_ISR();
301+
_owner_token = token;
302+
taskEXIT_CRITICAL_FROM_ISR(intr_status);
303+
}else
304+
{
305+
taskENTER_CRITICAL();
306+
_owner_token = token;
307+
taskEXIT_CRITICAL();
308+
}
309+
310+
return true;
311+
}
312+
313+
// returns true ONLY when (1) no PWM channel has a pin attached, and (2) the owner token matches
314+
bool HardwarePWM::releaseOwnership(uintptr_t token)
315+
{
316+
if (token == 0) {
317+
LOG_LV1("HwPWM", "zero / nullptr is not a valid ownership token (attempted use in releaseOwnership)");
318+
return false;
319+
}
320+
321+
if (!this->isOwner(token)) {
322+
LOG_LV1("HwPWM", "attempt to release ownership when not the current owner");
323+
return false;
324+
}
325+
326+
if (this->usedChannelCount() != 0) {
327+
LOG_LV1("HwPWM", "attempt to release ownership when at least on channel is still connected");
328+
return false;
329+
}
330+
331+
if (this->enabled()) {
332+
LOG_LV1("HwPWM", "attempt to release ownership when PWM peripheral is still enabled");
333+
return false; // if it's enabled, do not allow ownership to be released, even with no pins in use
334+
}
335+
336+
if (isInISR())
337+
{
338+
UBaseType_t intr_status = taskENTER_CRITICAL_FROM_ISR();
339+
_owner_token = 0;
340+
taskEXIT_CRITICAL_FROM_ISR(intr_status);
341+
}else
342+
{
343+
taskENTER_CRITICAL();
344+
_owner_token = 0;
345+
taskEXIT_CRITICAL();
346+
}
347+
348+
return true;
349+
}

cores/nRF5/HardwarePWM.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
#include "common_inc.h"
4040
#include "nrf.h"
41-
#include <atomic>
4241

4342
#ifdef NRF52840_XXAA
4443
#define HWPWM_MODULE_NUM 4
@@ -51,7 +50,7 @@ class HardwarePWM
5150
private:
5251
enum { MAX_CHANNELS = 4 }; // Max channel per group
5352
NRF_PWM_Type * const _pwm;
54-
std::atomic_uintptr_t _owner_token;
53+
uintptr_t _owner_token;
5554

5655
uint16_t _seq0[MAX_CHANNELS];
5756

@@ -73,11 +72,12 @@ class HardwarePWM
7372

7473
// returns true ONLY when (1) no PWM channel has a pin, and (2) the owner token is nullptr
7574
bool takeOwnership (uintptr_t token);
75+
7676
// returns true ONLY when (1) no PWM channel has a pin attached, and (2) the owner token matches
7777
bool releaseOwnership(uintptr_t token);
7878

7979
// allows caller to verify that they own the peripheral
80-
__INLINE bool isOwner(uintptr_t token) const
80+
bool isOwner(uintptr_t token) const
8181
{
8282
return this->_owner_token == token;
8383
}

cores/nRF5/wiring_analog.cpp

Lines changed: 27 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ void analogWriteResolution( uint8_t res )
5959
_analogResolution = res;
6060
for (int i = 0; i<HWPWM_MODULE_NUM; i++)
6161
{
62-
if (!HwPWMx[i]->isOwner(_analogToken)) continue;
63-
HwPWMx[i]->setResolution(res);
62+
if (HwPWMx[i]->isOwner(_analogToken))
63+
{
64+
HwPWMx[i]->setResolution(res);
65+
}
6466
}
6567
}
6668

@@ -73,65 +75,50 @@ void analogWriteResolution( uint8_t res )
7375
*/
7476
void analogWrite( uint32_t pin, uint32_t value )
7577
{
76-
/* If the pin is already in use for analogWrite, this should be fast
77-
If the pin is not already in use, then it's OK to take slightly more time to setup
78-
*/
79-
8078
// first, handle the case where the pin is already in use by analogWrite()
8179
for(int i=0; i<HWPWM_MODULE_NUM; i++)
8280
{
83-
if (!HwPWMx[i]->isOwner(_analogToken)) {
84-
continue; // skip if not owner of this PWM instance
81+
if (HwPWMx[i]->isOwner(_analogToken))
82+
{
83+
int const ch = HwPWMx[i]->pin2channel(pin);
84+
if (ch >= 0)
85+
{
86+
HwPWMx[i]->writeChannel(ch, value);
87+
return;
88+
}
8589
}
86-
87-
int const ch = HwPWMx[i]->pin2channel(pin);
88-
if (ch < 0) {
89-
continue; // pin not in use by this PWM instance
90-
}
91-
HwPWMx[i]->writeChannel(ch, value);
92-
return;
9390
}
9491

9592
// Next, handle the case where can add the pin to a PWM instance already owned by analogWrite()
9693
for(int i=0; i<HWPWM_MODULE_NUM; i++)
9794
{
98-
if (!HwPWMx[i]->isOwner(_analogToken)) {
99-
continue;
100-
}
101-
if (!HwPWMx[i]->addPin(pin)) {
102-
continue;
95+
if ( HwPWMx[i]->isOwner(_analogToken) && HwPWMx[i]->addPin(pin) )
96+
{
97+
// successfully added the pin, so write the value also
98+
LOG_LV2("Analog", "Added pin %" PRIu32 " to already-owned PWM %d", pin, i);
99+
HwPWMx[i]->writePin(pin, value);
100+
return;
103101
}
104-
105-
// successfully added the pin, so write the value also
106-
LOG_LV2("ANA", "Added pin %" PRIu32 " to already-owned PWM %d", pin, i);
107-
HwPWMx[i]->writePin(pin, value);
108-
return;
109102
}
110103

111104
// Attempt to acquire a new HwPWMx instance ... but only where
112105
// 1. it's not one already used for analog, and
113106
// 2. it currently has no pins in use.
114107
for(int i=0; i<HWPWM_MODULE_NUM; i++)
115108
{
116-
if (!HwPWMx[i]->takeOwnership(_analogToken)) {
117-
continue;
109+
if (HwPWMx[i]->takeOwnership(_analogToken))
110+
{
111+
// apply the cached analog resolution to newly owned instances
112+
HwPWMx[i]->setResolution(_analogResolution);
113+
HwPWMx[i]->addPin(pin);
114+
HwPWMx[i]->writePin(pin, value);
115+
LOG_LV2("Analog", "took ownership of, and added pin %" PRIu32 " to, PWM %d", pin, i);
116+
return;
118117
}
119-
120-
// apply the cached analog resolution to newly owned instances
121-
HwPWMx[i]->setResolution(_analogResolution);
122-
HwPWMx[i]->addPin(pin);
123-
HwPWMx[i]->writePin(pin, value);
124-
LOG_LV2("ANA", "took ownership of, and added pin %" PRIu32 " to, PWM %d", pin, i);
125-
return;
126118
}
127119

128-
// failed to allocate a HwPWM instance.
129-
// output appropriate debug message.
130-
LOG_LV1("ANA", "Unable to find a free PWM peripheral");
131-
// TODO: Add additional diagnostics to function at higher log levels
120+
LOG_LV1("Analog", "Unable to find a free PWM peripheral");
132121
return;
133122
}
134123

135124
} // end extern "C"
136-
137-

0 commit comments

Comments
 (0)