mbed library sources
Dependents: frdm_kl05z_gpio_test
Fork of mbed-src by
Diff: targets/hal/TARGET_NORDIC/TARGET_NRF51822/pwmout_api.c
- Revision:
- 229:9bd26d142f33
- Parent:
- 227:7bd0639b8911
- Child:
- 250:a49055e7a707
diff -r 85a676113daa -r 9bd26d142f33 targets/hal/TARGET_NORDIC/TARGET_NRF51822/pwmout_api.c --- a/targets/hal/TARGET_NORDIC/TARGET_NRF51822/pwmout_api.c Thu Jun 12 10:15:07 2014 +0100 +++ b/targets/hal/TARGET_NORDIC/TARGET_NRF51822/pwmout_api.c Thu Jun 12 14:45:07 2014 +0100 @@ -19,8 +19,9 @@ #include "pinmap.h" #include "error.h" -#define NO_PWMS 2 - +#define NO_PWMS 3 +#define TIMER_PRECISION 4 //4us ticks +#define TIMER_PRESCALER 6 //4us ticks = 16Mhz/(2**6) static const PinMap PinMap_PWM[] = { {p0, PWM_1, 1}, {p1, PWM_1, 1}, @@ -58,71 +59,56 @@ NRF_TIMER2 }; -uint8_t PWM_taken[NO_PWMS] = {0,0}; -uint16_t PERIOD[NO_PWMS] = {2500,2500};//20ms -uint16_t PULSE_WIDTH[NO_PWMS] = {1,1};//set to 1 instead of 0 -uint16_t ACTUAL_PULSE[NO_PWMS] = {0,0}; +uint16_t PERIOD = 20000/TIMER_PRECISION;//20ms +uint8_t PWM_taken[NO_PWMS] = {0,0,0}; +uint16_t PULSE_WIDTH[NO_PWMS] = {1,1,1};//set to 1 instead of 0 +uint16_t ACTUAL_PULSE[NO_PWMS] = {0,0,0}; /** @brief Function for handling timer 2 peripheral interrupts. */ #ifdef __cplusplus extern "C" { -#endif +#endif void TIMER2_IRQHandler(void) { - static uint16_t CCVal1 = 2501; - static uint16_t CCVal2 = 2501; + NRF_TIMER2->EVENTS_COMPARE[3] = 0; + NRF_TIMER2->CC[3] = PERIOD; - if ((NRF_TIMER2->EVENTS_COMPARE[1] != 0) && - ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE1_Msk) != 0)){ - - NRF_TIMER2->CC[0] = CCVal1; - NRF_TIMER2->EVENTS_COMPARE[1] = 0; - NRF_TIMER2->CC[1] = (NRF_TIMER2->CC[1] + PERIOD[0]); + if(PWM_taken[0]){ + NRF_TIMER2->CC[0] = PULSE_WIDTH[0]; + } + if(PWM_taken[1]){ + NRF_TIMER2->CC[1] = PULSE_WIDTH[1]; + } + if(PWM_taken[2]){ + NRF_TIMER2->CC[2] = PULSE_WIDTH[2]; + } + + NRF_TIMER2->TASKS_START = 1; - CCVal1 = NRF_TIMER2->CC[1] + PULSE_WIDTH[0]; - } - if ((NRF_TIMER2->EVENTS_COMPARE[3] != 0) && - ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE3_Msk) != 0)){ - - NRF_TIMER2->CC[2] = CCVal2; - NRF_TIMER2->EVENTS_COMPARE[3] = 0; - NRF_TIMER2->CC[3] = (NRF_TIMER2->CC[3] + PERIOD[1]); - - CCVal2 = NRF_TIMER2->CC[3] + PULSE_WIDTH[1]; - } } #ifdef __cplusplus } -#endif +#endif /** @brief Function for initializing the Timer peripherals. */ void timer_init(uint8_t pwmChoice) { - NRF_TIMER_Type *timer = Timers[pwmChoice/2]; - if(!(pwmChoice%2)){ + NRF_TIMER_Type *timer = Timers[0]; + timer->TASKS_STOP = 0; + + if(pwmChoice == 0){ timer->POWER = 0; - timer->POWER = 1; - timer->MODE = TIMER_MODE_MODE_Timer; + timer->POWER = 1; + timer->MODE = TIMER_MODE_MODE_Timer; timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; - timer->PRESCALER = 7;//8us ticks + timer->PRESCALER = TIMER_PRESCALER; + timer->CC[3] = PERIOD; } - if(pwmChoice%2){ - timer->CC[2] = PERIOD[pwmChoice] + PULSE_WIDTH[pwmChoice]; - timer->CC[3] = PERIOD[pwmChoice]; - - // Interrupt setup. - timer->INTENSET = (TIMER_INTENSET_COMPARE3_Enabled << TIMER_INTENSET_COMPARE3_Pos); - } - else{ - timer->CC[0] = PERIOD[pwmChoice] + PULSE_WIDTH[pwmChoice]; - timer->CC[1] = PERIOD[pwmChoice]; - - // Interrupt setup. - timer->INTENSET |= (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos); - } + timer->CC[pwmChoice] = PULSE_WIDTH[pwmChoice]; + //high priority application interrupt NVIC_SetPriority(TIMER2_IRQn, 1); NVIC_EnableIRQ(TIMER2_IRQn); @@ -149,35 +135,35 @@ /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ __NOP(); __NOP(); - __NOP(); + __NOP(); /* Launch the task to take the GPIOTE channel output to the desired level */ NRF_GPIOTE->TASKS_OUT[channel_number] = 1; - /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly. + /* Finally configure the channel as the caller expects. If OUTINIT works, the channel is configured properly. If it does not, the channel output inheritance sets the proper level. */ NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | ((uint32_t)pin << GPIOTE_CONFIG_PSEL_Pos) | ((uint32_t)GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) | - ((uint32_t)GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos); + ((uint32_t)GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos);// ((uint32_t)GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos);// /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */ __NOP(); __NOP(); - __NOP(); + __NOP(); } /** @brief Function for initializing the Programmable Peripheral Interconnect peripheral. */ static void ppi_init(uint8_t pwm) { -//using ppi channels 0-3 (0-7 are available) +//using ppi channels 0-7 (only 0-7 are available) uint8_t channel_number = 2*pwm; - NRF_TIMER_Type *timer = Timers[pwm/2]; + NRF_TIMER_Type *timer = Timers[0]; // Configure PPI channel 0 to toggle ADVERTISING_LED_PIN_NO on every TIMER1 COMPARE[0] match NRF_PPI->CH[channel_number].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[pwm]; NRF_PPI->CH[channel_number+1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[pwm]; - NRF_PPI->CH[channel_number].EEP = (uint32_t)&timer->EVENTS_COMPARE[channel_number-(4*(channel_number/4))]; - NRF_PPI->CH[channel_number+1].EEP = (uint32_t)&timer->EVENTS_COMPARE[channel_number+1-(4*(channel_number/4))]; + NRF_PPI->CH[channel_number].EEP = (uint32_t)&timer->EVENTS_COMPARE[pwm]; + NRF_PPI->CH[channel_number+1].EEP = (uint32_t)&timer->EVENTS_COMPARE[3]; // Enable PPI channels. NRF_PPI->CHEN |= (1 << channel_number) @@ -214,9 +200,8 @@ // determine the channel uint8_t pwmOutSuccess = 0; PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); - + MBED_ASSERT(pwm != (PWMName)NC); - if(PWM_taken[(uint8_t)pwm]){ for(uint8_t i = 1; !pwmOutSuccess && (i<NO_PWMS) ;i++){ @@ -261,30 +246,37 @@ void pwmout_write(pwmout_t* obj, float value) { uint16_t oldPulseWidth; + NRF_TIMER2->EVENTS_COMPARE[3] = 0; + NRF_TIMER2->TASKS_STOP = 1; + if (value < 0.0f) { value = 0.0; } else if (value > 1.0f) { value = 1.0; - } + } oldPulseWidth = ACTUAL_PULSE[obj->pwm]; - ACTUAL_PULSE[obj->pwm] = PULSE_WIDTH[obj->pwm] = value* PERIOD[obj->pwm]; + ACTUAL_PULSE[obj->pwm] = PULSE_WIDTH[obj->pwm] = value* PERIOD; if(PULSE_WIDTH[obj->pwm] == 0){ PULSE_WIDTH[obj->pwm] = 1; - setModulation(obj,0,0); + setModulation(obj,0,0); } - else if(PULSE_WIDTH[obj->pwm] == PERIOD[obj->pwm]){ - PULSE_WIDTH[obj->pwm] = PERIOD[obj->pwm]-1; + else if(PULSE_WIDTH[obj->pwm] == PERIOD){ + PULSE_WIDTH[obj->pwm] = PERIOD-1; setModulation(obj,0,1); } - else if( (oldPulseWidth == 0) || (oldPulseWidth == PERIOD[obj->pwm]) ){ - setModulation(obj,1,oldPulseWidth == PERIOD[obj->pwm]); - } + else if( (oldPulseWidth == 0) || (oldPulseWidth == PERIOD) ){ + setModulation(obj,1,oldPulseWidth == PERIOD); + } + + NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk; + NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk; + NRF_TIMER2->TASKS_START = 1; } float pwmout_read(pwmout_t* obj) { - return ((float)PULSE_WIDTH[obj->pwm]/(float)PERIOD[obj->pwm]); + return ((float)PULSE_WIDTH[obj->pwm]/(float)PERIOD); } void pwmout_period(pwmout_t* obj, float seconds) { @@ -297,18 +289,24 @@ // Set the PWM period, keeping the duty cycle the same. void pwmout_period_us(pwmout_t* obj, int us) { - uint32_t periodInTicks = us/8; + uint32_t periodInTicks = us/TIMER_PRECISION; + + NRF_TIMER2->EVENTS_COMPARE[3] = 0; + NRF_TIMER2->TASKS_STOP = 1; if(periodInTicks>((1<<16) -1)) { - PERIOD[obj->pwm] = (1<<16 )-1;//262ms + PERIOD = (1<<16 )-1;//131ms } else if(periodInTicks<5){ - PERIOD[obj->pwm] = 5; + PERIOD = 5; } else{ - PERIOD[obj->pwm] =periodInTicks; + PERIOD =periodInTicks; } + NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk; + NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk; + NRF_TIMER2->TASKS_START = 1; } void pwmout_pulsewidth(pwmout_t* obj, float seconds) { @@ -320,20 +318,26 @@ } void pwmout_pulsewidth_us(pwmout_t* obj, int us) { - uint32_t pulseInTicks = us/8; + uint32_t pulseInTicks = us/TIMER_PRECISION; uint16_t oldPulseWidth = ACTUAL_PULSE[obj->pwm]; + NRF_TIMER2->EVENTS_COMPARE[3] = 0; + NRF_TIMER2->TASKS_STOP = 1; + ACTUAL_PULSE[obj->pwm] = PULSE_WIDTH[obj->pwm] = pulseInTicks; if(PULSE_WIDTH[obj->pwm] == 0){ PULSE_WIDTH[obj->pwm] = 1; - setModulation(obj,0,0); + setModulation(obj,0,0); } - else if(PULSE_WIDTH[obj->pwm] == PERIOD[obj->pwm]){ - PULSE_WIDTH[obj->pwm] = PERIOD[obj->pwm]-1; + else if(PULSE_WIDTH[obj->pwm] == PERIOD){ + PULSE_WIDTH[obj->pwm] = PERIOD-1; setModulation(obj,0,1); } - else if( (oldPulseWidth == 0) || (oldPulseWidth == PERIOD[obj->pwm]) ){ - setModulation(obj,1,oldPulseWidth == PERIOD[obj->pwm]); - } + else if( (oldPulseWidth == 0) || (oldPulseWidth == PERIOD) ){ + setModulation(obj,1,oldPulseWidth == PERIOD); + } + NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE3_Msk; + NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk | TIMER_SHORTS_COMPARE3_STOP_Msk; + NRF_TIMER2->TASKS_START = 1; }