Esta es mi primera pregunta aquí, lo siento si me olvido de algo.
Estoy usando un Atmega2560 como procesador principal para mi proyecto, pero me estoy quedando sin RAM, así que le conecté una SRAM externa de 64 KB (64 x 8). Busqué y encontré un par de proyectos y bibliotecas que usan el sram externo:
http://andybrown.me.uk/wk/2011/08/28/512kb-sram-expansion-for-the-arduino-mega-design/
https://hackaday.io/project/21561-arduino-mega-2560-32kb-ram-escudo
Pero todos estos usan la SRAM externa como memoria de pila.
Me gustaría usar la memoria externa como memoria de datos, bss y montón, dejando toda la SRAM para la pila.
Encontré esto en el manual de avr-libc: https://www.nongnu.org/avr-libc/user-manual/malloc.html
Usando la información del manual, cambié el archivo MAKE para el cargador de arranque Arduino Mega aquí: C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\stk500v2
Enlace al archivo MAKE original: https://github.com/arduino/ArduinoCore-avr/blob/master/bootloaders/stk500v2/Makefile
Cambié "EXTMEMOPTS =" a esto:
EXTMEMOPTS = -Wl,--inicio-sección,.data=0x802200,--defsym=__heap_end=0x80ffff
0x800000 es el desplazamiento de la arquitectura Harvard, 0x802200 es la primera dirección de la memoria externa.
Estoy recompilando el gestor de arranque con el nuevo archivo make pero aparece el siguiente error:
Creo que se queja porque la dirección está fuera de la SRAM interna, no pude encontrar ninguna forma de solucionarlo.
No estoy seguro de lo que está mal, ¿qué me estoy perdiendo? Además, si esto se resuelve, ¿está bien inicializar el hardware de la memoria externa (configurando los registros XMCRA y XMCRB) en la función principal del gestor de arranque? Si no, ¿dónde debo hacerlo?
Actualización: aquí está el script del enlazador: https://codeshare.io/aJom3K
Actualización 2: El primer problema está resuelto ahora; Estaba editando el archivo ld incorrecto y después de cambiar el archivo correcto a lo siguiente funcionó:
DATA_REGION_ORIGIN = 0x802200;
El siguiente problema es dónde inicializar el hardware para la SRAM externa. Actualmente estoy haciendo esto en la función __jumpMain del cargador de arranque que también establece el registro del puntero de pila. ¿Está bien o debería hacerlo en otro lugar?
cargador de arranque: https://codeshare.io/5zNr1b
Actualización 3: como mencionó @Brian Drummond en la respuesta parcial, cambié los argumentos del enlazador a esto:
EXTMEMOPTS = -Wl,--inicio-sección,.data=0x802200,--defsym=__heap_end=0x80ffff,--defsym= DATA_REGION_ORIGIN =0x802200
y revirtió los cambios en el script de compilación para evitar problemas en el futuro.
Para cualquiera que haga algo similar: también debe agregar argumentos para cambiar DATA_REGION_LENGTH a la nueva longitud; de lo contrario, solo usará la longitud anterior, que en mi caso es: 0xfe00.
Actualización 4: después de algunas pruebas, aparentemente el MC no está usando la SRAM externa; después de programarlo con el nuevo script, puedo desconectar la SRAM y seguirá funcionando bien. También verifiqué las líneas de datos y direcciones a la SRAM y no se escribe ni lee nada.
Así que volví al principio. ¿Alguna idea de lo que está mal?
TL; DR Esto no funcionará de la manera que desea porque el Atmega2560 no tiene una interfaz de memoria externa.
Cuando crea una variable que se almacena en la SRAM [interna], es posible que la ALU del procesador busque esa variable porque la ALU y la SRAM están conectadas al mismo bus de memoria interna. En los procesadores de gama alta (por ejemplo, STM32F756), a veces tiene un periférico de interfaz de memoria externa dedicado que puede, por ejemplo, conectarse a SRAM, DRAM, SDRAMS, etc. Estos periféricos son especiales porque convierten el protocolo de bus de memoria interna del procesador en la interfaz de hardware externa necesaria para cargar/almacenar datos en un chip de memoria externo.
Una analogía simple[r] es esta: su ATmega2560 tiene un periférico SPI. Cuando configura eso como un maestro SPI y escribe algo en el registro de datos SPI, el periférico registra automáticamente los bits en el bus sin más intervención de la CPU. Ha traducido un acceso a la memoria (la escritura del registro de datos) en un protocolo físico.
Por el contrario, podría escribir código que movería manualmente los pines IO para lograr el mismo resultado de hardware que el periférico SPI. Esto tiene una serie de limitaciones, la principal es que debe desempaquetar manualmente un byte de datos y configurar los pines en los momentos apropiados manualmente (a través de un código). Debería ser obvio que este código está, bajo el capó, haciendo muchas lecturas y escrituras de memoria y ya no tiene la conversión automática de "escribir a registro de datos, bits de reloj" como con el periférico SPI dedicado.
Lo que está tratando de implementar con su SRAM externa y la secuencia de comandos del enlazador no va a funcionar porque, en lo que respecta al microcontrolador y al enlazador, ese espacio de direcciones simplemente no existe, y no hay ningún periférico de hardware que pueda convertir las instrucciones del bus. en señales de memoria externa. Los proyectos que vinculó simplemente usan una capa de software para controlar manualmente los pines IO para hablar con la SRAM externa (también conocida como bit-banging).
Edite para agregar: aún puede usar totalmente una SRAM externa, simplemente no será automática. Necesitará una biblioteca de software para que funcione, y tendrá que almacenar/cargar datos explícitamente a través de una API de algún tipo. Si se está quedando sin SRAM y su programa no se puede vincular, entonces no tiene suerte. Hay algunas formas extremadamente complicadas de evitar esto, pero no las recomiendo. En su lugar, reduzca los requisitos de memoria de su aplicación hasta que pueda vincularse o cambie a un microcontrolador más robusto. Recomendaría lo último, y diría que se deshaga de la memoria externa porque incluso en un procesador con una interfaz de memoria externa, agregar memoria externa es una adición importante en costo, complejidad y tiempo.
Respuesta parcial:
Mirando el archivo .ld (secuencia de comandos del enlazador) podemos ver
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;
que parece no estar de acuerdo con su deseado .data=802200
en la línea de comando. Puede rastrear la ruta desde __DATA_REGION_ORIGIN__
hasta .data
en el propio script .ld.
Lo que sugiere que puede configurar __DATA_REGION_ORIGIN__
los argumentos del enlazador (en la ld
línea de comando) y (si está configurado) anulará el valor 0x800200
dado en el script .ld.
O edite la expresión en el script del enlazador. Simplemente editar el valor debería funcionar (según tengo entendido), pero aparentemente algo más (pero ¿QUÉ?) En el ld
proceso, se proporciona un valor que anula el valor del script. Siento que el proceso .ld es innecesariamente oscuro y no pretendo entenderlo completamente.
Como solución alternativa, eliminar la expresión condicional dejando solo el valor lo pone en marcha, pero debe tener cuidado con los cambios "no oficiales" para compilar scripts, ya que tienden a causar problemas de mantenimiento más adelante.
Agregar -v
al comando ld puede generar más información que muestre lo que realmente está sucediendo ...
usuario_1818839
Pedro W.
oli
oli
usuario_1818839
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;
parece no estar de acuerdo con.data=802200
la línea de comando. ¿Tal vez necesite configurar__DATA_REGION_ORIGIN__
los argumentos del enlazador?oli
Lundin
oli
HaLailah HaZeh
__attribute__ ((section (".init3"))