Sunteți pe pagina 1din 22

Simple FAT y SD Tutorial Parte 1

¿Está limitado por 128 bytes de EEPROM en su MCU o incluso los pocos kilobytes de flash en
su proyecto? En lugar de simplemente descargar una biblioteca como Petit FAT File System
Module y seguir ciegamente un tutorial sobre cómo personalizarlo en su microcontrolador y
tarjeta SD, ¿le gustaría realmente entender lo que está haciendo, y tal vez aprender un poco
sobre los sistemas de archivos y SPI en ¿el proceso?
En esta primera parte de mi tutorial FAT y SD, tomaremos una imagen de tarjeta SD y
crearemos un programa simple en C para interpretar sus contenidos. Para esta parte, no necesita
ningún hardware, solo una computadora con gcc (GNU C Compiler) o cualquier otro
compilador compatible con ANSI C instalado.
Preparándose: editor hexadecimal e imagen de disco
Para facilitar la codificación, recomiendo un buen editor hexadecimal. El que estoy usando es
el HxD gratuito y excelente de Maël Hörz. También puede usarlo para crear una imagen de
disco 1: 1 desde una tarjeta SD física. Para tener un sistema de archivos para leer, compré una
tarjeta micro-SD de 1 GB con adaptador SD por 5 €, la conecté a mi computadora y la formateé
como FAT16 (tarjetas con más de 2 GB se formatearán como FAT32) y copié Hamlet
de Proyecto Gutenberg y algunos otros archivos de pruebas falsas (también creó un
subdirectorio con algunos archivos de texto):

Luego inicié HxD en modo Administrador para permitir que abra discos físicos. Tenga en
cuenta que no abre solo una partición FAT16 ("H:"), sino todo el disco extraíble (hice un
círculo en el icono que necesita hacer clic primero):
Debido a que los datos de la partición, el sistema de archivos y algunos archivos de prueba solo
ocupan el primer disco de 1 GB, procedí a seleccionar solo los primeros 1 MB (Edición>
Seleccionar bloque ...> Compensación 0-FFFFF) y copie eso en un nuevo archivo, que
luego test.img como test.img en la carpeta de mi proyecto. Si no tiene a mano una
tarjeta SD / micro-SD pequeña, puede tomar el archivo zip del proyecto y usar la imagen de
prueba.
Nota: Si está usando Linux o una Mac, puede usar dd if=/dev/sda of=~/test.img
bs=1M count=1 para crear la imagen (suponiendo que el kernel
seleccionó /dev/sda como el dispositivo para su tarjeta).Es posible que deba agregar "sudo"
al principio.
Leyendo los datos de la partición
Ahora que tenemos una imagen de archivo de la tarjeta SD (o al principio), podemos comenzar
a hurgar. Para empezar, leí por primera vez el tutorial FAT sobre [tarjetas SD] de Thiadmer
Riemersma y Claudio Toffoli de CompuPhase, y realmente sugiero que lea la 1 página de texto
bajo el encabezado "The Master Boot Record and the partition table" en este punto. En
resumen, esperamos que el test.img se distribuya de la siguiente manera:
 MBR y tabla de particiones
 ... tal vez algunos sectores para particiones lógicas o espacio reservado ...
 Sector de inicio de una partición FAT16
 ... opcionalmente algunos sectores reservados ...
 1-2 copias de la Tabla de asignación de archivos (FAT)
 Directorio raíz
 Otros directorios y datos
Actualización 2013-08-20:: Como señaló uno de mis lectores, algunas tarjetas SD / micro-SD
no tienen varias particiones y MBR en absoluto, pero están formateadas como los disquetes
antiguos. Estos tipos de medios comienzan directamente con un sector de arranque, que se
describe en la siguiente sección.
Antes de ir más allá, debe saber que el bloque de almacenamiento básico en los sistemas de
archivos se llama sector , y eso es simplemente un bloque de datos de 512 bytes (256
palabras). El MBR y la tabla de particiones ocupan un sector.El sector de arranque ocupará un
sector. Las copias de FAT toman algunos N sectores, y así sucesivamente. Los disquetes y los
sistemas operativos más antiguos usaban el llamado direccionamiento CHS (cilindro, cabeza,
sector) donde el sector era la unidad más pequeña, pero no necesitamos saber sobre cilindros y
cabezales, solo el sector lo hará por el momento.
Desde el tutorial que he vinculado anteriormente, nos damos cuenta de que la tabla de
particiones debe comenzar en el offset 0x1BE (los números hexadecimales se usan mucho) y
contiene cuatro entradas de particiones de 16 bytes, cada una de ellas dispuesta de la siguiente
manera:
Compensar Descripción tamaño

0 0x80 si está activo (arrancable), 0 de lo contrario 1

Inicio de la partición en el direccionamiento


1 CHS 3

4 Tipo de partición 1

5 Fin de la partición en el direccionamiento CHS 3

Desplazamiento relativo a la partición en


8 sectores (LBA) 4

12 Tamaño de la partición en sectores 4


El tipo de partición debe ser 4 para las particiones FAT16 que son menos de 32 MiB (MiB =
1024 ^ 2 bytes), 6 para más de 32 particiones MiB y 14 para las particiones FAT16 que usan el
direccionamiento LBA. Intentemos leer la tabla de particiones en C:
#include <stdio.h>
#include <stdlib.h>

int main () {
FILE * in = fopen ("test.img", "rb");
unsigned int i, start_sector, length_sectors;

fseek (en, 0x1BE, SEEK_SET); // ir al inicio de la tabla de particiones

para (i = 0; i <4; i ++) {// leer las cuatro entradas


printf ("Entrada de partición% d: Primer byte% 02Xn", i, fgetc (in));
printf ("Inicio de partición en CHS:% 02X:% 02X:% 02Xn", fgetc (en), fgetc (en), fgetc (en));
printf ("Tipo de partición% 02Xn", fgetc (in));
printf ("Partition end in CHS:% 02X:% 02X:% 02Xn", fgetc (in), fgetc (in), fgetc (in));

fread (y start_sector, 4, 1, in);


fread (y length_sectors, 4, 1, in);
printf ("Dirección relativa LBA% 08X,% d sectores longn", start_sector, length_sectors);
}

fclose (en);
return 0;
}
Guarde esto como read_mbr.c en la misma carpeta que guardó test.img , y compile
con gcc read_mbr.c -o read_mbr.exe y ejecute:
Muy fácil, eh! Pero leer cada campo manualmente se vuelve engorroso después de un tiempo,
por lo que podríamos definir todo en una struct agradable. Aquí está
el read_mbr2.c modificado:
#include <stdio.h>
#include <stdlib.h>

typedef struct {
unsigned char first_byte;
unsigned char start_chs [3];
unsigned char partition_type;
unsigned char end_chs [3];
unsigned long start_sector;
unsigned long_sectors;
} __attribute ((empaquetado)) PartitionTable;

int main () {
FILE * in = fopen ("test.img", "rb");
int i;
PartitionTable pt [4];

fseek (en, 0x1BE, SEEK_SET); // ir al inicio de la tabla de particiones


fread (pt, sizeof (PartitionTable), 4, in); // lee las cuatro entradas

para (i = 0; i <4; i ++) {


printf ("Partición% d, tipo% 02Xn", i, pt [i] .partition_type);
printf ("Sector de inicio% 08X,% d sectores longn",
pt [i] .start_sector, pt [i] .length_sectors);
}

fclose (en);
return 0;
}
Tenga en cuenta que esta vez imprimí solo la información mínima
necesaria. El __attribute((packed)) es necesario para que el compilador no alinee
nuestros campos de estructura de datos a límites de 32 bits o 64 bits (de manera
predeterminada, le gusta rellenar estructuras con áreas vacías para que el procesador pueda
manejar los datos un poco más rápido) y hacer un lío.Además, estoy usando un compilador
donde sizeof(char) es 1, sizeof(short) es 2 y sizeof(long) es 4, ¡ajuste sus
tipos de datos si está usando un sistema o compilador diferente!
Leyendo e interpretando el sector de arranque
Con base en el resultado anterior, es bastante evidente que la primera partición es la que
queremos examinar más a fondo.Ahora te aconsejo que leas el capítulo "FAT and the Boot
Sector" del tutorial de CompuPhase . Según el tutorial, el sector de arranque para un sistema de
archivos FAT16 debe encajar perfectamente en esta estructura:
typedef struct {
unsigned char jmp [3];
char oem [8];
unsigned short sector_size;
unsigned char sectors_per_cluster;
unsigned short reserved_sectors;
unsigned char number_of_fats;
unsigned short root_dir_entries;
unsigned short total_sectors_short; // si se usa cero, campo posterior
unsigned char media_descriptor;
unsigned short fat_size_sectors;
unsigned short sectors_per_track;
unsigned short number_of_heads;
unsigned long hidden_sectors;
unsigned long total_sectors_long;

unsigned char drive_number;


unsigned char current_head;
unsigned char boot_signature;
unsigned long volume_id;
char volume_label [11];
char fs_type [8];
char boot_code [448];
unsigned short boot_sector_signature;
} __attribute ((empaquetado)) Fat16BootSector;

Para que el código sea un poco más robusto, utilicé un ciclo for que se detiene cuando
encuentra la primera partición con tipo de partición compatible (4, 6 o 14), por lo que la entrada
de partición está en pt[i] . Para moverse dentro del archivo de imagen, primero usaremos
el fseek() , luego leeremos el sector de arranque:
fseek (en, 512 * pt [i] .start_sector, SEEK_SET);
fread (& bs, sizeof (Fat16BootSector), 1, in);
read_boot.c unos pocos comandos de impresión y read_boot.c el resultado
en read_boot.c . Debería entenderlo fácilmente cuando compare con read_mbr2.c . Los
resultados de una ejecución de prueba se pueden ver a la derecha.
Leyendo el directorio raíz
Antes de profundizar en la tabla de asignación de archivos, miraremos hacia adelante y
leeremos el directorio raíz. Para hacerlo, debemos omitir los sectores reservados (la cantidad de
sectores reservados es bs.reserved_sectors , que incluye el sector de arranque que
acabamos de leer) y todas las FAT (hay bs.number_of_fats de ellos,
cada bs.fat_size_sectors sectores bs.fat_size_sectors ) :
fseek (en, (bs.reserved_sectors-1 + bs.fat_size_sectors * bs.number_of_fats) *
bs.sector_size, SEEK_CUR);
Tenga en cuenta que estamos utilizando el modo de búsqueda SEEK_CUR , que utiliza la
ubicación actual como base. Esta declaración se agrega después de leer el sector de arranque,
por lo que lo compensamos restando uno de bs.reserved_sectors .
Para esta parte, estoy usando el tutorial del sistema de archivos FAT de Phobos como
referencia. Es más detallado en la parte FAT que en el tutorial anterior. El capítulo "El
directorio raíz" contiene la información que necesitamos para descifrar la estructura de las
entradas de archivos:
typedef struct {
unsigned char nombre de archivo [8];
unsigned char ext [3];
atributos de char sin firmar;
char sin firmar reservado [10];
unsigned short modify_time;
unsigned short modify_date;
unsigned short starting_cluster;
unsigned long file_size;
} __attribute ((empaquetado)) Fat16Entry;
Ahora que estamos en la posición correcta, leer las entradas
(hay bs.root_dir_entries de ellas) es muy sencillo:
para (i = 0; i <bs.root_dir_entries; i ++) {
fread (& entry, sizeof (entrada), 1, in);
print_file_info (& entrada);
}
Tenga en cuenta que estoy usando una función de ayuda para imprimir la información del
archivo, ya que el primer carácter de nombre de archivo tiene un significado especial y los
campos de fecha y hora de modificación están empaquetados. Consulte el archivo fuente para
obtener más información: no es nada difícil, y en caso de duda, puede consultar las
explicaciones claras proporcionadas para esos campos en el tutorial de
Phobos. read_root.c todo en read_root.c , lo compilé y lo ejecuté para ver si
funcionaba:
Asombroso. Si compara esta información con la captura de pantalla que se encuentra al
comienzo de este tutorial, podemos concluir con seguridad que estamos haciendo al menos un
trabajo tan bueno como el Explorador de Windows.
Un vistazo al futuro
Ahora que hemos leído el directorio raíz, estamos básicamente en el principio del área de datos
del sistema de archivos.Tratemos de encontrar el primer sector de README.TXT usando
nuestro editor hexadecimal. Antes de hacerlo, necesitamos saber que en FAT, el área de datos
se divide en unidades de asignación de archivos llamadas "clusters", donde cada clúster
es bs.sectors_per_cluster sectores de longitud. Esto se debe a que FAT utiliza la
numeración de 16 bits para clusters y si cada clúster tenía solo 512 bytes de longitud, solo se
podían abordar 32 megabytes de datos, ¡no lo suficiente para una tarjeta de memoria de 1 GB!
Desde la salida read_root.exe , podemos ver que el área de datos comienza en 0x50200 y
README.TXT se almacena en el clúster 0xE (14). Los clústeres se numeran a partir del 2 en
adelante (la razón por la cual aprenderemos más adelante), así que para alcanzarlo, debemos
saltear 12 clústeres (14-2) hacia adelante. En función de la salida de read_boot.exe ,
vemos que hay 32 sectores por clúster y el tamaño del sector es 512 (esto es 16 kB, no
coincidentemente el mismo valor que configuré como tamaño de unidad de asignación al
formatear la tarjeta SD), así que esto es exactamente 12 * 32 * 512 bytes o 0x30000 en
hex. Encendiendo mi editor hexadecimal, abrí el test.img y test.img el test.img "Ir
a" (Ctrl-G) para localizar la dirección 0x80200 (0x50200 + 0x30000):
¿Cuan genial es eso? Si solo necesita leer un máximo de 16 kilobytes, este es todo el código
que necesitará para conquistar el sistema de archivos FAT16. En la siguiente parte de este
tutorial, mostraré cómo navegar la FAT para leer archivos de cualquier tamaño, y tal vez
expandir a archivos de escritura o las diferencias de FAT32. Las partes posteriores mostrarán
cómo interactuar con la tarjeta SD usando un microcontrolador, y adaptarán el código utilizado
aquí para la memoria limitada de los chips AVR de 8 bits. Así que estad atentos, y si aún no te
has suscrito al feed, ¡hazlo ahora!
Observación en codificación progresiva
En este tutorial, he usado el mismo método de "construir sobre la iteración anterior" que uso al
abordar proyectos más grandes: comienzo con algo realmente simple, y solo cuando lo hago,
procedo a refinar el código para el próximo paso. De esta manera, la cantidad de información
que uno necesita absorber se mantiene más pequeña, y puede encontrar problemas más
fácilmente. Si todavía no has adoptado esta forma de desarrollo, ¡lo recomiendo
encarecidamente!
El mismo método también se puede aplicar a cualquier proyecto de electrónica: en lugar de
construir una olla de huevo controlada por IR de una sola vez, comience por tratar de controlar
la olla con un interruptor manual en una placa de prueba. Luego crea una versión que use un
microcontrolador para alternar el interruptor. Luego construye el receptor de IR, posiblemente
en una placa de prueba separada. Solo cuando hayas dominado cada tema individualmente,
deberías combinar todo junto. ¡De esa forma perderás menos huevos!
Pase a la siguiente parte de este tutorial

PUBLICADO POR

Joonas Pihlajamaa
Codificación desde 1990 en Basic, C / C ++, Perl, Java, PHP, Ruby y Python, por nombrar algunos. También está
interesado en matemáticas, películas, anime y ocasionalmente slashdot de vez en cuando. Ah, y también tengo una vida
real, ¡pero no hablemos de eso!Ver todos los mensajes de Joonas Pihlajamaa
Publicado en 2 de abril de 2012 10 de diciembre de 2013 Autor Joonas Pihlajamaa Categorías Electrónica Etiquetas disk
image , fat , fat16 , file allocation table , editor hexadecimal ,hxd , sd , tutorial
63 pensamientos sobre "Simple FAT y SD Tutorial Parte 1"

1. Pingback: Level Shifting 101 »Código y vida


2. Pingback: Simple FAT y SD Tutorial Parte 2 »Código y vida
3. Pingback: Tarjeta SD và Tarjeta MMC - Página 13

4. BJdice:
27 de abril de 2012 a las 08:51

Excelente tutorial, estoy deseando que llegue la cuarta entrega.Puede que necesite verificar esta
página, aunque creo que tiene un error tipográfico "la tabla de partición debe comenzar en el
offset 0x1CE", creo que es 0x1BE como en el código de ejemplo.
Tu estilo de enseñanza es excelente y espero ver más.
Saludos,
BJ
RESPUESTA

1. jokkebkdice:
27 de abril de 2012 a las 09:44

Gracias por mencionarlo. ¡Fijo!


RESPUESTA

5. Pingback: Simple FAT y tutorial SD Parte 4 »Código y vida


6. Pingback: Conseguir un problema al conectar la tarjeta micro SD con LPC2368
7. Pingback: listado de la tarjeta SD del programa para usar con ATMega8
8. Pingback: mega8 con tarjeta sd
9. Pingback: ¿Cómo enviar imágenes jpeg a avr?

10. Mikedice:
10 de marzo de 2013 a las 06:28

Interesante página, pero creo que su información está un poco desactualizada. No todos los
volúmenes de la tarjeta SD tendrán una partición. Consulte esta página para obtener una
cobertura más completa: http://www.maverick-
os.dk/FileSystemFormats/FAT16_FileSystem.html
RESPUESTA

1. jokkebkdice:
10 de marzo de 2013 a las 11:03

Sí, las tarjetas SD también se pueden formatear de una manera diferente, pero todas las tarjetas
seguí la estructura que describo en el tutorial, así que me salté los detalles más avanzados para
simplificar. :) Gracias por el enlace, es una adición útil a la publicación.
RESPUESTA

11. Rogerdice:
7 de junio de 2013 a las 00:39

hola, cuando veo el último sector que ocupa el HEMLET.TXT (grupo 13), hay algún texto de
Finlandia o algo así, que está en el offset 0x7F600. ¿Por qué podría estar allí?
Muchas gracias.
RESPUESTA

1. jokkebkdice:
9 de junio de 2013 a las 14:36
Buen hallazgo :) Hice algunas pruebas con la imagen del disco antes de decidir qué escribir allí,
y como FAT no elimina los datos antiguos, solo marca sectores libres, supongo que todavía
estaba allí.
Entonces, si hubiera usado una imagen de formato cero, todos los datos no utilizados serían
cero, pero ahora hay algunos datos antiguos en el área no utilizada del sector.
RESPUESTA

12. SMdice:
20 de junio de 2013 a las 03:03

Buena esa. Estoy hackeando ext3, aunque buena información.


Nota: El enlace está muerto en:

Ahora te aconsejo que leas el capítulo "FAT and the Boot Sector" del tutorial de CompuPhase.
RESPUESTA

1. Joonas Pihlajamaadice:
10 de diciembre de 2013 a las 10:21

Gracias por señalar eso. De hecho, me olvidé de http: // desde el principio, así que el enlace
simplemente se rompió. :)
RESPUESTA

13. Cristidice:
18 de agosto de 2013 a las 15:06

Estoy confundido. Las unidades extraíbles no tienen MBR, solo tienen un PBR único. ¿Por qué
tienes un MBR en una unidad extraíble?
RESPUESTA

1. jokkebkdice:
18 de agosto de 2013 a las 15:40

Al menos de acuerdo con http://www.compuphase.com/mbr_fat.htm muchas tarjetas CF y SD


se organizan de forma similar a los discos duros, y contienen un MBR. Han pasado 18 meses
desde que leí más sobre el tema y olvidé la mayoría de los detalles, pero al menos las tarjetas
SD que tenía seguían la estructura delineada en el tutorial. Creo que las memorias flash USB y
posiblemente algunas tarjetas SD podrían ser más simples.
RESPUESTA

1. Cristidice:
19 de agosto de 2013 a las 21:50

http://en.wikipedia.org/wiki/Master_boot_record
"Los MBR no están presentes en medios no particionados como disquetes, superflopias u otros
dispositivos de almacenamiento configurados para comportarse como tales".
Utilizo un lector de tarjetas microSD USB para formatear el microSD, que básicamente se ve
como un "Disco extraíble", y todos los "Discos extraíbles" que tengo no tienen un
MBR.BOOTICE también confirma esto al tener el botón "Process MBR" en gris y el editor
hexadecimal porque el primer sector comienza con PBR.
De todos modos, sigue siendo un gran tutorial.
¡Gracias!
RESPUESTA

1. jokkebkdice:
20 de agosto de 2013 a las 10:01

Entonces, si hace una copia en bruto de la tarjeta SD, ¿el primer sector realmente comienza con
cosas que se describen en "Lectura e interpretación del sector de arranque"? De todos modos,
agregaré una nota a mi sección MBR, que hay (micro) tarjetas SD que no la tienen en absoluto:
la encontré cuando investigaba para el tutorial, pero como todas mis tarjetas SD tenían MBR,
no recuerdo mencionarlo en absoluto. ¡Gracias por la información!
RESPUESTA

1. Cristidice:
20 de agosto de 2013 a las 10:32

Sí, el primer sector en mi microSD es el sector de arranque o PBR.


Investigar más demostró que la presencia del MBR en realidad depende de quién formateó el
disco.
A Windows le gusta formatear discos extraíbles como USB-FDD, que no contiene un MBR con
una tabla de particiones y puede tener solo una partición.
Sin embargo, al usar un software de terceros en Windows (utilicé BOOTICE 1.1.0), puede
formatear el disco extraíble como un USB-ZIP o USB-HDD, que tiene un MBR, y puede tener
múltiples particiones.

2. happycoderdice:
24 de junio de 2016 a las 06:49

¿Cómo verificar si un MBR está presente o no?


Obtendré valores basura cuando intento leer MBR desde una tarjeta SD formateada sin
ella. ¿No es así?
14. Vladimirdice:
29 de agosto de 2013 a las 19:45

Creo que hay una contradicción aquí.


El sector de inicio tiene una longitud de 512 bytes. A partir de 0x00 a 0x1FF.
El Master Boot Record es también un sector de 512 bytes.
Este sector contiene una tabla de particiones con cuatro entradas que comienzan en el
desplazamiento 446 (hex 0x1BE).
Cómo ? 0x1be está dentro del sector de arranque.
0x00 <0x1BE <0x1FF.
RESPUESTA

1. Joonas Pihlajamaadice:
29 de agosto de 2013 a las 21:17

No, creo que es consistente: si el SD está formateado como un disco duro con muchas
particiones, su primer sector (0) es el MBR, y la tabla de partición comienza en el offset
0x1BE. Si no hay sectores reservados entre MBR y la primera partición, el sector de inicio de la
primera partición es el siguiente (sector 1), también 512 bytes.
Entonces 0x1BE es un desplazamiento relativo en el sector 0 (MBR). El sector de arranque
(sector 1 o más) tiene datos diferentes en 0x1BE de ese sector.
Lo que puede ser confuso es el sector, el método de desplazamiento para abordar cosas en lugar
de solo desplazamiento lineal: si está viendo una imagen de disco en el editor hexadecimal, el
desplazamiento del sector X 0x1BE está en X * 0x200 + 0x1BE (por ejemplo 0x3BE para el
sector 1) .Como analogía del automóvil, podrías pensar un sector como un autobús con 512
asientos. El asiento del primer bus (MBR) 0x1BE es el comienzo de la tabla de particiones,
pero hay un asiento 0x1BE en cada bus después de eso, incluido el sector de arranque, que
generalmente es el segundo bus, justo después del MBR. :)
RESPUESTA

1. vladimirdice:
30 de agosto de 2013 a las 17:23

Está bien ahora. El problema era el software HxD.


Cuando abrí la tarjeta SD, me mostró todos los datos comenzando desde el primer sector de
arranque de una partición activa.
Ahora uso WinHex. Está bien. MBR está en el sector 0, y el registro de boor está en xxx butes
después.
RESPUESTA

1. Joonas Pihlajamaadice:
2 de septiembre de 2013 a las 09:44

Sí, también creo que si no se ejecuta como administrador, HxD ni siquiera ofrece la opción de
leer todo el dispositivo en bruto, solo las particiones.
RESPUESTA

2. Filbydice:
13 de junio de 2014 a las 17:16

Es lo mismo con WinHex. Debe abrir el disco físico si desea ver * todo * del disco. El disco
lógico solo mostrará el volumen / partición actual.
RESPUESTA

15. Sebastiandice:
3 de diciembre de 2013 a las 05:57

soy un novato tratando aquí. Conseguí el primer exempel compilado con éxito e imprimió el
Partition Tabel muy bien.Estoy usando el test.img que me proporcionaste.
Pero cuando imprimo el sector de arranque, coincide con la imagen que está mostrando. El
código de salto y el código OEM coinciden, pero luego se descarrila.
¿Es mi compilador de alguna manera, o es el test.img diferente del test.img impreso en la
imagen read_boot.png?
¡Gracias por el gran tutorial de todos modos!
RESPUESTA

1. Joonas Pihlajamaadice:
9 de diciembre de 2013 a las 23:12

El compilador podría ser el problema, por ejemplo, diferentes tamaños para abreviar o no
respetar el atributo __packed__ (es decir, no rellenar campos con límites de 32 bits). Puede
imprimir las compensaciones de campo con algo como:
printf ("Atributos en% d \ n", (void *) bs.attributes - (void *) bs);
No estoy muy seguro sobre el casting, pero una sustracción y el reparto adecuado deberían
hacer el truco.
Usé gcc del proyecto MinGW, ¿qué plataforma y compilador estás usando?
RESPUESTA

1. Sebastiandice:
11 de diciembre de 2013 a las 05:12

Sí, tiene usted razón. Después de investigar un poco encontré esto:


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991
El último comentario decía que había un parche para esto desde hace un tiempo, pero no sé
dónde puedo conseguirlo, ni aplicarlo ni nada.
Así que casi todo. Pero algunos bromeando encontré a un chico que hace esto: #define
PACKED __attribute__ ((__packed__))
Y después de aplicarlo a algunos de los miembros del instructor, es decir:
PACKED unsigned short sector_size;
Lo tengo para que coincida con el resultado que está mostrando. Así que estoy leyendo este
tutorial ahora :)
RESPUESTA

16. Sandeep Tayaldice:


10 de enero de 2014 a las 08:41

Muy buen tutorial. Me gustó su enfoque iterativo para desarrollar proyectos. Adaptaré eso.
RESPUESTA

17. Mirondice:
1 de febrero de 2014 a las 07:23

¡Buen trabajo! ¡Exactamente lo que necesito! ¡Muchas gracias por la descripción completa de
este material! ¡Buena suerte para su publicación!
RESPUESTA

18. Srinivas Nistaladice:


16 de agosto de 2014 a las 01:24

Gracias por este gran tutorial. Despejó muchas de mis dudas. :)


RESPUESTA

19. Markusdice:
3 de septiembre de 2014 a las 16:20

Moi ja gracias por los excelentes tutoriales!


RESPUESTA

20. serbandice:
28 de octubre de 2014 a las 11:31

¡Oye, antes que nada, este es un gran tutorial! Lo estoy leyendo paso a paso y es muy detallado
... pero tengo una pregunta sobre la fecha modificada y el tiempo de los cortos empaquetados
en la entrada de los directorios raíz. Si el segundo es un valor (entre 0 y 31 - 5 bits) que
representa un intervalo de 2 segundos, cualquier valor de segundo debe generar un número par
(0, 2, 4, 6, etc.).¿Por qué en su ejemplo el archivo README.TXT tiene el tiempo 20:
31.27? 27 ni siquiera es ...
RESPUESTA

1. Joonas Pihlajamaadice:
28 de octubre de 2014 a las 17:00

Jaja, observación aguda! Me lo pregunté yo mismo, pero creo que la explicación más obvia es
que olvidé multiplicar el valor del campo por 2 cuando lo imprimí. Entonces, en realidad es 20:
31: 54 ... :)
RESPUESTA

1. serbandice:
29 de octubre de 2014 a las 10:42

¡Pienso lo mismo! Lo observé porque he leído el tutorial muchas veces, solo para entenderlo
claramente.
Gracias y sigan trabajando bien :)
RESPUESTA

21. Markusdice:
28 de octubre de 2014 a las 21:40

Hola, gran implementación ligera de FAT. Pregunta rápida sobre moldes del fat16_buffer a
diferentes estucos. ¿Por qué lanzas el primer vacío * y luego struct *? ¿No bastaría
simplemente con lanzar directamente a struct *?
RESPUESTA

1. Joonas Pihlajamaadice:
28 de octubre de 2014 a las 22:24

Esa es también una excelente pregunta. Parece que no hay razón para lanzar. Solo uno puedo
pensar que algún compilador que utilicé advirtió sobre el lanzamiento entre tipos
incompatibles. O simplemente tuve un momento aburrido al escribir esas líneas. :)
RESPUESTA

22. Larrydice:
14 de noviembre de 2014 a las 04:50
Utilicé Tiny C Compiler para read_boot.c y obtuve resultados diferentes con su archivo
test.img. No sé cuál es el problema, pero se desmorona en sector_size informando 8194 en
lugar de 512 y continúa dando resultados erróneos desde allí
RESPUESTA

1. Joonas Pihlajamaadice:
14 de noviembre de 2014 a las 16:31

Lo más probable es que TCC tenga una forma diferente de especificar una estructura
empaquetada (es decir, sin alineación), en cuyo caso el tamaño de (estructura) es mayor y
algunos campos se leen en un lugar incorrecto. Este es el caso, buscando en Google
"Alineación de estructura de compilador de Tiny C" (o embalaje). O simplemente obtenga gcc
y haga algunas pruebas para determinar qué es diferente. Los tamaños de ints, shorts y longs
son la razón más común.
RESPUESTA

1. Larrydice:
14 de noviembre de 2014 a las 18:03

Descargué gcc 4.9.2 y obtuve los mismos resultados. Intenté read_mbr.c compilado con tcc y
gcc y obtuve resultados diferentes de su ejemplo. Por ejemplo, "Partition start in CHS" arroja
02:04:00 en lugar de 00:04:02. los resultados que obtengo están en el mismo orden que se
muestra en HxD comenzando en 0x1BF. Lo mismo sucede en "Partition end in CHS" donde
obtengo 04: E4: C9 en lugar de C9: E4: 04. No entiendo por qué la diferencia entre
read_mbr.exe de la carpeta del proyecto y lo que compilo.
RESPUESTA

1. Joonas Pihlajamaadice:
14 de noviembre de 2014 a las 23:12

Hmm, suena como un posible problema de endianness: si tienes 0x01, 0x02, 0x03, 0x04 en un
archivo y los lees en un dword, algunos sistemas manejarán eso como 0x01020304 y otro
0x04030201. Aunque hoy en día no puedo pensar en una plataforma de hardware que no se
ajuste a la que está usando Intel (como los Macs también están en la plataforma
Intel). Extraño. Bueno, al menos sabes que los bytes en sí parecen similares a lo que se supone
que debe ser ...
RESPUESTA

2. Larrydice:
14 de noviembre de 2014 a las 23:27
Esto puede ayudar: mi sistema operativo es win7 de 64 bits.gcc es mingw-w64 (x86_64-4.9.2-
posix-seh-rt_v3-rev0). Tamaño de: chr 1, short 2, int 4, long 4. Ejecuté la macro "offsetof" en la
estructura de read_mbr packed y unpacked, y obtuve el mismo resultado. first_byte = 0,
start_chs [3] = 1, start_partiton = 4, end_chs [3] = 8, start_sector = 8 y length_sectors = 12.
Todavía aturdido y confundido por qué obtengo resultados diferentes.
RESPUESTA

1. Joonas Pihlajamaadice:
15 de noviembre de 2014 a las 13:19

Ah, compilador de 64 bits. Recopilé el mío en la versión de 32 bits de MinGW. Devuelve los
mismos valores que usted, first_byte = 0, start_chs = 1, length_sectors = 12, y the sizeof
(PartitionTable) = 16. ¿Se lee correctamente esa estructura?
¿Qué obtienes por sizeof (Fat16BootSector)? Obtengo 518 (lo que es más raro, hubiera pensado
que 512) y el offset del miembro sector_size es 12.
RESPUESTA

1. Larrydice:
15 de noviembre de 2014 a las 19:01

Obten sizeof (PartitionTable) = 16 y sizeof (Fat16BootSector) = 518. Y offsetof


(Fat16BootSector, sector_size) = 12.
Decidí instalar el paquete "mingw32-gcc" clase "bin" versión "4.8.1-4" El compilador GNU C
y recompilar "read_boot.c". Todavía obtengo resultados falsos comenzando con el informe
sector_size 8194 y terminando con la firma del sector de inicio de 0x0000. Lo único que noto
es que la etiqueta del volumen muestra [me FAT16] en lugar de [sin nombre], por lo que las
lecturas se desplazan a la izquierda por algún motivo.
Realmente me gusta su tutorial y deseo que al volver a compilar el código C todo sea lo mismo.
Lo que busco es un registrador de datos de tarjeta SD ligero para Arduino en lugar de hacer
todas las combinaciones posibles para FAT12 16 y 32 tarjetas que la biblioteca SD.h arduino
realiza a expensas de usar aproximadamente el 50% del espacio del programa atmega328p .
No soy en absoluto un programa competente de C, pero he aprendido mucho intentando
depurar lo que está sucediendo. Gracias por su tiempo respondiendo mis problemas.

2. Larrydice:
16 de noviembre de 2014 a las 06:17

Descubrí que después de un char o una serie de caracteres (oem [8] o imprimir 3 resultados de
char en una fila), el compilador omite la siguiente ubicación. Cuando llega a la etiqueta de
volumen, se ha saltado cinco ubicaciones, dando la salida
"Etiqueta de volumen: [ME FAT16]". Ahora necesito descubrir cómo solucionar esto. Tal vez
intente byte en lugar de char.
2. Nhat Minhdice:
21 de noviembre de 2014 a las 16:41

Hola Larry,
También tengo el mismo problema.
Revisé, encontré que ese error proviene del compilador.
(Si usa la línea de comando para ejecutar read_bs.exe en código de ejemplo, estará bien). Paso
mucho tiempo para abordar este problema, pero aún no logro hacerlo.
¿Has resuelto tu problema? en caso afirmativo, comparta su solución.
Gracias,
Minh
RESPUESTA

1. Nguyen Nhat Minhdice:


25 de noviembre de 2014 a las 14:07

Hell Lary,
Esta es mi solución:
a) agregue la opción del compilador GCC: -mno-ms-bitfields
o
b) cambie _attribute en la fuente a: _attribute ((gcc_struct, _packed_))
Minh

2. Nguyen Nhat Minhdice:


25 de noviembre de 2014 a las 14:09

Lo siento por la opción b) Debe ser así.


_attribute ((gcc_struct, __packed__))

3. Larrydice:
12 de diciembre de 2014 a las 18:28

Hola Minh,
Resolví el problema usando MinGW32 g ++ antes de ver tu solución. Probé tu solución usando
__attribute ((gcc_struct, __packed__)) en mi código "offsetof_example.c" y obtuve un
resultado correcto.Necesité agregar un guión bajo adicional para atribuirlo para que compilara
correctamente. __attribute ((gcc_struct, __packed__)) not _attribute ((gcc_struct, __packed__))

23. fabiandice:
19 de noviembre de 2014 a las 03:02

Hola, no tengo ningún problema con la EEPROM, pero mi problema es que tengo una RAM de
512. ¿Es posible adaptar o hacer que FAT16 use menos RAM?
RESPUESTA

1. Joonas Pihlajamaadice:
19 de noviembre de 2014 a las 15:33

Si lee la siguiente parte del tutorial, notará que mi biblioteca AVR tiene una huella de memoria
de 51 bytes + alguna pila, por lo que 512 debería ser suficiente (128 bytes de SRAM también
funcionarían).
RESPUESTA

24. Larrydice:
12 de diciembre de 2014 a las 18:06

Comprobé las variables offset usando este código:


/ * offsetof ejemplo * /
#include / * printf * /
#include / * offsetof * /
typedef struct {
char c;
pantalones cortos;
int i;
largo l;
flotar f;
} __attribute ((packed)) sfoo;
int main ()
{
printf ("offset de char c es% d tamaño de% d \ n", offsetof (sfoo, c), sizeof (char));
printf ("desplazamiento de s corto es% d tamaño de% d \ n", offsetof (sfoo, s), sizeof (corto));
printf ("desplazamiento de int i es% d tamaño de% d \ n", offsetof (sfoo, i), sizeof (int));
printf ("offset de long l es% d tamaño de% d \ n", offsetof (sfoo, l), sizeof (largo));
printf ("desplazamiento de float f es% d tamaño de% d \ n", offsetof (sfoo, f), sizeof (float));
}
con el compilador MinGW 32bit obtengo un desplazamiento de 2 entre char e int y debería ser
1. Debe estar agregando un byte nulo después de un char.
MinGW32 instalado y compilado usando g ++. El desplazamiento entre char e int ahora es de 1
byte. Ahora puedo volver a compilar todos los programas en el tutorial y hacer que funcionen.
Minh,
Gracias por tu codigo No lo he probado aún, ya que lo vi hoy publicando este comentario.
RESPUESTA
25. Jesperdice:
23 de diciembre de 2014 a las 00:28

Solo quería decir muchas gracias por la guía.


Un gran trabajo.
RESPUESTA

26. Minhdice:
24 de diciembre de 2014 a las 10:57

Hola chico,
Tengo una pregunta sobre el directorio raíz.
si leemos el primer byte del nombre del archivo es 0x2e, indica que la entrada es para un
directorio, no un archivo normal.
Obviamente, "SUBDIR" es el nombre de la carpeta. Parece que esta línea de código no
funciona:
switch (entrada-> nombre de archivo [0]) {
.
.
.
estuche 0x2E:
printf ("Directorio: [% .8s.%. 3s] \ n", entry-> filename, entry-> ext);
descanso;
}
impresiones ans: "ARCHIVO: [SUBDIR. ] "
Y trata SUBDIR como archivo normal.
Por favor, ayúdame a explicar en este punto.
Muchas gracias,
Minh
RESPUESTA

27. Adithyadice:
14 de febrero de 2015 a las 12:38

¡Oye, muchas gracias por el tutorial! Estoy estancado al leer los datos de la partición después
de crear una imagen de mi tarjeta sd. Obtengo valores de tipo de partición extraños:
72,65,79,0D para las entradas de partición 0-3, respectivamente. ¿Me puede ayudar? Estoy
usando una tarjeta sd de 512MB formateada con un sistema de archivos FAT32.
RESPUESTA

28. Artedice:
18 de febrero de 2015 a las 20:36

Oye, realmente gracias por el tutorial. ¡Y muchas gracias por los comentarios que me han
ayudado mucho!
RESPUESTA

29. Marcodice:
19 de octubre de 2016 a las 13:27

¡Solo quería dejar un comentario para decir gracias!


Maravilloso tutorial :)
RESPUESTA

30. Pingback: ToVanTran

31. Nazar Gabrieldice:


4 de diciembre de 2016 a las 18:52

¿dónde está el archivo read_boot.c?


RESPUESTA

32. ARYAN BULATHSINHALAdice:


1 de octubre de 2017 a las 08:14

tutorial impresionante y directo !!!!!!!!!!!!!!


:)
RESPUESTA

33. Doug Gabbarddice:


11 de diciembre de 2017 a las 03:02

¡Gran página! Estoy en el proceso de tratar de integrar un SD con FAT en este momento y
encontré que su página era extremadamente informativa. Todavía estoy trabajando en mi
camino a través de toda la información. ¡Pero quería decir gracias!

S-ar putea să vă placă și