microchip-pic-avr-solutions / avr-iot-cellular-arduino-library

Arduino library for developing Cellular IoT Applications with the AVR-IoT Cellular Mini development board from Microchip
Other
21 stars 4 forks source link

Sleep Time incosistent in LowPower.powerDown(const uint32_t power_down_time_seconds) #27

Open CsFreiber opened 3 weeks ago

CsFreiber commented 3 weeks ago

Hello Microchip community,

Hardware: AVR-IoT-Cellular mini, Water level sensors (once Grove seeed connected to I2C, once Endress+Hauser Liquipoint connected to GPIO) Software: avr-iot-cellular-arduino-library version 1.3.11, DxCore version 1.5.11

We are using the example from LowPower for setting the board in sleep mode. Our sleep time is one hour (3600s = 1h). As recommended from previous discussions #20 we have commented the functions for the LDO. We log the sleep time on the external EEPROM 25CSM04. After the sleep time the modem connects to the network, gets current time and the water level sensor value is read. Now to our problem:

We made an interesting observation. If the board has no external sensors attached, the sleep time is always the same and correct (1h). If there is an external sensor attached, the sleep time varies significantly. It seems that the CPU is woken up from an external interrupt, which was caused possibly by an EMP. We think that could be one reason, because we have some machines in the production underneath our lab and the sleep time problems occur only during the time the production is running. For example, we have no issues on weekends, and the sleep time is also better during lunchtime. Especially at night time the program is running as expected (see Diagram below). Nevertheless, this should not happen, because the source of a potential EMP is several meters away and there are concrete walls between them. There should be also some EDI protection on the board I think.

Do you have any ideas or suggestions on how this phenomenon can occur and maybe how we could resolve this issue?

Low_Power_Duration

simengangstad commented 3 weeks ago

Hello @CsFreiber,

This is my personal account. We've spoken earlier through my former work account @M65649. I no longer work for Microchip so I'm not sure whether this would be looked into further from their side. That said, I do have an idea why your problem occurs.

This might be something with how all the pins are set in a specific way before going to sleep in low_power.cpp to minimise power consumption. Here is the function:

static void powerDownPeripherals(const bool keep_modem_active) {

    savePinState();

    // For low power, the following configuration should be used.
    // If no comment is specified, the pin is set to input with input buffer
    // disabled and pull-up on

    // On all pins along the feather, interrupts are left on for both edges in
    // case the user wants to wake the device up from external signals. This is
    // also the case for the buttons SW0 and SW1

    // clang-format off

    // Pin - Description            - Comment
    // PA0 - LED0 (CELLULAR)        -
    // PA1 - LED1 (CONNECTION)      -
    // PA2 - LED2 (DATA)            -
    // PA3 - LED3 (ERROR)           -
    // PA4 - SPI0 MOSI (Feather)    -
    // PA5 - SPI0 MISO (Feather)    -
    // PA6 - SPI0 MSCK (Feather)    -
    // PA7 - CLKO (Feather)         -

    // PB0 - USART3 TX              - No pullup, measuring yields lower uA
    // PB1 - USART3 RX              -
    // PB2 - LED4 (USER)            -
    // PB3 - VOLTAGE MEASURE EN     - Output, low, no pullup
    // PB4 - LOWQ EN                - Output, low, no pullup
    // PB5 - SPI0 CS (Feather)      -
    // PB6 - NC                     -
    // PB7 - NC                     -

    // PC0 - USART1 TX (Modem)      -
    // PC1 - USART1 RX (Modem)      -
    // PC2 - I2C0 SDA               - Has external pullup
    // PC3 - I2C0 SCL               - Has external pullup
    // PC4 - CTS0 (Modem)           -
    // PC5 - RESETN (Modem)         - Has external pulldown
    // PC6 - RING0 (modem)          - Source for wake up for PSM
    // PC7 - RTS0 (Modem)           - Has external pullup

    // PD0 - GPIO D9 (Feather)      -
    // PD1 - GPIO A1 (Feather)      -
    // PD2 - SW0 button (Feather)   -
    // PD3 - GPIO A2 (Feather)      -
    // PD4 - GPIO A3 (Feather)      -
    // PD5 - GPIO A4 (Feather)      -
    // PD6 - DAC A0  (Feather)      -
    // PD7 - AREF A5 (Feather)      -

    // PE0 - VMUX Measure           - Not pulled up
    // PE1 - GPIO D6 (Feather)      -
    // PE2 - GPIO D5 (Feather)      -
    // PE3 - SPI0 CS (EEPROM)       - Active low, so nothing extra done here
    // PE4 - NC                     -
    // PE5 - NC                     -
    // PE6 - NC                     -
    // PE7 - NC                     -

    // PF0 - XTAL32K1               - Input buffer not disabled, no pullup. Is used for PIT
    // PF1 - XTAL32K2               - Input buffer not disabled, no pullup. Is used for PIT
    // PF2 - I2C1 SDA (Feather)     - Has external pullup
    // PF3 - I2C1 SCL (Feather)     - Has external pullup
    // PF4 - USART2 TX (Feather)    -
    // PF5 - USART2 RX (Feather)    -
    // PF6 - SW1 button             -
    // PF7 - NC                     -

    // clang-format on

    PORTA.DIR = 0x00;
    PORTB.DIR = PIN3_bm | PIN4_bm;

    if (keep_modem_active) {
        PORTC.DIRCLR = PIN2_bm | PIN3_bm;
    } else {
        PORTC.DIR = 0x00;
    }

    PORTD.DIR = 0x00;
    PORTE.DIR = 0x00;
    PORTF.DIR = 0x00;

    PORTA.OUT = 0x00;
    PORTB.OUT = 0x00;

    if (keep_modem_active) {
        PORTC.OUTCLR = PIN2_bm | PIN3_bm;
    } else {
        PORTC.OUT = 0x00;
    }

    PORTD.OUT = 0x00;
    PORTE.OUT = 0x00;
    PORTF.OUT = 0x00;

    PORTA.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTA.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTA.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTA.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTA.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTA.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTA.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;

    PORTB.PIN0CTRL = PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN4CTRL = PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTB.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTB.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;

    PORTC.PIN2CTRL = PORT_ISC_INPUT_DISABLE_gc;
    PORTC.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;

    if (!keep_modem_active) {
        PORTC.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
        PORTC.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
        PORTC.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
        PORTC.PIN5CTRL = PORT_ISC_INPUT_DISABLE_gc;
        PORTC.PIN6CTRL = PORT_ISC_INPUT_DISABLE_gc;
        PORTC.PIN7CTRL = PORT_ISC_INPUT_DISABLE_gc;
    }

    PORTD.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTD.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;

    PORTE.PIN0CTRL = PORT_ISC_INPUT_DISABLE_gc;
    PORTE.PIN1CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTE.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTE.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTE.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTE.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTE.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;
    PORTE.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_INPUT_DISABLE_gc;

    PORTF.PIN0CTRL = 0x00;
    PORTF.PIN1CTRL = 0x00;
    PORTF.PIN2CTRL = PORT_ISC_BOTHEDGES_gc;
    PORTF.PIN3CTRL = PORT_ISC_BOTHEDGES_gc;
    PORTF.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTF.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTF.PIN6CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
    PORTF.PIN7CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc;
}

The ports on for example the feather connections are set to have interrupt enable on both edges. The reason for this is what I wrote in that comment in the function:

    // On all pins along the feather, interrupts are left on for both edges in
    // case the user wants to wake the device up from external signals. This is
    // also the case for the buttons SW0 and SW1

Your external sensor might be triggering these interrupt lines somehow, and the GPIO ports wake the CPU since the interrupts are on. My suggestion for you is to change all the entries of PORT_ISC_BOTHEDGES_gc to PORT_ISC_INPUT_DISABLE_gc and run some tests to see if that fixes the problem.