Mover datos, Bss y memoria heap a SRAM externa Atmega2560

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:

ingrese la descripción de la imagen aquí

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?

¿Cómo es el archivo .ld?
Odio decirlo, pero si su firmware necesita asignación dinámica y SRAM externa, es posible que AtMega no sea el chip adecuado para el trabajo.
Aquí está el archivo de script del enlazador: codeshare.io/aJom3K
@PeteW Sé que lo estoy presionando y me moveré para armar en el futuro, pero primero quiero resolver este problema.
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;parece no estar de acuerdo con .data=802200la línea de comando. ¿Tal vez necesite configurar __DATA_REGION_ORIGIN__los argumentos del enlazador?
@BrianDrummond Muchas gracias, estuve cambiando el archivo ld equivocado todo este tiempo. Después de que lo mencionaste me di cuenta. Eliminé la condición y cambié el archivo ld a esto: DATA_REGION_ORIGIN = 0x802200; y resolvió el problema. Pero no estoy seguro de dónde se estaba definiendo originalmente, ya que si dejo que la condición esté allí, me da el mismo error.
¿Por qué tiene un montón en un 8 bits y por qué no puede simplemente eliminarlo para liberar memoria? Simplemente se sienta en su RAM ocupando espacio sin una buena razón.
@Lundin No me importa el montón y no se usa, los argumentos del enlazador anterior son solo una prueba. Mi objetivo principal era mover los .data y .bss a la SRAM externa.
Tal vez intente inicializar XMCRA en la sección init3, con__attribute__ ((section (".init3"))

Respuestas (2)

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.

Gracias por aclararlo, estaba confundido por la hoja de datos sobre la interfaz XMEM (interfaz de memoria externa) y cómo maneja todo automáticamente, también la documentación AVR-LIBC hizo que pareciera que es posible hacerlo; el sistema en el que estoy trabajando es solo un prototipo y lo actualizaré a un ARM, ya que como mencionaste, es mucho más eficiente y simple.

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=802200en la línea de comando. Puede rastrear la ruta desde __DATA_REGION_ORIGIN__hasta .dataen el propio script .ld.

Lo que sugiere que puede configurar __DATA_REGION_ORIGIN__los argumentos del enlazador (en la ldlínea de comando) y (si está configurado) anulará el valor 0x800200dado 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 ldproceso, 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 -val comando ld puede generar más información que muestre lo que realmente está sucediendo ...

Esta respuesta pasa por alto el punto de que el ATMega2560 no tiene medios para mapear memorias SRAM externas, y ninguna cantidad de manipulación de scripts de vinculación solucionará eso. En todo caso, eso solo romperá el vínculo y nada funcionará.