@@ -53,9 +53,123 @@ HardwarePWM* HwPWMx[] =
53
53
#endif
54
54
};
55
55
56
- HardwarePWM::HardwarePWM (NRF_PWM_Type* pwm)
56
+ #if CFG_DEBUG
57
+ bool can_stringify_token (uintptr_t token)
57
58
{
58
- _pwm = pwm;
59
+ uint8_t * t = (uint8_t *)&token;
60
+ for (size_t i = 0 ; i < sizeof (uintptr_t ); ++i, ++t)
61
+ {
62
+ uint8_t x = *t;
63
+ if ((x < 0x20 ) || (x > 0x7E )) return false ;
64
+ }
65
+ return true ;
66
+ }
67
+
68
+ void HardwarePWM::DebugOutput (Stream& logger)
69
+ {
70
+ const size_t count = arrcount (HwPWMx);
71
+ logger.printf (" HwPWM Debug:" );
72
+ for (size_t i = 0 ; i < count; i++) {
73
+ HardwarePWM const * pwm = HwPWMx[i];
74
+ uintptr_t token = pwm->_owner_token ;
75
+ logger.printf (" || %d:" , i);
76
+ if (can_stringify_token (token)) {
77
+ uint8_t * t = (uint8_t *)(&token);
78
+ static_assert (sizeof (uintptr_t ) == 4 );
79
+ logger.printf (" \" %c%c%c%c\" " , t[0 ], t[1 ], t[2 ], t[3 ] );
80
+ } else {
81
+ static_assert (sizeof (uintptr_t ) == 4 );
82
+ logger.printf (" %08x" , token);
83
+ }
84
+ for (size_t j = 0 ; j < MAX_CHANNELS; j++) {
85
+ uint32_t r = pwm->_pwm ->PSEL .OUT [j]; // only read it once
86
+ if ( (r & PWM_PSEL_OUT_CONNECT_Msk) != (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos) ) {
87
+ logger.printf (" %02x" , r & 0x1F );
88
+ } else {
89
+ logger.printf (" xx" );
90
+ }
91
+ }
92
+ }
93
+ logger.printf (" \n " );
94
+ }
95
+ #else
96
+ void HardwarePWM::DebugOutput (Stream& logger) {}
97
+ #endif // CFG_DEBUG
98
+
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
+ HardwarePWM::HardwarePWM (NRF_PWM_Type* pwm) :
170
+ _pwm(pwm)
171
+ {
172
+ _owner_token = 0U ;
59
173
arrclr (_seq0);
60
174
61
175
_max_value = 255 ;
@@ -204,17 +318,35 @@ bool HardwarePWM::writePin(uint8_t pin, uint16_t value, bool inverted)
204
318
return writeChannel (ch, value, inverted);
205
319
}
206
320
207
- uint16_t HardwarePWM::readPin (uint8_t pin)
321
+ uint16_t HardwarePWM::readPin (uint8_t pin) const
208
322
{
209
323
int ch = pin2channel (pin);
210
324
VERIFY ( ch >= 0 , 0 );
211
325
212
326
return readChannel (ch);
213
327
}
214
328
215
- uint16_t HardwarePWM::readChannel (uint8_t ch)
329
+ uint16_t HardwarePWM::readChannel (uint8_t ch) const
216
330
{
217
331
// remove inverted bit
218
332
return (_seq0[ch] & 0x7FFF );
219
333
}
220
334
335
+ uint8_t HardwarePWM::usedChannelCount (void ) const
336
+ {
337
+ uint8_t usedChannels = 0 ;
338
+ for (int i=0 ; i<MAX_CHANNELS; i++)
339
+ {
340
+ if ( (_pwm->PSEL .OUT [i] & PWM_PSEL_OUT_CONNECT_Msk) != (PWM_PSEL_OUT_CONNECT_Disconnected << PWM_PSEL_OUT_CONNECT_Pos) )
341
+ {
342
+ usedChannels++;
343
+ }
344
+ }
345
+ return usedChannels;
346
+ }
347
+
348
+ uint8_t HardwarePWM::freeChannelCount (void ) const
349
+ {
350
+ return MAX_CHANNELS - usedChannelCount ();
351
+ }
352
+
0 commit comments