Trying to understand why my code takes up so much RAM1

Uija

Well-known member
Hey!

Because I am quite near the memory limits (after 2 iterations of trying to get it smaller) I would like to understand what areas of code take up what parts of the memory. I add some example code, maybe that helps me understand all that a little bit better

Code:
uint32_t global_var = 0; // takes up 4 bytes in RAM 1 because it is global

struct TestStruct {
  uint32_t a;
  uint32_t b;
  uint32_t c;
  uint32_t d;
}; // where does the definition of this struct go?

TestStruct* test_struct_ptr = 0; // takes up 4 Byte in RAM1 als pointer to the memory?

FLASHMEM void flash_func() {
  // with content
} // stays ins flash memory and does not take up RAM1 right?

void main() {
  test_struct_ptr = new TestStruct(); // takes up 16 bytes in RAM2 because it’s allocated dynamically
} // main is going to the start of RAM1 because of FASTRUN or at least somewhere else in RAM1?

I refactored as much Strings as somehow possible for the UI to be F(), I have every function in my UI classes as FLASHMEM function. All the dynamic project data (Tracks, Instrument-Configurations, tons of Notes- and Modulation data) is dynamically allocated into PSRAM. The structs that hold that data have some helper functions, mostly for initialization and for the UI. Those are marked as FLASHMEM also. All the UI -relevant classes are dynamically created during runtime to keep it away from RAM1.

and still I use up newly all of the available memory and receive that compile error from time to time when I am hitting the limit. Yes it’s a lot of Code (Drawing all those individual screens and every screen needs custom IO -event handling, but still, can that be over 300k of Code?
Is there a way to Analyse the code to see what functions and what classes/structs take up how much space?

maybe this helps me to find the part, where I might be doing something wrong or where I could change it, so I can continue to add features.
 
Seems like PJRC's Teensy 4 / 4.1 MEMORY storage info web page has been found indicating the keywords to use?

This info from building gives a snapshot of allocations:
Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:37248, data:5016, headers:8932   free for files:8075268
teensy_size:    RAM1: variables:6080, code:34624, padding:30912   free for local variables:452672
teensy_size:    RAM2: variables:12384  free for malloc/new:511904

Where padding can be up towards 32KB of unused space depending on the code space used in RAM1/ITCM. In the case above getting rid of ~2KB of code would return 32KB of RAM1 for DTCM.

Looking in the temp Build folder will have a .SYM file that shows locations of the named parts of the code.
 
The definition goes away during compile - but below:: 200012bc g O .bss 00000004 test_struct_ptr

Building:
Code:
uint32_t global_var = 0; // takes up 4 bytes in RAM 1 because it is global

struct TestStruct {
  uint32_t a;
  uint32_t b;
  uint32_t c;
  uint32_t d;
}; // where does the definition of this struct go?
TestStruct* test_struct_ptr = 0; // takes up 4 Byte in RAM1 als pointer to the memory?

FLASHMEM void flash_func() {
  // with content
} // stays ins flash memory and does not take up RAM1 right?

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  test_struct_ptr = new TestStruct(); // takes up 16 bytes in RAM2 because it’s allocated dynamically

}

void loop() {
  // put your main code here, to run repeatedly:

}

gives:
Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:12412, data:3992, headers:9192   free for files:8100868
teensy_size:    RAM1: variables:4896, code:9792, padding:22976   free for local variables:486624
teensy_size:    RAM2: variables:12384  free for malloc/new:511904

and
Code:
R:\temp\arduino_build_SymInfo.ino/SymInfo.ino.elf:     file format elf32-littlearm

SYMBOL TABLE:
60000000 l    d  .text.headers	00000000 .text.headers
60001400 l    d  .text.code	00000000 .text.code
60001e3c l    d  .text.progmem	00000000 .text.progmem
00000000 l    d  .text.itcm	00000000 .text.itcm
00002640 l    d  .fini	00000000 .fini
20000000 l    d  .data	00000000 .data
20000ec0 l    d  .bss	00000000 .bss
20200000 l    d  .bss.dma	00000000 .bss.dma
70000000 l    d  .bss.extram	00000000 .bss.extram
60005418 l    d  .text.csf	00000000 .text.csf
00000000 l    d  .debug_info	00000000 .debug_info
00000000 l    d  .debug_abbrev	00000000 .debug_abbrev
00000000 l    d  .debug_line	00000000 .debug_line
00000000 l    d  .debug_frame	00000000 .debug_frame
00000000 l    d  .debug_str	00000000 .debug_str
00000000 l    d  .ARM.attributes	00000000 .ARM.attributes
00000000 l    d  .comment	00000000 .comment
00000000 l    d  .debug_loclists	00000000 .debug_loclists
00000000 l    d  .debug_aranges	00000000 .debug_aranges
00000000 l    d  .debug_rnglists	00000000 .debug_rnglists
00000000 l    d  .debug_line_str	00000000 .debug_line_str
00000000 l    df *ABS*	00000000 bootdata.c
00000000 l    df *ABS*	00000000 startup.c
60001400 l     F .text.code	00000016 memory_copy
60001418 l     F .text.code	00000010 memory_clear
00000000 l    df *ABS*	00000000 tempmon.c
2000129c l     O .bss	00000004 s_hotCount
200012a0 l     O .bss	00000004 s_hotTemp
200012a4 l     O .bss	00000004 s_hot_ROOM
200012a8 l     O .bss	00000004 s_roomC_hotC
00000000 l    df *ABS*	00000000 usb.c
000003dc l     F .text.itcm	00000088 schedule_transfer
00000464 l     F .text.itcm	00000036 run_callbacks
0000049c l     F .text.itcm	00000098 endpoint0_transmit.constprop.0
20001228 l     O .bss	00000008 endpoint0_buffer
20001230 l     O .bss	00000004 endpoint0_notify_mask
20001080 l     O .bss	00000008 endpoint0_setupdata
20001234 l     O .bss	00000004 endpointN_notify_mask
20001264 l     O .bss	00000008 reply_buffer
200012e1 l     O .bss	00000001 sof_usage
200012e8 l     O .bss	00000001 usb_reboot_timer
00000000 l    df *ABS*	00000000 analog.c
200012dd l     O .bss	00000001 calibrating
00000000 l    df *ABS*	00000000 crti.o
00000000 l    df *ABS*	00000000 crtn.o
00000000 l    df *ABS*	00000000 crtstuff.c
00000020 l     F .text.itcm	00000000 register_tm_clones
00000044 l     F .text.itcm	00000000 frame_dummy
2000124c l     O .bss	00000000 object.0
60001e38 l     O .text.code	00000000 __frame_dummy_init_array_entry
00000000 l    df *ABS*	00000000 usb_desc.c
200008a8 l     O .data	00000012 device_descriptor
60001f08 l     O .text.progmem	0000000a qualifier_descriptor
00000000 l    df *ABS*	00000000 serialEvent.cpp
00000000 l    df *ABS*	00000000 SymInfo.ino.cpp
00000000 l    df *ABS*	00000000 delay.c
00000000 l    df *ABS*	00000000 usb_serial.c
00000cec l     F .text.itcm	00000060 rx_queue_transfer
20200060 l     O .bss.dma	00001000 rx_buffer
00000d4c l     F .text.itcm	000000b4 rx_event
00000e00 l     F .text.itcm	00000090 usb_serial_flush_callback
20201060 l     O .bss.dma	00002000 txbuffer
00000e90 l     F .text.itcm	000001b8 usb_serial_write.part.0
2000126c l     O .bss	00000004 rx_available
20001270 l     O .bss	00000010 rx_count
200012df l     O .bss	00000001 rx_head
20001280 l     O .bss	00000010 rx_index
20001290 l     O .bss	00000009 rx_list
200012d4 l     O .bss	00000002 rx_packet_size
200012e0 l     O .bss	00000001 rx_tail
20000f00 l     O .bss	00000100 rx_transfer
200012e2 l     O .bss	00000001 transmit_previous_timeout
200012d6 l     O .bss	00000002 tx_available
200012e3 l     O .bss	00000001 tx_head
200012e4 l     O .bss	00000001 tx_noautoflush
200012d8 l     O .bss	00000002 tx_packet_size
20001000 l     O .bss	00000080 tx_transfer
00000000 l    df *ABS*	00000000 EventResponder.cpp
00000000 l    df *ABS*	00000000 Print.cpp
00000000 l    df *ABS*	00000000 main.cpp
00000000 l    df *ABS*	00000000 new.cpp
00000000 l    df *ABS*	00000000 usb_inst.cpp
00000000 l    df *ABS*	00000000 yield.cpp
200012dc l     O .bss	00000001 yield::running
00000000 l    df *ABS*	00000000 memcpy-armv7m.S.o
00000000 l    df *ABS*	00000000 clockspeed.c
00000000 l    df *ABS*	00000000 nonstd.c
00000000 l    df *ABS*	00000000 pwm.c
00000000 l    df *ABS*	00000000 rtc.c
00000000 l    df *ABS*	00000000 sm_pool.c
00000000 l    df *ABS*	00000000 libc_a-malloc.o
00000000 l    df *ABS*	00000000 libc_a-mallocr.o
00000000 l    df *ABS*	00000000 libc_a-mlock.o
00000000 l    df *ABS*	00000000 libc_a-memset.o
00000000 l    df *ABS*	00000000 libc_a-sbrkr.o
00000000 l    df *ABS*	00000000 libc_a-errno.o
00000000 l    df *ABS*	00000000 libc_a-init.o
00000000 l    df *ABS*	00000000 libc_a-lock.o
00000000 l    df *ABS*	00000000 libc_a-freer.o
00000000 l    df *ABS*	00000000 libc_a-impure.o
00000000 l    df *ABS*	00000000 HardwareSerial.cpp
60001df8 l     F .text.code	00000008 __main_veneer
60001e00 l     F .text.code	00000008 __usb_init_serialnumber_veneer
60001e08 l     F .text.code	00000008 __pwm_init_veneer
60001e10 l     F .text.code	00000008 __sm_set_pool_veneer
60001e18 l     F .text.code	00000008 ____libc_init_array_veneer
60001e20 l     F .text.code	00000008 __delay_veneer
60001e28 l     F .text.code	00000008 __set_arm_clock_veneer
60001e30 l     F .text.code	00000008 __memset_veneer
00002628 l     F .text.itcm	00000008 ___init_veneer
00002630 l     F .text.itcm	00000008 ___reboot_Teensyduino__veneer
0000125c g     F .text.itcm	00000018 usb_serial_available
60001650 g     F .text.code	00000002 startup_default_late_hook
000014ec  w    F .text.itcm	000000f0 yield
200012d0 g     O .bss	00000004 usb_timer1_callback
60001e54 g     O .text.progmem	00000018 usb_string_manufacturer_name_default
6000174c g     F .text.code	00000384 configure_external_ram
0000149c g     F .text.itcm	0000001c Print::println()
00002248 g     F .text.itcm	0000000c __malloc_unlock
60001d98 g     F .text.code	00000054 analog_init
2000047c g     O .data	00000004 F_CPU_ACTUAL
00002644 g       .data	00000000 __exidx_end
200012da g     O .bss	00000001 EventResponder::runningFromYield
0000037c g     F .text.itcm	00000060 tempmonGetTemp
0000231c g     F .text.itcm	0000000c __errno
60001000 g     O .text.headers	00000020 ImageVectorTable
20001090 g     O .bss	00000004 EventResponder::firstInterrupt
00000c90 g     F .text.itcm	00000004 usb_transfer_status
00001c44 g     F .text.itcm	00000084 sm_set_pool
000014e4  w    F .text.itcm	00000008 usb_serial_class::write(unsigned char const*, unsigned int)
20001238 g     O .bss	00000004 errno
00002640 g       .text.itcm	00000000 _etext
20000ec0 g       .bss	00000000 _sbss
60001f14 g       *ABS*	00000000 _stextload
00000118 g     F .text.itcm	00000002 loop
00001a64 g     F .text.itcm	0000007a flexpwm_init
00000b54 g     F .text.itcm	00000064 usb_config_rx
2000108c g     O .bss	00000004 EventResponder::lastInterrupt
000015dc g     F .text.itcm	00000134 memcpy
20000ec0 g     O .data	00000000 .hidden __TMC_END__
200012b4 g     O .bss	00000004 systick_millis_count
200012e6 g     O .bss	00000001 usb_configuration
00001bf8 g     F .text.itcm	0000004c sm_align_pool
60000000 g     O .text.headers	00000200 FlexSPI_NOR_Config
60001e54  w    O .text.progmem	00000018 usb_string_manufacturer_name
00001ccc g     F .text.itcm	00000010 malloc
60001c5c g     F .text.code	000000e8 usb_init
200010ec g     O .bss	00000004 __malloc_top_pad
200012b8 g     O .bss	00000004 systick_safe_read
aaaaaaab g       *ABS*	00000000 _flexram_bank_config
20000000 g       .data	00000000 _sdata
60001ebc g     O .text.progmem	0000004b usb_config_descriptor_480
000022f8 g     F .text.itcm	00000024 _sbrk_r
60001648 g     F .text.code	00000002 startup_default_early_hook
60001428 g     F .text.code	00000220 ResetHandler
000012e4 g     F .text.itcm	00000020 usb_serial_getchar
200012c0 g     O .bss	00000008 usb_cdc_line_coding
20001094 g     O .bss	00000004 EventResponder::lastYield
2000123c g     O .bss	00000010 extmem_smalloc_pool
200010e4 g     O .bss	00000004 __malloc_max_sbrked_mem
[B]200012bc g     O .bss	00000004 test_struct_ptr[/B]
60005800 g     O .text.csf	00000c00 hab_csf
20280000 g       .text.csf	00000000 _heap_end
00002644 g       .data	00000000 __exidx_start
70000000 g       .bss.extram	00000000 _extram_end
20001088 g     O .bss	00000004 EventResponder::firstYield
00002328 g     F .text.itcm	00000048 __libc_init_array
000014cc  w    F .text.itcm	00000004 usb_serial_class::clear()
00000344 g     F .text.itcm	00000034 _sbrk
60004558 g       *ABS*	00000000 _sdataload
20000490 g     O .data	00000004 __brkval
200012e5 g     O .bss	00000001 usb_cdc_line_rtsdtr
60001dec g     F .text.code	00000000 _init
00001048 g     F .text.itcm	00000002 usb_serial_reset
60001e70 g     O .text.progmem	0000004b usb_config_descriptor_12
20001320 g       .bss	00000000 _ebss
20203060 g       .bss.dma	00000000 _heap_start
200010b8 g     O .bss	00000001 __lock___malloc_recursive_mutex
200010f0 g     O .bss	00000138 __sf
00000001 g       *ABS*	00000000 _itcm_block_count
20000ee0 g     O .bss	00000020 endpoint0_transfer_data
00001ae0 g     F .text.itcm	000000f4 pwm_init
60006400 g       .text.csf	00000000 __text_csf_end
60001ad0 g     F .text.code	0000005c usb_pll_start
20000ec0 g     O .bss	00000020 endpoint0_transfer_ack
200012c8 g     O .bss	00000004 usb_cdc_line_rtsdtr_millis
00000c4c g     F .text.itcm	00000028 usb_transmit
00001474 g     F .text.itcm	00000020 systick_isr
00002374 g     F .text.itcm	00000002 __retarget_lock_release_recursive
20000480 g     O .data	00000010 Serial
00001494  w    F .text.itcm	00000006 usb_serial_class::write(unsigned char)
60001648  w    F .text.code	00000002 startup_early_hook
00001218 g     F .text.itcm	00000044 usb_serial_peekchar
00001710 g     F .text.itcm	000002f0 set_arm_clock
200012b0 g     O .bss	00000004 systick_cycle_count
200008bc g     O .data	00000016 usb_string_serial_number_default
00002418 g     F .text.itcm	0000020c _free_r
000014dc  w    F .text.itcm	00000004 usb_serial_class::flush()
2000089c g     O .data	00000004 __malloc_sbrk_base
000014d4  w    F .text.itcm	00000004 usb_serial_class::read()
00000c1c g     F .text.itcm	00000030 usb_prepare_transfer
000001c4 g     F .text.itcm	00000180 unused_interrupt_vector
200012cc g     O .bss	00000004 usb_timer0_callback
60001b2c g     F .text.code	00000130 tempmon_init
00001cc8  w    F .text.itcm	00000002 serialEvent()
00001274 g     F .text.itcm	00000070 usb_serial_flush_input
00001304 g     F .text.itcm	0000002c usb_serial_putchar
00000025 g       *ABS*	00000000 _teensy_model_identifier
200010bc g     O .bss	00000028 __malloc_current_mallinfo
20001098 g     O .bss	00000020 HardwareSerial::s_serials_with_serial_events
60001d44 g     F .text.code	00000054 _reboot_Teensyduino_
6000164c g     F .text.code	00000002 startup_default_middle_hook
00000560 g     F .text.itcm	000005f4 usb_isr
20000280  w    O .data	00000028 vtable for usb_serial_class
200012ac g     O .bss	00000004 scale_cpu_cycles_to_microseconds
20000494 g     O .data	00000408 __malloc_av_
00001398 g     F .text.itcm	00000094 usb_serial_flush_output
0000223c g     F .text.itcm	0000000c __malloc_lock
20000c00 g     O .data	000002c0 _VectorsRam
200008d2 g     O .data	00000001 yield_active_check_flags
00002370 g     F .text.itcm	00000002 __retarget_lock_acquire_recursive
200012e7 g     O .bss	00000001 usb_high_speed
00002254 g     F .text.itcm	000000a4 memset
000014b8 g     F .text.itcm	00000010 main
200010e8 g     O .bss	00000004 __malloc_max_total_mem
20200000 g     O .bss.dma	0000004b usb_descriptor_buffer
00000c94 g     F .text.itcm	00000058 usb_init_serialnumber
60001e3c g       .text.code	00000000 __init_array_end
00001cdc g     F .text.itcm	00000560 _malloc_r
200012db g     O .bss	00000001 HardwareSerial::s_count_serials_with_serial_events
00002378 g     F .text.itcm	000000a0 _malloc_trim_r
60001e6c g     O .text.progmem	00000004 string0
00001330 g     F .text.itcm	00000018 usb_serial_write
60001650  w    F .text.code	00000002 startup_late_hook
000014d8  w    F .text.itcm	00000004 usb_serial_class::available()
60001f12 g     O .text.progmem	00000001 _serialEvent_default
20000000 g     O .data	00000280 endpoint_queue_head
60001e3c  w    O .text.progmem	00000016 usb_string_product_name
0000011c g     F .text.itcm	000000a8 delay
00002640 g     F .fini	00000000 _fini
60001020 g     O .text.headers	0000000c BootData
00000378 g     F .text.itcm	00000004 Panic_Temp_isr
200008a4 g     O .data	00000004 _impure_ptr
60001e38 g       .text.code	00000000 __preinit_array_end
00000534 g     F .text.itcm	0000002c usb_stop_sof_interrupts
00000068 g     F .text.itcm	000000b0 setup
200002ec g     O .data	0000006c usb_descriptor_list
20078000 g       .text.csf	00000000 _estack
00001348 g     F .text.itcm	00000050 usb_serial_write_buffer_free
0000104c g     F .text.itcm	000000ec usb_serial_configure
20000ec0 g       .data	00000000 _edata
200012de g     O .bss	00000001 external_psram_size
000014e0  w    F .text.itcm	00000004 usb_serial_class::availableForWrite()
00001a00 g     F .text.itcm	00000062 ultoa
000014c8 g     F .text.itcm	00000004 operator new(unsigned int)
0000142c g     F .text.itcm	00000044 EventResponder::runFromInterrupt()
200008a0 g     O .data	00000004 __malloc_trim_threshold
000014d0  w    F .text.itcm	00000004 usb_serial_class::peek()
20000358 g     O .data	00000120 _impure_data
60001e38 g       .text.code	00000000 __init_array_start
20000478 g     O .data	00000004 F_BUS_ACTUAL
00000000 g       .text.itcm	00000000 _stext
60001e3c g     O .text.progmem	00000016 usb_string_product_name_default
6000164c  w    F .text.code	00000002 startup_middle_hook
60001654 g     F .text.code	000000f8 configure_cache
60001e38 g       .text.code	00000000 __preinit_array_start
00000c74 g     F .text.itcm	0000001c usb_receive
00006400 g       *ABS*	00000000 _flashimagelen
00001bd4 g     F .text.itcm	00000024 rtc_get
70000000 g       .bss.extram	00000000 _extram_start
00001470 g     F .text.itcm	00000004 pendablesrvreq_isr
00001138 g     F .text.itcm	000000e0 usb_serial_read
00000bb8 g     F .text.itcm	00000064 usb_config_tx
200008bc  w    O .data	00000016 usb_string_serial_number
 
Hey! Thanks for that detailed response! I already spent some time on the memory-section of the Teensy page, because in the last 25years of earning money with programming, I never needed to care how compilers use memory. Those few projects that were not in languages that did all the memory management for me were small enough to ignore that and focus more on getting the manual memory management right, and even in the late 90th, while working on quite big web applications, it was easy enough to put a few more boxes into the racks, or upgrade RAM :p
Maybe I start learning about that, now that I seem to need that...

I spent some time this morning playing around with an empty sketch, trying to get a feel of how much memory code takes up, and besides realizing that even those few libraries I use (one for the OLED display and the USBHost_t3) take up quite some kilobytes of ram with variables and code, so comparing the amount of source code in my project to those libs it seems okay.

will play around more to find ways to reduce the 340k code that is placed in RAM1.
It feels as if most functions now have a FLASHMEM and still code takes up nearly as much space in RAM1 than in FLASH :(

Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:461108, data:54892, headers:8924   free for files:7601540
teensy_size:    RAM1: variables:130144, code:336144, padding:24304   free for local variables:33696
teensy_size:    RAM2: variables:7200  free for malloc/new:517088
 
Last edited:
Is the issue that you put YOUR code in FLASHMEM so that it is not copied to FastRun but the libraries still get copied to FastRun?
 
I tested it in an empty sketch and it seems, that the libraries take up maybe 30-40k of the 334k memory that is used, so I would be more than fine, if I get my code out there :p
 
Have fun. p#4 padding shows the next 8K of code out of RAM1 ITCM almost doubles the 33KB of free space for DATA DTCM giving another 32KB.

... then it is on to the next 32KB of code to remove ...

Perhaps the SMALLEST CODE build would help and not hurt speed too much ... as least it may free more code space to build and run.
 
I am not 100% sure why it freed up so much RAM, but YAY!

Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:372928, data:55916, headers:9040   free for files:7688580
teensy_size:    RAM1: variables:74208, code:243152, padding:18992   free for local variables:187936
teensy_size:    RAM2: variables:47616  free for malloc/new:476672

I have a 15 byte big struct, that contains the intervals and a name of chords, I have 27 of them, I moved them from being const and directly initialized to static and being initialized in a method.

Old:

Code:
    #define NUM_CHORDS 27
    struct Chord {
        char chord_name[8];
        int8_t chord_intervals[NUM_CHORDS_INTERVALS];
        Chord( const __FlashStringHelper* name, int8_t i1, int8_t i2, int8_t i3, int8_t i4, int8_t i5, int8_t i6, int8_t i7) : chord_intervals{i1, i2, i3, i4, i5, i6, i7} {memset( chord_name, 0, 8); strncpy( chord_name, (const char*)name, 7);}
    };
    const Chord MODIFIER_CHORDS[NUM_CHORDS] = {
        {F("-"), 0, 100, 100, 100, 100, 100, 100},
        {F("maj"), 0, 4, 7, 100, 100, 100, 100},
        ...
    };

I already tried to make it smaller by passing FlashLocated Strings into the constructor, but if I remember correctly, it didn't help...

I changed it to:

Code:
    #define NUM_CHORDS 27
    struct Chord {
        char chord_name[8];
        int8_t chord_intervals[NUM_CHORDS_INTERVALS];
        Chord( const __FlashStringHelper* name, int8_t i1, int8_t i2, int8_t i3, int8_t i4, int8_t i5, int8_t i6, int8_t i7) : chord_intervals{i1, i2, i3, i4, i5, i6, i7} {memset( chord_name, 0, 8); strncpy( chord_name, (const char*)name, 7);}
    };

     static Chord MODIFIER_CHORDS[NUM_CHORDS];

    void prepareGlobalData() {
        MODIFIER_CHORDS[0] = {F("-"), 0, 100, 100, 100, 100, 100, 100};
        MODIFIER_CHORDS[1] = {F("maj"), 0, 4, 7, 100, 100, 100, 100};
        ...
        MODIFIER_CHORDS[26] = {F("add11"), 0, 4, 7, 17, 100, 100, 100};
    }

I call this method from my setup(). Memory usage moved from

RAM1: variables:130144, code:336144, padding:24304 free for local variables:33696

to

teensy_size: RAM1: variables:114592, code:243152, padding:18992 free for local variables:147552

Thats ~15kbyte variables and ~90kbyte code. Why? 27*(7+8) = 405bytes

I See, I have a hell lot to learn :p
By moving the Array to DMAMEM and the prepareGlobalData to FLASHMEM I ended with:

RAM1: variables:74208, code:243152, padding:18992 free for local variables:187936
 
Thats ~15kbyte variables and ~90kbyte code. Why? 27*(7+8) = 405bytes

My guess is that if they are consts then the compiler treated them like #defines, rather than putting a single copy somewhere and pointing to it each time you used the values it duplicated the values every time they were used. This saves an extra step of indirection every access and so gives a speed increase at the cost of code size.
By making them static you are forcing the compiler to only have one copy and refer back to it each time. Slower but a far smaller memory footprint.
 
I find the following code a bit confusing:
Code:
    struct Chord {
        char chord_name[8];
        int8_t chord_intervals[NUM_CHORDS_INTERVALS];
        Chord( const __FlashStringHelper* name, int8_t i1, int8_t i2, int8_t i3, int8_t i4, int8_t i5, int8_t i6, int8_t i7) : chord_intervals{i1, i2, i3, i4, i5, i6, i7}\
                     {memset( chord_name, 0, 8); strncpy( chord_name, (const char*)name, 7);}
    };

It looks as if you are defining a Chord struct which has as one of its elements a Chord struct. That brings back recursion nightmares--which could probably be solved by changing the name of the structure element to "ChordData".

It would probably be helpful to do:
Serial.printf("Chord Struct size: %lu, Chord Array Size: %lu\n", sizeof(Chord), sizeof(Chords)).

I suspect that you will find that the array size is not numchords * sizeof(Chord), since the array elements will be padded out to either 16 or 32 bits. The padding may also occur in the struct definition where the individual byte elements may be padded to 16 or 32 bits so that the CPU doesn't have to access odd addresses for individual items.
 
Where do you find that that nested Chord struct. maybe I am blind, but I see a struct with a Constructor there, or am I understanding that wrong?
 
Where do you find that that nested Chord struct. maybe I am blind, but I see a struct with a Constructor there, or am I understanding that wrong?

I'm not that familiar with the nuances of the current C++ usage of constructors. It may be perfectly legitimate to include a constructor inside a struct definition.

I have made my peace with an alternate way to initialize the elements of a struct:

struct foo {
bool a = true;
bool b = true;
bool c;
} bar;

which does not require a constructor.
 
Back
Top