cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to erase external NOR flash memory while read, write works.

Klassic
Associate III

I am using STM32L496ZG to interface ISSI IS29GL064-70TLET nor flash by using HAL library. I used CUBE MX to generate the code and running code on Keil compiler. I am able to detect device ID, write and read block. But unable to erase data. I have used example code provided in application note AN4761.

Erase code snippet is below:

WRITE_READ_ADDR 0x8000

NOR_BANK_ADDR 0x64000000

HAL_NOR_ReturnToReadMode(&hnor1);

/* Erase the NOR memory block to write on */

HAL_NOR_Erase_Block(&hnor1, WRITE_READ_ADDR, NOR_BANK_ADDR);

/* Return the NOR memory status */

if(HAL_NOR_GetStatus(&hnor1, NOR_BANK_ADDR, NOR_TIMEOUT_VALUE) !=

HAL_NOR_STATUS_SUCCESS)

{

/* Erase Error */

HAL_UART_Transmit(&huart2, (uint8_t *) "Erase error" , 12, 100);

  return NOR_STATUS_ERASE_ERROR;

}

The status returns erase success. But the bits are still the same, they don't turn to ones at all.

Can any one please help me out on this?

29 REPLIES 29

HI Pavel,   

  Thanks for replying. 

The new code you sent in the link is same as old one except that the new code adds option for 8 bit data.

I am already using 16 bit data. So for me, no change in code. Can you please show me how did you write own erase code please? The only challenge I see is writing send address/data function like NOR_WRITE(). Sorry for simple question. I am new to memory programming.

The memory is divided into 128 uniform sectors as mentioned in datasheet. The only difference I find between library & datasheet  is that erase operation is carried out sector wise in datasheet whereas erase is done block wise in library. Does that cause any interruption in operation?

Pavel A.
Evangelist III

Well, found my old project, for STM32H7. The flash there is IS29GL256 (32 MB), also in 16-bit mode. IIRC it has only one size of erase block, 128K (no sub-blocks).

The erase sector function looks pretty same as the ST's one.... but devil is in details.

 

 

#define EXTFL_BASE_ADDR    (0x60000000)
#define EXTFL_ERASE_BLK_SIZE (128*1024U)
#define EXTFL_ERASE_TMO     600 /*ms, erase one block, see [1 pg.58]*/

unsigned EXTFL_Block_erase(unsigned nblk)
{
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(nblk, 0);
    if (!p)
        return 1;
    unsigned start_tick = HAL_GetTick();

    // Procedure: [1 pg.25]
    // Write unlock
    extfl_write_unlock3_(0x80);
    extfl_write_unlock_();
    // Write start erase
    p[0] = 0x30;
    // Poll for completion - simplified. Rely on data toggling.
    bool done = false;
    do {
        if (FL_ReadStatus(nblk, 0) == 0) {
            done = true;
            break;
        }
    } while ((HAL_GetTick() - start_tick) <= EXTFL_ERASE_TMO);

    extfl_cmd_reset_(); // return to read state
    if (!done) {
        if (FL_ReadStatus(0, 0) != 0) {
            return (2|8); // bad status after reset
        }
        return 2; // timeout
    }

    // Verify that all bytes are 0xFF
    // ......
    return 0;
}

// Block#, offset in block -> physical address casted to u16 ptr
// Offset must be even.
static inline uint16_t *EXTFL_block_and_offset_to_addr(unsigned blk, unsigned offs)
{
  return (uint16_t *) (EXTFL_BASE_ADDR + blk * EXTFL_ERASE_BLK_SIZE + offs);
}


// send RESET cmd [1, pg.50]
static void extfl_cmd_reset_(void)
{
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(0, 0);
    p[0] = 0xF0;
    __DMB();
    __DSB();
}

// write unlock cmd 555/AA,2AA/55
static void extfl_write_unlock_(void)
{
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(0, 0);
    p[0x555] = 0xAA;
    __DSB();
    p[0x2AA] = 0x55;
    __DSB();
}

// write unlock+cmd: 555/AA,2AA/55, 555/cmd
static void extfl_write_unlock3_(uint8_t cmd3)
{
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(0, 0);
    extfl_write_unlock_();
    p[0x555] = cmd3;
    __DSB();
}

 

FBL
ST Employee

Hello @Klassic

Would you check if the blocks are protected? If all blocks are protected, it is possible that they are not erased.  the CHIP ERASE operation appears to start but will leave the data unchanged. No error is reported when protected blocks are not erased.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Klassic
Associate III

Hi @FBL,

        The current erase operation behaves same way as you said. The erased location has same contents as before, and if I re write on them, the data gets jumbled up due to unsuccessful erase operation.  The erase operation returns success. But how to check whether all sectors are protected?  

Thanks pavel for the code. I will try this and let you know.

Thanks for the code Pavel. 
I thought it worked, but after rechecking, it could not erase again. It could have been first read. My bad.
And, can I use same function with different chip erase cmd sequence for chip erase? For some reason, entire chip erase is not working.

Pavel A.
Evangelist III

Chip erase takes a long time. For my 32 MB chip it was ~ two minutes at optimal voltage.

Below is mass erase function

 

#define EXTFL_ERASE_CHIP_TMO   (110*1000) /*ms, erase chip, see [1 pg.58]*/

// Mass erase - poll for completion for <timeout> ms
unsigned EXTFL_Mass_erase_poll(unsigned timeout)
{
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(0, 0);
    uint32_t start_tick = HAL_GetTick();
    if (timeout == 0 || timeout > EXTFL_ERASE_CHIP_TMO)
    {
        timeout = EXTFL_ERASE_CHIP_TMO;
    }
    // Poll for completion - simplified
    uint16_t w1, w2;
    char fs;
    do {
        fs = FL_ReadStatus(0, 0);
        if (fs == (char)0) {
            break; // finished
        }
        if (fs == 'B') {
            HAL_Delay(5);
            continue; // still busy...
        }
        break;
    } while ((HAL_GetTick() - start_tick) <= timeout);

    if (fs != 0) {
        if (fs != 'B') {
          printf("NOR: After mass erase bad status %c\n", fs);
        }
        return fs;
    }
    w1 = p[0];
    __DMB(); __DSB();
    w2 = p[0];
    if ((w1 & w2) != 0xFFFF)
        return 2; // timeout or other error

    // Verify erase
    // TODO ........... read all?
    return 0;
}

 

 

 

unsigned EXTFL_Mass_erase_begin(void)
{
    // Procedure: [1 pg.25]
    extfl_write_unlock3_(0x80);
    extfl_write_unlock3_(0x10);
    return 0;
}

 

 

No idea why it fails with different base address. And how exactly it fails? Poll timeout? 

@Pavel A. , Can you send code for FL_ReadStatus()? I used HAL library status function for block erase:

if(HAL_NOR_GetStatus(&hnor1, ((uint32_t)0x60000000U), NOR_TIMEOUT_VALUE) !=
HAL_NOR_STATUS_SUCCESS).

                            But I think I need FL_ReadStatus() code for chip erase.
   Another thing, the block erase code worked at least twice. But doesn't work afterwards. I tried many times. I suspect the reading & writing location address is different from erase location. Can u plz check;

#define EXTFL_ERASE_BLK_SIZE  0x1000U
#define NOR_BANK_ADDR ((uint32_t)0x60000000U)

static inline uint16_t *EXTFL_block_and_offset_to_addr(unsigned blk, unsigned offs)
{
  return (uint16_t *) (NOR_BANK_ADDR + blk * EXTFL_ERASE_BLK_SIZE + offs);
}

 Can you break down this; what should be the value of blk & offs to erase at address 0x8000?
Read function;

if(HAL_NOR_ReadBuffer(&hnor1, ((uint32_t)0x60000000U + pAddress), aRxBuffer,BUFFER_SIZE) != HAL_OK)

   pAddress I am using is 0x8000, 0x10000, 0x18000. 
  Poll timeout seems ok for different base address, but read cmd simply returns old data instead of FFs.
Thanks

Pavel A.
Evangelist III

 

char FL_ReadStatus(unsigned nblk, unsigned int offset)
{
    uint16_t status[3];
    uint16_t toggle_6;
    uint16_t volatile *p = EXTFL_block_and_offset_to_addr(nblk, offset);

    status[0] = p[0];
    __DMB();
    status[1] = p[0];
    __DMB();
    status[2] = p[0];
    toggle_6 = ((status[0] ^ status[1]) & (status[1] ^ status[2])) & (1<<6);

    if (toggle_6) {
        if(status[0] & (1<<1))
                return 'A';    //WRITE_BUFFER_ABORT
        if(status[0] & (1<<5))
                return 'T';   //EXCEEDED_TIME_LIMITS;
        return 'B';           //BUSY;
    } else {
        uint16_t toggle_2;
        toggle_2 = ((status[0])^(status[1])) & (1<<2);

        if (toggle_2)
            return 'S'; //SUSPEND;
        else
            return (char)0; //READY;
    }
}

 

The erase block size of my flash (ISSI IS29GL128/256)  is only 128K, not 4K. and address 0x8000 is within block 0 (0-0x1FFFF). Maybe my code is not compatible with your ISSI flash. Unfortunately I don't have this board now.

On other 'H753 board (designed by the same engineer) I've seen that the ST NOR driver freezes during sector  and mass erase (systick interrupts do not arrive) so simple detection of timeout by counting systick fails. I guessed then that it is effect of CM7 "speculative execution". But you have L4, it should not be subject to this...