Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow nRF51 to use up to 6 pwm pins #369

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cores/nRF5/wiring_analog.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ typedef enum _eAnalogReference
AR_EXT0,
AR_EXT1
} eAnalogReference ;
//not standard, set timer prescaller
void pwmPrescaller( int div );
#endif


Expand Down
162 changes: 125 additions & 37 deletions cores/nRF5/wiring_analog_nRF51.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,61 @@
extern "C" {
#endif

#define PWM_COUNT 3
#define PWM_COUNT 6
#define PWM_CH_COUNT 3
#define PIN_FREE 0xffffffff

struct PWMSrc {
NRF_TIMER_Type* timer;
bool used;
};

struct PWMSrc srcs[2]={
{NRF_TIMER1,false},
{NRF_TIMER2,false}
};

struct PWMContext {
uint32_t pin;
uint32_t value;
uint32_t channel;
uint32_t mask;
uint32_t event;
int src;
};

static struct PWMContext pwmContext[PWM_COUNT] = {
{ PIN_FREE, 0, 1, TIMER_INTENSET_COMPARE1_Msk, 1 },
{ PIN_FREE, 0, 2, TIMER_INTENSET_COMPARE2_Msk, 2 },
{ PIN_FREE, 0, 3, TIMER_INTENSET_COMPARE3_Msk, 3 }
extern struct PWMContext pwmContext[PWM_COUNT];
// static
struct PWMContext pwmContext[PWM_COUNT] = {
{ PIN_FREE, 0, 1, TIMER_INTENSET_COMPARE1_Msk, 1, 0 },
{ PIN_FREE, 0, 2, TIMER_INTENSET_COMPARE2_Msk, 2, 0 },
{ PIN_FREE, 0, 3, TIMER_INTENSET_COMPARE3_Msk, 3, 0 },
{ PIN_FREE, 0, 1, TIMER_INTENSET_COMPARE1_Msk, 1, 1 },
{ PIN_FREE, 0, 2, TIMER_INTENSET_COMPARE2_Msk, 2, 1 },
{ PIN_FREE, 0, 3, TIMER_INTENSET_COMPARE3_Msk, 3, 1 }
};

static int timerEnabled = 0;

static uint32_t adcReference = ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling;
static uint32_t adcPrescaling = ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling;

static uint32_t readResolution = 10;
static uint32_t writeResolution = 8;

void analogReadResolution( int res )
static uint32_t timerPrescaller=7;
//not standard, set timer prescaller
inline void pwmPrescaller( int div ) {timerPrescaller=div;}

inline void analogReadResolution( int res )
{
readResolution = res;
}

void analogWriteResolution( int res )
inline void analogWriteResolution( int res )
{
writeResolution = res;
//this might need to reconfigure the timer...
//for now call it once on setup before using pwm
//TODO: check if this is the expected behaviour
}

static inline uint32_t mapResolution( uint32_t value, uint32_t from, uint32_t to )
Expand Down Expand Up @@ -217,6 +239,25 @@ uint32_t analogRead( uint32_t ulPin )
return mapResolution(value, resolution, readResolution);
}

// int getFreePwm() {
// for (int i = 0; i < PWM_COUNT; i++)
// if (pwmContext[i].pin == PIN_FREE) return i;
// return -1;
// }

static int timerResolution(int nbits) {
if(nbits<=8) return TIMER_BITMODE_BITMODE_08Bit;
if(nbits<=16) return TIMER_BITMODE_BITMODE_16Bit;
if(nbits<=24) return TIMER_BITMODE_BITMODE_24Bit;
return TIMER_BITMODE_BITMODE_32Bit;
}

int getPwmFromPin(uint32_t ulPin) {
for (int i = 0; i < PWM_COUNT; i++)
if (pwmContext[i].pin == ulPin||pwmContext[i].pin==PIN_FREE) return i;
return -1;
}

// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// pins_*.c file. For the rest of the pins, we default
Expand All @@ -229,43 +270,56 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )

ulPin = g_ADigitalPinMap[ulPin];

if (!timerEnabled) {
NVIC_SetPriority(TIMER1_IRQn, 3);
NVIC_ClearPendingIRQ(TIMER1_IRQn);
NVIC_EnableIRQ(TIMER1_IRQn);
int pwm=getPwmFromPin(ulPin);
struct PWMSrc* src=&srcs[pwmContext[pwm].src];
NRF_TIMER_Type* pwmSrc=src->timer;

NRF_TIMER1->MODE = (NRF_TIMER1->MODE & ~TIMER_MODE_MODE_Msk) | ((TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos) & TIMER_MODE_MODE_Msk);
if (!src->used) {

NRF_TIMER1->BITMODE = (NRF_TIMER1->BITMODE & ~TIMER_BITMODE_BITMODE_Msk) | ((TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos) & TIMER_BITMODE_BITMODE_Msk);
if (pwmSrc==NRF_TIMER1) {
NVIC_SetPriority(TIMER1_IRQn, 3);
NVIC_ClearPendingIRQ(TIMER1_IRQn);
NVIC_EnableIRQ(TIMER1_IRQn);
} else if (pwmSrc==NRF_TIMER2) {
NVIC_SetPriority(TIMER2_IRQn, 4);
NVIC_ClearPendingIRQ(TIMER2_IRQn);
NVIC_EnableIRQ(TIMER2_IRQn);
} else return;
src->used = true;

NRF_TIMER1->PRESCALER = (NRF_TIMER1->PRESCALER & ~TIMER_PRESCALER_PRESCALER_Msk) | ((7 << TIMER_PRESCALER_PRESCALER_Pos) & TIMER_PRESCALER_PRESCALER_Msk);
pwmSrc->MODE = (pwmSrc->MODE & ~TIMER_MODE_MODE_Msk) | ((TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos) & TIMER_MODE_MODE_Msk);

NRF_TIMER1->CC[0] = 0;
pwmSrc->BITMODE = (pwmSrc->BITMODE & ~TIMER_BITMODE_BITMODE_Msk) | ((timerResolution(writeResolution) << TIMER_BITMODE_BITMODE_Pos) & TIMER_BITMODE_BITMODE_Msk);

NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
pwmSrc->PRESCALER = (pwmSrc->PRESCALER & ~TIMER_PRESCALER_PRESCALER_Msk) | ((timerPrescaller << TIMER_PRESCALER_PRESCALER_Pos) & TIMER_PRESCALER_PRESCALER_Msk);

NRF_TIMER1->TASKS_START = 0x1UL;
pwmSrc->CC[0] = (1<<writeResolution)-1;//0;

timerEnabled = true;
pwmSrc->INTENSET = TIMER_INTENSET_COMPARE0_Msk;

pwmSrc->TASKS_START = 0x1UL;
}

for (int i = 0; i < PWM_COUNT; i++) {
if (pwmContext[i].pin == PIN_FREE || pwmContext[i].pin == ulPin) {
pwmContext[i].pin = ulPin;

NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
if (pwmContext[i].pin != ulPin) {
pwmContext[i].pin = ulPin;

NRF_GPIO->PIN_CNF[ulPin] = ((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos)
| ((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
| ((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
}

ulValue = mapResolution(ulValue, writeResolution, 8);
// ulValue = mapResolution(ulValue, writeResolution, writeResolution);

pwmContext[i].value = ulValue;

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

NRF_TIMER1->INTENSET = pwmContext[i].mask;
pwmSrc->INTENSET = pwmContext[i].mask;

break;
}
Expand All @@ -275,26 +329,60 @@ void analogWrite( uint32_t ulPin, uint32_t ulValue )
void TIMER1_IRQHandler(void)
{
if (NRF_TIMER1->EVENTS_COMPARE[0]) {
for (int i = 0; i < PWM_COUNT; i++) {
if (pwmContext[i].pin != PIN_FREE && pwmContext[i].value != 0) {
NRF_GPIO->OUTSET = (1UL << pwmContext[i].pin);
for (int i = 0; i < PWM_CH_COUNT; i++) {
if (pwmContext[i].pin != PIN_FREE) {
if(pwmContext[i].value != 0)
NRF_GPIO->OUTSET = (1UL << pwmContext[i].pin);
else
NRF_GPIO->OUTCLR = (1UL << pwmContext[i].pin);
}
NRF_TIMER1->TASKS_CLEAR = 1;//restart count
}

NRF_TIMER1->EVENTS_COMPARE[0] = 0x0UL;
NRF_TIMER1->EVENTS_COMPARE[0] = 0x0UL;//restart cpimying (this gives us more control over frequency and resolution)
}

for (int i = 0; i < PWM_COUNT; i++) {
for (int i = 0; i < PWM_CH_COUNT; i++) {
if (NRF_TIMER1->EVENTS_COMPARE[pwmContext[i].event]) {
if (pwmContext[i].pin != PIN_FREE && pwmContext[i].value != 255) {
NRF_GPIO->OUTCLR = (1UL << pwmContext[i].pin);
if (pwmContext[i].pin != PIN_FREE) {
if (pwmContext[i].value != (1<<writeResolution)-1)
NRF_GPIO->OUTCLR = (1UL << pwmContext[i].pin);
else
NRF_GPIO->OUTSET = (1UL << pwmContext[i].pin);
}

NRF_TIMER1->EVENTS_COMPARE[pwmContext[i].event] = 0x0UL;
}
}
}

void TIMER2_IRQHandler(void)
{
if (NRF_TIMER2->EVENTS_COMPARE[0]) {
for (int i = PWM_CH_COUNT; i < PWM_COUNT; i++) {
if (pwmContext[i].pin != PIN_FREE) {
if(pwmContext[i].value != 0)
NRF_GPIO->OUTSET = (1UL << pwmContext[i].pin);
else
NRF_GPIO->OUTCLR = (1UL << pwmContext[i].pin);
}
NRF_TIMER2->TASKS_CLEAR = 1;//restart count
}
NRF_TIMER2->EVENTS_COMPARE[0] = 0x0UL;
}

for (int i = PWM_CH_COUNT; i < PWM_COUNT; i++) {
if (NRF_TIMER2->EVENTS_COMPARE[pwmContext[i].event]) {
if (pwmContext[i].pin != PIN_FREE) {
if (pwmContext[i].value != (1<<writeResolution)-1)
NRF_GPIO->OUTCLR = (1UL << pwmContext[i].pin);
else
NRF_GPIO->OUTSET = (1UL << pwmContext[i].pin);
}
NRF_TIMER2->EVENTS_COMPARE[pwmContext[i].event] = 0x0UL;
}
}
}

#ifdef __cplusplus
}
#endif
Expand Down