¿Cómo funciona el direccionamiento de E / S con asignación de memoria?
Estoy tratando de entender un ejemplo de I2S suministrado : ¿Alguien lo tiene funcionando? .
Configurar relojes:
#define BCM2708_PERI_BASE 0x20000000
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
Primero mapea el código así ...
clk_map = (unsigned char *)mmap(
(caddr_t)clk_mem,
MAP_BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
CLOCK_BASE
);
Entonces hace algo ...
// Always use volatile pointer!
clk = (volatile unsigned *)clk_map;
Y cuando se hace referencia a estas extrañas adiciones de 0x26 y 0x27, ¿de qué se trata?
printf("Disabling I2S clock\n");
*(clk+0x26) = 0x5A000000;
*(clk+0x27) = 0x5A000000;
usleep(10);
printf("Confiure I2S clock\n");
*(clk+0x26) = 0x5A000001;
*(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001
usleep(10);
printf("Enabling I2S clock\n");
*(clk+0x26) = 0x5A000011;
Mirando la hoja de datos, puedo ver de dónde obtuvieron algunos de estos valores, como la dirección base, pero me cuesta entender los otros. ¿Dónde se CLOCK_BASE
determina eso y qué está pasando?
Respuestas:
En una computadora, escribe en una 'dirección de memoria' especificada. El sistema reconoce esta dirección como una dirección de hardware, y el hardware apropiado recibe o envía el valor apropiado.
La mayoría de los sistemas de hardware tienen muchos registros diferentes que se pueden configurar o leer. Algunos pueden tener algunos, algunos pueden tener muchos. Estos registros se agruparán en un rango continuo. Un puntero base apunta al primero en el rango, y usted escribe, por ejemplo, en el segundo puerto con base_pointer + 1. No es necesario, puede escribir directamente en un puntero, pero el uso de un desplazamiento facilita el trabajo.
La Raspberry Pi reconoce una amplia gama de registros de hardware en la dirección 0x20000000. Se accede a un rango de registros que controlan los sistemas de reloj desde BCM2708_PERI_BASE + 0x101000. Los registros que controlan el reloj I2S son el registro 38 y 39 en ese bloque, escrito usando BCM2708_PERI_BASE + 0x101000 + 0x26 y 0x27
Sin embargo, no puede simplemente cambiar los valores del reloj, debe deshabilitar el reloj, cambiar los valores y reiniciarlo.
Si esta respuesta es demasiado básica, mis disculpas. En cuyo caso su pregunta es realmente hardcore, buena suerte. Puede encontrar este enlace útil
Actualización: ¿Por qué usar mmap y no escribir directamente en la memoria?
Cuando un programa ejecuta las direcciones de memoria que considera que no son direcciones reales, el administrador de memoria las asigna a direcciones reales. Esto impide que un programa pueda afectar a otro. Dos procesos pueden leer y escribir en su propia dirección 1234 perfectamente felices, y el administrador de memoria mantendrá las dos ubicaciones completamente separadas.
Los puertos de hardware, sin embargo, están en direcciones físicas absolutas. Pero no puede escribirles directamente porque el administrador de memoria tomará su dirección y la asignará a su área de memoria personal.
En Linux / dev / mem es un ' archivo de dispositivo de caracteres que es una imagen de la memoria principal de la computadora '
Si abre esto como un archivo, puede leerlo y escribirlo como un archivo. En la muestra suministrada, mem_fd es un identificador de archivo que resultó de abrir / dev / mem
Otro sistema que puede hacer la vida mucho más fácil es la capacidad de asignar un archivo a la memoria y escribir en él como memoria. Entonces, si tiene un archivo en el que desea leer o escribir diferentes bits específicos, en lugar de mover el puntero del archivo hacia adelante y hacia atrás, puede asignarlo a una ubicación en la memoria y luego escribirlo directamente como si fuera memoria.
Entonces, en este ejemplo, el código está creando un controlador para la memoria física, como si fuera un archivo en el disco, y luego solicita al sistema que lo trate como si fuera memoria. Un poco complicado, pero necesario para sortear el administrador de memoria virtual y escribir en una dirección física real. El valor 0x20000000, al parecer, es un poco una pista falsa. El código propone esta dirección como una pista, el sistema no tiene que asignar / dev / mem aquí, aunque probablemente sí. Normalmente, se pasaría el valor nulo y el sistema asignaría el identificador de archivo a la dirección que creyera mejor.
Ahora la memoria física se asigna a la memoria virtual de procesos, y las lecturas y escrituras van a donde espera.
Referencias
http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359
https://superuser.com/questions/71389/what-is-dev-mem
fuente
@AlexChamberlain esto se debe a la estructura del sistema operativo. Puede ir sin,
mmap
pero se declara la paginación, por lo tanto, no hay acceso directo. En el modo kernel puede prescindirmmap
, por ejemplo, insertando su controlador como módulo kernel sin necesidad de hacerlommap
. Además, en el caso más simple del sistema operativo, donde no se utiliza la memoria de la tabla de páginas, puede acceder sin ellasmmap
, es decir. Acceso directo a la dirección física.fuente