cancel
Showing results for 
Search instead for 
Did you mean: 

Problem writing string to emulated Eeprom

jlourencao
Associate II

Can anyone explain to me what is wrong in my code?

Microcontroller: STM32C031K6T6

I'm trying to make an interface so that the user can change the name of their environment in real time, my idea and what I tried to write is something that holds the previous strings (which may already be edited) in RAM, makes the modifications and then then write in flash again. Currently my code is like this, it shows the environments ("AMBIENTE  01...24"), I can edit the name of the string, it "saves" when i call Grava();, but when I turn my board off and on the changes do not continue... 

I tried to copy the txtL strings to b_txtL using memcpy, and strncpy at the beginning of main();, but when i do this my my display goes "crazy" showing the strings "AMBIENTE ..." all broken in line 1 and 2

Note: I can't debug and at the same time see the changes that happen on the display because the SWCLK pin was used for a display pin, I had to implement a code that erased the memory after holding down some buttons to be able to record another code, workaround ...


 

 

const char txtL[][17] = {
    "  AMBIENTE L01  ", "  AMBIENTE L02  ", "  AMBIENTE L03  ",
    "  AMBIENTE L04  ", "  AMBIENTE L05  ", "  AMBIENTE L06  ",
    "  AMBIENTE L07  ", "  AMBIENTE L08  ", "  AMBIENTE L09  ",
    "  AMBIENTE L10  ", "  AMBIENTE L11  ", "  AMBIENTE L12  ",
    "  AMBIENTE L13  ", "  AMBIENTE L14  ", "  AMBIENTE L15  ",
    "  AMBIENTE L16  ", "  AMBIENTE L17  ", "  AMBIENTE L18  ",
    "  AMBIENTE L19  ", "  AMBIENTE L20  ", "  AMBIENTE L21  ",
    "  AMBIENTE L22  ", "  AMBIENTE L23  ", "  AMBIENTE L24  ",
    "   ENGFOX 24L   "
}; // default flash text
char b_txtL[26][17]; //BUFFER

int main{
//lcd and gpios inits
EEPROM_INIT();
lerEeprom();

//button config and enters the prog
Prog();

//test to see if saved something
lcd_set_cursor(0, 0);
lcd_write_string2((const char*)txtL[0]);
lcd_set_cursor(0, 1);
lcd_write_string2((const char*)b_txtL[15]);

// Prog func
/* I'm using a eeprom_write function to write flags of 0 or 1, due to the limitation of my microcontroller I can only use DOUBLEWORD, which ends up recording a flag in 32 bits, and the next 32 bits are empty */

 while (loop < 26) {
    	DisplayLaco(loop);
    	HAL_Delay(60);

    	if (HAL_GPIO_ReadPin(GPIOA, SW1_Pin) == GPIO_PIN_RESET)
    	{
    		HAL_Delay(200);

    		// Verifica o estado atual dos bits
    		int re_bit = (ure.re_all[loop / 8] & (1 << (loop % 8))) ? 1 : 0;
    		int rfl_bit = (urfl.rfl_all[loop / 8] & (1 << (loop % 8))) ? 1 : 0;

    		// Alterna entre as combinações S N, N S, N N, S S
    		if (re_bit && !rfl_bit)
    		{
    			// Caso atual seja S N -> Muda para N S
    			ure.re_all[loop / 8] &= ~(1 << (loop % 8));  // Desativa o bit em re_all
    			urfl.rfl_all[loop / 8] |= (1 << (loop % 8)); // Ativa o bit em rfl_all
    		}
    		else if (!re_bit && rfl_bit)
    		{
    			// Caso atual seja N S -> Muda para N N
    			ure.re_all[loop / 8] &= ~(1 << (loop % 8));  // Desativa o bit em re_all
    			urfl.rfl_all[loop / 8] &= ~(1 << (loop % 8)); // Desativa o bit em rfl_all
    		}
    		else if (!re_bit && !rfl_bit)
    		{
    			// Caso atual seja N N -> Muda para S S
    			ure.re_all[loop / 8] |= (1 << (loop % 8));   // Ativa o bit em re_all
    			urfl.rfl_all[loop / 8] |= (1 << (loop % 8)); // Ativa o bit em rfl_all
    		}
    		else
    		{
    			// Caso atual seja S S -> Muda para S N
    			ure.re_all[loop / 8] |= (1 << (loop % 8));   // Ativa o bit em re_all
    			urfl.rfl_all[loop / 8] &= ~(1 << (loop % 8)); // Desativa o bit em rfl_all
    		}

    		DisplayLaco(loop);  // Atualiza o display
    	}

            if (HAL_GPIO_ReadPin(GPIOA, SW2_Pin) == GPIO_PIN_RESET) {
                HAL_Delay(200);
                uoff.off_all[loop / 8] ^= (1 << (loop % 8));
                DisplayLaco(loop);
            }

            if (HAL_GPIO_ReadPin(GPIOA, SW3_Pin) == GPIO_PIN_RESET) {
                HAL_Delay(200);
                Conf_txt(loop);
                lcd_display_control(true, false, false);
                DisplayLaco(loop);
                loop++;
            }
        }

        dcBKL_ch2(200);
    }

//Display func (Maybe the trouble is here, idk)

void DisplayLaco(int loop)
{
    // Exibe informações sobre o laço atual e o nome correspondente
    char nomeL[20];
    snprintf(nomeL, sizeof(nomeL), "L%02d:", loop + 1);

    lcd_set_cursor(0, 0);
    lcd_write_string(nomeL);
    lcd_write_string((uoff.off_all[loop / 8] & (1 << (loop % 8))) ? "S " : "N ");
    lcd_write_string((ure.re_all[loop / 8] & (1 << (loop % 8))) ? "RE:S " : "RE:N ");
    lcd_write_string((urfl.rfl_all[loop / 8] & (1 << (loop % 8))) ? "RFL:S" : "RFL:N");

    // Exibe o nome do ambiente correspondente (da RAM)
    lcd_set_cursor(0, 1);
    // Copiar as strings de b_txtL para txtL (presumindo que b_txtL foi modificado)
    lcd_write_string(b_txtL[loop]);  // `b_txtL[loop]` já deve estar em `char[]`

}
// Conf_txt func, it's a bit buggy, I'm trying to solve it...

void Conf_txt(uint16_t loop)
{
    // Permite a edição em tempo real do nome selecionado em b_txtL
    bool edit = true;
    // Posição do caractere dentro do nome
    uint8_t pressCounter = 0;
    uint8_t col = 0;
    // Exibe o nome inicial na LCD
    lcd_write_string2((const char*)b_txtL[loop]);
    lcd_set_cursor(col, 1);  // Coloca o cursor na posição inicial

    while (edit)
    {
        lcd_display_control(true, true, true);
        lcd_set_cursor(col, 1);  // Atualiza a posição do cursor

        bool SW3 = (HAL_GPIO_ReadPin(GPIOA, SW3_Pin) == GPIO_PIN_RESET);

        // Pressão longa do SW3 para sair do modo de edição
        if (SW3)
        {
            pressCounter++;  // Incrementa o contador
            if (pressCounter >= 15)  // 3 segundos (ajuste conforme necessário)
            {
                edit = false;
                lcd_display_control(true, false, false);
                Grava();
                return;
            }
        }
        else
        {
            pressCounter = 0;  // Resetando o contador após uma ação
            col++;  // Avança para a próxima coluna
            lcd_set_cursor(col, 1);
            if (col >= 16)
            {
                col = 0;
            }
        }

        // Controle de incremento e decremento do caractere na posição atual
        if (HAL_GPIO_ReadPin(GPIOA, SW1_Pin) == GPIO_PIN_RESET)
        {
            HAL_Delay(200);
            b_txtL[loop][col]++;
            if (b_txtL[loop][col] > 0x5A) b_txtL[loop][col] = 0x30;  // "Z" -> "0"
            else if (b_txtL[loop][col] < 0x30) b_txtL[loop][col] = 0x41;  // " " -> "A"
            else if (b_txtL[loop][col] > 0x39 && b_txtL[loop][col] < 0x41) b_txtL[loop][col] = 0x20;  // "9" -> " "
            lcd_write_string2((const char*)b_txtL[loop]);   // Atualiza o caractere na posição do cursor
        }

        if (HAL_GPIO_ReadPin(GPIOA, SW2_Pin) == GPIO_PIN_RESET)
        {
            HAL_Delay(200);
            b_txtL[loop][col]--;
            if (b_txtL[loop][col] < 0x20) b_txtL[loop][col] = 0x39;  // " " -> "9"
            else if (b_txtL[loop][col] < 0x30) b_txtL[loop][col] = 0x5A;  // "0" -> "Z"
            else if (b_txtL[loop][col] > 0x39 && b_txtL[loop][col] < 0x41) b_txtL[loop][col] = 0x20;  // "A" -> " "
            lcd_write_string2((const char*)b_txtL[loop]);  // Atualiza o caractere na posição do cursor
        }

        HAL_Delay(200);
        }
    }

// Then, after i call grava(); function to write the changes in the eeprom

for (int i = 0; i < 26; i++) // i is my ID
    {
    	EEPROM_WRITE_STRING(i, b_txtL[i]);
    }

// EEPROM write stirng. 
void EEPROM_WRITE_STRING(uint16_t id, const char* c)
{

    HAL_Delay(10); // Pode ser ajustado conforme necessário
    HAL_FLASH_Unlock();  // Desbloqueia a memória FLASH para gravação

    uint32_t address = ACTIVE_PAGE;  // Começa no endereço da última gravação

    // Verifica o comprimento da string
    int str_len = strlen(c);
    if (str_len > 17) str_len = 17;  // Limita o comprimento a 17 caracteres (tamanho máximo da string)

    // Garantir que o endereço está alinhado a 8 bytes
    if (address % 8 != 0)
    {
        address += 8 - (address % 8);  // Ajuste de alinhamento
    }

    // Grava a string na Flash em blocos de 8 bytes
    for (int offset = 0; offset < str_len; offset += 8)
    {
        uint64_t data_to_write = 0;

        // Preenche os próximos 8 bytes (ou menos, se a string terminar antes)
        for (int i = 0; i < 8; i++)
        {
            if (offset + i < str_len) {
                data_to_write |= ((uint64_t)c[offset + i]) << (i * 8);
            }
        }

        // Grava os dados na memória FLASH
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data_to_write);
        address += 8;  // Avança para o próximo endereço
    }


    if (address >= (ACTIVE_PAGE + PAGE_SIZE - sizeof(EEPROM)))
    {EEPROM_SWAP();}

    HAL_FLASH_Lock();  // Bloqueia a memória FLASH após a gravação
}




void EEPROM_READ_STRING(uint16_t id, char* c)
{
    uint32_t address = ACTIVE_PAGE + (id * sizeof(EEPROM));  // Endereço baseado no ID
    uint64_t data_read = 0;

    // Lê os dados da memória FLASH em blocos de 8 bytes
    while (address < (ACTIVE_PAGE + PAGE_SIZE))
    {
    	EEPROM* entry = (EEPROM*)address;

    	if (entry->id == id)
    	{
    		for (int offset = 0; offset < 17; offset += 16)
    		{
    			data_read = *(volatile uint64_t*)address;

    			// Copia os dados lidos de volta para a string
    			memcpy(&c[offset], &data_read, (offset + 8 <= 17) ? 8 : (17 - offset));

    			address += 8;  // Avança para o próximo endereço
    		}
    	}
    	address += sizeof(EEPROM);
    }

}



 

 



1 ACCEPTED SOLUTION

Accepted Solutions
Andrew Neil
Evangelist III

Flash needs to be erased before you can write to it.

Where does that happen in your code?

You don't check return values from the HAL_ functions - maybe they are telling you something ... ?

View solution in original post

12 REPLIES 12

Use the Code pasting tool </> so it's readable. See Icon Bar immediately about editing window. Edit your top-post

State which model of STM32 you're talking about.

Show what is and is not happening. Perhaps but dumping the memory content to establish what exactly is going on, and what exactly is failing, or not working as you expected.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you friend, I already made the changes

Andrew Neil
Evangelist III

Flash needs to be erased before you can write to it.

Where does that happen in your code?

You don't check return values from the HAL_ functions - maybe they are telling you something ... ?

In the eeprom init i think

void EEPROM_INIT(void) {
    uint32_t address = ACTIVE_PAGE;
    uint8_t format_ = 1;

    while (address < (ACTIVE_PAGE + PAGE_SIZE))
    {
        EEPROM* entry = (EEPROM*)address;
        if (entry->id != 0xFFFF || entry->data != 0xFFFF)
        {
            format_ = 0;
            break;
        }
        address += sizeof(EEPROM);
    }

    if (format_)
    {
        EEPROM_ERASE(ACTIVE_PAGE);
        EEPROM_ERASE(BACKUP_PAGE);
    }
}

 

LCE
Principal

Check the reference manual, but I'm pretty sure that the flash must be erased before each writing.

No "real" EEPROM on the C0 ?

 

That'd be a bit of a blow!

@jlourencao maybe take a look at how X-CUBE-EEPROM does it:

https://www.st.com/en/embedded-software/x-cube-eeprom.html

LCE
Principal

I was curious and just checked the website's shot description of that C0: there's no EEPROM.

So you have to use the eeprom emulation by writing to flash, what you are already doing by using the HAL_FLASH_* functions.

So, as Andrew said before, flash must be erased before each writing (unless you only want to change bits from 1 to 0 :D ).

-> check if HAL_FLASH_Program() does the erasing for you

jlourencao
Associate II

I thought that when using emulated eeprom it would not be necessary to erase it to be able to write later, I was very silly haha xD. Thank you guys.

Part of the job of the emulation is to get around that - again, you could see how X-CUBE-EEPROM does it...