Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PWM library simpler way for on/off (enable/disable) than the example with SDK?

Is there a way to set duty cycle before app_pwm_enable(&PWM1) call ?

Or some other simple way to switch on and off a passive buzzer signal without every time at off/on cycle to go with complex sequence for setting duty value as per pwm_library example?

Let say some app like Morse Code where the frequency will be resonance of the buzzer and duty cycle will be constant 50 (or less).

Thanks

Parents
  • Hi 

    You mean you only want to turn on/off a simple square wave where the frequency and duty cycle will always be the same?

    If this is the case it might be easier just to use a timer to generate events, and connect them to  a GPIO through the GPIOTE and PPI peripherals. 

    Then you can set the frequency simply by changing the compare value in the timer. 

    Best regards
    Torbjørn

  • Ok, I tried the gpiote example and browse documentation. But still cant find what is(are) the way once I start the square wave, to stop it , then to restart it (with minimum operations)?

    While in stopped/idle mode – is there any of those components involved:  timer, gpiote, ppi  that would consumes excessive power (in a scale for a battery operated devices) that I have to be worry about?

    Thanks

  • Hi Torbjørn,

    I just check the code you've sent before on nRF42 DK as well measure the frequency - works Ok so far.

    Could you explain  this line from you code, please:

    SOUND_TIMER->CC[2] = ((16000000 / (1 << SOUND_TIMER_PRESCALER)) + (frequency / 2)) / frequency;

    which looks initially scary ;), but simplified is

    = (16000000 / (1 << SOUND_TIMER_PRESCALER))/frequency +0.5;

    Why is this 0.5 - only to to round on the upper integer or there is something else that I'm missing?

    Thank you very much and best regards!

  • Hi

    It's just to round to the closest integer value, yes (rather than always rounding down) to ensure the frequency is as close as possible to the intended value. 

    Similar to the code snippet below from this stackoverflow case:

    unsigned int round_closest(unsigned int dividend, unsigned int divisor)
    {
        return (dividend + (divisor / 2)) / divisor;
    }

    Best regards
    Torbjørn

  • Thanks, will take a closer look at stackoverflow - good to know all issues when computer math doesn't follow standard math :)

    Regarding tutorials that you refer to in the previous post - I think I passed most valuable tutorials published there couple months ago when started actively evaluating nRF52, but didn't remember any place tutoring how to work direct with nRF registers. Let say in my particular case is more interesting what is the naming convention for all those defines that are made especially to facilitate work with registers, and in which files/locations are they. Browsed yesterday again your link to tutorials and didn't find anything new that might be related? If you know for sure that such information for working with registers is available somewhere, could  you point it or at least give me a hint what to search for, because there are tons of tutorials there and is quite possible I could miss it?

    Thank you and best regards

  • Hi 

    samsam said:
    Thanks, will take a closer look at stackoverflow - good to know all issues when computer math doesn't follow standard math :)

    It's integer math basically. When I started in Nordic we were still using 8-bit microcontrollers with only 16kB of code flash, and you didn't use float unless you really had no other choice. 

    In the nRF52 you could easily just convert to float and do the calculations in a more intuitive way, but staying with integer operations exclusively is still a bit more efficient ;)

    samsam said:
    If you know for sure that such information for working with registers is available somewhere, could  you point it or at least give me a hint what to search for, because there are tons of tutorials there and is quite possible I could miss it?

    I don't think there are any tutorials or guides for this as such. The intention behind the SDK is to provide drivers and abstractions so you don't have to access hardware directly, but I often find the hardware easier to deal with than some of the drivers ;)

    What I can give you is a link to a repository full of hardware level examples, showing how you can use most of the peripherals in the nRF52 by accessing registers only. These examples should give you a good indication to what kind of registers are available, and how to access them:

    https://github.com/andenore/NordicSnippets

    Just open the "examples" folder for all the different examples. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    I finally got some time to play with your example - it works perfect, unfortunately only standalone itself. As soon as I combined it with some my code that uses some  nrf_drv_gpiote* and the problems start:

     Those hardcoded SOUND_GPIOTE_CH 0 clashes with some of the  nrf_drv_gpiote* inits.

    How can get/ allocate a free gpiote channel and use it instead of channel 0, but also to be safe that later eventual calls to nrf_drv_gpiote_*_init will not mess with this channel,

    or

    opposite approach: use nrf_drv_gpiote_out_init to allocate a gpiote channel, but than how can hook it to ppi as the channel that nrf_drv_gpiote_out_init  allocates is somehow hidden?

    Also this timer NRF_TIMER1 that is hardcoded - is there any chance to interfere with something else? ( I have an SPI display that start behave weird after I add this code for driving a passive buzzer, but havent investigate yet if the problem is from the code or electrical noise that the buzzer spreads on the circuit 

    Thanks

Reply
  • Hi Torbjørn,

    I finally got some time to play with your example - it works perfect, unfortunately only standalone itself. As soon as I combined it with some my code that uses some  nrf_drv_gpiote* and the problems start:

     Those hardcoded SOUND_GPIOTE_CH 0 clashes with some of the  nrf_drv_gpiote* inits.

    How can get/ allocate a free gpiote channel and use it instead of channel 0, but also to be safe that later eventual calls to nrf_drv_gpiote_*_init will not mess with this channel,

    or

    opposite approach: use nrf_drv_gpiote_out_init to allocate a gpiote channel, but than how can hook it to ppi as the channel that nrf_drv_gpiote_out_init  allocates is somehow hidden?

    Also this timer NRF_TIMER1 that is hardcoded - is there any chance to interfere with something else? ( I have an SPI display that start behave weird after I add this code for driving a passive buzzer, but havent investigate yet if the problem is from the code or electrical noise that the buzzer spreads on the circuit 

    Thanks

Children
  • Hi 

    If you are using the nrf_drv_gpiote driver already I would recommend using this driver instead of accessing registers directly, like in my example. After you initialize an out channel using nrf_drv_gpiote_out_init you should be able to read out the channel index, which you can then reference in the code. 

    You should be able to check in your other drivers if they use the TIMER1 module. Maybe you can change my code to use TIMER2 instead?

    Best regards
    Torbjørn

  • Hi Torbjørn,

    Still struggle to find easy way to get gpiote channel index after  nrf_drv_gpiote_out_init (). The best I could do is from nrfx_gpiote_out_task_get(pinNo) to get the task enum and after compare swithc/case with all nrf_gpiote_tasks_t  enums to get the channel index (0-7). Any better idea?

    Is there a way to check what timers are in use while at breakpoint in debugging? This to dig in the code for the timers seems have far more chances to miss some timer definition somewhere deep buried in the code?

    Thanks

  • Hi 

    You should be able to initialize an out channel, and then just use the nrf_drv_gpiote_out_task_addr_get function to get the task address directly. Then there is no need to know the channel index. 

    Just setup the PPI task endpoint with the task address provided. 

    Regarding which timers are enabled it should be possible to check this in the sdk_config.h file, assuming the other libraries use the nrfx_timer library. 
    It will have various defines on the form TIMERx_ENABLED or NRFX_TIMERx_ENABLED, showing which timers are enabled already. 

    Please note that if you use a SoftDevice it will use TIMER0, even if this is not reflected in sdk_config.h. 

    Best regards
    Torbjørn

  • Hi, but you have in your code, that you put as example before, couple lines that using gpiote channel index? 

     NRF_GPIOTE->TASKS_CLR[SOUND_GPIOTE_CH] = 1;

    NRF_PPI->CH[SOUND_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[SOUND_GPIOTE_CH];

    NRF_PPI->CH[SOUND_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[SOUND_GPIOTE_CH];

    The only task address I could get right away is the out task I created in order to use nrf_drv_gpiote_out_init and it has same config as what you made with registers in your example?

    I by the way still didn't  clear all the mess I made with adding the code for the passive buzzer, but move one step better, by getting at least the sound working and I'm using 

    gpioteChIndex = (nrfx_gpiote_out_task_get(SS_SDK_CFG_BZR_PIN) % 48) / 4;

    But if I could rid of need of gpiote channel index would be better.

    Regards

  • Hi

    There are two functions called nrfx_gpiote_set_task_addr_get(nrfx_gpiote_pin_t pin) and nrfx_gpiote_clr_task_addr_get(nrfx_gpiote_pin_t pin)

    I believe these functions should provide the task addresses you need. 

    Best regards
    Torbjørn

Related