0

I have been banging my head for several hours because I have a rare problem. I suspect I have a memory issue

I have a pcb with an atmega328p in DIP format and an I2C OLED display with 128x64 pixels. At first I was using the adafruit library but I quickly met stability issues when my RAM reached about 48%. I learned that the adafruit library uses more RAM than my compiler (arduino cli) would tell me..

So I migrated to the <U8x8lib.h> library. Which works signaficantly better.

But now my program starts to grow I again face strange behaviour.

The 'weird' part is happening in this switch-case

void updateLCD() 
{
    clearDisplay() ;
    delay(10);
    printNumberAt(5,5,2,mode) ;
    delay(1000);

    switch( mode )
    {  
    case locos :
        drawSpeed( speed ) ;
        drawFunctions() ;
        printAt(0,0, F("Loco:")) ; printNumberAt( 7, 0, 3, currentAddress ) ;
        break ;

    case points :
        printAt(0, 0, F("POINT #") ) ;
        printNumberAt( 7, 0, 3, pointAddress ) ;
        uint8_t bit      = pointAddress % 8 ;
        uint8_t group    = pointAddress / 8 ;

        bool state = !bitRead( pointStates[ group ], bit) ;
        if( !state )  printCustom( 13, 0, 0, straight ) ;
        else          printCustom( 13, 0, 0,   curved ) ; 
        break ;   

    case gettingAddress:
        printAt(0, 0, F("ENTER ADDRESS") ) ;
        break ;

    case gettingSlot:
        printAt(0, 0, F("ENTER SLOT") ) ;
        break ;
    
    case pointStreets :
        printAt(0, 0, F("setting street" ) ) ;
        printAt(0, 1, F("enter number" ) ) ;
        break ;

    case locoSlots:
        drawFunctions() ;
        drawSpeed( speed) ;
        printAt(0,0, F("Loco Slot")) ; printNumberAt( 9, 0, 3, slot ) ;
        printDescription( eepromLoco.name, 1 );
        break ;

    case programs:
        printAt(0, 0, F("PROGRAM MODE") ) ;
        printAt(0, 1, F("CHANNEL #") ) ;
        printNumberAt(5,2, 4, channel ) ;
        uint8 state1 = program1.getState() ;
        if( state1 == recording ) printAt(0, 3, F("recording") ) ;
        if( state1 == playing )   printAt(0, 3, F("playing") ) ;
        if( state1 == finishing ) printAt(0, 3, F("finishing") ) ;
        if( state1 == idle )      printAt(0, 3, F("idle") ) ;
        break; 
    }
}

What is happening. Each and every last case has worked without flaw. And now only the one or two top most cases work. If I change the order of these cases I can let some texts 'dissapear' and others 'reappear'.

To verify that the switch variable mode was not containing an invalid value, I added these lines.

    delay(10);
    printNumberAt(5,5,2,mode) ;
    delay(1000);

Mode is always correct in al situations... yet the text of the following case.. it is not to be seen.

My best guess is that my heap and stack are colliding. From what I read, that can cause rather vague symptoms like I am having now.

As my program is this big and the bug is related to the OLED display with which I had earlier stability issues. I think I may be on the right track.

Sketch uses 22554 bytes (69%) of program storage space. Maximum is 32256 bytes.
Global variables use 1414 bytes (69%) of dynamic memory, leaving 634 bytes for local variables. Maximum is 2048 bytes.

Are there methods to verify or detect that heap and stack are colliding? What more could be propable causes?

bask185
  • 377
  • 1
  • 3
  • 12
  • _"To verify that the switch variable mode was not containing an invalid value,..."_ - why not simply add a default case? – Clifford May 07 '22 at 21:31
  • _"more RAM than my compiler (arduino cli) would tell me.."_ Strictly it is the linker that tells you that, but the assertion makes no sense. The stack and heap sizes are determined by the linker, but the usage of those resources is a runtime variable. – Clifford May 07 '22 at 21:37
  • Avoid dynamic memory; you don't need it and on a 2K part, it is inappropriate. Then you can reduce the heap size to zero ( if it is not already). Then it is just a matter of insufficient stack rather than collision. 634 bytes for a stack is rather small. You might want to a) get a rather part b) avoid third-party libraries with unknown resource requirement. What is all that global data space? Some of it may be the heap of course. Besides the memory resource is utilised by _all_ the code, so the fragment you have posted is largely irrelevant. You would do better to post the link map – Clifford May 07 '22 at 21:44
  • I do try to avoid third party stuff as the plague. But sometimes I just want my stuff to work and I am not always in the mood and I do not always have the time to dive in some datasheet to figure out how to get an oled thing to work. About the link map. I have a .elf and .eep files. I am not familiair with these. Which is the link map? – bask185 May 07 '22 at 21:56
  • To get a link map from Arduino cli I think you have to add the necessary linker flags to the platform.txt file. Under the hood it is a gnu toolchain so I am guessing : `compiler.ldflags=-Map=output.txt`. alternatively you can use `arduino-objdump` to extract link map information from the .elf file. – Clifford May 07 '22 at 22:07
  • Sometimes you just have to accept that you are doing too much with too little. There are parts with more RAM that would be more appropriate, but this question is unanswerable from the information given. You need to take a holistic view. For example you mention a 128x64 display, but do not state whether you have a frame buffer or if it writes directly to the display RAM. If you have a frame buffer, that is half your RAM used already. – Clifford May 07 '22 at 22:12
  • I did mention what library I am using. That frame buffer method was used by the adafruit library, that project already failed working at 48%. I believe that my current library is writing directly to the RAM of the oled display. I will try to get me a link map tomorrow. – bask185 May 07 '22 at 22:20
  • I had no idea that an oled display would cause so much trouble. Should have used a plain ol' lcd.. – bask185 May 07 '22 at 22:24
  • Why would that make any difference? It is the fact that it is a graphic display that makes it potentially resource hungry (128x64)/8 = 1024K. I don't know that that is a problem (the library may or may not create a buffer); I was simply pointing out one of many potential resource overheads that you have not told us about in your question. The response I expected was for you to provide the missing information. That said I would suggest that it is your choice of MCU rather then display that is the issue here. – Clifford May 07 '22 at 22:31
  • I took a quick look at [u8x8](https://github.com/olikraus/u8g2/wiki) it does state that it writes directly to the display and requires no display buffer (unlike U8g2). It does not give much information about stack usage. The fact remains that you need information about what is using memory and how much. – Clifford May 07 '22 at 22:48
  • This: https://docs.arduino.cc/learn/programming/memory-guide#sram-memory-measurement may be a direct answer to your question; but I am not sure how helpful it is. It won't tell you if you have a stack overflow, only how much heap remains (and you will have to have asked _before_ it crashes!). You would do well to read the whole article. I can find no information on heap size on Arduino - on a 2K part I would hope none. – Clifford May 07 '22 at 23:06
  • I used the function and it shows around 602 on display. I call it before running the switch-case. That is consistent with the linker that tells me that 635 bytes are left for ram. It seems I need abr-objdump installed in order to produce a map file. I have not yet found a non sketchy website to download it from without downloading the entire gcc toolchain. I'll go dig on my windows machine to find it. I think mailing the author is also a good idea. I doubt what else it could be. I recompiled the entire project, but the problem remains. – bask185 May 08 '22 at 12:42

0 Answers0