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

nrf51822 PWM with softdevice and ppi

I am using nRF51822 to generate 3K HZ PWM signal for a buzzer. I read other people's question and try it.But as far i can't solve this issue.Please help.

At first i use the simplest way,use for loop and delay. Someone said that when softdevice enable,in some interval time will be effected(i forget the word, sorry). It's look like the same circumstances.The PWM signal sometimes display wrong period,like something have affect the waveform.I guess ,it will be some relation with BLE?

SO i try another way.I copy the code from the example project pwm_example and do some change.It works's well.But when i use it with softdevice ,here comes the same trouble. It uses PPI ,i think it can avoid BLE or other effect,but it's not.

Could someone give me some suggestion?Thank you. Below it's my code.Please help. Use S110 .keil

void TIMER2_IRQHandler(void) { static bool cc0_turn = false; /**< Keeps track of which CC register to be used. */

if ((NRF_TIMER2->EVENTS_COMPARE[1] != 0) && 
   ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE1_Msk) != 0))
{
    // Sets the next CC1 value
    NRF_TIMER2->EVENTS_COMPARE[1] = 0;
    //NRF_TIMER2->CC[1]             = (NRF_TIMER2->CC[1] + MAX_SAMPLE_LEVELS);
		NRF_TIMER2->CC[1]             = (NRF_TIMER2->CC[1] + 83);

    // Every other interrupt CC0 and CC2 will be set to their next values.
       uint32_t next_sample = 40;
    if (cc0_turn)
    {
        NRF_TIMER2->CC[0] = NRF_TIMER2->CC[1] + next_sample;
    }
    else
    {
        NRF_TIMER2->CC[2] = NRF_TIMER2->CC[1] + next_sample;
    }
    // Next turn the other CC will get its value.
    cc0_turn = !cc0_turn;
}

}

/** @brief Function for initializing the Timer 2 peripheral. */ void timer2_init(void) { // Start 16 MHz crystal oscillator .

NRF_TIMER2->MODE      = TIMER_MODE_MODE_Timer;
NRF_TIMER2->BITMODE   = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
NRF_TIMER2->PRESCALER = TIMER_PRESCALERS;

// Clears the timer, sets it to 0.
NRF_TIMER2->TASKS_CLEAR = 1;

// Load the initial values to TIMER2 CC registers.

N RF_TIMER2->CC[0] = MAX_SAMPLE_LEVELS + next_sample_get(); NRF_TIMER2->CC[1] = MAX_SAMPLE_LEVELS;

// CC2 will be set on the first CC1 interrupt.
NRF_TIMER2->CC[2] = 0;

// Interrupt setup.
NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);

}

/** @brief Function for initializing the GPIO Tasks/Events peripheral. */ void gpiote_init(void) { // Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output.

nrf_gpio_cfg_output(22);


// @note Only one GPIOTE task can be connected to an output pin.
nrf_gpiote_task_config(0, 22, \
                       NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);

}

/** @brief Function for initializing the Programmable Peripheral Interconnect peripheral. */ void ppi_init(void) {

sd_ppi_channel_assign(0, &(NRF_TIMER2->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[0]));
sd_ppi_channel_assign(1, &(NRF_TIMER2->EVENTS_COMPARE[1]), &(NRF_GPIOTE->TASKS_OUT[0]));
sd_ppi_channel_assign(3, &(NRF_TIMER2->EVENTS_COMPARE[2]), &(NRF_GPIOTE->TASKS_OUT[0]));

		sd_ppi_channel_enable_set(PPI_CHEN_CH0_Msk);
		sd_ppi_channel_enable_set(PPI_CHEN_CH1_Msk);
		sd_ppi_channel_enable_set(PPI_CHEN_CH2_Msk);

}

gpiote_init();

ppi_init();

timer2_init();

sd_nvic_SetPriority(TIMER2_IRQn,3);

sd_nvic_EnableIRQ(TIMER2_IRQn);

leds_init();//BLE LED

timers_init();

buttons_init();

uart_init();

	ble_stack_init(); 

	gap_params_init();

	services_init();

	advertising_init();

         conn_params_init();

         sec_params_init();

	adc_init();

	advertising_start();
Parents
  • What you're trying to do here isn't going to work. Yes you are using PPI to actually toggle the pin to make each cycle of your waveform, which works independent of the softdevice, but you are relying on the TIMER2 interrupt to rewrite new values into the TIMER2 registers for the next part of the waveform after every toggle - which is just as bad as using the timer to generate the waveform in the first place. The softdevice is going to randomly delay timer interrupts for up to milliseconds at a time, so by the time your interrupt handler is called it may be many ticks later (I don't know because I don't know what your prescalar value is so I don't know how long '40 ticks' is).

    I would assume looking at this code that you get huge gaps in the waveform where the timer has already counted past the value you want to set and possibly it's even more random than that and CC[0], CC[1] and CC[2] get totally out of sync.

    You can't get the kind of control you're looking for here with the softdevice running, where you can change the timer values every time. You can set the ppi channels up to generate a certain frequency with a certain duty cycle, by having them clear the timer at the end of each cycle, you can change that cycle on an occasional basis, but that's about the best you can do.

    It doesn't help that you have your IRQ priority set to 3, but even if you set it to 1, the highest you're allowed with the softdevice, you're still going to have problems,

  • Thank you for your answer.I made a try.Like your suggestion,set the ppi channels up to generate a waveform.SET CC[0], CC[1], CC[2].it comes a huge gaps between next wave.It needs to clear the timer.But Can PPI function clear the timer?it only can connect to gpiote's task?And i try to clear the timer in CC[3].CC[3]'s interrupt enabled, but it seems not going to the handler.Where i can't understand is that,I only assigned event CC[O]~CC[2] to PPI[0]~PPI[2].Doesn't assigned CC[3]'s event to any PPI function.Did i do something wrong that i don't noticed?

Reply
  • Thank you for your answer.I made a try.Like your suggestion,set the ppi channels up to generate a waveform.SET CC[0], CC[1], CC[2].it comes a huge gaps between next wave.It needs to clear the timer.But Can PPI function clear the timer?it only can connect to gpiote's task?And i try to clear the timer in CC[3].CC[3]'s interrupt enabled, but it seems not going to the handler.Where i can't understand is that,I only assigned event CC[O]~CC[2] to PPI[0]~PPI[2].Doesn't assigned CC[3]'s event to any PPI function.Did i do something wrong that i don't noticed?

Children
No Data
Related