Skip to content

Commit 3ec284c

Browse files
micookeJones Chi
authored and
Jones Chi
committed
wiring_analog_* : fallback to digitalWrite if no available PWM channel (copied from AVR core) wiring_analog_nRF52.c : convert pwmChannelPins & pwmChannelSequence -> pwmContext to semi-standardise pwm pin allocation and pwm status between nRF51 and nRF52 wiring_private.h : Move pwm structures defines out of wiring_analog_* into wiring_private and make the instantiation of these structure externs instead of statics wiring_digital.c : disable the appropriate pwm timer when a digitalWrite is sent to an allocated (from analogWrite) pwm pin, and free up the pwm channel for re-allocation
1 parent 7df7543 commit 3ec284c

File tree

4 files changed

+93
-41
lines changed

4 files changed

+93
-41
lines changed

cores/nRF5/wiring_analog_nRF51.c

+17-22
Original file line numberDiff line numberDiff line change
@@ -28,27 +28,16 @@
2828
extern "C" {
2929
#endif
3030

31-
#define PWM_COUNT 3
32-
#define PIN_FREE 0xffffffff
33-
34-
struct PWMContext {
35-
uint32_t pin;
36-
uint32_t value;
37-
uint32_t channel;
38-
uint32_t mask;
39-
uint32_t event;
40-
};
31+
static uint32_t adcReference = ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling;
32+
static uint32_t adcPrescaling = ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling;
4133

42-
static struct PWMContext pwmContext[PWM_COUNT] = {
34+
struct PWMContext pwmContext[PWM_COUNT] = {
4335
{ PIN_FREE, 0, 1, TIMER_INTENSET_COMPARE1_Msk, 1 },
4436
{ PIN_FREE, 0, 2, TIMER_INTENSET_COMPARE2_Msk, 2 },
4537
{ PIN_FREE, 0, 3, TIMER_INTENSET_COMPARE3_Msk, 3 }
4638
};
4739

48-
static int timerEnabled = 0;
49-
50-
static uint32_t adcReference = ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling;
51-
static uint32_t adcPrescaling = ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling;
40+
struct PWMStatus pwmStatus[PWM_TIMER_COUNT] = {0, TIMER1_IRQn};
5241

5342
static uint32_t readResolution = 10;
5443
static uint32_t writeResolution = 8;
@@ -229,7 +218,7 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
229218

230219
ulPin = g_ADigitalPinMap[ulPin];
231220

232-
if (!timerEnabled) {
221+
if (pwmStatus[0].numActive == 0) {
233222
NVIC_SetPriority(TIMER1_IRQn, 3);
234223
NVIC_ClearPendingIRQ(TIMER1_IRQn);
235224
NVIC_EnableIRQ(TIMER1_IRQn);
@@ -245,8 +234,6 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
245234
NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
246235

247236
NRF_TIMER1->TASKS_START = 0x1UL;
248-
249-
timerEnabled = true;
250237
}
251238

252239
for (int i = 0; i < PWM_COUNT; i++) {
@@ -259,17 +246,25 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
259246
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
260247
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
261248

262-
ulValue = mapResolution(ulValue, writeResolution, 8);
263-
264249
pwmContext[i].value = ulValue;
265250

266251
NRF_TIMER1->CC[pwmContext[i].channel] = ulValue;
267252

268253
NRF_TIMER1->INTENSET = pwmContext[i].mask;
269-
270-
break;
254+
pwmStatus[0].numActive++;
255+
return;
271256
}
272257
}
258+
259+
// fallback to digitalWrite if no available PWM channel
260+
if (ulValue < 128)
261+
{
262+
digitalWrite(ulPin, LOW);
263+
}
264+
else
265+
{
266+
digitalWrite(ulPin, LOW);
267+
}
273268
}
274269

275270
void TIMER1_IRQHandler(void)

cores/nRF5/wiring_analog_nRF52.c

+23-14
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,19 @@ extern "C" {
3131
static uint32_t saadcReference = SAADC_CH_CONFIG_REFSEL_Internal;
3232
static uint32_t saadcGain = SAADC_CH_CONFIG_GAIN_Gain1_5;
3333

34-
#define PWM_COUNT 3
35-
36-
static NRF_PWM_Type* pwms[PWM_COUNT] = {
34+
NRF_PWM_Type* pwms[PWM_COUNT] = {
3735
NRF_PWM0,
3836
NRF_PWM1,
3937
NRF_PWM2
4038
};
4139

42-
static uint32_t pwmChannelPins[PWM_COUNT] = {
43-
0xFFFFFFFF,
44-
0xFFFFFFFF,
45-
0xFFFFFFFF
40+
struct PWMContext pwmContext[PWM_COUNT] = {
41+
{ PIN_FREE, 0 },
42+
{ PIN_FREE, 0 },
43+
{ PIN_FREE, 0 }
4644
};
47-
static uint16_t pwmChannelSequence[PWM_COUNT];
45+
46+
struct PWMStatus pwmStatus[PWM_TIMER_COUNT] = {0, 0};
4847

4948
static int readResolution = 10;
5049
static int writeResolution = 8;
@@ -220,9 +219,9 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
220219
ulPin = g_ADigitalPinMap[ulPin];
221220

222221
for (int i = 0; i < PWM_COUNT; i++) {
223-
if (pwmChannelPins[i] == 0xFFFFFFFF || pwmChannelPins[i] == ulPin) {
224-
pwmChannelPins[i] = ulPin;
225-
pwmChannelSequence[i] = ulValue | bit(15);
222+
if (pwmContext[i].pin == PIN_FREE || pwmContext[i].pin == ulPin) {
223+
pwmContext[i].pin = ulPin;
224+
pwmContext[i].value = ulValue | bit(15);
226225

227226
NRF_PWM_Type* pwm = pwms[i];
228227

@@ -236,15 +235,25 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
236235
pwm->COUNTERTOP = (1 << writeResolution) - 1;
237236
pwm->LOOP = 0;
238237
pwm->DECODER = ((uint32_t)PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | ((uint32_t)PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
239-
pwm->SEQ[0].PTR = (uint32_t)&pwmChannelSequence[i];
238+
pwm->SEQ[0].PTR = (uint32_t)&(pwmContext[i].value);
240239
pwm->SEQ[0].CNT = 1;
241240
pwm->SEQ[0].REFRESH = 1;
242241
pwm->SEQ[0].ENDDELAY = 0;
243242
pwm->TASKS_SEQSTART[0] = 0x1UL;
244-
245-
break;
243+
pwmStatus[0].numActive++;
244+
return;
246245
}
247246
}
247+
248+
// fallback to digitalWrite if no available PWM channel
249+
if (ulValue < 128)
250+
{
251+
digitalWrite(ulPin, LOW);
252+
}
253+
else
254+
{
255+
digitalWrite(ulPin, LOW);
256+
}
248257
}
249258

250259
#ifdef __cplusplus

cores/nRF5/wiring_digital.c

+35-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020
#include "nrf.h"
2121

2222
#include "Arduino.h"
23+
#include "wiring_private.h"
24+
25+
extern struct PWMContext pwmContext[PWM_COUNT];
26+
extern struct PWMStatus pwmStatus[PWM_TIMER_COUNT];
27+
#ifdef NRF52
28+
extern NRF_PWM_Type* pwms[PWM_COUNT];
29+
#endif
2330

2431
#ifdef __cplusplus
2532
extern "C" {
@@ -86,18 +93,42 @@ void digitalWrite( uint32_t ulPin, uint32_t ulVal )
8693

8794
ulPin = g_ADigitalPinMap[ulPin];
8895

96+
for (uint8_t i = 0; i < PWM_COUNT; i++)
97+
{
98+
if (pwmContext[i].pin == ulPin)
99+
{
100+
pwmContext[i].pin = PIN_FREE;
101+
#ifdef NRF52
102+
// Disable the PWM
103+
NRF_PWM_Type* pwm = pwms[i];
104+
pwm->ENABLE = (PWM_ENABLE_ENABLE_Disabled << PWM_ENABLE_ENABLE_Pos);
105+
#endif
106+
pwmStatus[0].numActive--;
107+
}
108+
}
109+
110+
#ifdef NRF51
111+
// Turn off the Timer if no pwm signals are allocated
112+
for (uint8_t i = 0; i < PWM_TIMER_COUNT; i++)
113+
{
114+
if (pwmStatus[i].numActive == 0)
115+
{
116+
NVIC_ClearPendingIRQ(pwmStatus[i].irqNumber);
117+
NVIC_DisableIRQ(pwmStatus[i].irqNumber);
118+
}
119+
}
120+
#endif
121+
89122
switch ( ulVal )
90123
{
91124
case LOW:
92125
NRF_GPIO->OUTCLR = (1UL << ulPin);
93-
break ;
126+
break;
94127

95128
default:
96129
NRF_GPIO->OUTSET = (1UL << ulPin);
97-
break ;
130+
break;
98131
}
99-
100-
return ;
101132
}
102133

103134
int digitalRead( uint32_t ulPin )

cores/nRF5/wiring_private.h

+18-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,26 @@
2626
extern "C" {
2727
#endif
2828

29-
3029
#include "wiring_constants.h"
3130

31+
#define PWM_COUNT 3
32+
#define PWM_TIMER_COUNT 1 // 3 channels of TIMER1 are used. TIMER2 also could be used for PWM
33+
#define PIN_FREE 0xffffffff
34+
35+
struct PWMContext {
36+
uint32_t pin;
37+
uint32_t value;
38+
#ifdef NRF51
39+
uint32_t channel;
40+
uint32_t mask;
41+
uint32_t event;
42+
#endif
43+
};
44+
45+
struct PWMStatus {
46+
int8_t numActive;
47+
int8_t irqNumber;
48+
};
3249

3350
#ifdef __cplusplus
3451
} // extern "C"

0 commit comments

Comments
 (0)