STM32 EEPROM Testing

Dependencies:   mbed

cal.cpp

Committer:
chromaticdeth87
Date:
2018-04-04
Revision:
0:77080c9376de

File content as of revision 0:77080c9376de:

#include "mbed.h"
#include "globals.h"
#include "cal.h"

#define ENABLE_DEBUG_PRINTING  1  // turn on diagnostic printing
#define ENABLE_TEST_CODE       1  // turn on self-test code (disable for release)


// Must customize which page of flash is used for calibration data
// The STM32F334C8 has 32 pages (0..31) so use the last one
// Note that on the initial prototype boards, a STM32F334C6 was used
#define CAL_PAGE  31

static uint32_t CalPageAddress = FLASH_BASE + (CAL_PAGE * FLASH_PAGE_SIZE);


#define CAL_HALFWORD_COUNT    (sizeof(CALIBRATION_DATA)/sizeof(uint16_t))
#define CAL_WORD_COUNT        (sizeof(CALIBRATION_DATA)/sizeof(uint32_t))
#define CAL_DOUBLEWORD_COUNT  (sizeof(CALIBRATION_DATA)/sizeof(uint64_t))



CALIBRATION_DATA g_cal;

static uint32_t DataAddress;     // address of last saved data

static HAL_StatusTypeDef erase_page(uint32_t PageAddress)
{
    HAL_StatusTypeDef Status;
    FLASH_EraseInitTypeDef EraseInit;
    uint32_t PageError;

    EraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInit.PageAddress = PageAddress;
    //EraseInit.PageAddress = FLASH_BASE + (page_number * FLASH_PAGE_SIZE);
    EraseInit.NbPages = 1;

    HAL_FLASH_Unlock();
    Status = HAL_FLASHEx_Erase(&EraseInit, &PageError);
    HAL_FLASH_Lock();
    return Status;
}

static uint16_t calc_checksum()
{
    int i;
    uint16_t *p;
    uint16_t checksum;

    // read cal data from flash in 16 bit chunks
    p = (uint16_t *)&g_cal;

    checksum = 0;

    for (i=0; i < (CAL_HALFWORD_COUNT - 1); i++) {  // don't sum checksum field

        checksum += *p;

        p++;
    }
    return checksum;
}

static void factory_defaults()
{
    //ppb_per_mv = 100.0f / 871.0f;  // From Pyxis with factory cal
    //ppb_per_mv = 95.3f / (418.0f - 80.0f);  // From Megatron and protoboard (reading-dark current) and scope
    //ppb_per_mv = 95.3f / (418.0f);  // From Megatron and protoboard and scope
    //ppb_per_mv = 0.3225f;  // manual 300/930
    //ppb_per_mv = 0.305f;  // manual 300/981

    g_cal.uv_zero_mV =  81;  // uv adc mV reading at 0 ppb  (might try dark current scaled up a bit here as a guess)
    g_cal.uv_cal_mV  = 981;  // uv adc mV reading at calibration point
    g_cal.uv_cal_ppb = 300;  // uv user ppb value at calibration point

    g_cal.vis_zero_mV =  81;
    g_cal.vis_cal_mV  = 981;
    g_cal.vis_cal_ppb = 300;

    g_cal.trim_4mA    =  816;  // dac value to use for  4 mA  (see mA.cpp)
    g_cal.trim_20mA   = 4080;  // dac value to use for 20 mA  (see mA.cpp)
    g_cal.ppb_at_20mA =  300;  // factory default 4-20 mA range is 0-300 ppb
    
    g_cal.padding = 0;
    
    //g_cal.mAOffsetValue = 0.0;

    g_cal.checksum = calc_checksum();
}



void cal_print()
{
    printf("cal data = %.0f,  %.0f,  %.0f,  %.0f,  %.0f,  %.0f, %u,  %u, %.0f, %u, %u\n",
           g_cal.uv_zero_mV,
           g_cal.uv_cal_mV,
           g_cal.uv_cal_ppb,
           g_cal.vis_zero_mV,
           g_cal.vis_cal_mV,
           g_cal.vis_cal_ppb,
           g_cal.trim_4mA,
           g_cal.trim_20mA,
           g_cal.ppb_at_20mA,
           g_cal.padding,
           g_cal.checksum);

}


static void read_cal_data(uint32_t address)
{

    int i;
    uint16_t *p;

    // read cal data from flash address in 16 bit chunks
    p = (uint16_t *)&g_cal;

    for (i=0; i < CAL_HALFWORD_COUNT; i++) {

        *p = *(__IO uint16_t *)address;  // read cal data

        address += sizeof(uint16_t);
        p++;
    }
#ifdef ENABLE_DEBUG_PRINTING
    cal_print();
#endif
}

void cal_init()
{
    uint32_t address;
    
    // Assign factory defaults
    factory_defaults();

    // Start at beginning
    DataAddress = CalPageAddress;
    address = CalPageAddress;

    while (IS_FLASH_PROGRAM_ADDRESS(address)) {
        uint32_t val;
        uint8_t *p;

        p = (uint8_t *)&val;

        val = *(__IO uint32_t*)address;  // read 32 bits (4 bytes)

        pc.printf("%hhX  %hhX  %hhX  %hhX\n", p[0], p[1], p[2],p[3]);

        // If the first 4 bytes are all 0xFF, the end of data has been reached
        if ( (p[0] == 0xFF) && (p[1] == 0xFF) && (p[2] == 0xFF) && (p[3] == 0xFF)) break;
#ifdef ENABLE_DEBUG_PRINTING
        pc.printf("Saved data found at %lX\n", address);
#endif

        // Read cal data (this might not be the last one yet)
        read_cal_data(address);

        DataAddress = address;  // save last used data address
        address += sizeof(CALIBRATION_DATA);  // Keep looking
    }

    // Verify checksum
    if (g_cal.checksum != calc_checksum()) {
#ifdef ENABLE_DEBUG_PRINTING
        pc.printf("Checksum mismatch, using factory defaults, flash = %u, calc = %u\n", g_cal.checksum, calc_checksum());
#endif
        factory_defaults();
    }
#ifdef ENABLE_DEBUG_PRINTING
    else {
        pc.printf("Checksum OK\n");
    }
#endif


    // Either valid data was found, or factory defaults are set

}


void cal_save()
{
    int i;
    uint16_t *p;

    /*
     * FLASH_TYPEPROGRAM_HALFWORD is 16 bits
     * FLASH_TYPEPROGRAM_WORD is 32 bits = sizeof(float)
     * FLASH_TYPEPROGRAM_DOUBLEWORD is 64 bits
     * HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
     */

    //HAL_StatusTypeDef Status;
    uint32_t NextDataAddress;  // address to use for next saved data
    uint32_t LastByteAddress;  // address of last byte when new data is added
    NextDataAddress = DataAddress + sizeof(CALIBRATION_DATA);
    LastByteAddress = NextDataAddress + sizeof(CALIBRATION_DATA) - 1;

    // First, decide if there is room at the end of the page for new data
    if (!IS_FLASH_PROGRAM_ADDRESS(LastByteAddress)) {
        // Erase the entire cal page
        erase_page(CalPageAddress);
        // Point to new location
        NextDataAddress = CalPageAddress;
    }
    // Remember the location of the start of the new data
    DataAddress = NextDataAddress;

    // Update the checksum
    g_cal.checksum = calc_checksum();

    p = (uint16_t *) &g_cal;

    HAL_FLASH_Unlock();

    for (i=0; i < CAL_HALFWORD_COUNT; i++) {
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, NextDataAddress, (uint64_t )(*p));
        NextDataAddress += sizeof(uint16_t);
        p++;
    }

    HAL_FLASH_Lock();
}


void cal_factory()
{
    // Set device to factory defaults
    erase_page(CalPageAddress);
    cal_init();
    cal_save();
}
    



#ifdef ENABLE_TEST_CODE

void direct()
{
    int i;

    //HAL_StatusTypeDef Status;
    FLASH_EraseInitTypeDef EraseInit;
    uint32_t PageError;

    EraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
    EraseInit.PageAddress = FLASH_BASE + (18 * FLASH_PAGE_SIZE);
    EraseInit.NbPages = 1;

    HAL_FLASH_Unlock();
    HAL_FLASHEx_Erase(&EraseInit, &PageError);
    HAL_FLASH_Lock();


    printf("\nFlash memory values at start of each page:\n");
    for (i=0; i<32; i++) {
        uint32_t address;
        uint32_t val;
        uint8_t *p;

        p = (uint8_t *)&val;
        address = FLASH_BASE + (i * FLASH_PAGE_SIZE);

        val = *(__IO uint32_t*)address;  // read 32 bits (4 bytes)

        printf("%i  %hhX  %hhX  %hhX  %hhX\n", i, p[0], p[1], p[2],p[3]);
    }
}


static void increment_data()
{
    g_cal.uv_zero_mV += 1;  // uv adc mV reading at 0 ppb
    g_cal.uv_cal_mV  += 1;  // uv adc mV reading at calibration point
    g_cal.uv_cal_ppb += 0;  // uv user ppb value at calibration point

    g_cal.vis_zero_mV += 1;
    g_cal.vis_cal_mV  += 1;
    g_cal.vis_cal_ppb += 1;

    g_cal.trim_4mA  +=  1;  // dac value to use for  4 mA
    g_cal.trim_20mA += 1;   // dac value to use for 20 mA

    g_cal.checksum = calc_checksum();
}

void cal_test()
{

    pc.printf("\b\nSTM32 Test Flash Memory\n");
    pc.printf("Flash page size = %d bytes\n", FLASH_PAGE_SIZE);
    pc.printf("CALIBRATION_DATA size = %d bytes\n", sizeof(CALIBRATION_DATA));
    pc.printf("Max saves per page = %d\n", FLASH_PAGE_SIZE / sizeof(CALIBRATION_DATA));
    pc.printf("Number of   half-words = %d\n", CAL_HALFWORD_COUNT);
    pc.printf("Number of        words = %d\n", CAL_WORD_COUNT);
    pc.printf("Number of double-words = %d\n", CAL_DOUBLEWORD_COUNT);
    pc.printf("g_cal.vis_cal_ppb = %2.2f\n", g_cal.vis_cal_ppb);
    pc.printf("Page Address: %lX \n", CalPageAddress);
   // pc.printf("g_cal.mAOffsetValue = %f\n",   g_cal.mAOffsetValue);
  


    //cal_init();
    //increment_data();
    //cal_save();

    //direct();

    // Test 1: empty flash
    // Test 2: junk in flash
    // Test 3: valid stuff in flash
    // Test 4: invalid checksum in flash
    // Test 5: Repeated saves - does it loop back correctly ?


}
#endif