How to make the same IO port serve as both the wake-up pin and the PWM detection pin?

I need to use one IO port of the nrf52832. This IO can not only detect the ECG signal but also achieve system off wake-up. The ECG signal is a PWM signal with a duty cycle of 20%. By detecting the PWM period, the RR value can be detected. I would like to ask how to configure the code? The PWM detection code has been written. How can this IO be used for wake-up at the same time?

The following code is the configuration code for the PWM detection pin:
static uint32_t timer_ticks_to_us(uint32_t ticks)
{
return ticks;
}


static uint32_t calculate_time_diff(uint32_t current, uint32_t previous)
{
if (current >= previous)
{
return current - previous;
}
else
{

return (0xFFFFFFFF - previous) + current + 1;
}
}


void timer_event_handler(nrf_timer_event_t event_type, void *p_context)
{
switch (event_type)
{
case NRF_TIMER_EVENT_COMPARE0:

break;

case NRF_TIMER_EVENT_COMPARE1:

break;

default:

break;
}
}


void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
// if (!m_measurement_active) return;
uint32_t rr_interval;
uint32_t current_time = nrf_drv_timer_capture(&m_timer, NRF_TIMER_CC_CHANNEL0);

switch (action)
{
case NRF_GPIOTE_POLARITY_LOTOHI:

if (m_last_heartbeat_time != 0)
{

uint32_t period_ticks = calculate_time_diff(current_time, m_rise_time);
m_period_us = timer_ticks_to_us(period_ticks);
m_measurement_valid = true;
NRF_LOG_DEBUG("Rising edge - Period: %u us", m_period_us)

rr_interval= m_period_us/1000;
NRF_LOG_DEBUG("rr interval %u ", rr_interval)

uint16_t rr_interval_ble = (uint16_t)( rr_interval * 1024 /1000);


if (rr_interval >= 500 && rr_interval <= 2000)
{
if (m_rr_count < BLE_HRS_MAX_RR_INTERVALS)
{
m_rr_interval[m_rr_count++] = rr_interval_ble;
NRF_LOG_DEBUG("m-rr-interval %u ", rr_interval_ble);
}
}


}
m_rise_time = current_time;
m_last_heartbeat_time = current_time;
break;

default:
break;
}
}


ret_code_t pwm_detector_init(uint32_t pwm_input_pin)
{
ret_code_t err_code;

NRF_LOG_INFO("Initializing RR detector on pin %d", pwm_input_pin);


if (!nrf_drv_gpiote_is_init())
{
err_code = nrf_drv_gpiote_init();
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("GPIOTE init failed: 0x%X", err_code);
return err_code;
}
}


nrf_drv_gpiote_in_config_t in_config =
{
.sense =NRF_GPIOTE_POLARITY_HITOLO, 
.pull = NRF_GPIO_PIN_PULLUP,
.is_watcher = false,
.hi_accuracy = true, 
.skip_gpio_setup = false
};

err_code = nrf_drv_gpiote_in_init(pwm_input_pin, &in_config, gpiote_event_handler);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("GPIOTE in init failed: 0x%X", err_code);
return err_code;
}


nrf_drv_timer_config_t timer_cfg =
{
.frequency = TIMER_FREQUENCY,
.mode = NRF_TIMER_MODE_TIMER,
.bit_width = NRF_TIMER_BIT_WIDTH_32,
.interrupt_priority = APP_IRQ_PRIORITY_LOW,
.p_context = NULL
};

err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_event_handler);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Timer init failed: 0x%X", err_code);
return err_code;
}

nrf_drv_timer_enable(&m_timer);


nrf_drv_gpiote_in_event_enable(pwm_input_pin, true);

m_measurement_active = true;

NRF_LOG_INFO("RR detector initialized successfully");
return NRF_SUCCESS;
}


uint32_t pwm_get_period_us(void)
{
return m_last_heartbeat_time;
}

  • Hi,

     

    This IO can not only detect the ECG signal but also achieve system off wake-up. The ECG signal is a PWM signal with a duty cycle of 20%. By detecting the PWM period, the RR value can be detected. I would like to ask how to configure the code? The PWM detection code has been written. How can this IO be used for wake-up at the same time?

    You can use GPIOTE + PPI + TIMER for this purpose.

    In the case of measuring a pulse width, you must have 2 GPIOs in total, ie. connect the same signal to two available GPIOs.

    1 for falling edge detection (GPIOTE IN + PPI + TIMER)

    1 for rising edge detection (GPIOTE IN + PPI + TIMER)

     

    When your signal goes active, you setup PPI to start a TIMER, and when it goes in-active, the second channel stops the TIMER.

    You then have a ISR active on the second edge, then read out the TIMER->CC value and calculate the pulse width.

     

    See here for more details:

     Best way to measure time between falling/rising edges (NCS, Zephyr, NRF52840) 

     

    Kind regards,

    Håkon

  • My PWM check code has been successfully completed. What I want to ask is how to configure this pin simultaneously to enable system off wake-up.

  • Hi,

     

    Sorry, I missed this.

    a9876 said:
    this pin simultaneously to enable system off wake-up.

    Before calling systemoff, you should include "nrf_gpio.h", and call function nrf_gpio_cfg_sense_set() on your selected GPIO, with your selected level (high or low).

    Please note that this is now a level triggering, and not an edge-triggering. 

     

    Kind regards,
    Håkon

  • void WAKEUP_init(void)
    {
    // ret_code_t err_code;
    // err_code = nrfx_gpiote_init();
    // APP_ERROR_CHECK(err_code);
    nrf_drv_gpiote_in_event_disable(HR_INPUT_PIN);
    nrf_gpio_cfg_sense_input(HR_INPUT_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH);
    }


    /**@brief Function for putting the chip into sleep mode.
    *
    * @note This function will not return.
    */
    static void sleep_mode_enter(void)
    {
    ret_code_t err_code;

    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);

    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);

    WAKEUP_init();
    // Go to system-off mode (this function will not return; wakeup will cause a reset).
    err_code = sd_power_system_off();
    APP_ERROR_CHECK(err_code);
    }

    I used nrf_gpio_cfg_sense_input(HR_INPUT_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH) before sd_power_system_off() in the sleep_mode_enter() function. The code is as follows. At this point, I pressed key 1 on the DK, but instead of entering sleep mode, it directly woke up and restarted. What could be the reason for this?

  • Hi,

     

    a9876 said:
    I used nrf_gpio_cfg_sense_input(HR_INPUT_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_HIGH) before sd_power_system_off() in the sleep_mode_enter() function. The code is as follows. At this point, I pressed key 1 on the DK, but instead of entering sleep mode, it directly woke up and restarted. What could be the reason for this?

    You are setting a pull-up and _SENSE_HIGH. This will cause the wake-up condition to be active when you enter system off. You probably want pull-down + _SENSE_HIGH, or pull-up + SENSE_LOW.

     

    Kind regards,

    Håkon

Related