Level based control of GPIOTE



Hi,

I have a comparator acting as a UVLO, it connects to a NRF52 pin with a pull-up. The comparator also pulls down two other circuits using a diode, which in turn are connected to other NRF52 pins using pull-ups. It works well.

I'd like if possible to remove the diodes and connecting the UVLO signal via GPIO Event through PPI and controlling the other two pins via GPIOTE SET and CLEAR.

What I can't determine from the datasheet is whether once the initial output of GPIOTE is set if PPI & GPIOTE are fully async to the clock in which case it would be like level control where they couldn't miss an event, or whether the clock is working to determine the event (like a D gate) in which case potentially the event could be missed.

It is only a small optimisation but one I thought I'd look at as I was contemplating moving the comparator to the built-in one.

Andrew

Parents
  • Hi,

     

    What I can't determine from the datasheet is whether once the initial output of GPIOTE is set if PPI & GPIOTE are fully async to the clock in which case it would be like level control where they couldn't miss an event, or whether the clock is working to determine the event (like a D gate) in which case potentially the event could be missed.

    If I understand the scenario correct, you want two IN channels to, based on falling/rising edge-triggering, SET/CLR two other GPIOs. Please correct me if I'm mistaken.

    GPIOTE IN/OUT, when connected through PPI, will be synchronous to the internal 16 MHz peripheral clock.

    If more than one operation occurs on the same clock cycle, one event can be postponed to the next clock cycle.

     

    There is however one scenario that can occur, which is errata #155:

    https://infocenter.nordicsemi.com/topic/errata_nRF52810_Rev3/ERR/nRF52810/Rev3/latest/anomaly_810_155.html?cp=5_5_1_0_1_12

     

    If you have two GPIOTE IN channels occurring within the timed scope (ie. < 1.3 us apart), you will hit this errata. 

    The side-effect of this errata workaround is higher current consumption, as the peripheral clock tree will be kept in sleep mode.

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    What I can't determine from the datasheet is whether once the initial output of GPIOTE is set if PPI & GPIOTE are fully async to the clock in which case it would be like level control where they couldn't miss an event, or whether the clock is working to determine the event (like a D gate) in which case potentially the event could be missed.

    If I understand the scenario correct, you want two IN channels to, based on falling/rising edge-triggering, SET/CLR two other GPIOs. Please correct me if I'm mistaken.

    GPIOTE IN/OUT, when connected through PPI, will be synchronous to the internal 16 MHz peripheral clock.

    If more than one operation occurs on the same clock cycle, one event can be postponed to the next clock cycle.

     

    There is however one scenario that can occur, which is errata #155:

    https://infocenter.nordicsemi.com/topic/errata_nRF52810_Rev3/ERR/nRF52810/Rev3/latest/anomaly_810_155.html?cp=5_5_1_0_1_12

     

    If you have two GPIOTE IN channels occurring within the timed scope (ie. < 1.3 us apart), you will hit this errata. 

    The side-effect of this errata workaround is higher current consumption, as the peripheral clock tree will be kept in sleep mode.

     

    Kind regards,

    Håkon

Children
  • Hi,

    LMV393 has a propagation of 0.2us, which is 5 MHz.

    As you say it's synchronous to the 16MHz clock, so let's say at max there are 5 edges at 0.2us apart. Would PPI/GPIOTE be able to keep up driving an output pin using the SET/CLEAR events?

    It sounds like it would, so long as the propagation didn't take more than 3 clock cycles.

  • Hi,

     

    With such a high input frequency, it will be problematic for the PPI/GPIOTE to be able to handle both events. This is because the propagated delay in PPI is based on the system as a whole, and one cannot guarantee that other PPI signals does not occur within the same timeframe. Also, do you require rising and falling edge detection of these two 5 MHz signals? If yes, then it would effectively double the frequency.

     

    Kind regards,

    Håkon

  • Hi Hakon,

    I've resolved it a different way. The external comparator was due to all analog pins being used for ADC, but I've cleared one by means of some pin auxing and now have the built in comparator available.

    So without the GPIOTE pin detect I now have comparator -> ppi -> GPIOTE pin out.

    However related to the original question I must ensure the GPIOTE pin always has the correct output. My understanding is if the GPIOTE is enabled as a task after the comparator is running then the PPI wont be picked up, because it's not propagating continuously by clock. I may be wrong with this and it is a fundamental question.

    Otherwise I intend to enable GPIOTE, enable the comparator, call comparator.sample (which I think will always fire one of the events? And then only disable the GPIOTE pin, but not the task, so it should be switching correctly.

    I have to be careful as I need to disable the pin output then reconnect it transparent to the comparator output, which must always be outbound when I reenable the pin output.

    Cheers!

    Andrew

     


  • So, for some reason I thought GPIOTE PSEL had a null, it doesn't. That means I have to toggle from task to disable and vice versa sometimes, which potentially could race with the comparator output.

    So when I come to set a GPIOTE output I have to:

    a) ensure the comparator is level high
    b) set the gpiote pin high
    c) do the above atomically - the comparator can't go low between a and b.

    Some init code.

      // gpiote
      NRF_GPIOTE->CONFIG[CFG_GPIOTE_POWERMANAGER_USB] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos | CFG_PIN_POWERMANAGER_USB_ENABLE << GPIOTE_CONFIG_PSEL_Pos;
      NRF_GPIOTE->CONFIG[CFG_GPIOTE_POWERMANAGER_FRONT] = GPIOTE_CONFIG_MODE_Disabled << GPIOTE_CONFIG_MODE_Pos | CFG_PIN_POWERMANAGER_FRONT_ENABLE << GPIOTE_CONFIG_PSEL_Pos;
      NRF_GPIOTE->CONFIG[CFG_GPIOTE_POWERMANAGER_REAR] = GPIOTE_CONFIG_MODE_Disabled << GPIOTE_CONFIG_MODE_Pos | CFG_PIN_POWERMANAGER_REAR_ENABLE << GPIOTE_CONFIG_PSEL_Pos;
    
      // ppi
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_USB_BAD].EEP = (uint32_t) &NRF_COMP->EVENTS_DOWN;
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_USB_BAD].TEP = (uint32_t) &NRF_GPIOTE->TASKS_CLR[CFG_GPIOTE_POWERMANAGER_USB];
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_GOOD].EEP = (uint32_t) &NRF_COMP->EVENTS_UP;
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_GOOD].TEP = (uint32_t) &NRF_GPIOTE->TASKS_SET[CFG_GPIOTE_POWERMANAGER_FRONT];
      NRF_PPI->FORK[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_GOOD].TEP = (uint32_t) &NRF_GPIOTE->TASKS_SET[CFG_GPIOTE_POWERMANAGER_FRONT];
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_BAD].EEP = (uint32_t) &NRF_COMP->EVENTS_DOWN;
      NRF_PPI->CH[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_BAD].TEP = (uint32_t) &NRF_GPIOTE->TASKS_CLR[CFG_GPIOTE_POWERMANAGER_REAR];
      NRF_PPI->FORK[CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_BAD].TEP = (uint32_t) &NRF_GPIOTE->TASKS_CLR[CFG_GPIOTE_POWERMANAGER_REAR];
    
      NRF_PPI->CHENSET = 1 << CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_GOOD
        | 1 << CFG_PPI_POWERMANAGER_UVLO_FRONTREAR_BAD
        | 1 << CFG_PPI_POWERMANAGER_UVLO_USB_BAD;
    
      // UVLO
      NRF_COMP->REFSEL = UVLO_REFERENCE << COMP_REFSEL_REFSEL_Pos;
      NRF_COMP->TH = UVLO_HYSTERESIS << COMP_TH_THUP_Pos;
      NRF_COMP->PSEL = COMP_UVLO << COMP_PSEL_PSEL_Pos;
      NRF_COMP->ENABLE = COMP_ENABLE_ENABLE_Enabled << COMP_ENABLE_ENABLE_Pos;
      NRF_COMP->TASKS_SAMPLE = COMP_TASKS_SAMPLE_TASKS_SAMPLE_Trigger << COMP_TASKS_SAMPLE_TASKS_SAMPLE_Pos;
    
      // wait a moment for voltage to stablize
      // if it doesn't happen watchdog will reset
      while (!NRF_COMP->RESULT) {
        NRF_COMP->TASKS_SAMPLE = 1;
      };
      NRF_COMP->EVENTS_DOWN = 0;

  • Hi,

    snoopy20 said:
    So, for some reason I thought GPIOTE PSEL had a null, it doesn't. That means I have to toggle from task to disable and vice versa sometimes, which potentially could race with the comparator output.

    So when I come to set a GPIOTE output I have to:

    a) ensure the comparator is level high
    b) set the gpiote pin high
    c) do the above atomically - the comparator can't go low between a and b.

    Your code disables the CFG_GPIOTE_POWERMANGER_FRONT /_REAR channels, ie. these will not be used by the GPIOTE module at all. Is this intended?

    If you want 'n' amount of GPIOTE TASKs to occur when EVENTS_DOWN is triggered, you should configure all your GPIOTE channels as TASK.

    In your PPI configuration, you seem to .FORK with the exact same TASK EP as originally set i CH[].TEP. 

    I highly suspect that you want the triggered GPIOTE OUT tasks to be reset in the .FORK operation? ie. if EVENTS_UP occurs, set "CFG_GPIOTE_POWERMANAGER_FRONT" and SET "CFG_GPIOTE_POWERMANAGER_REAR" ? Vice-versa on the EVENTS_DOWN ?

     

    snoopy20 said:
    However related to the original question I must ensure the GPIOTE pin always has the correct output. My understanding is if the GPIOTE is enabled as a task after the comparator is running then the PPI wont be picked up, because it's not propagating continuously by clock. I may be wrong with this and it is a fundamental question.

    It is clear to me that you're using the NRF_COMP peripheral, and not a external circuit, as I initially thought. Sorry for misunderstanding.

    GPIOTE is related to TASK and EVENT system. It can be tied towards an event or task occurring and performing a specific GPIO related task, like SET/CLR.

    Please note that PPI cannot perform a logical operation, like evaluating a if/else condition. PPI is quite simple in terms of what features can be done without CPU intervention.

     

    That being said, it looks like you want to set a given "bit pattern" on each event on a total of 3 GPIOs. Could you share the wanted state(s) based on each EVENTS_* that occurs?

     

    Kind regards,

    Håkon

Related