AnsweredAssumed Answered

Problem Erasing STM32F767 FLASH (IAP)

Question asked by Chris Pad on Jun 16, 2017
Latest reply on Jul 24, 2017 by Chris Pad

Platform: STM32F767 Nucleo-144 (STM32F767ZIT6U)

Toolchain: ARM GCC (mbed CLI)

 

Hi everyone. I am having trouble erasing FRASH. It seems to part work for some sectors and not others. I am setting the nWRP bits in FLASH->OPTCR. A subsequent write to 0x00000000 does work so it's definitely a sector erase issue.

 

My full routine code is below.  It forms part of a bootloader and is put at the TOP of FLASH and I will be erasing the bottom of FLASH. I realise this is unconventional, but it is the way I would like to go and is consistent with Bootloader_K64F - a mercurial repository | mbed 

 

I get the following output over UART (please note that the UART of preconfigured before this code is called):

00000011000000000000000000000000<\r><\n>
11111111111111111010101011111100<\r><\n>
ABCDEFGH<\0>

I can then check the FLASH using ST-LINK Utility and can see that it is only FFFFFFFF up to address 0x0800FFFF.

 

I'd be very grateful if someone could help me as I am not seeing what I am doing wrong. I have based my approach on the Reference Manual and still no joy.

 

#include "mbed.h"


#define BANK_BANKS_ERASE       8   // goes up to 1024K
#define FLASH_SPACE_TO_COPY     0x000F0000
#define FLASH_FROM_ADDRESS      0x08100000
#define FLASH_TO_ADDRESS        0x08000000
#define NUMBER_OF_FFFF_LIMIT    0x00000100

#define LOG(str)        {int i = 0; while(str[i] != '\0'){while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = str[i]; i++;}} while( !(USART3->ISR & (1 << 7)) )
#define NOP_WAIT(T)     {int i = 0; i = T; while(i) {__NOP(); i--;}}

// https://developer.mbed.org/users/Sissors/code/Bootloader_K64F/file/3d0391cda333/main.cpp

/*

    Change required to linker file:
        MEMORY
        {
          FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1984K
          CHRIS_BL (rx) : ORIGIN = 0x081F0000, LENGTH = 64K
          RAM (rwx)  : ORIGIN = 0x200001F8, LENGTH = 512K - 0x1F8
        }
   
     and before .data :
       
        .chris_bl :
        {
            *(.CHRIS_bootloader*);
        } > CHRIS_BL

*/


/*
    MBED does not use dual bank!
*/


//__attribute__((section(".ARM.__at_0x081F0000"))) void bootloader(void) {
__attribute__((section(".CHRIS_bootloader"))) void bootloader(void) {
    uint32_t temp = 0;
    uint32_t timeout = 0;
   
    __disable_irq();
   
    // make PB_7 an output and flash it
    RCC->AHB1ENR |= (1 << 1);    // GPIOBEN
    GPIOB->MODER &= ~(3 << 14);
    GPIOB->MODER |= (1 << 14);
    GPIOB->OTYPER &= ~(1<< 7);  // PushPull
    GPIOB->OSPEEDR &= ~(3 << 14);
    GPIOB->OSPEEDR |= (3 << 14);    // Very High Speed
   
//    LOG("Bootloader Entry\r\n");
   
    GPIOB->ODR |= (1 << 7);
        for(uint32_t j = 0; j < 100000000; j++) {
            __NOP();
        }
    GPIOB->ODR &= ~(1 << 7);
   
    // Enable FLASH access
//    LOG("Set keys and enable FLASH access\r\n");
    #define FLASH_FKEY1     0x45670123  // page 106 of RM0410
    #define FLASH_FKEY2     0xCDEF89AB  // page 106 of RM0410
    // ensure FLASH memory is not busy
    __DSB();
    while( FLASH->SR & (1 << 16) );
    // See if FLASH already unlocked, unlock if not
    if( FLASH->CR & (1 << 31) ){
        FLASH->KEYR = FLASH_FKEY1;
        FLASH->KEYR = FLASH_FKEY2;
    }
    __DSB();
    while( FLASH->SR & (1 << 16) );
    if( FLASH->CR & (1 << 31) ){
        while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '@'; while( !(USART3->ISR & (1 << 7)) );
    }
    FLASH->CR &= ~(3 << 8);
    //FLASH->CR |= (1 << 8);      // x16 parellelism
    // x32 if Vprog = 2.7 - 3, x16 if Vprog = 2.1 - 3.6, x8 if Vprog = 1.7 - 3.6
   
    // Erase Application memory space
//    LOG("Erase sectors:\r\n");
    FLASH->CR |= (1 << 24) | (1 << 25);                     // EOPIE / ERRIE: End of operation interrupt enable, error interrupt enable
   
    // print contents of FLASH->CR
    uint32_t reg_val = 0;
    reg_val = FLASH->CR;
    for(uint32_t j = 0; j < 32; j++) {
        if( 0x80000000 & (reg_val << j) ) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '1'; while( !(USART3->ISR & (1 << 7)) );
        } else {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '0'; while( !(USART3->ISR & (1 << 7)) );
        }
    }
    while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '\r'; while( !(USART3->ISR & (1 << 7)) );
    while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '\n'; while( !(USART3->ISR & (1 << 7)) );
   
    #define OPTKEY1         0x08192A3B
    #define OPTKEY2         0x4C5D6E7F
    // ensure FLASH memory is not busy
    __DSB();
    while( FLASH->SR & (1 << 16) );
    // See if FLASH already unlocked, unlock if not
    if( FLASH->OPTCR & (1 << 0) ){
        FLASH->OPTKEYR = OPTKEY1;
        FLASH->OPTKEYR = OPTKEY2;
    }
    __DSB();
    while( FLASH->SR & (1 << 16) );
    FLASH->OPTCR |= (0x0FFF << 16);     // nWRP[11:0]: Not write protect
    FLASH->OPTCR |= (0xAA << 8);        // RDP[7:0]: Read protect
    //FLASH->OPTCR &= ~(3 << 2);           // BOR
    //FLASH->OPTCR |= (1 << 2);           // BOR Level2
    FLASH->OPTCR |= (1 << 1);           // OPTSTART
    __DSB();
    while( FLASH->SR & (1 << 16) );
    if( FLASH->OPTCR & (1 << 0) ){
        while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '?'; while( !(USART3->ISR & (1 << 7)) );
    }
   
    // print contents of FLASH->OPTCR
    //uint32_t reg_val = 0;
    reg_val = FLASH->OPTCR;
    for(uint32_t j = 0; j < 32; j++) {
        if( 0x80000000 & (reg_val << j) ) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '1'; while( !(USART3->ISR & (1 << 7)) );
        } else {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '0'; while( !(USART3->ISR & (1 << 7)) );
        }
    }
    while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '\r'; while( !(USART3->ISR & (1 << 7)) );
    while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '\n'; while( !(USART3->ISR & (1 << 7)) );
   
   
    // BANK 1:
    for(uint32_t j = 0; j < BANK_BANKS_ERASE; j++) {
//        char log_str[] = "Sector   ...\r\n";
//        log_str[8] = (char)j + '0';
//        LOG(log_str);
        while( FLASH->SR & (1 << 16) );       // loop while busy
        FLASH->CR |= (1 << 1);                  // SER : sector erase
        FLASH->CR |= (j << 3);                  // SNB : Sector select
        FLASH->CR |= (1 << 16);                 // STRT : start the erase
//        LOG("      await FLASH busy going low\r\n");
        __DSB();
        while( FLASH->SR & (1 << 16) );       // loop while busy
//        LOG("      await FLASH EOP going high\r\n");
        //while( !(FLASH->SR & (1 << 0)) );       // loop EOP not set
        while( !(FLASH->SR & (3 << 0)) );       // loop EOP and ERR not set
        if((FLASH->SR & (1 << 0))) {
            while( !(USART3->ISR & (1 << 7)) );
            USART3->TDR = 'A' + (j % 26);
            while( !(USART3->ISR & (1 << 7)) );
        } else {
            if(FLASH->SR & (1 << 4))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '!'; while( !(USART3->ISR & (1 << 7)) ); }   // WRPERR write protection
            if(FLASH->SR & (1 << 5))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '$'; while( !(USART3->ISR & (1 << 7)) ); }   // PGAERR aligment
            if(FLASH->SR & (1 << 6))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '='; while( !(USART3->ISR & (1 << 7)) ); }   // PGPERR parallelism
            if(FLASH->SR & (1 << 7))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '*'; while( !(USART3->ISR & (1 << 7)) ); }   // ERSERR
        }
        FLASH->SR |= ((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));                  // Clear EOP etc
        //FLASH->SR |= (1 << 0);                  // Clear EOP
        NOP_WAIT(100000000);
    }
   
    GPIOB->ODR |= (1 << 7);
   
    while(1);
   
    /*
    if( FLASH->OPTCR & (1 << 29) ) {
        FLASH->CR |= (11 << 3);                  //SNB : Sector select
        FLASH->CR |= (1 << 1);                  // SER : sector erase
        FLASH->CR |= (1 << 16);                 // STRT : start the erase
        //while( FLASH->SR & (1 << 16) );       // loop while busy
        while( !(FLASH->SR & (1 << 0)) );       // loop EOP not set
        FLASH->SR |= (1 << 0);                  // Clear EOP
        // BANK 2:
        for(uint32_t j = 0; j < 11; j++) {
            FLASH->CR |= (1 << 7) | (j << 3);                  //SNB : Sector select
            FLASH->CR |= (1 << 1);                  // SER : sector erase
            FLASH->CR |= (1 << 16);                 // STRT : start the erase
            //while( FLASH->SR & (1 << 16) );       // loop while busy
            while( !(FLASH->SR & (1 << 0)) );       // loop EOP not set
            FLASH->SR |= (1 << 0);                  // Clear EOP
        }
    }
    */

   
    NOP_WAIT(10000000);
    //char log_str[] = "Erase finished\r\n";
    //LOG(log_str);
//    LOG("Erase finished\r\n");
    NOP_WAIT(10000000);
   
    // Copy New App into start of FLASH
//    LOG("Programming FLASH...\r\n");
    NOP_WAIT(10000000);
    FLASH->CR |= (1 << 0);         // PG: Programming - Flash programming activated.
    uint16_t* flash_to_ptr   = (uint16_t*)FLASH_TO_ADDRESS;
    uint16_t* flash_from_ptr = (uint16_t*)FLASH_FROM_ADDRESS;
    uint32_t number_of_ffff = 0;
    uint16_t data = 0;
   
    NOP_WAIT(10000000);
//    LOG("PSIZE=");
    if(FLASH->CR & (1 << 9))   {
        //LOG("PSIZE[1]=1\r\n");
        while( !(USART3->ISR & (1 << 7)) );
        USART3->TDR = '1';
        while( !(USART3->ISR & (1 << 7)) );
    } else {
        //LOG("PSIZE[1]=0\r\n");
        while( !(USART3->ISR & (1 << 7)) );
        USART3->TDR = '0';
        while( !(USART3->ISR & (1 << 7)) );
    }
    NOP_WAIT(1000000);
    if(FLASH->CR & (1 << 8))   {
        //LOG("PSIZE[0]=1\r\n");
        while( !(USART3->ISR & (1 << 7)) );
        USART3->TDR = '1';
        while( !(USART3->ISR & (1 << 7)) );
    } else {
        //LOG("PSIZE[0]=0\r\n");
        while( !(USART3->ISR & (1 << 7)) );
        USART3->TDR = '0';
        while( !(USART3->ISR & (1 << 7)) );
    }
    NOP_WAIT(1000000);
   
    number_of_ffff = 0;
    for(uint32_t j = 0; j < (FLASH_SPACE_TO_COPY / 2); j++) {
       
        __DSB();
        timeout = 1000000;
        while( (FLASH->SR & (1 << 16)) && timeout ){ timeout--; }      // loop while busy
        if(timeout == 0) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = 't'; while( !(USART3->ISR & (1 << 7)) );
        }
       
        data = *flash_from_ptr;
        //data = 0xCCCC;
        data = 0x0000;
       
        __DSB();
        timeout = 1000000;
        while( (FLASH->SR & (1 << 16)) && timeout ){ timeout--; }      // loop while busy
        if(timeout == 0) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = 't'; while( !(USART3->ISR & (1 << 7)) );
        }
       
        *flash_to_ptr = data;
       
        __DSB();
        timeout = 1000000;
        while( (FLASH->SR & (1 << 16)) && timeout ){ timeout--; }      // loop while busy
        if(timeout == 0) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = 't'; while( !(USART3->ISR & (1 << 7)) );
        }
        __DSB();
        timeout = 1000000;
        while( (!(FLASH->SR & (3 << 0))) && timeout ){ timeout--; }        // loop EOP and ERR not set
        if(timeout == 0) {
            while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = 'T'; while( !(USART3->ISR & (1 << 7)) );
        }
        if(!(FLASH->SR & (2 << 0))) {
           
        } else {
            if(FLASH->SR & (1 << 4))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '!'; while( !(USART3->ISR & (1 << 7)) ); }   // WRPERR write protection
            if(FLASH->SR & (1 << 5))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '$'; while( !(USART3->ISR & (1 << 7)) ); }   // PGAERR aligment
            if(FLASH->SR & (1 << 6))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '='; while( !(USART3->ISR & (1 << 7)) ); }   // PGPERR parallelism
            if(FLASH->SR & (1 << 7))   { while( !(USART3->ISR & (1 << 7)) ); USART3->TDR = '*'; while( !(USART3->ISR & (1 << 7)) ); }   // ERSERR
        }
        FLASH->SR |= ((1 << 0) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));                  // Clear EOP etc
       
        if( data == 0xFFFF ) {
            number_of_ffff++;
        }
        flash_from_ptr++;
        flash_to_ptr++;
     //   if(j % 1024 == 0)      GPIOB->ODR |= (1 << 7);
     //   if(j % 1024 == 512)    GPIOB->ODR &= ~(1 << 7);
#if( NUMBER_OF_FFFF_LIMIT )
        if(number_of_ffff > NUMBER_OF_FFFF_LIMIT)   break;
#endif
    }
   
//    LOG("FLASH programming finished\r\n");
   
    // Reset
    //NVIC_SystemReset();     // Inlined so should be OK here
   
   
    /**/   
    temp = 100000000;
    if( FLASH->OPTCR & (1 << 29) ) {
        temp = 10000000;
    }
   
    while(1) {
        GPIOB->ODR |= (1 << 7);
        for(uint32_t j = 0; j < temp; j++) {
            __NOP();
        }
        GPIOB->ODR &= ~(1 << 7);
        for(uint32_t j = 0; j < temp; j++) {
            __NOP();
        }
    }
/**/
   
    while(1);
}

Outcomes