Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запись структуры во флеш.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Jenya7
Есть структура.
Код
typedef struct TEST_S
{
    unsigned char start;
    unsigned int length;
    char *text;
}TEST;

extern TEST tests[MAX_TESTS];

я инициализирую структуру и пытаюсь записать.
Код
unsigned int TESTER_SaveTest(unsigned int user_page)
{
    unsigned int ret;
    unsigned int  addr;
    
    tests[0].start = 0xDA;
    tests[0].length = 5;
    tests[0].text = "HELLO";
    
    tests[1].start = 0xDA;
    tests[1].length = 6;
    tests[1].text = "WORLD!";
    
    ret = FLASH_PageErase(user_page);
    if (ret)
        return ret;
    
    addr = 0;
    ret = FLASH_PageProgram(user_page, addr, (uint8_t *) &tests[0], BUFFER_SIZE_BYTE);
    if (ret)
        return ret;
    
    addr += (sizeof(tests[0])) + 1;
    ret = FLASH_PageProgram(user_page, addr, (uint8_t *) &tests[1], BUFFER_SIZE_BYTE); //тут я получаю ошибку - 32.
    if (ret)  
        return ret;
    
    return ret;
}

Первая запись проходит нормально. Вторая со смещением 13 выдает ошибку 32 - Access error is set in the FSTAT register.

Я что то упускаю в логике?
aaarrr
Цитата(Jenya7 @ Nov 14 2016, 17:01) *
Я что то упускаю в логике?

Для сферической флеш в вакууме? Вангую, требования по выравниванию по строкам.
Jenya7
Цитата(aaarrr @ Nov 14 2016, 20:26) *
Для сферической флеш в вакууме? Вангую, требования по выравниванию по строкам.

Они в Kinetis так намутили с флеш драйвером!
Запись такая.
Код
FlashProgram(&flashSSDConfig, dest, size, buffer, FlashCommandSequence);

Логично предположить что size это размер записываемого массива buffer.
Смотрим реализацию
CODE

uint32_t SIZE_OPTIMIZATION FlashProgram(PFLASH_SSD_CONFIG pSSDConfig, \
uint32_t dest, \
uint32_t size, \
uint8_t* pData, \
pFLASHCOMMANDSEQUENCE pFlashCommandSequence)
{
uint32_t ret = FTFx_OK; /* return code variable */
uint8_t i;
uint32_t temp;

if (size & (PGM_SIZE_BYTE - 0x01U))
{
ret = FTFx_ERR_SIZE;
}
else
{
/* convert to byte address */
dest = WORD2BYTE(dest);
#if (DEBLOCK_SIZE)
temp = WORD2BYTE(pSSDConfig->DFlashBlockBase);
if((dest >= temp) && (dest < (temp + pSSDConfig->DFlashBlockSize)))
{
dest = dest - temp + 0x800000U;
}
else
#endif
{
temp = WORD2BYTE(pSSDConfig->PFlashBlockBase);
if((dest >= temp) && (dest < (temp + pSSDConfig->PFlashBlockSize)))
{
dest -= temp;
}
else
{
ret = FTFx_ERR_ACCERR;
}
}
while((size > 0x0U) && (FTFx_OK == ret))
{
/* clear RDCOLERR & ACCERR & FPVIOL flag in flash status register. Write 1 to clear*/
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FSTAT_OFFSET;
REG_WRITE(temp, FTFx_SSD_FSTAT_ERROR_BITS);
/* passing parameter to the command */
#if (PGM_SIZE_BYTE == FTFx_PHRASE_SIZE)
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB0_OFFSET;
REG_WRITE(temp, FTFx_PROGRAM_PHRASE);
#else
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB0_OFFSET;
REG_WRITE(temp, FTFx_PROGRAM_LONGWORD);
#endif
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB1_OFFSET;
REG_WRITE(temp, GET_BIT_16_23(dest));
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB2_OFFSET;
REG_WRITE(temp, GET_BIT_8_15(dest));
temp = pSSDConfig->ftfxRegBase + FTFx_SSD_FCCOB3_OFFSET;
REG_WRITE(temp, GET_BIT_0_7(dest));

for (i = 0x0U; i < PGM_SIZE_BYTE; i++)
{
temp = pSSDConfig->ftfxRegBase + i + 0x08U;
REG_WRITE(temp, *(pData + i));
}

/* calling flash command sequence function to execute the command */
ret = pFlashCommandSequence(pSSDConfig);

/* update destination address for next iteration */
dest += PGM_SIZE_BYTE;
/* update size for next iteration */
size -= PGM_SIZE_BYTE;
/* increment the source address by 1 */
pData += PGM_SIZE_BYTE;
}
}
#if C90TFS_ENABLE_DEBUG
/* Enter Debug state if enabled */
if (TRUE == (pSSDConfig->DebugEnable))
{
ENTER_DEBUG_MODE;
}
#endif

return(ret);
}


Код
/* update size for next iteration */
   size -= PGM_SIZE_BYTE;

это как? учитывая что
Код
#define PGM_SIZE_BYTE  0x0008U     /* 8 bytes */


то есть размер моей структуры должен быть кратный 8?
aaarrr
Цитата(Jenya7 @ Nov 14 2016, 17:43) *
Они в Kinetis так намутили с флеш драйвером!

Может, они и намутили, но и вы вносите свою лепту: в первом сообщении было FLASH_PageProgram, теперь FlashProgram. Какая между ними связь?

Подозраваю, что раз запись идет блоками по 8 байт, то и выравнивание записываемого должно быть соответствующим.
Jenya7
Цитата(aaarrr @ Nov 14 2016, 21:03) *
Может, они и намутили, но и вы вносите свою лепту: в первом сообщении было FLASH_PageProgram, теперь FlashProgram. Какая между ними связь?

Подозраваю, что раз запись идет блоками по 8 байт, то и выравнивание записываемого должно быть соответствующим.

это структуру нужно выравнивать? что то вроде #pragma pack(8)?
aaarrr
Что-то вроде.
Jenya7
Цитата(aaarrr @ Nov 14 2016, 21:27) *
Что-то вроде.

а где вставить прагму? так вроде не ругается
Код
#pragma pack(8)
typedef  struct TEST_S
{
    unsigned char start;
    unsigned int length;
    char *text;
}TEST;

я вообще не понимаю что за клоунада такая. в STM32 и EFM32 я писал любой размер и все были довольны и я и флеш.
aaarrr
Цитата(Jenya7 @ Nov 14 2016, 18:29) *
я вообще не понимаю что за клоунада такая. в STM32 и EFM32 я писал любой размер и все были довольны и я и флеш.

О, сколько нам открытий чудных... Надо было начинать с LPC.
Jenya7
Цитата(aaarrr @ Nov 14 2016, 21:33) *
О, сколько нам открытий чудных... Надо было начинать с LPC.

так не я это решаю. как по мне остался бы на STM32 там все уже написано.

пробовал так
Код
#pragma pack(8)
typedef struct TEST_S
{
    unsigned char start;
    unsigned int length;
    char *text;
}TEST;

и так
Код
typedef
#pragma pack(8)
struct TEST_S
{
    unsigned char start;
    unsigned int length;
    char *text;
}TEST;

uint32_t n = sizeof(tests[0]); возвращает 12. почему 12 непонятно.

по моему я понял. три члена структуры компайлер выравнивает до 4 байт. получаем 12. чтобы получить реальную длину я должен прибавить длину строки? "HELLO" - еще 5 байт?
Alex11
Цитата
чтобы получить реальную длину я должен прибавить длину строки?

Какой-такой павлин-мавлин - у Вас строка в структуру не входит, только ссылка на нее.
Jenya7
Цитата(Alex11 @ Nov 14 2016, 23:45) *
Какой-такой павлин-мавлин - у Вас строка в структуру не входит, только ссылка на нее.

к тому же они в К-70 используют phrase programming (8 bytes). длина должна быть кратная 8.
k155la3
Цитата(Jenya7 @ Nov 14 2016, 18:29) *
. . . .
я вообще не понимаю что за клоунада такая. в STM32 и EFM32 я писал любой размер и все были довольны и я и флеш.


Не Вы первый ходите по этим граблям.
Такой метод записи сильно "компиляторо-прагма"-зависим.
Чтоб с этим не заморачиваться (раз и навсегда), почитайте за сериализацию.

Jenya7
Цитата(k155la3 @ Nov 15 2016, 13:22) *
Не Вы первый ходите по этим граблям.
Такой метод записи сильно "компиляторо-прагма"-зависим.
Чтоб с этим не заморачиваться (раз и навсегда), почитайте за сериализацию.

сериализация очень широкое понятие. буду признателен если ткнете носом.
k155la3
Цитата(Jenya7 @ Nov 15 2016, 13:11) *
сериализация очень широкое понятие. буду признателен если ткнете носом.

ссылки, где это внятно расписано, под рукой нет.
Если в двух словах - преобразование различных данных (в том числе структур, классов и чегоугодно)
в последовательность байт (в нашем случае) для сохранения или передачи где-куда-либо.
С целю последующего однозначного восстановления, напр. при приеме из канала связи.
Одна из основных особенностей-достоинств - платформо и компиляторо-независимость.
Вы сохраняете структуру "оптом", по сути в виде образа из памяти.
При сериализации придется
- брать каждое поле структуры,
- определять его размер,
- преобразовывать его в последовательность байт (исходя из размера поля/типа данных),
- и затем их (поля) "цепочкой" записывать в флеш.

При этом на выравнивание можно не обращать внимание.
Единственный ньюанс - надо учитывать платформенный Big-Little Endian формат для чисел конкретного процессора.
Jenya7
Цитата(k155la3 @ Nov 15 2016, 17:21) *
ссылки, где это внятно расписано, под рукой нет.
Если в двух словах - преобразование различных данных (в том числе структур, классов и чегоугодно)
в последовательность байт (в нашем случае) для сохранения или передачи где-куда-либо.
С целю последующего однозначного восстановления, напр. при приеме из канала связи.
Одна из основных особенностей-достоинств - платформо и компиляторо-независимость.
Вы сохраняете структуру "оптом", по сути в виде образа из памяти.
При сериализации придется
- брать каждое поле структуры,
- определять его размер,
- преобразовывать его в последовательность байт (исходя из размера поля/типа данных),
- и затем их (поля) "цепочкой" записывать в флеш.

При этом на выравнивание можно не обращать внимание.
Единственный ньюанс - надо учитывать платформенный Big-Little Endian формат для чисел конкретного процессора.

(uint8_t *) &MyStruct - прекрасная сериализация только речь тут о другом . ребята из NXP говорят надо делать падинг буферу до размера кратного 8.
k155la3
Цитата(Jenya7 @ Nov 15 2016, 15:58) *
(uint8_t *) &MyStruct - прекрасная сериализация только речь тут о другом . ребята из NXP говорят надо делать падинг буферу до размера кратного 8.


Может и так.

Вы вообще делали "гарантированное" чтение из флеш ее содержимого, в смысле, например, программатором ?

Если нет, то ошибка может быть как на записи, так и на чтении инф. из нее.
Причем даже не при работе процедуры RD/WR во флеш, а при "прокачке" в них данных.

К примеру, если в параметре ф-ии указано fun( t_uint32 * ptr)
то делать так fun( (t_uint32 *) &MyCharArr[0] ) - чревато боком, особенно когда
в качестве параметра передается указатель, по адресу которого вызываемая ф-ия должна записать данные.

Jenya7
Цитата(k155la3 @ Nov 15 2016, 19:43) *
Может и так.

Вы вообще делали "гарантированное" чтение из флеш ее содержимого, в смысле, например, программатором ?

Если нет, то ошибка может быть как на записи, так и на чтении инф. из нее.
Причем даже не при работе процедуры RD/WR во флеш, а при "прокачке" в них данных.

К примеру, если в параметре ф-ии указано fun( t_uint32 * ptr)
то делать так fun( (t_uint32 *) &MyCharArr[0] ) - чревато боком, особенно когда
в качестве параметра передается указатель, по адресу которого вызываемая ф-ия должна записать данные.

скажем так
Код
status = FLASH_Init();
status = FLASH_PageErase(250);
status = FLASH_PageProgram(250, 0, "hello", BUFFER_SIZE_BYTE);
  
uint8_t buff[5];
#define FLASH_PARAM_ADDR (0x00000000U + (250 * 0x00001000U))
memcpy(&buff, (uint8_t*)FLASH_PARAM_ADDR, 5);

пишется и читается правильно. но если писать кусками надо будет дополнять буфер до кратного 8.
HardEgor
Цитата(Jenya7 @ Nov 15 2016, 21:09) *
пишется и читается правильно. но если писать кусками надо будет дополнять буфер до кратного 8.

Я для таких приколов делаю union массива байтов и структуры. Конечно приходится пересчитывать размер массива при изменении структуры, но удобно в пересылке или вот при таком выравнивании.
Jenya7
Цитата(HardEgor @ Nov 15 2016, 20:23) *
Я для таких приколов делаю union массива байтов и структуры. Конечно приходится пересчитывать размер массива при изменении структуры, но удобно в пересылке или вот при таком выравнивании.

я как раз об этом думаю. как пересчитать размер масива? а если просто передать размер кратный 8? недостающие данные будут взяты с левых адресов и запишеться мусор. я могу мусорные байты просто игнорировать.
k155la3
Цитата(HardEgor @ Nov 15 2016, 17:23) *
Я для таких приколов делаю union массива байтов и структуры. Конечно приходится пересчитывать размер массива при изменении структуры, но удобно в пересылке или вот при таком выравнивании.


А что, компилятор ругается на MyCharArray[ sizeof( TypeMyStuct ) ] ?
(если конечно с #pragma pack(1) не накручено)

Jenya7
Цитата(k155la3 @ Nov 15 2016, 20:35) *
А что, компилятор ругается на MyCharArray[ sizeof( TypeMyStuct ) ] ?
(если конечно с #pragma pack(1) не накручено)

структура включает в себя указатель на строку переменной длины. Я не знаю ее конечный размер. Только в ран-тайм.

HardEgor
Цитата(Jenya7 @ Nov 15 2016, 22:10) *
структура включает в себя указатель на строку переменной длины. Я не знаю ее конечный размер. Только в ран-тайм.

Вы не правы. У вас получается структура отдельно, а строка отдельно. соответственно и сохранять надо и структуру и строку. А смысл?
Jenya7
Цитата(HardEgor @ Nov 15 2016, 21:54) *
Вы не правы. У вас получается структура отдельно, а строка отдельно. соответственно и сохранять надо и структуру и строку. А смысл?

вот тут я кстати в раздумьях. я принимаю строки от пользователя по UART.
Эти строки мне надо сохранить во флеш. поэтому я сделал структуру включающую строку, длину строки, начало пакета.
Код
typedef struct TEST_S
{
    unsigned char start;
    unsigned int length;
    char *text;
}TEST;

extern TEST tests[MAX_TESTS];

допустим я принял строку.
Код
void TESTER_AddTest(const char *test)
{
    if (test_idx < MAX_TESTS)
    {
        memcpy (tests[test_idx].text, test, strlen(test));
        test_idx++;
    }
    else
        test_idx = 0;
}

теперь мне надо вычислить общий размер дополнить до кратный 8 и записать во флеш.

aaarrr
Цитата(Jenya7 @ Nov 15 2016, 19:16) *
...я сделал структуру включающую строку

Эта структура НЕ включает строку. И размер её никоим образом не меняется.
Jenya7
Цитата(aaarrr @ Nov 15 2016, 22:18) *
Эта структура НЕ включает строку. И размер её никоим образом не меняется.

я понял. то есть мне нужно записать в два приема? сначала члены структуры потом строку?
aaarrr
Совершенно верно, в два приема.
toweroff
Коллеги, прекратите использовать этот "ньюанс"
Либо уберите лишнюю букву, либо добавьте недостающую
XVR
Цитата(Jenya7 @ Nov 15 2016, 19:16) *
допустим я принял строку.
Код
void TESTER_AddTest(const char *test)
{
    if (test_idx < MAX_TESTS)
    {
        memcpy (tests[test_idx].text, test, strlen(test));
        test_idx++;
    }
    else
        test_idx = 0;
}
Жесть wacko.gif А память под строку кто выделять будет?

Цитата
я понял. то есть мне нужно записать в два приема?
Я бы сказал в три приема (или даже в 4) - еще надо выделить память под строку, а потом ее вернуть обратно

То, как вы пытаетесь записать принятую от пользователя строку, крайне неэффективно и в текущем виде не работоспособно.

  1. Вам надо писать строки во флешь сразу при их поступлении, или можно с некоторой задержкой?
  2. Что еще кроме строк надо записать?
  3. Может ли в строках встречаться код 0?

Jenya7
Цитата(XVR @ Nov 16 2016, 15:22) *
Жесть wacko.gif А память под строку кто выделять будет?

Я бы сказал в три приема (или даже в 4) - еще надо выделить память под строку, а потом ее вернуть обратно

То, как вы пытаетесь записать принятую от пользователя строку, крайне неэффективно и в текущем виде не работоспособно.

  1. Вам надо писать строки во флешь сразу при их поступлении, или можно с некоторой задержкой?
  2. Что еще кроме строк надо записать?
  3. Может ли в строках встречаться код 0?

надо записать:
1.стартовый маркер
2.длину строки
3.саму строку.
писать во флеш сразу по принятии строки? я думаю не критично хотя наверно правильней всего.
ломаю голову как выделить место под строку.
Кроме как динамическое выделение памяти я придумать не смог.
Код
char *test_str = malloc(sizeof(char) *  (strlen(str) + padding_size));

но мне это очень не нравиться.
aaarrr
Цитата(Jenya7 @ Nov 16 2016, 15:49) *
Кроме как динамическое выделение памяти я придумать не смог.
Код
char *test_str = malloc(sizeof(char) *  (strlen(str) + padding_size));

но мне это очень не нравиться.

Мне, например, тоже. И в чем смысл динамического выделения, если строка - str - уже есть?
Jenya7
Цитата(aaarrr @ Nov 16 2016, 18:06) *
Мне, например, тоже. И в чем смысл динамического выделения, если строка - str - уже есть?

у К-70 так устроен флеш что надо писать размер кратный 8. мне строку надо проверить и дополнить до кратной 8. поэтому я выделяю + padding_size.
XVR
Советую сделать так.

Строки в FLASH упаковывать в такую структуру:
Код
typedef struct PackedStr {
  unsigned int length;
  unsigned char tag;
  char string[1];
} PackedStr;
Реально ваша строка (string[1]) будет занимать столько места, сколько надо (после конца структуры).

В памяти строки складывать в буфер достаточной длинны (что бы принять целиком строку) и длинны, кратной 8

Там же (в памяти) у вас будет 2 индекса в этом буфере:
  1. Индекс последнего занятого байта
  2. Индекс (в пределах первых 8ми байтов) хвоста от предыдущей записи


При приеме новой строки записываете ее в память, увеличивая длинну. После приема смотрите, если индекс занятого места больше 8 - записываете целое количество страниц, а незаписанный хвост переносите в начало буфера (корректируя указатели).
После приема всех данных записываете последний неполный блок (если он есть)

Чтение из FLASH аналогично: читаете в память и перемещаетесь по ней

Код
#define BUF_SIZE 1024
char buffer[BUF_SIZE];

PackedStr* get_next(PackedStr* str)
{
  int len = sizeof(str)-1+str->length;
  if (len&-sizeof(int)) len=(len&-sizeof(int))+sizeof(int); // Align for 'int' field
  return (PackedStr*)(len+(char*)str);
}

PackedStr* start = (PackedStr*)buffer;

void write_string(char* your_string, char tag)
{
  start->tag = tag;
  start->length = strlen(your_string);
  memcpy(start->string,your_string,start->length);

  start = get_next(start);

  int len = (char*)start - buffer;
  if ( len >= PGM_SIZE_BYTE)
  {
     int page_aligned = len&-PGM_SIZE_BYTE;
     WriteToFlash(buffer,page_aligned);
     len &= PGM_SIZE_BYTE-1;
     if (len) memcpy(buffer,buffer+page_aligned,len);
     start = (PackedStr*)(buffer+len);
  }
}

void final_flush()
{
  if ((char*)start != buffer)
  {
    ... pad buffer with 0 ...
    WriteToFlash(buffer,PGM_SIZE_BYTE);
    start = (PackedStr*)buffer;
  }
}

Чтение напишите сами (по аналогии)
Jenya7
это интересно. надо попробовать. char buffer[BUF_SIZE] вместо heap. спасибо.
HardEgor
Цитата(XVR @ Nov 16 2016, 20:26) *
Код
PackedStr* get_next(PackedStr* str)
{
  int len = sizeof(str)-1+str->length;
  if (len&-sizeof(int)) len=(len&-sizeof(int))+sizeof(int); // Align for 'int' field
  return (PackedStr*)(len+(char*)str);
}

А почему-бы при выравнивании, длину не вычислить напрямую:
len = (str->length/8+1)*8
два сдвига на 8 и сложение.
k155la3
Цитата(Jenya7 @ Nov 16 2016, 16:49) *
. . . .
ломаю голову как выделить место под строку.
. . . .

Сколько в процессоре RAM ?
И какой тип флеш ?
(ответ требуется в формате исповеди)
---
Смысл выделять динамически, если памяти достаточно.
Размер стоки (максимальный) имеет какие-то приближенные к жизни размеры,
илиже ОНО бескоечно, аки Вселенная ?
sm.gif


Jenya7
Цитата(k155la3 @ Nov 16 2016, 18:41) *
Сколько в процессоре RAM ?
И какой тип флеш ?
(ответ требуется в формате исповеди)
---
Смысл выделять динамически, если памяти достаточно.
Размер стоки (максимальный) имеет какие-то приближенные к жизни размеры,
илиже ОНО бескоечно, аки Вселенная ?
sm.gif

Посмотрел сейчас и был приятно удивлен - 64К RAM. Можно выделить кусок под строки и не париться. Какая максимальная длинна строки? да кто их знает. предположительно не более 1 К.
XVR
Цитата(HardEgor @ Nov 16 2016, 16:37) *
А почему-бы при выравнивании, длину не вычислить напрямую:
len = (str->length/8+1)*8
Эта формула увеличит длинну на 8 даже если она уже была выровнена на 8, а этого делать не стоит rolleyes.gif
ViKo
Цитата(XVR @ Nov 16 2016, 22:47) *
Эта формула увеличит длинну на 8 даже если она уже была выровнена на 8, а этого делать не стоит rolleyes.gif

len = ((str->length - 1) / 8 + 1) * 8
Jenya7
Тестирую запись.
Создал структуру.
Код
typedef struct TEST_S
{
    unsigned int start;
    unsigned int length;
    unsigned int text_addr;
    unsigned int padding; //for padint to 8 bytes
}TEST;

TEST test;

Инициализирую
Код
uint32_t struct_size = sizeof(TEST);  //16 bytes
test.start = 0xDADA;
test.length = total_len;      
test.text_ptr = 0;
tests[test_idx].padding = 0;

Пишу.
Код
flash_addr = 0;  //from the start of the page -> 0x000FA000, USER_PAGE = 250
ret = FLASH_PageProgram(USER_PAGE, flash_addr, (uint8_t*) &test,  struct_size);
if (ret)
  return ret;

Получаю ошибку (ret = 1) - Protection violation is set in FSTAT register.
В дебагере вижу первые 8 байт записывает нормально. На второй восьмерке генерируется ошибка.

Я понял. Или стирать страницу или держать в памяти текущий адрес чтоб знать куда писать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.