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

Why is current consumption unstable in k_cpu_idle() after GPIO interrupt?

Current consumption during  k_cpu_idle() after GPIO interrupt does not take the same value. Why does this happen? Any idea? Thank you for reading this post in advance.

<Environment>
- DK v0.8.5(SB43 cut)
- modem firmware v1.0.0
- nrf; v1.0.0
- current measurement tool: multimeter

I configure GPIO11 as interrupt pin. I connect it to GND and disconnect again and again by jumper wire. After I connect it back to GND, the DK sometimes continuously consumes 25 uA and in another time 150 uA. 

CONFIG_TRUSTED_EXECUTION_NONSECURE=y

CONFIG_GPIO=y
CONFIG_SERIAL=n
# CONFIG_SERIAL=n in spm program
CONFIG_LOG=n

CONFIG_AT_HOST_LIBRARY=n

CONFIG_REBOOT=y

#include <zephyr.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gpio.h>
#include <device.h>

#define GPIO_IN_INT GPIO_IN_PIN11_Pos

struct device *gpio_controller;
struct gpio_callback gpio_cb;
bool is_interrupted;

void gpio_test_interrupt(struct device *gpio, struct gpio_callback *cb, u32_t pins) {
    is_interrupted = true;
}

u8_t init_gpio_interrupt() {
    int8_t ret;
    
    ret = gpio_pin_configure(gpio_controller, GPIO_IN_INT, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH));
    if (ret) {
        return -1;
    }
    
    gpio_init_callback(&gpio_cb, gpio_test_interrupt, BIT(GPIO_IN_INT));

    ret = gpio_add_callback(gpio_controller, &gpio_cb);
    if (ret){
        return -1;
    }

    ret =  gpio_pin_enable_callback(gpio_controller, GPIO_IN_INT);
    if (ret){
        return -1;
    }

    return 0;
}

void main(void)
{
    gpio_controller = device_get_binding("GPIO_0");
    if (!gpio_controller) {
        sys_reboot();
    }

    if (init_gpio_interrupt() != 0) {
        sys_reboot();
    }

    while (1) {
        k_cpu_idle();
    }            
}

Parents
  • Hello,

    Can you try using a more stable input source? The way you do it by connecting and disconnecting a jumper wire to GND can cause the input signal to bounce, and thus trigger the interupt handler several times unnecessarily.

  • Hi, Hakon.

    The above test program isn't suitable. sorry.

    I originally made a program which configures an external accelerometer chip through I2C. The chip sets an interrupt GPIO in H level which is connected to nRF9160 GPIO11 when it detects motion. 

    I attached 0.1uF between the interrupt signal line and GND. So there shouldn't be bouncing when the interrupt pin gets H.

    Additionally, I added GPIO_INT_DEBOUNCE in this code

    ret = gpio_pin_configure(gpio_controller, GPIO_IN_ACCEL_INT, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));

    However, I got the same result.

    The DK sometimes continuously consumes 25 uA and in another time 150 uA after the accelerometer detects motion and the interrupt pin gets H. 

    So, bouncing isn't the cause of this issue.

    This is rising edge take by an oscilloscope.

    #include <zephyr.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <gpio.h>
    #include <i2c.h>
    #include <device.h>
    
    /* for accelerometer */
    #define I2C_ACCEL_ADDR (0x32 >> 1)
    #define GPIO_IN_ACCEL_INT GPIO_IN_PIN11_Pos
    #define GPIO_LED GPIO_OUT_PIN18_Pos
    
    struct device *i2c_1;
    struct device *gpio_accel_interrupt;
    struct device *gpio_controller;
    struct gpio_callback gpio_cb;
    bool is_move = false;
    
    void accel_interrupt_callback(struct device *gpio, struct gpio_callback *cb, u32_t pins) {
        is_move = true;
    }
    
    u8_t configure_accelerometer() {
    
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x20, 0x2F) != 0) { // CTRL_REG1 (20h), Enable x,y,z axis, 10Hz, normal mode
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x21, 0x01) != 0) { // CTRL_REG2 (21h), High-pass filter enabled for AOI function on Interrupt 1.
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x22, 0x40) != 0) { // CTRL_REG3 (23h), IA1 interrupt on INT1 pin enable
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x30, 0x2A) != 0) { // INT1_CFG (30h), Enable interrupt generation on X,Y,Z high event or on direction recognition
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x32, 0x08) != 0) { // INT1_THS (32h), 1 LSb = 16 mg, threshold = 128mg
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x33, 0x00) != 0) { // INT1_DURATION (33h), Set the minimum duration of the Interrupt 1 event to be recognized
                return -1;
        }
    
        return 0;
    }
    
    u8_t init_accel_interrupt_gpio() {
        int8_t ret;
        
        ret = gpio_pin_configure(gpio_controller, GPIO_IN_ACCEL_INT, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));
        if (ret) {
            printk("Error configuring %lu!\n", GPIO_IN_ACCEL_INT);
            return -1;
        }
        
        gpio_init_callback(&gpio_cb, accel_interrupt_callback, BIT(GPIO_IN_ACCEL_INT));
    
        ret = gpio_add_callback(gpio_controller, &gpio_cb);
        if (ret){
            printk("Cannot setup callback!\n");
            return -1;
        }
    
        ret =  gpio_pin_enable_callback(gpio_controller, GPIO_IN_ACCEL_INT);
        if (ret){
            printk("Error enabling callback!\n");
            return -1;
        }
    
        return 0;
    }
    
    void disable_i2c(){
        NRF_TWIM1->TASKS_STOP = 1;
    }
    
    void main(void)
    {
        i2c_1 = device_get_binding("I2C_1");
        if (!i2c_1) {
            sys_reboot();
        }
    
        gpio_controller = device_get_binding("GPIO_0");
        if (!gpio_controller) {
            sys_reboot();
        }
    
        if(configure_accelerometer() != 0) {
            sys_reboot();
        }
    
        if (init_accel_interrupt_gpio() != 0) {
            sys_reboot();
        }
    
        gpio_pin_configure(gpio_controller, GPIO_LED, GPIO_DIR_OUT);
        
        disable_i2c();
        NRF_UARTE0->ENABLE = 0;
    
        while (1) {
    
            k_cpu_idle();
    
        }            
    }
    

Reply
  • Hi, Hakon.

    The above test program isn't suitable. sorry.

    I originally made a program which configures an external accelerometer chip through I2C. The chip sets an interrupt GPIO in H level which is connected to nRF9160 GPIO11 when it detects motion. 

    I attached 0.1uF between the interrupt signal line and GND. So there shouldn't be bouncing when the interrupt pin gets H.

    Additionally, I added GPIO_INT_DEBOUNCE in this code

    ret = gpio_pin_configure(gpio_controller, GPIO_IN_ACCEL_INT, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));

    However, I got the same result.

    The DK sometimes continuously consumes 25 uA and in another time 150 uA after the accelerometer detects motion and the interrupt pin gets H. 

    So, bouncing isn't the cause of this issue.

    This is rising edge take by an oscilloscope.

    #include <zephyr.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <gpio.h>
    #include <i2c.h>
    #include <device.h>
    
    /* for accelerometer */
    #define I2C_ACCEL_ADDR (0x32 >> 1)
    #define GPIO_IN_ACCEL_INT GPIO_IN_PIN11_Pos
    #define GPIO_LED GPIO_OUT_PIN18_Pos
    
    struct device *i2c_1;
    struct device *gpio_accel_interrupt;
    struct device *gpio_controller;
    struct gpio_callback gpio_cb;
    bool is_move = false;
    
    void accel_interrupt_callback(struct device *gpio, struct gpio_callback *cb, u32_t pins) {
        is_move = true;
    }
    
    u8_t configure_accelerometer() {
    
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x20, 0x2F) != 0) { // CTRL_REG1 (20h), Enable x,y,z axis, 10Hz, normal mode
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x21, 0x01) != 0) { // CTRL_REG2 (21h), High-pass filter enabled for AOI function on Interrupt 1.
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x22, 0x40) != 0) { // CTRL_REG3 (23h), IA1 interrupt on INT1 pin enable
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x30, 0x2A) != 0) { // INT1_CFG (30h), Enable interrupt generation on X,Y,Z high event or on direction recognition
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x32, 0x08) != 0) { // INT1_THS (32h), 1 LSb = 16 mg, threshold = 128mg
                return -1;
        }
        if (i2c_reg_write_byte(i2c_1, I2C_ACCEL_ADDR, 0x33, 0x00) != 0) { // INT1_DURATION (33h), Set the minimum duration of the Interrupt 1 event to be recognized
                return -1;
        }
    
        return 0;
    }
    
    u8_t init_accel_interrupt_gpio() {
        int8_t ret;
        
        ret = gpio_pin_configure(gpio_controller, GPIO_IN_ACCEL_INT, (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE));
        if (ret) {
            printk("Error configuring %lu!\n", GPIO_IN_ACCEL_INT);
            return -1;
        }
        
        gpio_init_callback(&gpio_cb, accel_interrupt_callback, BIT(GPIO_IN_ACCEL_INT));
    
        ret = gpio_add_callback(gpio_controller, &gpio_cb);
        if (ret){
            printk("Cannot setup callback!\n");
            return -1;
        }
    
        ret =  gpio_pin_enable_callback(gpio_controller, GPIO_IN_ACCEL_INT);
        if (ret){
            printk("Error enabling callback!\n");
            return -1;
        }
    
        return 0;
    }
    
    void disable_i2c(){
        NRF_TWIM1->TASKS_STOP = 1;
    }
    
    void main(void)
    {
        i2c_1 = device_get_binding("I2C_1");
        if (!i2c_1) {
            sys_reboot();
        }
    
        gpio_controller = device_get_binding("GPIO_0");
        if (!gpio_controller) {
            sys_reboot();
        }
    
        if(configure_accelerometer() != 0) {
            sys_reboot();
        }
    
        if (init_accel_interrupt_gpio() != 0) {
            sys_reboot();
        }
    
        gpio_pin_configure(gpio_controller, GPIO_LED, GPIO_DIR_OUT);
        
        disable_i2c();
        NRF_UARTE0->ENABLE = 0;
    
        while (1) {
    
            k_cpu_idle();
    
        }            
    }
    

Children
Related