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

CPU running from RAM halted during page erase

Hi to community again!

I'm having trouble with TWIS during page erase on nRF52840 (FICR "Read 4 bytes @ address 0x10000104 (Data = 0x41414330)") as the bus is stalled while waiting for IRQ handler to be called. Product specification says "The CPU is halted IF the CPU executes code FROM THE FLASH while the NVMC is writing to the flash." So I've moved critical parts to RAM already and verified it is really called called from RAM but the TWI bus is still being stalled during page erase. It seems CPU is halted regardless the code source or there is something else I've missed.

Moved isr vector to RAM and redirected VTOR:

#define VECTOR_TABLE_SIZE 0x200
static uint32_t vector_table_ram[VECTOR_TABLE_SIZE] __attribute__((aligned (128)));

int main(void)
{
    memcpy(vector_table_ram, (uint32_t *)&__isr_vector, VECTOR_TABLE_SIZE);
    __disable_irq();
    SCB->VTOR = (uint32_t)&vector_table_ram;
    __enable_irq();

TWIS IRQ handler inf nrfx_twis.c:

__attribute__((used, long_call, section(".RAMfunc"))) void nrfx_twis_0_irq_handler(void)
{
    nrf_gpio_pin_set(24U);
    nrfx_twis_state_machine(NRF_TWIS0, &m_cb[NRFX_TWIS0_INST_IDX]);
    nrf_gpio_pin_clear(24U);
}

Page erase function in nrf_nvmc.c

__attribute__((used, long_call, section(".RAMfunc"))) void nrf_nvmc_page_erase(uint32_t address)
{
    nrf_gpio_pin_set(23U);
    // Enable erase.
    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een;
    __ISB();
    __DSB();

    // Erase the page
    NRF_NVMC->ERASEPAGE = address;
    wait_for_flash_ready();

    NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
    __ISB();
    __DSB();
    nrf_gpio_pin_clear(23U);
}

But scope output is still like this (first line SDA, second SCL, third high when inside twis handler in application, fourth high when inside IRQ handler, fifth high when in page erase func):

Any help is really appreciated! Thanks.

Parents
  • Interesting, I assume you have verified by debugger and possibly breakpoints that the code don't "touch" the flash here when jumping to the vector table in ram. Could be interesting to see if the cache have any influence on this:
    https://infocenter.nordicsemi.com/topic/ps_nrf52840/nvmc.html#register.ICACHECNF

    This is a slight corner case, so not sure if this actually have been tested, so it may be that you need to avoid interrupts while running the code from RAM while nvmc is executing, for instance you may need to handle the twis directly. Though typically it is allowed in twi to delay and stall bytes by clock stretching, this is something that the hardware will automatically do if the CPU don't process or handle the data fast enough. Does the peer twi master device support clock stretching?

  • NVMC->ICACHECNF is 0 in this configuration. Targeted master is capable of clock stretching, but not for tens of ms, it will timeout way earlier. The setup from scope picture is not with targeted master. Will try to investigate if there is other interrupt left enabled from MBR that could touch flash and cause the stall here.

Reply Children
  • With the help of a colleague we can see the same here, so it looks like there is still some hardware dependency that prevent this to work with interrupts even when running from RAM.

    Update: My colleague may have made it work now, I am attaching an example that use timer to trigger a timer interrupt during the flash operation, it show in principle it should work. Hope the example can be of use.

    3364.sdk_17.0.2_peripheral_nvmc_cpu_halt3.zip

    Maybe your problem can be related to the flash wait is not inlined (ref wait_for_flash_ready()).

    Alternative solution: The page erase can be done partially by using ERASEPAGEPARTIALCFG, e.g. run flash partial erase 9 times with a duration of 10ms = 90ms (which is more than the required 85ms). Then you can have application interrupts only delayed by 10ms during erase.

    Best regards,
    Kenneth

  • Thank you for the tip! Checking, that nvmc_page_erase is called from RAM was not enough, wait_for_flash_ready() was not inlined despite "inline" suggestion to compiler, after adding "__attribute__((always_inline))" it is really inlined and the IRQ is triggered, now I just have to check all dependencies of TWIS IRQ handler are really in RAM.

Related