This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430F233:这是使用闪存保护数据的好方法吗?

Guru**** 2513185 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1073115/msp430f233-is-this-a-good-way-to-protect-data-with-flash

部件号:MSP430F233

#include "data.h"
#include "ks0108.h"
#include "Flash.h"

// these defines need changing as we add or remove data elements
// they must be even values rounded up!
#define CAL_DATA_LENGTH 24
#define PERSISTENT_DATA_LENGTH 6
#define MEM_POINTER_LENGTH 4


extern Fonts fonts;

// split up save structures as may have different save times.

// save/load persistent tested with infoSegB
void Data_Save_Persistent(PersistentData* pd, MemPointers* mp){

    uint8_t dataBuf[PERSISTENT_DATA_LENGTH];
    uint8_t errBuf[PERSISTENT_DATA_LENGTH];
    uint8_t ii;
    uint8_t fails;
    uint8_t testFail = 0x01;

    // initalize arrays to 0xFF
    for(ii = 0; ii < PERSISTENT_DATA_LENGTH; ii++){
        dataBuf[ii] = 0xFF;
        errBuf[ii]  = 0xFF;
    }

    // 16 bit fields
    Split_16(pd->trip1, dataBuf, 0);
    Split_16(pd->tankLevel1, dataBuf, 2);
    Split_16(pd->tankLevel2, dataBuf, 4);

    do{
        fails = 0;

        // erase flash
        Flash_Erase((uint16_t*)mp->persistentDataPtr);
        Flash_Read(errBuf, (uint16_t*)mp->persistentDataPtr, PERSISTENT_DATA_LENGTH);

        /* failure simulation test
        if(testFail == 0x01){
            fails++;
            testFail--;
            GLCD_Debug_Print("fail test per", font);
            __delay_cycles(200000);
        } */

        for(ii = 0; ii < PERSISTENT_DATA_LENGTH; ii++){
            if(errBuf[ii] != 0xff){
                fails++;
            }
        }

        // copy arrays for error test
        for(ii = 0; ii < PERSISTENT_DATA_LENGTH; ii++){
            errBuf[ii] = dataBuf[ii];
        }


        // save persistent data to infoSegB
        Flash_Write(dataBuf, (uint16_t*)mp->persistentDataPtr, PERSISTENT_DATA_LENGTH);

        // check saved data against written data
        Flash_Read(errBuf, (uint16_t*)mp->persistentDataPtr, PERSISTENT_DATA_LENGTH);

        for(ii = 0; ii < PERSISTENT_DATA_LENGTH; ii++){
            if(errBuf[ii] != dataBuf[ii]){
                fails++;
            }
        }
        if(fails > 0){
            if(mp->persistentDataPtr + PERSISTENT_DATA_LENGTH < INFO_SEG_A){
                mp->persistentDataPtr += PERSISTENT_DATA_LENGTH; // add length of persistent data to the mem pointer
            }
            else{

                // restore the first address of infoSegB
                mp->persistentDataPtr = INFO_SEG_B;

                // add half the length of byte array to stagger over memory in case of one bad cell
                mp->persistentDataPtr += (PERSISTENT_DATA_LENGTH >> 0x01);
            }

            // save this new memory pointer
            Data_Save_Mem_Pointers(mp);
        }

    }while(fails > 0);

}

void Data_Load_Persistent(PersistentData* pd, MemPointers* mp){
    uint8_t dataBuf[PERSISTENT_DATA_LENGTH];

    Flash_Read(dataBuf, (uint16_t*)mp->persistentDataPtr, PERSISTENT_DATA_LENGTH); // read in data from flash
    pd->trip1 = Merge_16(dataBuf, 0);
    pd->tankLevel1 = Merge_16(dataBuf, 2);
    pd->tankLevel2 = Merge_16(dataBuf, 4);
}

// just save cal data, use after calibration changes.
void Data_Save_Cal(CalData* cd, MemPointers* mp){

    uint8_t dataBuf[CAL_DATA_LENGTH];
    uint8_t errBuf[CAL_DATA_LENGTH];
    uint8_t ii;
    uint8_t fails;
    uint8_t testFail = 0x01;
    bool flags[8]= {0,0,0,0,0,0,0,0};

    // initalize arrays to 0xFF
     for(ii = 0; ii < CAL_DATA_LENGTH; ii++){
         dataBuf[ii] = 0xFF;
         errBuf[ii]  = 0xFF;
     }

    // save bits
    flags[0] = cd->lang;
    flags[1] = cd->gpsDisable;
    flags[2] = cd->backlightDim;
    flags[3] = cd->singleDualProduct;

    // save bytes to buffer
    dataBuf[0] = Merge_Flags(flags);
    dataBuf[1] = cd->product1Rate;
    dataBuf[2] = cd->product2Rate;
    dataBuf[3] = cd->rate1Units;
    dataBuf[4] = cd->rate2Units;
    dataBuf[5] = cd->rate1Span;
    dataBuf[6] = cd->rate2Span;
    dataBuf[7] = cd->pwm1Min;
    dataBuf[8] = cd->pwm1Max;
    dataBuf[9] = cd->pwm2Min;
    dataBuf[10] = cd->pwm2Max;
    dataBuf[11] = cd->primeSpeed;
    dataBuf[12] = cd->slowSpeed;
    dataBuf[13] = cd->holdSpeed;
    dataBuf[14] = cd->simulateSpeed;

    // save multibytes to buffer
    Split_16(cd->boomWidth, dataBuf, 15);
    Split_16(cd->PPL1, dataBuf, 17);
    Split_16(cd->PPL2, dataBuf, 19);
    Split_16(cd->wheelCoEff, dataBuf, 21);

    do{
        fails = 0;
        Flash_Erase((uint16_t*)mp->calDataPtr);
        Flash_Read(errBuf, (uint16_t*)mp->calDataPtr, CAL_DATA_LENGTH);

        /* Debug failure test
        if(testFail == 0x01){
           fails++;
           testFail--;
           GLCD_Debug_Print("fail test cal", font);
           __delay_cycles(20000000);
        }
        */


        for(ii = 0; ii < CAL_DATA_LENGTH; ii++){
            if(errBuf[ii] != 0xFF){
                fails++;
            }
        }

        // copy arrays for error test
        for(ii = 0; ii < CAL_DATA_LENGTH; ii++){
          errBuf[ii] = dataBuf[ii];
        }

        // save calData data to infoSegC
        Flash_Write(dataBuf, (uint16_t*)mp->calDataPtr, CAL_DATA_LENGTH);

        // check saved data against written data
        Flash_Read(errBuf, (uint16_t*)mp->calDataPtr, CAL_DATA_LENGTH);

        for(ii = 0; ii < CAL_DATA_LENGTH; ii++){
            if(errBuf[ii] != dataBuf[ii]){
                fails++;
            }
        }
        if(fails > 0){
            if(mp->calDataPtr + CAL_DATA_LENGTH < INFO_SEG_B){
                mp->calDataPtr += CAL_DATA_LENGTH; // add length of cal data to the mem pointer
            }
            else{
                // restore to the first memory address of infoSegC
                mp->calDataPtr = INFO_SEG_C;

                // add half of calData byte array length
                mp->calDataPtr += (CAL_DATA_LENGTH >> 0x01);
            }

            // save new pointer
            Data_Save_Mem_Pointers(mp);
        }
    }while(fails > 0);
}

// create calibration data default
// these values just for testing
void Data_Cal_Default(CalData* cd){

    // bits
    cd->lang = 0;
    cd->gpsDisable = 1;
    cd->backlightDim = 1;
    cd->singleDualProduct = 0;

    // bytes
    cd->product1Rate = 0x00;
    cd->product2Rate = 0x01;
    cd->rate1Units = 0x02;
    cd->rate2Units = 0x03;
    cd->rate1Span = 0x04;
    cd->rate2Span = 0x05;
    cd->pwm1Min   = 0x06;
    cd->pwm1Max  =  0x07;
    cd->pwm2Min  =  0x08;
    cd->pwm2Max  =  0x09;
    cd->primeSpeed = 0x0A;
    cd->slowSpeed = 0x0B;
    cd->holdSpeed = 0x0C;
    cd->simulateSpeed = 0x0D;
    cd->boomWidth = 0x0E;
    cd->PPL1 = 0x0F;
    cd->PPL2 = 0x10;
    cd->wheelCoEff = 0x11;

}

// function to just load calibration data
void Data_Load_Cal(CalData* cd, MemPointers* mp){

    uint8_t dataBuf[CAL_DATA_LENGTH];
    bool flags[8];
    Flash_Read(dataBuf, (uint16_t*)mp->calDataPtr, CAL_DATA_LENGTH); // read in data from flash

    // split bits into bool array
    Split_Flags(flags, dataBuf[0]);

    // set bits
    cd->lang = flags[0];
    cd->gpsDisable = flags[1];
    cd->backlightDim = flags[2];
    cd->singleDualProduct = flags[3];

    // set bytes
    cd->product1Rate = dataBuf[1];
    cd->product2Rate = dataBuf[2];
    cd->rate1Units = dataBuf[3];
    cd->rate2Units = dataBuf[4];
    cd->rate1Span  = dataBuf[5];
    cd->rate2Span = dataBuf[6];
    cd->pwm1Min = dataBuf[7];
    cd->pwm1Max = dataBuf[8];
    cd->pwm2Min = dataBuf[9];
    cd->pwm2Max = dataBuf[10];
    cd->primeSpeed = dataBuf[11];
    cd->slowSpeed = dataBuf[12];
    cd->holdSpeed = dataBuf[13];
    cd->simulateSpeed = dataBuf[14];

    // multi bytes
    cd->boomWidth = Merge_16(dataBuf, 15);
    cd->PPL1 = Merge_16(dataBuf, 17);
    cd->PPL2 = Merge_16(dataBuf, 19);
    cd->wheelCoEff = Merge_16(dataBuf, 21);

}

void Data_Default_Mem_Pointers(MemPointers* mp){
    mp->calDataPtr = INFO_SEG_C;
    mp->persistentDataPtr = INFO_SEG_B;

}

void Data_Load_Mem_Pointers(MemPointers* mp){
    uint8_t dataBuf[MEM_POINTER_LENGTH];
    Flash_Read(dataBuf, (uint16_t*)INFO_SEG_D, MEM_POINTER_LENGTH); // read in data from flash
    mp->persistentDataPtr = Merge_16(dataBuf, 0);
    mp->calDataPtr = Merge_16(dataBuf, 2);
}

void Data_Save_Mem_Pointers(MemPointers* mp){
    uint8_t dataBuf[MEM_POINTER_LENGTH];
    uint8_t errBuf[MEM_POINTER_LENGTH];
    uint8_t ii, jj = 0;
    uint8_t fails;
    Split_16(mp->persistentDataPtr, dataBuf, 0);
    Split_16(mp->calDataPtr, dataBuf, 2);

    // loop over this while loop a maximum of 100 times
    // to save from destroying memory in case of infinite loop?
    do{
        fails = 0;
        Flash_Erase((uint16_t*)INFO_SEG_D);
        Flash_Read(errBuf, (uint16_t*)INFO_SEG_D, MEM_POINTER_LENGTH);

        for(ii = 0; ii < MEM_POINTER_LENGTH; ii++){
            if(errBuf[ii] != 0xFF){
                fails++;
            }
        }

        // save memPointer data to infoSegD
        Flash_Write(dataBuf, (uint16_t*)INFO_SEG_D, MEM_POINTER_LENGTH);

        // check saved data against written data
        Flash_Read(errBuf, (uint16_t*)INFO_SEG_D, MEM_POINTER_LENGTH);

        for(ii = 0; ii < MEM_POINTER_LENGTH; ii++){
            if(errBuf[ii] != dataBuf[ii]){
                   fails++;
            }
        }
        jj++;
    }
    while(fails > 0 && jj < 100);

    if(fails > 0){
        // this is the main failure point.
        // if the memory pointers can't be saved to 0x01000 and 0x01001
        // due to bad cells I'm not sure how to recover from that.
        // erases and writes to this segment only occur on failure of the other
        // segments
    }
}

// load all data
void Data_Load(MemPointers* mp, CalData* cd, PersistentData* pd){
        Data_Load_Mem_Pointers(mp);
        Data_Load_Persistent(pd, mp);
        Data_Load_Cal(cd, mp);
}

// helper functions
void Split_Flags(bool outFlags[], uint8_t flagArray){
    uint8_t ii;
    for(ii = 0; ii < 8; ii++){
        outFlags[ii] = (flagArray & (1<<ii)) != 0;
    }
}

uint8_t Merge_Flags(bool inFlags[]){
    uint8_t ii;
    uint8_t result = 0x00;
    for(ii = 0; ii < 8; ii++){
        if(inFlags[ii]){
            result |= 0x01 << ii;
        }
    }
    return result;
}

void Split_16(uint16_t input, uint8_t dataBuf[], uint8_t index){
    dataBuf[index] = (uint8_t)(input >> 0x08);
    index++;
    dataBuf[index] = (uint8_t)((input << 0x08) >> 0x08);
}

uint16_t Merge_16(uint8_t* dataBuf, uint8_t index){
    uint16_t result = 0x0000;
    result = dataBuf[index];
    result <<= 0x08;
    index++;
    result += dataBuf[index];
    return result;
}

// debug functions:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    爱德华:

    MCU 闪存寄存器中已有一个写保护位,您需要禁用闪存写入功能,以便在不需要操作闪存时保护闪存中的数据。

    谢谢!

    此致

    约翰逊

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,约翰逊,

    感谢你的答复。 我很抱歉我没有回来,我一直很忙。 我已解锁/锁定另一个在该文件下工作的文件中的保护位。 我的问题(事后看不太清楚)更多地涉及到如果出现错误的擦除或坏写入周期(由于过度使用导致闪存单元硬件故障)。 这种产品将在另一个国家/地区具有较长的使用寿命,因此我想确保它是正确的。 我也会在这里发布较低级别的代码。 我知道使用 FRAM 会更好,但由于当前的可用性问题,我们所做的工作与我们的工作有关。 我已经尽可能地测试了故障,并且看到了非常间歇性的故障。 我非常感谢您的任何意见。

    此致

    编辑

    #include "Flash.h"
    
    
    void Flash_Init(void){
    
        // setup clock divider depending on SMCLK
        // prescaler = divider + 1
    
    #ifdef MHZ_1
        FCTL2 = FWKEY + FSSEL_2 + 0x02; // divide by 3 = 333khz
    #endif
    
    #ifdef MHZ_4
        FCTL2 = FWKEY + FSSEL_2 + 0x09; // divide by 10 = 400khz
    #endif
    
    #ifdef MHZ_8
        FCTL2 = FWKEY + FSSEL_2 + 0x13; // divide by 20 = 400khz
    #endif
    
    #ifdef MHZ_16
        FCTL2 = FWKEY + FSSEL_2 + 0x27; // divide by 40 = 400khz
    #endif
    }
    
    // must erase flash segment before write
    void Flash_Erase(uint16_t* address){
        __bic_SR_register(GIE);       // disable interrupts
        while(FCTL3 & BUSY);          // wait while flash is busy
        FCTL1 = FWKEY + ERASE;        // set erase bit for segment erase
        FCTL3 =  FWKEY;               // clear lock bit in FCTL3
        *address = 0;                 // dummy write to erase flash
        while(FCTL3 & BUSY);          // wait while flash is busy
        FCTL1 = FWKEY;                // clear erase bit
        FCTL3 = FWKEY + LOCK;         // lock flash
        __bis_SR_register(GIE);       // enable interrupts
    }
    
    
    void Flash_Write(uint8_t* dataBuf, uint16_t* address, uint8_t numBytes){
        uint8_t ii = 0;
        uint16_t word;
        __bic_SR_register(GIE);       // disable interrupts
        while(FCTL3 & BUSY);          // wait while flash is busy
        FCTL3 = FWKEY;                // clear lock bit
        FCTL1 = FWKEY + WRT;          // setup for write
    
        // copy bytes
        for(ii = 0; ii < numBytes; ii += 2){
            word = *dataBuf++;
            word <<= 0x08;
            word += *dataBuf++;
            *address++ = word;
            while(FCTL3 & BUSY);      // wait while flash is busy
        }
    
        FCTL1 = FWKEY;                // clear write bit
        FCTL3 = FWKEY + LOCK;         // lock flash
        __bis_SR_register(GIE);       // enable interrupts
    
    }
    
    void Flash_Read(uint8_t* array, uint16_t* address, uint8_t readLength){
        uint8_t ii = 0;
        uint16_t word;
    
        for(ii = 0; ii < readLength; ii += 2){
            word = *address++;
            *array++ = (uint8_t)(word >> 0x08);
            *array++ = (uint8_t)((word << 0x08) >> 0x08);
        }
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    爱德华:

    很抱歉错过了此主题,您的问题是否已解决?

    谢谢!

    此致

    约翰逊

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你知道这是如何运作的?

    您知道吗?您的平台上有一个代码示例,它将在10分钟内使芯片上的闪存呈现死?

    我不会关闭这件事,因为似乎没有人知道这件事。 这是我的守则,但人们必须知道。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    爱德华:

    我不明白这一点:

    [引用 userid="511733" url="~ë/support/microcontroller/MSP-low-Power-microcontroller-group/MSP4300/f/MSP-low-Power-microcontroller-forum/1073115/msp430f233-is—这是一种好的保护数据芯片的方法,闪存/4004731#4004731"10分钟后,您会知道吗?]

    您能否添加有关此问题的更多信息?

    谢谢!

    此致

    约翰逊