ADC and PWM events

Hi,

I have set up the PWM to trigger the ADC via PPI. It works but now i want to verify the exact behaviour by setting a GPIO when the ADC starts a conversion and when it stops. Once the ADC has a new value it will report it via

NRF_DRV_SAADC_EVT_DONE

But how do I do know when the ADC started the task?

The ADC only has following events:

/** @brief Macro for forwarding the new implementation. */
#define NRF_DRV_SAADC_EVT_DONE          NRFX_SAADC_EVT_DONE
/** @brief Macro for forwarding the new implementation. */
#define NRF_DRV_SAADC_EVT_LIMIT         NRFX_SAADC_EVT_LIMIT
/** @brief Macro for forwarding the new implementation. */
#define NRF_DRV_SAADC_EVT_CALIBRATEDONE NRFX_SAADC_EVT_CALIBRATEDONE
/** @brief Macro for forwarding the new implementation. */
#define nrf_drv_saadc_evt_type_t        nrfx_saadc_evt_type_t
/** @brief Macro for forwarding the new implementation. */
#define nrf_drv_saadc_done_evt_t        nrfx_saadc_done_evt_t
/** @brief Macro for forwarding the new implementation. */
#define nrf_drv_saadc_limit_evt_t       nrfx_saadc_limit_evt_t
/** @brief Macro for forwarding the new implementation. */
#define nrf_drv_saadc_evt_t             nrfx_saadc_evt_t
/** @brief Macro for forwarding the new implementation. */
#define nrf_drv_saadc_event_handler_t   nrfx_saadc_event_handler_t

So I guess with the ADC this is not possible. Then I though of finding the "ADC start" with the PWM.

The PWM is set up this way:

APP_ERROR_CHECK(nrfx_pwm_init(&pwm_instance_s, &pwm_config_s, pwmHandler));

With this handler:

void pwmHandler(nrfx_pwm_evt_type_t event_type, void * p_context) {
        nrf_gpio_pin_set(gpio.pin_number);
}

But this way it would trigger on every event. So I need to specify it. Since the PWM triggers the ADC on NRF_PWM_EVENT_SEQSTARTED0 I need to check it in the handler.

nrfx_ppi_channel_assign(GENAPI_ppi_channels_as[0],
                            nrfx_pwm_event_address_get(&pwm_instance_s, NRF_PWM_EVENT_SEQSTARTED0),
                            nrfx_saadc_sample_task_get());

But the events are different:

void pwmHandler(nrfx_pwm_evt_type_t event_type, void * p_context) {
    if(event_type == NRF_PWM_EVENT_SEQSTARTED0) //left side of "==" has different event than right side
    {
        nrf_gpio_pin_set(gpio.pin_number);
    }
}

PWM event type 1 which is used for PPI:

/** @brief PWM events. */
typedef enum
{
    NRF_PWM_EVENT_STOPPED      = offsetof(NRF_PWM_Type, EVENTS_STOPPED),       ///< Response to STOP task, emitted when PWM pulses are no longer generated.
    NRF_PWM_EVENT_SEQSTARTED0  = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[0]), ///< First PWM period started on sequence 0.
    NRF_PWM_EVENT_SEQSTARTED1  = offsetof(NRF_PWM_Type, EVENTS_SEQSTARTED[1]), ///< First PWM period started on sequence 1.
    NRF_PWM_EVENT_SEQEND0      = offsetof(NRF_PWM_Type, EVENTS_SEQEND[0]),     ///< Emitted at the end of every sequence 0 when its last value has been read from RAM.
    NRF_PWM_EVENT_SEQEND1      = offsetof(NRF_PWM_Type, EVENTS_SEQEND[1]),     ///< Emitted at the end of every sequence 1 when its last value has been read from RAM.
    NRF_PWM_EVENT_PWMPERIODEND = offsetof(NRF_PWM_Type, EVENTS_PWMPERIODEND),  ///< Emitted at the end of each PWM period.
    NRF_PWM_EVENT_LOOPSDONE    = offsetof(NRF_PWM_Type, EVENTS_LOOPSDONE)      ///< Concatenated sequences have been played the specified number of times.
} nrf_pwm_event_t;

PWM event type 2 which is available in the handler:

/** @brief PWM driver event type. */
typedef enum
{
    NRFX_PWM_EVT_FINISHED, ///< Sequence playback finished.
    NRFX_PWM_EVT_END_SEQ0, /**< End of sequence 0 reached. Its data can be
                                safely modified now. */
    NRFX_PWM_EVT_END_SEQ1, /**< End of sequence 1 reached. Its data can be
                                safely modified now. */
    NRFX_PWM_EVT_STOPPED,  ///< The PWM peripheral has been stopped.
} nrfx_pwm_evt_type_t;

My question is: how is it possible to measure with an oscilloscope via GPIOs when the ADC that is triggered via PPI from PWM exactly starts and stops.

Parents
  • Maybe try using the PPI, either separate channels or FORK from PWM. Here's an example just using the SAADC (not tested):

    // softdevice uses PPI channels 17-31 and groups 4-5
    // See "Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled"
    //  nrf_soc.h: NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK
    //             NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK
    // maybe use sd_ppi_channel_assign() if enabling when SD enabled
    // Up to three tasks can be used in each GPIOTE channel for performing write operations to a pin, two
    // are fixed (SET and CLR), and one (OUT) configurable to perform Set, Clear or Toggle
    //  - "HiToLo" Task mode: Clear pin from OUT[n] task 
    
    // PPI Peripheral channel assignments for driving PIN_MONITOR_SAADC
    #define SAADC_GPIOTE_CH      0
    #define SAADC_PPI_CH_A       0
    #define SAADC_PPI_CH_B       1
    // Arbitrary pin - say P0.05
    #define PIN_MONITOR_SAADC    5
    
       // Set PIN_MONITOR_SAADC high at start of sample
       NRF_PPI->CH[SAADC_PPI_CH_A].EEP = (uint32_t)&NRF_SAADC->EVENTS_STARTED;
       NRF_PPI->CH[SAADC_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[SAADC_GPIOTE_CH];
    // NRF_PPI->FORK[SAADC_PPI_CH_A].TEP = (uint32_t)&NRF_PWM0->TASKS_STOP;     // <<== optionally can do a second action with a FORK
       // Clear PIN_MONITOR_SAADC low at end of sample
       NRF_PPI->CH[SAADC_PPI_CH_B].EEP = (uint32_t)&NRF_SAADC->EVENTS_DONE;
       NRF_PPI->CH[SAADC_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[SAADC_GPIOTE_CH];
    // NRF_PPI->FORK[SAADC_PPI_CH_B].TEP = (uint32_t)&NRF_PWM0->TASKS_NEXTSTEP; // <<== optionally can do a second action with a FORK
    
       NRF_GPIOTE->CONFIG[SAADC_GPIOTE_CH] = GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos | 
                                             GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos | 
                                             PIN_MONITOR_SAADC             << GPIOTE_CONFIG_PSEL_Pos | 
                                             GPIOTE_CONFIG_OUTINIT_Low     << GPIOTE_CONFIG_OUTINIT_Pos;
       // Enable
       NRF_PPI->CHENSET = ((1UL << SAADC_PPI_CH_A) | (1UL << SAADC_PPI_CH_B));
    

    Using the PWM PPI FORK as the set should also work ok

Reply
  • Maybe try using the PPI, either separate channels or FORK from PWM. Here's an example just using the SAADC (not tested):

    // softdevice uses PPI channels 17-31 and groups 4-5
    // See "Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled"
    //  nrf_soc.h: NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK
    //             NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK
    // maybe use sd_ppi_channel_assign() if enabling when SD enabled
    // Up to three tasks can be used in each GPIOTE channel for performing write operations to a pin, two
    // are fixed (SET and CLR), and one (OUT) configurable to perform Set, Clear or Toggle
    //  - "HiToLo" Task mode: Clear pin from OUT[n] task 
    
    // PPI Peripheral channel assignments for driving PIN_MONITOR_SAADC
    #define SAADC_GPIOTE_CH      0
    #define SAADC_PPI_CH_A       0
    #define SAADC_PPI_CH_B       1
    // Arbitrary pin - say P0.05
    #define PIN_MONITOR_SAADC    5
    
       // Set PIN_MONITOR_SAADC high at start of sample
       NRF_PPI->CH[SAADC_PPI_CH_A].EEP = (uint32_t)&NRF_SAADC->EVENTS_STARTED;
       NRF_PPI->CH[SAADC_PPI_CH_A].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[SAADC_GPIOTE_CH];
    // NRF_PPI->FORK[SAADC_PPI_CH_A].TEP = (uint32_t)&NRF_PWM0->TASKS_STOP;     // <<== optionally can do a second action with a FORK
       // Clear PIN_MONITOR_SAADC low at end of sample
       NRF_PPI->CH[SAADC_PPI_CH_B].EEP = (uint32_t)&NRF_SAADC->EVENTS_DONE;
       NRF_PPI->CH[SAADC_PPI_CH_B].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[SAADC_GPIOTE_CH];
    // NRF_PPI->FORK[SAADC_PPI_CH_B].TEP = (uint32_t)&NRF_PWM0->TASKS_NEXTSTEP; // <<== optionally can do a second action with a FORK
    
       NRF_GPIOTE->CONFIG[SAADC_GPIOTE_CH] = GPIOTE_CONFIG_MODE_Task       << GPIOTE_CONFIG_MODE_Pos | 
                                             GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos | 
                                             PIN_MONITOR_SAADC             << GPIOTE_CONFIG_PSEL_Pos | 
                                             GPIOTE_CONFIG_OUTINIT_Low     << GPIOTE_CONFIG_OUTINIT_Pos;
       // Enable
       NRF_PPI->CHENSET = ((1UL << SAADC_PPI_CH_A) | (1UL << SAADC_PPI_CH_B));
    

    Using the PWM PPI FORK as the set should also work ok

Children
No Data
Related