MSP430F5529: no se puede escribir en FLASH

2

Background:

Estoy intentando escribir un valor de 8 bits en el bloque de información C de FLASH en el MSP430F5529. La información C comienza en la dirección 0x1880, así que uso un #define para mantener este valor:

#define     INFOC_REGISTER       0x1880

En mi función principal hago una llamada a un método que está destinado a escribir este valor de 8 bits (digamos 0x01 por el bien del argumento) en el byte más bajo de la dirección 0x1880:

writeValueToFlash(data);

Esta función tiene dos llamadas a funciones declaradas en flashctl.c, que obtuve de MSP430Ware_3_80_05_04. Mi función writeValueToFlash() es la siguiente:

/*********************************************************************
 * @fn      bool writeValueToFlash(uint8_t data)
 * @brief   Write 8-bit value to FLASH
 * @param   data - 8-bit value
 * @return  bool - Returns true
 */
bool writeValueToFlash(uint8_t data) {

    FlashCtl_eraseSegment((uint8_t*)INFOC_REGISTER);

    FlashCtl_write8((uint8_t*)data, (uint8_t*)INFOC_REGISTER, 1);

    return true;                                // Baud rate changed
}

A continuación se muestran las dos funciones del paquete MSP430Ware. No he realizado ningún cambio en estas funciones, excepto para agregar el comentario del encabezado del archivo flashctl.h:

//*******************************************************************
//
//! \brief Erase a single segment of the flash memory.
//!
//! For devices like MSP430i204x, if the specified segment is the information
//! flash segment, the FLASH_unlockInfo API must be called prior to calling
//! this API.
//!
//! \param flash_ptr is the pointer into the flash segment to be erased
//!
//! \return None
//
//********************************************************************

void FlashCtl_eraseSegment(uint8_t *flash_ptr){
    //Clear Lock bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY;

    //Set Erase bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY + ERASE;

    //Dummy write to erase Flash seg
    *flash_ptr = 0;

    //test busy
    while(HWREG8(FLASH_BASE + OFS_FCTL3) & BUSY)
    {
        ;
    }

    //Clear ERASE bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY;

    //Set LOCK bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY + LOCK;
}



//********************************************************************
//
//! \brief Write data into the flash memory in byte format, pass by reference
//!
//! This function writes a byte array of size count into flash memory. Assumes
//! the flash memory is already erased and unlocked. FlashCtl_eraseSegment can
//! be used to erase a segment.
//!
//! \param data_ptr is the pointer to the data to be written
//! \param flash_ptr is the pointer into which to write the data
//! \param count number of times to write the value
//!
//! \return None
//
//********************************************************************

void FlashCtl_write8(uint8_t *data_ptr,
                 uint8_t *flash_ptr,
                 uint16_t count)
{
    //Clear Lock bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY;

    //Enable byte/word write mode
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY + WRT;

    while(count > 0)
    {
        //test busy
        while(HWREG8(FLASH_BASE + OFS_FCTL3) & BUSY)
        {
            ;
        }

        //Write to Flash
        *flash_ptr++ = *data_ptr++;
        count--;
    }

    //Clear WRT bit
    HWREG16(FLASH_BASE + OFS_FCTL1) = FWKEY;

    //Set LOCK bit
    HWREG16(FLASH_BASE + OFS_FCTL3) = FWKEY + LOCK;
}

El problema:

El problema al que me estoy enfrentando es que cuando intento escribir "datos" (o 0x01 en este caso) en el INFOC_REGISTER (dirección 0x1880 ), no funciona correctamente. Cuando intento borrar el bloque, termino con algo parecido a FF7E en esa ubicación de memoria (esto fluctúa un poco, no siempre es FF7E , cambia cada vez que reinicio el micro y vuelvo a intentar borrar) ), y cuando intento escribir 0x01 termino con algo similar como FF50 en esa ubicación de memoria. Este valor también fluctúa. Estoy esperando FF01 .

¿Hay errores obvios en la forma en que estoy borrando o escribiendo en FLASH? Sé que lo tuve funcionando en algún momento hace bastante tiempo, pero no estoy seguro de qué cambio habría podido causar este problema.

Actualizar:

Según la respuesta de CL, modifiqué el código de la siguiente manera, pero parece que todavía tengo problemas similares.

#define     INFOC_REGISTER       ((uint8_t*)0x1880)

bool writeValueToFlash(uint8_t data) {

    FlashCtl_eraseSegment(INFOC_REGISTER);

    FlashCtl_write8(&data, INFOC_REGISTER, 1);
}

Parecía que funcionaba la primera vez (escribí 0x08 y funcionó correctamente), pero cuando regresé y traté de cambiarlo a 0x01 o 0x0A no lo hizo. Después de pasar por encima de la función FlashCtl_eraseSegment() , la llamada cambió a FF0C, y cuando paso por encima de la función FlashCtl_write8() (con data = 0x0A ), simplemente regresó a FF08.

Actualización adicional:

A veces parece funcionar, otras veces no. Es muy escamoso ....

    
pregunta DerStrom8

2 respuestas

2

Bueno, no lo vi venir.

Si bien la respuesta de CL es definitivamente precisa y mi código era incorrecto (¡y he corregido mi código, +1 para la ayuda!), en realidad no fue la raíz de este problema exacto. La mayor pista es esta:

  

Cuando intento borrar el bloque, termino con algo parecido a FF7E en esa ubicación de memoria (esto fluctúa un poco, no siempre es FF7E, cambia cada vez que reinicio el micro y vuelvo a intentar borrar)

Cuando estaba borrando el byte en FLASH, no se estaba borrando correctamente. Resulta que tengo un par de células malas. Para ser justos, he estado desarrollando este proyecto durante bastante tiempo y en ese tiempo he reescrito a esa dirección FLASH (0x1880) muchas, muchas veces. Puede que haya llegado al punto en el que ya no se puede escribir correctamente. En la operación real, no espero escribir en esa ubicación más de una docena de veces (de manera realista solo estará en uno o dos) durante un período de vida de 20 años, por lo que este no debería ser un problema en el futuro.

De todos modos, para solucionarlo, por el momento he cambiado la dirección de FLASH a 0x1882 y está funcionando perfectamente en todo momento. ¡Gracias a todos por la ayuda!

    
respondido por el DerStrom8
2

No es así como funcionan los punteros en C.

La función FlashCtl_write8() espera que se escriba un puntero a los datos. Normalmente, tendría varios bytes en una matriz, y escribir el nombre de la matriz sin un índice da como resultado un puntero a la matriz (primer elemento de la matriz):

uint8_t data[3] = { 11, 22, 33 };

FlashCtl_write8(data, (uint8_t *)INFOC, 3);

Podrías hacer lo mismo con una matriz de tamaño 1. Sin embargo, si no tiene una matriz, debe usar el operador & para obtener el puntero a esos datos:

uint8_t data;

FlashCtl_write8(&data, (uint8_t *)INFOC, 1);

Sin la dirección del operador, la función tomaría el valor de data como la dirección y escribiría el valor encontrado en esa dirección en la memoria flash.

Tenga en cuenta que la memoria de información no es un registro. Y necesita un puntero cada vez que accede a él (especialmente cuando quiere leerlo), por lo que debe definir el símbolo para que ya sea un puntero:

#define INFO_MEM_C ((uint8_t *)0x1880)
    
respondido por el CL.

Lea otras preguntas en las etiquetas