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.

  • Hi,

    how is it possible that the PWM blocks the ADC? Shouldn't the PWM only start the ADC? And then it is up to the ADC how long it will need. These are my PWM settings:

    static nrfx_pwm_t TIMEAPI_pwm_instance_s = NRFX_PWM_INSTANCE(0);
    static nrf_pwm_values_individual_t TIMEAPI_pwm_sequence_values_s;
    nrf_pwm_sequence_t const TIMEAPI_pwm_sequence_s =
    {
        .values.p_individual = &TIMEAPI_pwm_sequence_values_s,
        .length              = NRF_PWM_VALUES_LENGTH(TIMEAPI_pwm_sequence_values_s),
        .repeats             = 0,
        .end_delay           = 0
    };

        nrfx_pwm_config_t const pwm_config_s =
        {
            .output_pins =
            {
                GENAPI_GpioGetMotorDir1_s().pin_number, // channel 0
                GENAPI_GpioGetMotorDir2_s().pin_number, // channel 1
                NRFX_PWM_PIN_NOT_USED, // channel 2
                NRFX_PWM_PIN_NOT_USED  // channel 3
            },
            .irq_priority = APP_IRQ_PRIORITY_HIGHEST,
            .base_clock   = NRF_PWM_CLK_2MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 100, // 100 @ 2MHz -> 20kHz
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        APP_ERROR_CHECK(nrfx_pwm_init(&TIMEAPI_pwm_instance_s, &pwm_config_s, NULL));

        TIMEAPI_pwm_sequence_values_s.channel_0 = motor_pwm_duty_cycle_U8;
        TIMEAPI_pwm_sequence_values_s.channel_1 = 0;
        (void)nrfx_pwm_simple_playback(&TIMEAPI_pwm_instance_s, &TIMEAPI_pwm_sequence_s, 2, NRFX_PWM_FLAG_LOOP);

  • Hello again,

    Thank you for your patience with this - I have been out of office for some time, but now I am back again.

    Nppn7 said:
    how is it possible that the PWM blocks the ADC? Shouldn't the PWM only start the ADC? And then it is up to the ADC how long it will need.

    The PWM will not be blocking the SAADC's execution - the SAADC will start a conversion as soon as the TASKS_SAMPLE task is triggered if it is not already busy. Which SAADC event are you now using to indicate that a single conversion has finished, and what buffer size for the SAADC are you using?

    It seems to me that the conversions itself take a lot shorter than 190 µs, if that is what is being indicated by the second channel going low in your oscilloscope picture.

    Please also see my other questions in my previous comment.

    Best regards,
    Karl

Related