B4R Question NumberFormat problem

kolbe

Active Member
Licensed User
Longtime User
I'm working with a Feather M0 and when I call NumberFormat twice the program halts. Using a timer and and leds I know the execution stops. I've checked StackBufferUsage and it is only 13 after the first call so I don't think I'm running out of memory. In the case below I'm using the AdafruitSSD1306 library but I first noticed this problem using it with logs. I comment out the first line and it works. Comment out the second and it works. Only when both are called that the code crashes.

Any ideas?

B4X:
oled.GFX.DrawText(NumberFormat(temp(counter),1,1)).DrawText(" F").DrawText(CRLF)
oled.GFX.DrawText(NumberFormat(humid(counter),1,1)).DrawText(" %")
 

kolbe

Active Member
Licensed User
Longtime User
It's an Adafruit Feather M0 Bluefruit LE. So it is using the ATSAMD21G18 ARM Cortex M0 processor. This is the same as the Aurduino Zero.

I tried both things you suggested without luck. I have about 25K of free RAM. This chip has 32K RAM. AvailabeRAM doesn't work but this alternative does. Increasing the StackBufferUsage doesn't help either.

I'm wondering if it has to do with memory usage differences listed at the bottom of the link above.
 
Upvote 0

kolbe

Active Member
Licensed User
Longtime User
Here's the code.

Here's output from the code below

AppStart
25467
73.8100
43.3469
-
25287
13
--
73.7907
43.3469
-
25287
13
--
73.8100
43.3469
-
25287
13
--

B4X:
#
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 600
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public Serial1 As Serial
    Private timer1 As Timer
    Private master As WireMaster
    Private const SLAVE_ADDRESS As Byte = 64
    Private temp(300) As Float
    Private humid(300) As Float
    Private counter=0 As Int
    Private pin13 As Pin
    Private oled As AdafruitSSD1306
    Private free As Int
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    master.Initialize
    pin13.Initialize(13, pin13.MODE_OUTPUT)
    timer1.Initialize("Timer1_Tick", 1000)
    oled.InitializeI2C(10,0x3c)
    timer1.Enabled = True
    RunNative("FreeRam", Null)
    Log(free)
End Sub

Sub Timer1_Tick
    timer1.Enabled=False
    pin13.DigitalWrite(True)
   
    Dim readbyte(3) As Byte
    Dim writebyte(1) As Byte
   
    writebyte(0)=0xe3 'read temp register
   
    master.WriteTo2(SLAVE_ADDRESS,True,writebyte)
    Delay(50)
    readbyte = master.RequestFrom(SLAVE_ADDRESS,3)
    If readbyte.Length=3 Then
        Dim partial1=(Bit.ShiftLeft(Bit.And(readbyte(0),0xff),8)+Bit.And(readbyte(1),0xfc)) As Int
        Dim partial2=-46.85+(175.72*(partial1/65536)) As Float
    Else
        'Log(readbyte.length)
    End If
   
    Delay(50)
   
    writebyte(0)=0xe5 'read humidity register
    master.WriteTo2(SLAVE_ADDRESS,True,writebyte)
    Delay(50)
    readbyte = master.RequestFrom(SLAVE_ADDRESS,3)
    If readbyte.Length=3 Then
        Dim partial3=(Bit.ShiftLeft(Bit.And(readbyte(0),0xff),8)+Bit.And(readbyte(1),0xfc)) As Int
        Dim partial4=-6+(125*(partial3/65536)) As Float
    Else
'        Log(readbyte.length)
    End If
   
'    Log(NumberFormat(partial2*1.8+32,1,1),",",Round(partial4))
   
    If counter >= 299 Then
        temp(counter)=partial2*1.8+32
        humid(counter)=partial4
       
        Dim sum=0 As Float
        For i=0 To 299
            sum=sum+temp(i)
        Next
        Dim avgtemp=(sum/300) As Float
       
        sum=0
        For i=0 To 299
            sum=sum+humid(i)
        Next
        Dim avghumid=(sum/300) As Float
       
        counter=0
        Log(avgtemp,",",avghumid)
       
    Else
        temp(counter)=partial2*1.8+32
        humid(counter)=partial4
       
'        Log(counter)
        Log(temp(counter))
        Log(humid(counter))
        oled.ClearDisplay
        oled.GFX.SetCursor(0,0)
        oled.GFX.ConfigureText(2,oled.WHITE,False)
        oled.GFX.DrawText(NumberFormat(temp(counter),1,1)).DrawText(" F").DrawText(CRLF)
        oled.GFX.DrawText(temp(counter)).DrawText(" F").DrawText(CRLF)
'        oled.GFX.DrawText(NumberFormat(humid(counter),1,1)).DrawText(" %")
        oled.Display
        counter=counter+1
    End If
   
    pin13.DigitalWrite(False)
    timer1.Enabled=True
   
    RunNative("FreeRam", Null)
    Log("-")
    Log (free)
    Log(StackBufferUsage)
    Log("--")
End Sub

#if C

extern "C" char *sbrk(int i);

void FreeRam (B4R::Object* o) {
  char stack_dummy = 0;
  b4r_main::_free = &stack_dummy - sbrk(0);
}

#End if
 
Upvote 0

kolbe

Active Member
Licensed User
Longtime User
Note that you don't need to disable and enable the timer. It will never fire while the code is executing. It is better to remove it.

Does it crash if you call Log(NumberFormat(humid(counter),1,1)) ?

Understood for the timer. I got in the habit of doing this for Android stuff.

Yes if I uncomment that line it crashes. Don't know if it helps but after the crash I need to put the board in bootloader mode to be able the upload again.
 
Upvote 0

kolbe

Active Member
Licensed User
Longtime User
Didn't understand correctly your question perhaps. As far as I can tell... in the timer sub using NumberFormat once is fine. Once I call it again it crashes. It doesn't seem to make a difference if the second call is in a log or in for the lcd. I'll make a few more tests.
 
Upvote 0

kolbe

Active Member
Licensed User
Longtime User
After a few more tests.

This doesn't work.
B4X:
Log(NumberFormat(10.4545,1,1))
Log(NumberFormat(20.4545,1,1))

This does work.
B4X:
Log(NumberFormat(2,1,1))
Log(NumberFormat(20.4545,1,1))

This doesn't work
B4X:
Log(NumberFormat(10.4545,1,1))
Log(NumberFormat(2,1,1))

this works
B4X:
Log(NumberFormat(2,1,1))
Log(NumberFormat(2,1,1))
Log(NumberFormat(10.4545,1,1))

doesn't work
B4X:
Log(NumberFormat(2,1,1))
Log(NumberFormat(2,1,1))
Log(NumberFormat(10.4545,1,1))
Log(NumberFormat(2,1,1))

doesn't work
B4X:
Log(NumberFormat(10,1,1))
Log(NumberFormat(10.4545,1,1))

this works
B4X:
Log(NumberFormat(9,1,1))
Log(NumberFormat(10.4545,1,1))

Incidentally, taking out the timer enable true/false lines does change the rate the leds blink. If I want the time between running the sub to be as close to 1s as posible I can do what I did. Otherwise the time it takes to run the sub is subtracted from the time the sub is run. In this case 214 ms to run the sub so the sub would be run every 786 ms. Now maybe you are saying that doing this is not the best idea for code backend reasons.
 
Upvote 0

kolbe

Active Member
Licensed User
Longtime User
Trying a workaround discovered this too.

The code below outputs

73.35
73.3467

Then it crashes.

Why does str1 round off? Byte alignment problems?
B4X:
Dim str1="" As String
str1 = temp(counter)
Log(str1)
Log(temp(counter))
Log(bconv.SubString2(str1,0,2))


also this works
B4X:
Dim str1="" As String
str1 = temp(counter)


but this doesn't
B4X:
Dim str1="" As String
str1 = temp(counter)
Dim str2="" As String
str2 = humid(counter)
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Incidentally, taking out the timer enable true/false lines does change the rate the leds blink
The best solution is to remove all the delay calls and use CallSubPlus instead to call the next sub each time.
However lets first debug the memory issue.

Can you reproduce this memory issue on an Arduino or ESP8266?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Works fine on ESP8266.

Try this:
Download the attached Define-Template.h and put it in the projects Files folder.

It should show this message during compilation:
Parsing code. (0.00s)
Compiling code. (0.02s)
Building project (0.02s)
Using custom define-template file.

It sets the byte alignment to 8.
 

Attachments

  • Defines-Template.zip
    400 bytes · Views: 426
Upvote 0

kolbe

Active Member
Licensed User
Longtime User

Seems to fix the problem. I'll try some more cases soon.
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…