@@ -53,9 +53,123 @@ HardwarePWM* HwPWMx[] =
5353#endif
5454};
5555
56- HardwarePWM::HardwarePWM (NRF_PWM_Type* pwm)
56+ #if CFG_DEBUG
57+ bool can_stringify_token (uintptr_t token)
5758{
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 ;
59173 arrclr (_seq0);
60174
61175 _max_value = 255 ;
@@ -204,17 +318,35 @@ bool HardwarePWM::writePin(uint8_t pin, uint16_t value, bool inverted)
204318 return writeChannel (ch, value, inverted);
205319}
206320
207- uint16_t HardwarePWM::readPin (uint8_t pin)
321+ uint16_t HardwarePWM::readPin (uint8_t pin) const
208322{
209323 int ch = pin2channel (pin);
210324 VERIFY ( ch >= 0 , 0 );
211325
212326 return readChannel (ch);
213327}
214328
215- uint16_t HardwarePWM::readChannel (uint8_t ch)
329+ uint16_t HardwarePWM::readChannel (uint8_t ch) const
216330{
217331 // remove inverted bit
218332 return (_seq0[ch] & 0x7FFF );
219333}
220334
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