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

GPIOTE PWM config question

Hi, in the (not great) mBed PWM driver, when setting up GPIOTE to toggle the output pin they do this:

/** @brief Function for initializing the GPIO Tasks/Events peripheral.
 */
void gpiote_init(PinName pin, uint8_t channel_number)
{
    // Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as an output.
    NRF_GPIO->PIN_CNF[pin] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
                            | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
                            | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
                            | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
                            | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
    NRF_GPIO->OUTCLR = (1UL << pin);
    // Configure GPIOTE channel 0 to toggle the PWM pin state
    // @note Only one GPIOTE task can be connected to an output pin.
    /* Configure channel to Pin31, not connected to the pin, and configure as a tasks that will set it to proper level */
    NRF_GPIOTE->CONFIG[channel_number] = (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
                                         (31UL << GPIOTE_CONFIG_PSEL_Pos) |
                                         (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos);
    /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
    __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.
       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_High <<
                                                                                                             // GPIOTE_CONFIG_OUTINIT_Pos);//

    /* Three NOPs are required to make sure configuration is written before setting tasks or getting events */
    __NOP();
    __NOP();
    __NOP();
}

Can someone explain why they set pin 31 (which doesn't exist) to low using GPIOTE? What won't work if you only do the final CONFIG? Also what do the mean by If OUTINIT works? Does it not always work?

  • All I can say is that I've never done anything like that and never had an issue, the nordic driver code doesn't do anything like that, including the three NOPs, I've never heard of anything using one pin before using the one you want, P0.31 does exist (just not on the QFN48) and I've never head of an issue with OUTINIT, well apart from it is possible to get a one clock cycle blip when you configure the GPIOTE, but you can avoid that by setting the pin to the right level before you set it up.

    I really don't know what issue they thought they were solving with that piece of code.

  • Ah I think I understand a bit now. Maybe. When they connect GPIOTE to the pin it will immediately set the pin to the internal GPIOTE level, which may be high, and therefore cause an unwanted pulse. Therefore to get the internal GPIOTE level low they disconnect it from any pins and trigger the HiToLo task. Then the internal level is low so when the reconnect it to the target pin it will stay low. This is just a guess but it makes sense to me.

  • That's possible. I actually have an open case for a one-cycle pin blip like that, however it wasn't so simple and only showed up when a number of channels were being used at the same time and I never got it pinned down. We did discuss the possibility of it being the internal GPIOTE level, but testing that exact thing didn't show it up. That may be a belt-and-suspenders bit of code however to try and ensure everything possible has been done before the real pin is connected to ensure there's no chance of a blip.

    Wouldn't work on the BGA chip version, that does have P0.31 available for use.

  • This is a workaround for a known anomaly on some of the nrf51 chips, where the initial value for GPIOTE output after configuration can be undefined.

    Take a look at PAN 9 at infocenter.nordicsemi.com/.../nRF51822-pan_v2.3.pdf To find the explanation and whether your chipset is affected by the said issue.

Related