@@ -38,15 +38,23 @@ Version Modified By Date Comments
38
38
#include " Tone.h"
39
39
#include " WVariant.h"
40
40
41
- unsigned long int count_duration=0 ;
41
+ volatile unsigned long int count_duration=0 ;
42
42
volatile bool no_stop = false ;
43
43
uint8_t pin_sound=0 ;
44
44
static uintptr_t _toneToken = 0x656e6f54 ; // 'T' 'o' 'n' 'e'
45
45
46
+ // NOTE: Currently hard-coded to only use PWM2 ...
47
+ // These are the relvant hard-coded variables
48
+ // (plus the ISR PWM2_IRQHandler)
49
+ static IRQn_Type const _IntNo = PWM2_IRQn;
50
+ static NRF_PWM_Type * const _PWMInstance = NRF_PWM2;
51
+ static HardwarePWM * const _HwPWM = HwPWMx[2 ];
52
+
46
53
void tone (uint8_t pin, unsigned int frequency, unsigned long duration)
47
54
{
48
55
static_assert (sizeof (unsigned long ) == sizeof (uint32_t ));
49
-
56
+ bool new_no_stop;
57
+ unsigned long int new_count_duration = (unsigned long int )-1L ;
50
58
unsigned int time_per=0 ;
51
59
52
60
// limit frequency to reasonable audible range
@@ -55,9 +63,15 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration)
55
63
return ;
56
64
}
57
65
66
+ // set nostop to true to avoid race condition.
67
+ // Specifically, race between a tone finishing
68
+ // after checking for ownership (which releases ownership)
69
+ // No effect if a tone is not playing....
70
+ no_stop = true ;
71
+
58
72
// Use fixed PWM2 (due to need to connect interrupt)
59
- if (!HwPWMx[ 2 ] ->isOwner (_toneToken) &&
60
- !HwPWMx[ 2 ] ->takeOwnership (_toneToken)) {
73
+ if (!_HwPWM ->isOwner (_toneToken) &&
74
+ !_HwPWM ->takeOwnership (_toneToken)) {
61
75
LOG_LV1 (" TON" , " unable to allocate PWM2 to Tone" );
62
76
return ;
63
77
}
@@ -66,15 +80,15 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration)
66
80
time_per=per/0.000008 ;
67
81
unsigned int duty=time_per/2 ;
68
82
if (duration > 0 ) {
69
- no_stop = false ;
83
+ new_no_stop = false ;
70
84
float mil=float (duration)/1000 ;
71
85
if (per>mil) {
72
- count_duration= 1 ;
86
+ new_count_duration = 1 ;
73
87
} else {
74
- count_duration = mil/per;
88
+ new_count_duration = mil/per;
75
89
}
76
90
} else {
77
- no_stop = true ;
91
+ new_no_stop = true ;
78
92
}
79
93
80
94
// Configure PWM
@@ -88,42 +102,45 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration)
88
102
0 ,
89
103
0
90
104
};
91
-
92
- // Use fixed PWM2, TODO could conflict with other usage
105
+
93
106
uint32_t pins[NRF_PWM_CHANNEL_COUNT]={NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED};
94
107
pins[0 ] = g_ADigitalPinMap[pin];
95
108
96
- IRQn_Type IntNo = PWM2_IRQn;
97
- NRF_PWM_Type * PWMInstance = NRF_PWM2;
98
-
99
- nrf_pwm_pins_set (PWMInstance, pins);
100
- nrf_pwm_enable (PWMInstance);
101
- nrf_pwm_configure (PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, time_per);
102
- nrf_pwm_decoder_set (PWMInstance, NRF_PWM_LOAD_COMMON, NRF_PWM_STEP_AUTO);
103
- nrf_pwm_sequence_set (PWMInstance, 0 , &seq);
104
- nrf_pwm_shorts_enable (PWMInstance, NRF_PWM_SHORT_SEQEND0_STOP_MASK); // shortcut for when SEQ0 ends, PWM output will automatically stop
105
-
106
109
// enable interrupt
107
- nrf_pwm_event_clear (PWMInstance, NRF_PWM_EVENT_PWMPERIODEND);
108
- nrf_pwm_int_enable (PWMInstance, NRF_PWM_INT_PWMPERIODEND_MASK);
109
- NVIC_SetPriority (IntNo, 6 ); // low priority
110
- NVIC_ClearPendingIRQ (IntNo);
111
- NVIC_EnableIRQ (IntNo);
112
-
113
- nrf_pwm_task_trigger (PWMInstance, NRF_PWM_TASK_SEQSTART0);
110
+ count_duration = 0x6FFF ; // large enough to avoid hitting zero in next few lines
111
+ no_stop = new_no_stop;
112
+
113
+ nrf_pwm_pins_set (_PWMInstance, pins);
114
+ nrf_pwm_enable (_PWMInstance);
115
+ nrf_pwm_configure (_PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, time_per);
116
+ nrf_pwm_decoder_set (_PWMInstance, NRF_PWM_LOAD_COMMON, NRF_PWM_STEP_AUTO);
117
+ nrf_pwm_sequence_set (_PWMInstance, 0 , &seq);
118
+ nrf_pwm_shorts_enable (_PWMInstance, NRF_PWM_SHORT_SEQEND0_STOP_MASK); // shortcut for when SEQ0 ends, PWM output will automatically stop
119
+ nrf_pwm_event_clear (_PWMInstance, NRF_PWM_EVENT_PWMPERIODEND);
120
+ nrf_pwm_int_enable (_PWMInstance, NRF_PWM_INT_PWMPERIODEND_MASK);
121
+ NVIC_SetPriority (_IntNo, 6 ); // low priority
122
+ NVIC_ClearPendingIRQ (_IntNo);
123
+ NVIC_EnableIRQ (_IntNo);
124
+ count_duration = new_count_duration;
125
+ nrf_pwm_task_trigger (_PWMInstance, NRF_PWM_TASK_SEQSTART0);
114
126
}
115
127
116
128
117
129
void noTone (uint8_t pin)
118
130
{
119
- if (!HwPWMx[ 2 ] ->isOwner (_toneToken)) {
131
+ if (!_HwPWM ->isOwner (_toneToken)) {
120
132
LOG_LV1 (" TON" , " Attempt to set noTone when not the owner of the PWM peripheral. Ignoring call...." );
121
133
return ;
122
134
}
123
-
124
- NRF_PWM_Type * PWMInstance = NRF_PWM2;
125
- nrf_pwm_task_trigger (PWMInstance, NRF_PWM_TASK_STOP);
126
- nrf_pwm_disable (PWMInstance);
135
+ nrf_pwm_task_trigger (_PWMInstance, NRF_PWM_TASK_STOP);
136
+ nrf_pwm_disable (_PWMInstance);
137
+ _PWMInstance->PSEL .OUT [0 ] = NRF_PWM_PIN_NOT_CONNECTED;
138
+ NVIC_DisableIRQ (_IntNo);
139
+ _HwPWM->releaseOwnership (_toneToken);
140
+ if (_HwPWM->isOwner (_toneToken)) {
141
+ LOG_LV1 (" TON" , " stopped tone, but failed to release ownership of PWM peripheral?" );
142
+ return ;
143
+ }
127
144
}
128
145
129
146
#ifdef __cplusplus
@@ -137,6 +154,9 @@ void PWM2_IRQHandler(void){
137
154
if (count_duration == 0 ) {
138
155
nrf_pwm_task_trigger (NRF_PWM2, NRF_PWM_TASK_STOP);
139
156
nrf_pwm_disable (NRF_PWM2);
157
+ _PWMInstance->PSEL .OUT [0 ] = NRF_PWM_PIN_NOT_CONNECTED;
158
+ NVIC_DisableIRQ (PWM2_IRQn);
159
+ _HwPWM->releaseOwnershipFromISR (_toneToken);
140
160
} else {
141
161
nrf_pwm_task_trigger (NRF_PWM2, NRF_PWM_TASK_SEQSTART0);
142
162
}
0 commit comments