mbed w/ spi bug fig

Dependents:   display-puck

Fork of mbed-src by mbed official

Files at this revision

API Documentation at this revision

Comitter:
mbed_official
Date:
Thu Jun 12 14:45:07 2014 +0100
Parent:
228:85a676113daa
Child:
230:b37c24245c0d
Commit message:
Synchronized with git revision fb13a684ae512b82e9e0bc1734e0375b017708ec

Full URL: https://github.com/mbedmicro/mbed/commit/fb13a684ae512b82e9e0bc1734e0375b017708ec/

[NRF] PWM issue solved when Softdevice is running

Changed in this revision

targets/hal/TARGET_NORDIC/TARGET_NRF51822/pwmout_api.c Show annotated file Show diff for this revision Revisions of this file
--- 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;      
 }