ARMmbed / mbed-os

Arm Mbed OS is a platform operating system designed for the internet of things
https://mbed.com
Other
4.66k stars 2.97k forks source link

EFM32 doesn't support QSPI in deep sleep, but there are no locks #14544

Open amq opened 3 years ago

amq commented 3 years ago

Description of defect

According to the reference manual of EFM32GG11, QSPI is not available in EM2 (deep sleep), but I don't see any locks preventing deep sleep in mbed-os.

image

Under light load, everything is mostly fine, most of the time. But when I tried a stress test, there are many problems.

Target(s) affected by this defect ?

EFM32GG11

Toolchain(s) (name and version) displaying this defect ?

All

What version of Mbed-os are you using (tag or sha) ?

Any

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

Any

How is this defect reproduced ?

Here's a stress test I used:

#include "mbed.h"
#include "platform/mbed_power_mgmt.h"

static DigitalOut redLed(LED_RED, 0);
static DigitalOut greenLed(LED_GREEN, 0); 

int main() {

    // Delay for power supply stabilizing
    ThisThread::sleep_for(100);

    int _fail_step;
    int _fail_stage;
    int _fail_rc;

    auto _ext_mem_step = [&_fail_stage, &_fail_rc](int _step) {
        QSPIFBlockDevice qspif_bd(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3,
                                  QSPI_FLASH1_SCK, QSPI_FLASH1_CSN, QSPIF_POLARITY_MODE_0, MBED_CONF_QSPIF_QSPI_FREQ/4);
        printf("External memory chip test, step %d", _step + 1);
        int _rc = qspif_bd.init();
        if (_rc != QSPIF_BD_ERROR_OK) {
            printf("Error initialize external memory chip");
            _fail_rc = _rc;
            _fail_stage = 0;
            return true;
        }

        bd_size_t _chip_block_size = qspif_bd.get_erase_size();
        bd_size_t _chip_size = qspif_bd.size();
        bd_size_t _block_number = _chip_size/_chip_block_size;
        printf("External memory chip - size: %llu, block size: %llu, blocks number: %llu", _chip_size, _chip_block_size, _block_number);

        printf("Try erase entire external memory chip");
        for (bd_size_t i = 0; i < _block_number; i++) {
            bd_size_t _block_adr = i*_chip_block_size;
            greenLed = !greenLed;
            _rc = qspif_bd.erase(_block_adr, _chip_block_size);
            if (_rc != QSPIF_BD_ERROR_OK) {
                printf("Error erase external memory chip block at 0x%llX", _block_adr);
                qspif_bd.deinit();
                _fail_rc = _rc;
                _fail_stage = 1;
                return true;
            }
            printf("Ok erase external memory chip block at 0x%llX", _block_adr);
        }

        printf("Try program entire external memory chip");
        for (bd_size_t i = 0; i < _block_number; i++) {
            bd_size_t _block_adr = i*_chip_block_size;
            greenLed = !greenLed;
            uint8_t *_buff = new uint8_t[_chip_block_size];
            if (_buff == nullptr) {
                printf("Memory allocation error");
                qspif_bd.deinit();
                _fail_rc = 0;
                _fail_stage = 2;
                return true;
            }
            for (bd_size_t j = 0; j < _chip_block_size; j++) {
                bd_size_t _value = i + j + _step;
                uint8_t *_at_value = (uint8_t *)&_value;
                _buff[j] = _at_value[0];
            }
            _rc = qspif_bd.program(_buff, _block_adr, _chip_block_size);
            if (_rc != QSPIF_BD_ERROR_OK) {
                printf("Error program external memory chip block at 0x%llX", _block_adr);
                delete[] _buff;
                qspif_bd.deinit();
                _fail_rc = _rc;
                _fail_stage = 3;
                return true;
            }
            delete[] _buff;
            printf("Ok program external memory chip block at 0x%llX", _block_adr);
        }

        printf("Verify programmed external memory chip");
        for (bd_size_t i = 0; i < _block_number; i++) {
            bd_size_t _block_adr = i*_chip_block_size;
            greenLed = !greenLed;
            uint8_t *_buff = new uint8_t[_chip_block_size];
            if (_buff == nullptr) {
                printf("Memory allocation error");
                qspif_bd.deinit();
                _fail_rc = 0;
                _fail_stage = 4;
                return true;
            }
            _rc = qspif_bd.read(_buff, _block_adr, _chip_block_size);
            if (_rc != QSPIF_BD_ERROR_OK) {
                printf("Error read external memory chip block at 0x%llX", _block_adr);
                delete[] _buff;
                qspif_bd.deinit();
                _fail_rc = _rc;
                _fail_stage = 5;
                return true;
            }
            printf("Ok read external memory chip block at 0x%llX", _block_adr);
            for (bd_size_t j = 0; j < _chip_block_size; j++) {
                bd_size_t _value = i + j + _step;
                uint8_t *_at_value = (uint8_t *)&_value;
                if (_buff[j] != _at_value[0]) {
                    printf("The values read from the chip do not match the expected values");
                    delete[] _buff;
                    qspif_bd.deinit();
                    _fail_rc = 0;
                    _fail_stage = 6;
                    return true;
                }
            }
            delete[] _buff;
        }

        qspif_bd.deinit();
        return false;
    };

    bool _test_fail = false;
    for (int i = 0; i < 20; i++) {
        uint64_t _step_time_begin = rtos::Kernel::get_ms_count();
        if (_ext_mem_step(i)) {
            _test_fail = true;
            _fail_step = i;
            break;
        }
        printf("External memory chip test step %d passed in %llu ms", i + 1, rtos::Kernel::get_ms_count() - _step_time_begin);
    }

    greenLed = 0;

    while (true) {
        if (_test_fail) {
            printf("Test fail - step: %d, stage: %d, error code: %d", _fail_step, _fail_stage, _fail_rc);
            redLed = 1;
        }
        else {
            printf("Test passed successfully");
            greenLed = 1;
        }
        ThisThread::sleep_for(200);
        redLed = 0;
        greenLed = 0;
        ThisThread::sleep_for(800);
    }

}
0xc0170 commented 3 years ago

@ARMmbed/team-silabs Please review

ciarmcom commented 3 years ago

@amq thank you for raising this issue.Please take a look at the following comments:

How can we reproduce your issue?

NOTE: If there are fields which are not applicable then please just add 'n/a' or 'None'. This indicates to us that at least all the fields have been considered. Please update the issue header with the missing information, the issue will not be mirrored to our internal defect tracking system or investigated until this has been fully resolved.

amq commented 3 years ago

@ciarmcom updated

ciarmcom commented 3 years ago

Thank you for raising this detailed GitHub issue. I am now notifying our internal issue triagers. Internal Jira reference: https://jira.arm.com/browse/IOTOSM-3820

0xc0170 commented 3 years ago

Under light load, everything is mostly fine, most of the time. But when I tried a stress test, there are many problems.

If you add locks, all works as expected? Shall they be added?

golgor commented 3 years ago

Under light load, everything is mostly fine, most of the time. But when I tried a stress test, there are many problems.

If you add locks, all works as expected? Shall they be added?

I was also involved in this issue together with @amq and some other colleagues. We finished some tests today. Our modification in this case was to disable deep sleep before any initialization of the QSPI-drivers, effectively forcing you to do dynamic allocation if you don't want to make changes in the drivers yourself.

We have 7 devices that experienced problems with this during regular use (not entirely sure why only a few units was affected) and adding locks fixes the issue for all these 7. We have also used the stress test above to test more units and adding the locks solves the issue in all our cases.

Our original setup (some devices not behaving correct & most units failed during stress testing):

// FLASH INIT HERE
int main() {
    // FLASH READING/WRITING HERE
    mbed_start_application(POST_APPLICATION_ADDR);
}

Our testing setup (all tested devices so far behaving correct):

int main() {
    sleep_manager_lock_deep_sleep();
    // FLASH INIT HERE
    // FLASH READING/WRITING HERE
    sleep_manager_unlock_deep_sleep();
    mbed_start_application(POST_APPLICATION_ADDR);
}
reiniercoetzer commented 3 years ago

Hi @0xc0170 , and progress on this issue yet? Thanks in advance!

reiniercoetzer commented 3 years ago

@ciarmcom @0xc0170

Hi guys, any news on this issue?

0xc0170 commented 3 years ago

@ARMmbed/team-silabs Can you have a look?