This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PPI CHANNEL USED TO generate pulse wave

Hi All,

I am using NRF51822 chip pca10001 development board.

I flashed ble_app_hrs application to the board.

I configure 3 channel for PPI.

static void ppi_init(void)
{
  
  uint32_t err_code;

	 err_code = sd_ppi_channel_assign(0,
                                     &(NRF_TIMER2->EVENTS_COMPARE[0]),
                                     &(NRF_GPIOTE->TASKS_OUT[0]));
    APP_ERROR_CHECK(err_code);
	
		
		err_code = sd_ppi_channel_assign(1,
                                     &(NRF_TIMER2->EVENTS_COMPARE[1]),
                                     &(NRF_GPIOTE->TASKS_OUT[0]));
    APP_ERROR_CHECK(err_code);
	
		err_code = sd_ppi_channel_assign(2,
                                     &(NRF_TIMER2->EVENTS_COMPARE[1]),
                                     &(NRF_TIMER2->TASKS_CLEAR));
    APP_ERROR_CHECK(err_code);
}

I configure gpiote task for channel 0.

void gpiote_channel_0_set(void)
{
	 nrf_gpiote_task_config(0, AC_OUT_PIN, NRF_GPIOTE_POLARITY_TOGGLE, \
                           NRF_GPIOTE_INITIAL_VALUE_HIGH);
}

Now i enable all 3 channels.

__inline void ppi_enable(void)
{
		uint32_t err_code;
		err_code = sd_ppi_channel_enable_set( (PPI_CHEN_CH0_Msk) |  (PPI_CHEN_CH1_Msk)| (PPI_CHEN_CH2_Msk));
    APP_ERROR_CHECK(err_code)
}

The timer2 is intialised as fallows.

static void timer2_init(void)
{
		
   /* Start 16 MHz crystal oscillator */
    NRF_CLOCK->EVENTS_HFCLKSTARTED    = 0;
    NRF_CLOCK->TASKS_HFCLKSTART       = 1;
    /* Wait for the external oscillator to start up */
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)       
    {
        // Do nothing.
    }
		NRF_TIMER2->TASKS_CLEAR = 1;
    NRF_TIMER2->MODE        = TIMER_MODE_MODE_Timer;
		NRF_TIMER2->PRESCALER   = 4;

    /* Load initial values to Timer 2 CC registers */
    /* Set initial CC0 value to anything > 1 */
		NRF_TIMER2->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
	
}

Now i am updating timer2 cc0 value and cc1 value from BLE characteristic interrupt and then i start the timer.

But for constant cc0 and cc1 value its giving two waveform.

ex- cc0=1000(1ms), cc1=10000(9ms);

i am getting two wave

  1. 1ms on and 9ms off.

  2. 1ms off and 9ms on.

I need to get only first wave all the time if i write constant value to ble characteristic

Could any one tell me how to solve this?. ( I need to do this with PPI only).

I tried by reinitialising all ppi and gpiote for every ble characteristic interrupt then also it dont work.

Kindly tell me what is the issue.

Regards Punit

  • Hi ALL,

    Here i have tried without ble but there also getting inverted ouput .

    I also tried for every power reset of the board , i am getting two output.

    Here is my code :

        #include <stdbool.h>
    #include <stdint.h>
    #include "nrf_delay.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_gpiote.h"
    
    #define AC_OUT_PIN 5
    /**
     * @brief Function for application main entry.
     */
     void gpiote0_timer_dis(void)
    {
    	NRF_GPIOTE->CONFIG[0] = (GPIOTE_CONFIG_MODE_Disabled << GPIOTE_CONFIG_MODE_Pos);
    	NRF_GPIOTE->CONFIG[2] = (GPIOTE_CONFIG_MODE_Disabled << GPIOTE_CONFIG_MODE_Pos);
    	NRF_TIMER2->TASKS_STOP = 1;
    	NVIC_DisableIRQ(GPIOTE_IRQn);
    }
    void gpiote_channel_0_set(void)
    {
    	 nrf_gpiote_task_config(0, AC_OUT_PIN, NRF_GPIOTE_POLARITY_TOGGLE, \
                               NRF_GPIOTE_INITIAL_VALUE_HIGH);
    }
    
    static void timer2_init(void)
    {
    		
    //   /* Start 16 MHz crystal oscillator */
    //    NRF_CLOCK->EVENTS_HFCLKSTARTED    = 0;
    //    NRF_CLOCK->TASKS_HFCLKSTART       = 1;
    //    /* Wait for the external oscillator to start up */
    //    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)       
    //    {
    //        // Do nothing.
    //    }
    		NRF_TIMER2->TASKS_CLEAR = 1;
        NRF_TIMER2->MODE        = TIMER_MODE_MODE_Timer;
    		NRF_TIMER2->PRESCALER   = 4;
    
        /* Load initial values to Timer 2 CC registers */
        /* Set initial CC0 value to anything > 1 */
      
    		NRF_TIMER2->CC[0]       = 8000;//(32);
    		//NRF_TIMER2->CC[1] = 10000;//10ms
    		NRF_TIMER2->BITMODE   = TIMER_BITMODE_BITMODE_16Bit;
    		
       // NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos);
    }
    static void ppi_init(void)
    {
        // Configure PPI channel 0 to toggle GPIO_OUTPUT_PIN on every TIMER0 COMPARE[0] match (200 ms)
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
    	
    //		NRF_PPI->CH[1].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[1];
    //    NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
    
    //		NRF_PPI->CH[2].EEP =  (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[1];
    //		NRF_PPI->CH[2].TEP =  (uint32_t)&NRF_TIMER2->TASKS_CLEAR;
    //    
    		NRF_PPI->CH[1].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[2];
        NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
    
    		NRF_PPI->CH[2].EEP =  (uint32_t)&NRF_GPIOTE->EVENTS_IN[2];
    		NRF_PPI->CH[2].TEP =  (uint32_t)&NRF_TIMER2->TASKS_CLEAR;
        
                                         
        // Enable PPI channel 0
        NRF_PPI->CHEN = ((PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos) | (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos)|(PPI_CHEN_CH2_Enabled << PPI_CHEN_CH2_Pos));
    }
    
    __inline void ppi_enable(void)
    {
    	NRF_PPI->CHEN = ((PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos) | (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos)|(PPI_CHEN_CH2_Enabled << PPI_CHEN_CH2_Pos));
    	
    }
    __inline static void ppi_disable(void)
    {
    	NRF_PPI->CHEN = ((PPI_CHEN_CH0_Disabled << PPI_CHEN_CH0_Pos) | (PPI_CHEN_CH1_Disabled << PPI_CHEN_CH1_Pos)|(PPI_CHEN_CH2_Enabled << PPI_CHEN_CH2_Pos));
    	
    }
    static void gpiote_init(void)
    {
        // Enable interrupt on input 1 event.
        NRF_GPIOTE->INTENSET = GPIOTE_INTENSET_IN3_Msk |GPIOTE_INTENSET_IN2_Msk;
    		nrf_gpiote_event_config(3, 16, NRF_GPIOTE_POLARITY_HITOLO);
    		nrf_gpiote_event_config(2, 20, NRF_GPIOTE_POLARITY_LOTOHI);
     
        // Configure GPIOTE channel 0 to generate event on input pin low-to-high transition.
        //nrf_gpiote_event_config(4, 16, NRF_GPIOTE_POLARITY_TOGGLE);
    	  NVIC_EnableIRQ(GPIOTE_IRQn);
    }
    
    
    void GPIOTE_IRQHandler(void)
    {
    	if(NRF_GPIOTE->EVENTS_IN[3]==1)
    	{
    		nrf_gpio_pin_toggle(18);
    		NRF_GPIOTE->EVENTS_IN[3]=0;
    		gpiote0_timer_dis();	
    		gpiote_channel_0_set();
    		gpiote_init();
    		timer2_init();
    		ppi_init();
    		nrf_gpio_pin_clear(AC_OUT_PIN);
    		NRF_TIMER2->TASKS_START=1;
    
    	}
    	if(NRF_GPIOTE->EVENTS_IN[2]==1)
    	{
    		nrf_gpio_pin_toggle(19);
    		NRF_GPIOTE->EVENTS_IN[2]=0;
    	}	
    }
    
    
    int main(void)
    {
    	nrf_gpio_pin_set(AC_OUT_PIN);
    		int i=0;
        // Configure LED-pins as outputs
    		nrf_gpio_cfg_input(16,GPIO_PIN_CNF_PULL_Pullup );
    		nrf_gpio_cfg_input(17,GPIO_PIN_CNF_PULL_Disabled);
    		nrf_gpio_cfg_input(20,GPIO_PIN_CNF_PULL_Disabled);
        nrf_gpio_cfg_output(LED_0);
        nrf_gpio_cfg_output(LED_1);
    		nrf_gpio_cfg_output(AC_OUT_PIN);
        nrf_gpio_pin_set(AC_OUT_PIN);
    		gpiote_init();	
        // LED 0 and LED 1 blink alternately.
    		
    	  gpiote_channel_0_set();
    		timer2_init();
    		ppi_init();
    		nrf_gpio_pin_set(AC_OUT_PIN);
    		NRF_TIMER2->TASKS_START=1;
    		
    		while (true)
        {
    	
            
        }
    }
    

    Here my gpio interrupt(pin 20) is coming for every 10ms.

    Since CC0=8000 , i should get always PWM (8ms on and 2ms off). But for every power reset i am getting two PWM. 1.sometime PWM of 2ms on and 8ms off. 2.sometime PWM of 8ms on and 2ms off.

    If any one know what will be the issue , kindly let me know the problem.

    I need to use PPI only instead of interrupt handler.

    Regards Punith

  • if CC0 and CC1 are constant and not changing at all, i have verified that the signal does not invert using your code. This is because you are clearing the timer after CC[1] toggle.

    Anyways if you are updating the CC values in characteristic event then try this

    1. Make sure that CC[1] is the last toggle that has happened, you can achieve this by stopping the timer and comparing the capture value to be less than CC[0].

    2. now you can safely update the CC values and start the timer again.

    The problem of reversing signal happens when you update the CC values after CC[0] event but before CC[1] event.

    Edit:

    attaching my main.c

  • Hi Aryan,

    Thanks for your reply, the problem that i solved by reinitializing timer2 for every ble characteristic interrupt. Now it is working fine. Anyway i will try your method also.

    I also facing same issue while gpiote event instead of CC1 that i posted in my second comment.there i am getting two different output for every power reset.

    Could you tell me what is issue.

  • This could be because your GPIOTE interrupt handler is called depending on two input pins

    nrf_gpiote_event_config(3, 16, NRF_GPIOTE_POLARITY_HITOLO);
    nrf_gpiote_event_config(2, 20, NRF_GPIOTE_POLARITY_LOTOHI);
    

    So the inverse is happening depending on which input has triggered the GPIOTE interrupt handler first. If you disable one of these two pins, you will see that the signal will not change on power on reset.

  • Hi Aryan,

    I am using PCA10001 board to test the code. so 16th pin is a button which will generate event only when you press the button, so that is not an issue.

    I also toggling gpio 5 based on event of 20th pin so 16th pin is not at all issue.

    Could you let me know what may be other issue.

    Regards Punith

Related