STM32 EEPROM Testing

Dependencies:   mbed

Revision:
0:77080c9376de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cal.cpp	Wed Apr 04 15:16:19 2018 +0000
@@ -0,0 +1,322 @@
+#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
\ No newline at end of file