El día de hoy me encontraba programando una FFT en un S32K144 en el IDE S32 Design Studio for ARM. El S32K144 tiene 64kB de RAM por lo que no me preocupé en declarar variables inmensas.
Las variables globales que declaré fueron:
#define FFT_SAMPLE_MAX (2048U)
#define FFT_FREQUENCY_RESP_SIZE ((FFT_SAMPLE_MAX / 2) + 1)
#define FFT_FREQ_BANDS (10U)
static uint16_t FFT_AudioSamples[FFT_SAMPLE_MAX];
static float FFT_HammingWindow[FFT_SAMPLE_MAX];
static float FFT_Frequency_Bands[FFT_FREQ_BANDS];
Alrededor de 13kB, entre otras variables estáticas locales que no contabilicé.
Posteriormente, dentro de una función declaré más variables pero esta vez como variables locales que se depositarán en el stack.
void FFT_GetFrequencyResponse(float* freqResponsePerBand)
{
if (1 == FFT_bufferReady)
{
float audioReal[FFT_SAMPLE_MAX];
float audioImag[FFT_SAMPLE_MAX];
float freqResp[FFT_FREQUENCY_RESP_SIZE];
Alrededor de 20kB en esa función únicamente. Si sigo llamando funciones con nuevas variables en stack, éste seguirá creciendo.
Después de ver que mi código sospechosamente estaba corrompiendo las variables me di cuenta de que no había modificado el tamaño del stack y que por ello se estaban sobreeescribiendo.
Utilicé C/C++ Watchpoints para ver cuándo se escribía y leía la variable corrupta. Basta con abrir el Memory Browser (Menú Window, Show view) y poner el nombre de la variable. Se le da click derecho y se agrega el watchpoint (Range = 40 porque pesa 40 bytes mi arreglo). Esto también se conoce como Hardware Breakpoint.
Si uno abre el archivo .map de la aplicación encontrará el tamaño del stack configurado así como el del heap, que en mi caso no necesito:
0x00000400 HEAP_SIZE = DEFINED (__heap_size__)?__heap_size__:0x400
0x00000400 STACK_SIZE = DEFINED (__stack_size__)?__stack_size__:0x400
0x400 = 1kB
Ese kB es mucho menos que lo que necesito.
Claro, pude haber declarado las variables como globales para evitar el problema... pero no habría aprendido cómo cambiar el stack en este IDE.
El tamaño de heap y stack se configuran en el archivo *.ld (linker directive) del proyecto:
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000400;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00000400;
Cambiémoslos por algo más sensato:
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x00000000;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x00005400;
También agregué el siguiente argumento para obtener el stack por función. GCC lo reporta en un archivo .su (stack usage) por cada .c:
-fstack-usage
fft_app.c:128:6:FFT_GetFrequencyResponse 20528 static
Compilé, pero empecé a invadir la sección .bss:
arm-none-eabi-gcc -o "s32k1_st7735.elf" "@s32k1_st7735.args"
d:/s32k1/s32ds/s32ds/build_tools/gcc_v6.3/gcc-6.3-arm32-eabi/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/bin/real-ld.exe: region m_data_2 overflowed with stack and heap
d:/s32k1/s32ds/s32ds/build_tools/gcc_v6.3/gcc-6.3-arm32-eabi/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/bin/real-ld.exe: section .stack VMA [20001c00,20006fff] overlaps section .bss VMA [20000000,200030e7]
El stack crece hacia abajo.
Por lo que revisé cómo es que la RAM del S32K144 está distribuida:
0x14000000 - 0x14000FFF - FlexRAM (4kB)
0x1FFF8000 - 0x1FFFFFFF - SRAM L (32kB)
0x20000000 - 0x20006FFF - SRAM U (28kB)
La sección bss estaba ubicada en SRAM U:
/* Specify the memory areas */
MEMORY
{
/* Flash */
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x0007FBF0
/* SRAM_L */
m_data (RW) : ORIGIN = 0x1FFF8000, LENGTH = 0x00008000
/* SRAM_U */
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00007000
}
/* Uninitialized data section. */
.bss :
{
/* This is used by the startup in order to initialize the .bss section. */
. = ALIGN(4);
__BSS_START = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__BSS_END = .;
} > m_data_2
Que estaba siendo invadida por el stack. Por lo tanto reubiqué la sección bss en m_data, donde hay suficiente espacio:
/* Uninitialized data section. */
.bss :
{
/* This is used by the startup in order to initialize the .bss section. */
. = ALIGN(4);
__BSS_START = .;
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
__BSS_END = .;
} > m_data
Esta vez sí pasó el proceso de linking.
.bss
0x1fff86a0 __bss_start__ = .
0x1fffb788 __bss_end__ = .
Line 3144: 0x20001c00 __stack_start__ = .
Line 3147: 0x20007000 __stack_end__ = .
bss y stack ya están ubicadas donde se espera.
No hay comentarios.:
Publicar un comentario