Sample IAP test code for Nucleo_F091RC

stm_iap.cpp

Committer:
narasimma23
Date:
2017-06-17
Revision:
0:de2687a62a94

File content as of revision 0:de2687a62a94:

/**
 * Author: Narasimma DLN
 * Email: narasimma23@gmail.com
 */
 
#include "stm_iap.h"

static uint32_t flash_sectors[FLASH_SECTORS];
static uint16_t *flash_size_addr = (uint16_t *)FLASH_SIZE_ADDR;

static IAPCode check_error(void);
static void unlock_flash(bool unlock);

// Get Flash Sectors
void get_flash_sectors(void)
{
    uint8_t i;
    uint32_t _addr = FLASH_START_ADDR;
    
    for (i=0; i<FLASH_SECTORS; i++) {
        flash_sectors[i] = _addr;
        _addr += FLASH_SECTOR_SIZE;
    }
}

// Get Flash Size
uint32_t get_flash_size(void) {
    return *flash_size_addr * 1024;
}


// Get Sector Number
uint8_t get_sector_number(uint32_t _addr) {
    uint8_t retval = 0;
    while(1) {
        //If start address of next sector is higher than wanted address, return current value
        if (_addr < flash_sectors[retval + 1])
            return retval;
        
        retval++;
    }
}

// Get Sector Size
uint32_t get_sector_size(uint32_t _addr)
{
    uint8_t sector = get_sector_number(_addr);
    return flash_sectors[sector+1] - flash_sectors[sector];
}

static IAPCode check_error(void)
{    
    //Wait until done
    while (FLASH->SR & FLASH_SR_BSY);
    
    //Check for errors
    if (FLASH->SR & FLASH_SR_WRPERR)
        return WriteProtError;
    if (FLASH->SR & FLASH_SR_PGERR)
        return ProgrammingError;
    
    return Success;
}

// Erase a Flash Sector
IAPCode erase_sector(int address)
{
    uint8_t sec_num = get_sector_number(address);
    
    unlock_flash(true);
    
    //Clear current errors
    FLASH->SR = FLASH_SR_WRPERR | FLASH_SR_PGERR;
    
    //Run command
    // Page 1
    FLASH->CR |= FLASH_CR_PER;
    FLASH->AR = flash_sectors[sec_num]; 
    FLASH->CR |= FLASH_CR_STRT;
    while (FLASH->SR & FLASH_SR_BSY);
    
    // Page 2
    FLASH->CR |= FLASH_CR_PER;
    FLASH->AR = flash_sectors[sec_num] + FLASH_PAGE_SIZE; 
    FLASH->CR |= FLASH_CR_STRT;
    while (FLASH->SR & FLASH_SR_BSY);
    
    if ((FLASH->SR & FLASH_SR_EOP) != 0)
        FLASH->SR = FLASH_SR_EOP;
        
    FLASH->CR &= ~FLASH_CR_PER;

    unlock_flash(false);    
    IAPCode retval = check_error();
    
    return retval;
}

// Unlocking Flash
static void unlock_flash(bool unlock)
{
    if (unlock) {
        __disable_irq();
        //Wait until not busy
        while (FLASH->SR & FLASH_SR_BSY);
        if ((FLASH->CR & FLASH_CR_LOCK) != 0) {
            FLASH->KEYR = 0x45670123;
            FLASH->KEYR = 0xCDEF89AB;
        }
    } else {
        FLASH->CR |= FLASH_CR_LOCK;
        __enable_irq();
    }
}

// Programming Flash Memory 
IAPCode program_flash(uint32_t address, uint16_t *data, unsigned int length)
{ 
    unlock_flash(true);
    
    FLASH->CR |= FLASH_CR_PG;
    
    uint16_t* write_addr = (uint16_t*)address;
    for (int i = 0; i<length/2; i++) {
        write_addr[i] = data[i];
        while (FLASH->SR & FLASH_SR_BSY);
    }
    
    if ((FLASH->SR & FLASH_SR_EOP) != 0)
        FLASH->SR = FLASH_SR_EOP;
    
    IAPCode retval = check_error();
    FLASH->CR &= ~FLASH_CR_PG;
    
    unlock_flash(false);

    return retval;
}