Например TDA7294

Форум РадиоКот :: Просмотр темы - Записать массив в структуру.
Форум РадиоКот
https://radiokot.ru/forum/

Записать массив в структуру.
https://radiokot.ru/forum/viewtopic.php?f=59&t=195355
Страница 1 из 2

Автор:  Юрий1239 [ Сб окт 26, 2024 20:38:14 ]
Заголовок сообщения:  Записать массив в структуру.

Имеется структура диска

typedef struct
{
unsigned char JmpBoot[3]; // JMP на загрузчик (0xEB5890)
unsigned char OEMName[8]; // Строка форматера ОС ("MSDOS5.0")
unsigned short BytePerSec; // Количество байт в секторе ............ 0x00B: 512
unsigned char SecPerClus; // Количество секторов к кластере ....... 0x00D: 8
unsigned short RsvdSecCnt; // Всего резервных секторов (ВРВ + копия) ................. 0x00E: 2 186
unsigned char NumFATs; // Сколько копий FAT-таблицы 0x010: 2
unsigned short RootEntCnt; // Объектов в корневом каталоге (нуль для FAT-32)
unsigned short TotSec16; // Всего секторов на диске (нуль для FAT-32)
unsigned char Media; // Тип диска (F8)
unsigned short FATSz16; // Размер таблицы FAT-16 в секторах (нуль для FAT-32)
unsigned short SecPerTrk; // Секторов в дорожке (63)
unsigned short NumHeads; // Всего головок Head (255)
unsigned int HiddSec; // Cекторов перед началом раздела ....... 0x01C: 2 048
unsigned int TotSec32; // Всего секторов на диске .............. 0x020: 15 689 728
unsigned int FATSz32; // Размер таблицы FAT-32 в секторах ..... 0x024: 15 291
unsigned short ExtFlags; // Флаги
unsigned short FSVer; // Версия файловой системы
unsigned int RootClus; // Кластер корневого каталога (смещение в блоке данных) ... 0x02C: 2
unsigned short FSInfo; // Сектор структуры FSINFO .............. 0x030: 1
unsigned short BkBootSec; // Сектор копии этой записи (6)
unsigned char Reserved[12]; //
unsigned char DrvNum; // Номер диска для INT-13h (00 или 80h)
unsigned char Reserved1; //
unsigned char BootSig; // Сигнатура 29h, если имеются сл.три поля
unsigned int VolID; // Серийник тома
unsigned char VolLabel[11]; // Строка с меткой тома по умолчанию ("NO NAME ").
unsigned char FilSysType[8]; // Строка "FAT32 ".
unsigned char Reserved2[420]; //
unsigned short Signature; // Сигнатура 55AAh
} FAT32_BPB;

Есть функция которая читает сектор 512 байт из SD карты и записывает в массив.
Как можно эти данные массива записать в структуру, чтобы потом можно было пользоваться полями структуры ?
Какие есть способы ?

Автор:  Martian [ Сб окт 26, 2024 20:39:41 ]
Заголовок сообщения:  Re: Записать массив в структуру.

union

Автор:  Юрий1239 [ Сб окт 26, 2024 20:42:38 ]
Заголовок сообщения:  Re: Записать массив в структуру.

union

можно поподробней ?

Автор:  Martian [ Сб окт 26, 2024 20:45:58 ]
Заголовок сообщения:  Re: Записать массив в структуру.

конечно. https://www.google.com/search?q=union+c%2B%2B

Автор:  Базилюк [ Сб окт 26, 2024 20:59:37 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Указатель. Указатель на структуру. Любая структура, объявленная в виде указателя, "натягивается" на любой участок памяти, как разметочный шаблон.
То есть:
Код:
typedef struct {
   uint32_t a;
   uint8_t b;
   uint8_t c;
   uint16_t d;
}Str;

Str *x = (Str*)0x20000F00; // указатель инициализуется каким-то адресом
x->a = 10;
x->b = 5;
x->c = 8;
x->d = 100;

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

Автор:  Юрий1239 [ Сб окт 26, 2024 21:08:47 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Указатель. Указатель на структуру. Любая структура, объявленная в виде указателя, "натягивается" на любой участок памяти, как разметочный шаблон.


Черканите пару строк чтоб я мог начать копать в правильную сторону. Я уже сломал мозг.

Пробовал по разному. на пример так не работает:

unsigned char buf[512];

FAT32_BPB *bpb;
bpb = (void *)buf;

Автор:  Базилюк [ Сб окт 26, 2024 21:09:39 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Добавил пример выше

то есть, если есть uint8_t buf[512];, тогда Str *x = (Str*)buf; указателю *x присваивается адрес начала buf[] и участок памяти от начала buf[] будет разбит на ячейки в соответствии с "натянутой" на него структурой.

Автор:  Юрий1239 [ Сб окт 26, 2024 21:14:39 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Добавил пример выше

Так, сейчас буду пробовать, благодарю.

Автор:  Базилюк [ Сб окт 26, 2024 21:15:08 ]
Заголовок сообщения:  Re: Записать массив в структуру.

да, еще раз добавил мессаг выше.

Автор:  Martian [ Сб окт 26, 2024 21:28:38 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Код:
typedef union
{
  struct
  {
    unsigned char JmpBoot[3]; // JMP на загрузчик (0xEB5890)
    unsigned char OEMName[8]; // Строка форматера ОС ("MSDOS5.0")
    unsigned short BytePerSec; // Количество байт в секторе ............ 0x00B: 512
    unsigned char SecPerClus; // Количество секторов к кластере ....... 0x00D: 8
    unsigned short RsvdSecCnt; // Всего резервных секторов (ВРВ + копия) ................. 0x00E: 2 186
    unsigned char NumFATs; // Сколько копий FAT-таблицы 0x010: 2
    unsigned short RootEntCnt; // Объектов в корневом каталоге (нуль для FAT-32)
    unsigned short TotSec16; // Всего секторов на диске (нуль для FAT-32)
    unsigned char Media; // Тип диска (F8)
    unsigned short FATSz16; // Размер таблицы FAT-16 в секторах (нуль для FAT-32)
    unsigned short SecPerTrk; // Секторов в дорожке (63)
    unsigned short NumHeads; // Всего головок Head (255)
    unsigned int HiddSec; // Cекторов перед началом раздела ....... 0x01C: 2 048
    unsigned int TotSec32; // Всего секторов на диске .............. 0x020: 15 689 728
    unsigned int FATSz32; // Размер таблицы FAT-32 в секторах ..... 0x024: 15 291
    unsigned short ExtFlags; // Флаги
    unsigned short FSVer; // Версия файловой системы
    unsigned int RootClus; // Кластер корневого каталога (смещение в блоке данных) ... 0x02C: 2
    unsigned short FSInfo; // Сектор структуры FSINFO .............. 0x030: 1
    unsigned short BkBootSec; // Сектор копии этой записи (6)
    unsigned char Reserved[12]; //
    unsigned char DrvNum; // Номер диска для INT-13h (00 или 80h)
    unsigned char Reserved1; //
    unsigned char BootSig; // Сигнатура 29h, если имеются сл.три поля
    unsigned int VolID; // Серийник тома
    unsigned char VolLabel[11]; // Строка с меткой тома по умолчанию ("NO NAME ").
    unsigned char FilSysType[8]; // Строка "FAT32 ".
    unsigned char Reserved2[420]; //
    unsigned short Signature; // Сигнатура 55AAh
  };
  unsigned char raw[512];
}FAT32_type;

extern FAT32_type Data_Fat32;


....


Data_Fat32.raw[0] = ...
Data_Fat32.JmpBoot[0] = ...
эти две операции обращаются к одной и той же области памяти


Добавлено after 11 minutes 31 second:
но вообще, это неэкономно. Для чтения FAT достаточно байт 32, наверное, чтобы удобно следовать алгоритму его разбора, описанного в спецификации.

Автор:  Юрий1239 [ Сб окт 26, 2024 22:00:17 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Что-то не получается наверно я что-то делаю не так.

unsigned char buf[512];
FAT32_BPB *bpb = (FAT32_BPB *)buf;
SDSPI_ReadBlock(AT91C_BASE_SPI, CH0, 0x00000800, buf);

После функции чтения в buf[510], buf[511] xранится сигнатура 55AAh
А если обращаться к полю bpb->Signature то там 02ECh

Автор:  Martian [ Сб окт 26, 2024 22:09:24 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Потому что размер Вашей структуры больше 512 байт. Вы где-то ошиблись с типом данных или размером массива в ней. Вот поле и берёт данные откуда-то за пределами 512 байт

Автор:  viiv [ Сб окт 26, 2024 23:58:42 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Потому что размер Вашей структуры больше 512 байт.
.....
Вот поле и берёт данные откуда-то за пределами 512 байт

Все верно, мой компилятор (кросс-gcc Cortex-M3) говорит, что размер структуры 520 байт.

Вы где-то ошиблись с типом данных или размером массива в ней.

Не считал точно, но возможно ошибки с типом/размером нет. Но в структуре есть "дырки" (не компилировал для проверки, но есть уверенность, что это именно так).

Юрий1239,

1) не есть хорошо предполагать размеры char/short/int/long... и их беззнаковые варианты. Как минимум - это непереносимо. Если надо поля/переменные определенного размера, для этих целей существуют специальные типы int8_t/int16_t/int32_t... (uint8_t/uint16_t/uint32_t...) из stdint.h

2) Не стоит предполагать, что компилятор разместит поля в структуре одно за другим без "дырок". Если это (размещение полей без "дырок") требуется, то надо явно об этом указать компилятору. Для gcc - __attribute__((packed)), в других компиляторах - по-другому.

Берем этот конкретный пример, очень вероятно (близко к 100%), что будет скомпилировано так:
Код:
struct
  {
    /*смещение 0 */ unsigned char JmpBoot[3];
    /*смещение 3 */ unsigned char OEMName[8];
    /* ВНИМАНИЕ! Здесь будет "дырка",  */
    /*смещение 12 */ unsigned short BytePerSec;
....

Вы (наверное) надеялись, что у поля BytePerSec будет смещение 11 (ведь перед полем два массива байт 3 + 8 ), а на самом деле это не так - компилятор после двух полей сделает "дырку" (вставит байт) и, соответственно, смещение поля BytePerSec будет 12.

Если добавить к структуре __attribute__((packed)), то "дырка" уберется (и поле BytePerSec будет иметь смещение 11).
НО ПОЯВИТСЯ ДРУГАЯ ПРОБЛЕМА - как только в вашей программе будет обращение к полю BytePerSec, будет сгенерировано исключение. Дело в том, что в ARMах (не знаю во всех ли вариантах, но на тех, с которыми я знаком) не допускается обращения к слову/полуслову по адресу не выровненному на границу слова/полуслова. Другими словами к при обращении к 32 битному слову, адрес должен быть кратным 4, к 16 битному полуслову - кратным 2 (а в этом примере смещение 11, что не кратно 2).

3) Опять же, не надо забывать, что бывает разный порядок байт - big-endian (BE) или little-endian (LE). Желательно, чтобы код работал и там, и там.

Т.е. исходя из сказанного выше, ничего плохого не вижу, если в подобных случаях не будет "наложения" считанного буфера на какую-либо структуру, свои структуры делаем как нам надо, доступ к полям в буфере будет через функцию/макрос. Типа так:
Спойлер
Код:
/* определяем смещения */
...
#define BYTE_PER_SEC_OFFSET  11
...
/* "вытаскивает" 8/16/32-ти битное значение по смещению
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * можно заинлайнить (или определить макросами), если надо
 * для переносимости сделать две версии: одна - для little-endian (LE), вторая -
 * для big-endian (BE) и условной компиляцией подключать нужные */

uint8_t fetch_u8 (void* ptr, int offset)
{
   return ((uint8_t *) ptr) [offset];
}
uint16_t fetch_u16 (void* ptr, int offset)
{
   uint16_t val = fetch_u8 (ptr, offset);
   return val | (fetch_u8 (ptr, offset + 1) << 8);
}
uint32_t fetch_u32 (void* ptr, int offset)
....
uint8_t *buf; - это указатель на считанный блок
....
uint16_t block_size = fetch_u16 (buf, BYTE_PER_SEC_OFFSET).

Автор:  Юрий1239 [ Вс окт 27, 2024 05:46:25 ]
Заголовок сообщения:  Re: Записать массив в структуру.

На сколько я понял вы имеете введу, что, все поля объявить в виде смещения?
Код:
#define  JMP_BOOT_OFFSET         0
#define  OEM_NAME_OFFSET         3
#define  BYTE_PER_SEC_OFFSET    11
...
...

Но ведь тогда нужно заранее каждого поля знать его размер.

Автор:  Martian [ Вс окт 27, 2024 06:04:17 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Разве они неизвестны? В структуре Вы заранее определили их размер. Работа со смещениями избавляет программу хранить 512 байт в ОЗУ, Вы всегда можете взять только нужное, если организуете обработку этих смещений в чтении данных с SD карты.
К тому же, часть полученных данных этого блока необходимо хранить всю жизнь работы с FAT, и не хранить же его весь, как минимум, пустышка в 420 байт вообще не нужна. Уж лучше тогда отдельно прочитать сигнатуру, чем ради неё стольким жертвовать.

Автор:  Юрий1239 [ Вс окт 27, 2024 07:15:13 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Что-то я не совсем понимаю. Если я объявил поля через #define то тогда зачем объявлять структуру ?

Автор:  Martian [ Вс окт 27, 2024 07:20:12 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Вот именно. Она тогда не нужна. Говоря, что Вы в структуре определили размеры данных, я лишь имел ввиду, что они Вам известны. Вы можете добавить их в комментарии к #define, чтобы лишний раз не лазить в документацию. Например, как здесь: https://asf.microchip.com/docs/latest/s ... group.html

Автор:  Юрий1239 [ Вс окт 27, 2024 08:07:15 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Да. я так об этом тоже думал но остановился и решил поискать более красивое решение. Но с #define конечно будет экономичней с памятью. Буду так делать, тем более не все поля нужно использовать.

Автор:  tonyk [ Вс окт 27, 2024 08:12:43 ]
Заголовок сообщения:  Re: Записать массив в структуру.

viiv писал(а):
1) не есть хорошо предполагать размеры char/short/int/long... и их беззнаковые варианты. Как минимум - это непереносимо.

Читайте спецификации языка. Непереносим только тип int, размеры остальных детерминированы.
viiv писал(а):
3) Опять же, не надо забывать, что бывает разный порядок байт - big-endian (BE) или little-endian (LE). Желательно, чтобы код работал и там, и там.

Вопрос был про FAT, а в нём порядок байт определён.

Добавлено after 2 minutes:
Юрий1239 писал(а):
Имеется структура диска

Зачем весь этот геморрой, когда есть FATFS от Чана? Много лишнего времени?

Автор:  Юрий1239 [ Вс окт 27, 2024 08:26:55 ]
Заголовок сообщения:  Re: Записать массив в структуру.

Цитата:
не есть хорошо предполагать размеры char/short/int/long... и их беззнаковые варианты. Как минимум - это непереносимо.


Я использую старый чип ATSAM7S256, Там все драйвера и файл заголовков написаны unsigned int, unsigned char... и т. д. Правилом хорошего тона считается использовать один стиль написания. К тому же я знаю что все эти типы просто переопределены.

Код:
typedef unsigned int uint32_t
...


Добавлено after 2 minutes 32 seconds:
Цитата:
Зачем весь этот геморрой, когда есть FATFS от Чана? Много лишнего времени?


Долго разбираться, не знаю как она работает, много лишнего кода. А там есть поддержка длинных имён ?

Страница 1 из 2 Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/