B4R Question Overflowing stack when doing multiple EEPROM Readbytes in a loop

BertI

Member
Licensed User
I have been getting an exception which I eventually worked out was due to a stack overflow when I had implemented an EEPROM blank check type of sub. The sub is shown here:
B4X:
Private Sub Check_EEprom(start As UInt, finish As UInt) As Boolean
    Log("Start checking ...")
    ' Check if any location not cleared to zero
    Dim success As Boolean = True
    Dim n As UInt
    For n=start To finish
        Log(n, " ", EE.ReadBytes(n,1)(0))
        Log("stack: ", StackBufferUsage)
        If EE.ReadBytes(n,1)(0) <> 0 Then success = False
    Next
    Log("EEPROM check result: ",success)
    Return success
End Sub

As you can see I'm logging the stack buffer usage in the loop and from the logs I can see this increasing by 24 every step until n=168 when the exception is thrown up (and causes a reset of an ESP8266 module in my case). I think I understand that EE.ReadBytes gets a new array each time so I guess that these are just stacking up (though why 24 bytes each time not sure - 12 bytes for each EE.Readbyte). Any views on this and perhaps suggestions for better ways to achieve it? I do know that I can avoid the continual stacking by doing something like x=EE.ReadBytes(n,1)(0) in a second sub which I then call from the above, but this seems like a crude work around arising from my poor underlying understanding.
 
Last edited:

BertI

Member
Licensed User
Would reading all the bytes (potentially 2048 - extended EEprom) not take up stack space for all those bytes? (though I'm guessing not x12)
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
1. You can increase #StackBufferSize.
2. The log in line #7 will also consume memory as you are implicitly creating an array there.

3.
Moving the loop code to a separate sub will allow the memory to be released after each iteration:
B4X:
Private Sub Check_EEprom(start As UInt, finish As UInt) As Boolean
    Log("Start checking ...")
    ' Check if any location not cleared to zero
    Dim success As Boolean = True
    Dim n As UInt
    For n=start To finish
        If ReadSingleByte(n) Then success = False
    Next
    Log("EEPROM check result: ",success)
    Return success
End Sub

Private Sub ReadSingleByte(n As UInt) As Boolean
Log(n, " ", EE.ReadBytes(n,1)(0))
        Log("stack: ", StackBufferUsage)
 Return EE.ReadBytes(n,1)(0) <> 0
End Sub
 
Upvote 0

BertI

Member
Licensed User
I suppose I was trying to understand what was going on. I know I could have increased stack size but felt that would be just covering up my lack of understanding and does not really resolve the intrinsic problem in the general case. From the tutorials I did have a vague understanding that if I put the EE.readbytes operation in another sub then likely that the memory allocation would be cleared upon return from that sub, but my first attempt to do this didn't actually work. For example say I changed my original code to:
B4X:
Private Sub Check_EEprom(start As UInt, finish As UInt) As Boolean
    Log("Start checking ...")
    ' Check if any location not cleared to zero
    Dim success As Boolean = True
    Dim n As UInt
    For n=start To finish
        Log(n, " ", ReadSingleByte(n))
        Log("stack: ", StackBufferUsage)
        If ReadSingleByte2(n) <> 0 Then success = False
    Next
    Log("EEPROM check result: ",success)
    Return success
End Sub

Private Sub ReadSingleByte(n As UInt) As Byte
    Return EE.ReadBytes(n,1)(0)
End Sub
I found that this resulted in the same stack overflow issue. But if I changed the second sub to:
B4X:
Private Sub ReadSingleByte(n As UInt) As Byte
    Dim sb As Byte
    sb = EE.ReadBytes(n,1)(0)
    Return sb
End Sub
Then in the latter case no stack overflow. So I did have a solution, but couldn't really understand why the second method did clear the memory allocation for the array whereas the first didn't. Your suggestion is of course even more code efficient :)

Anyhow the problem is resolved. Like I say, more curiosity to see if there was some other way that I had missed to read the bytes efficiently without resorting to a second sub. Also perhaps a point of caution to others.
 
Last edited:
Upvote 0

BertI

Member
Licensed User
Ah, I see. So casting this into my original code just for philosophical clarity, I'm guessing this might be the way:
B4X:
Private Sub Check_EEprom(start As UInt, finish As UInt) As Boolean
    Log("Start checking ...")
    ' Check if any location not cleared to zero
    Dim success As Boolean = True
    Dim n As UInt
    Dim sb(1) As Byte
    For n=start To finish
        EE.ReadBytes2(n,1,sb)
        Log(n, " ", sb(0))
        Log("stack: ", StackBufferUsage)
        If sb(0) <> 0 Then success = False
    Next
    Log("EEPROM check result: ",success)
    Return success
End Sub
So though still involving an intermediate variable (philosophic), avoids the call to another sub. This feels neater to me. Thanks for that insight.
 
Upvote 0
Top