Memory error adding few line of code also if memory free are some kbytes..

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
BOB63
Posts: 58
Joined: Sat Jul 25, 2015 8:24 pm
Location: Monza , Italy

Memory error adding few line of code also if memory free are some kbytes..

Post by BOB63 » Thu Oct 04, 2018 9:33 pm

I'm working on a circui with Adafruit Feather HUZZAH ESP8266 and a voice synthesizer Big Buddy Talker http://www.engineeringshock.com/the-big ... -page.html that read some data from a bme280 sensor , an infrared termal sensor publish the value via MQtt on Adafruit-IO , show on a oled display and with a voice synthesizer say values .
The program works perfectly until I don't add really few line of code to write via SPI to the voice synthesizer.
Using during the loop the gc.mem_free() I see between 7 and 13 kb free so I'm quite surprised that those lines can generate the memory issue. I know that i could freeze the modules into micropython foirmware but before start something on which I've not experience at all , I would like be sure that there isn't any other reason or action that I can put inplace to avoid this problem .

Any suggestion will be appreciated.


This is the main program that show the issue . Find " ****** start piece of code that generate the memory error" to see the code involved Uncommenting that code I got the memory problem.

Code: Select all

import mlx90614
import machine
import bme280
import time
import ssd1306
from umqtt.simple import MQTTClient
import network
import gc
from machine import Pin
from machine import SPI

spi = SPI(1, baudrate=600000, polarity=0, phase=0)  #  HW SPI

print(spi)

i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4))
bme = bme280.BME280(i2c=i2c)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
irsensor = mlx90614.MLX90614(i2c)

print(i2c.scan())

cs1 = Pin(2, Pin.OUT)
cs1.value(1)

cs2 = Pin(16, Pin.OUT)
cs2.value(1)

cs3 = Pin(0, Pin.OUT)
cs3.value(1)

cs4 = Pin(15, Pin.OUT)
cs4.value(1)


def num_convert(dato):

    valore=0

    valore=float(dato)

    decimale=0
    valore_i=0
    cod_m=0
    cod_c=0
    cod_d=0
    cod_u=0
    cod_dec=0
    cod_cen=0
    cod_mil=0

    if valore-int(valore)==0 : #intero
       decimale=0
       valore_d=0
    else:
       decimale=1
       valore_d=(round((valore-int(valore)) * 100))
       if valore_d>9:
          valore_dstr=str(round((valore-int(valore)) * 100))

    valore_i=str(int(valore))

    if len(valore_i)==4:
       vale=(int(valore_i[2])*10)+int(valore_i[3])
       cod_m=54+int(valore_i[0])
       cod_c=54+int(valore_i[1])

       if vale<20 :
          cod_d=54+vale
          cod_u=0
       else:
          cod_d=54+int(valore_i[2])+18
          cod_u=54+int(valore_i[3])


    if len(valore_i)==3:
       vale=(int(valore_i[1])*10)+int(valore_i[2])

       cod_c=54+int(valore_i[0])

       if vale<20 :
          cod_d=54+vale
          cod_u=0
       else:
          cod_d=54+int(valore_i[1])+18
          cod_u=54+int(valore_i[2])

    if len(valore_i)==2:

       vale=(int(valore_i[0])*10)+int(valore_i[1])

       if vale<20 :
          cod_d=54+vale
          cod_u=0
       else:
          cod_d=54+int(valore_i[0])+18
          cod_u=54+int(valore_i[1])

    if len(valore_i)==1:
       cod_u=54+int(valore_i[0])

    if decimale==1:
       if valore_d<10:
          cod_dec=54
          cod_cen=54+valore_d
       else:
          vale=(int(valore_dstr[0])*10)+int(valore_dstr[1])

          if vale<20 :
             cod_dec=54+vale
             cod_cen=0
          else:
             cod_dec=54+int(valore_dstr[0])+18
             cod_cen=54+int(valore_dstr[1])

    hxcod_m=bytes([cod_m])
    hxcod_c=bytes([cod_c])
    hxcod_d=bytes([cod_d])
    hxcod_u=bytes([cod_u])
    hxcod_dec=bytes([cod_dec])
    hxcod_cen=bytes([cod_cen])
    hxcod_mil=bytes([cod_mil])

##    print( cod_m,cod_c,cod_d,cod_u,cod_dec,cod_cen,cod_mil)
##    print(hxcod_m,hxcod_c,hxcod_d,hxcod_u,hxcod_dec,hxcod_cen,hxcod_mil)

    if cod_m>54 :

        cs1.value(0)
        spi.write(b'\x98')
        spi.write(hxcod_m)
        cs1.value(1)

        time.sleep_ms(550)

        cs1.value(0)
        spi.write(b'\x98')
        spi.write(b'\x53') # 83=thousand
        cs1.value(1)

        time.sleep_ms(550)

    if cod_c>54:
        cs1.value(0)
        spi.write(b'\x98')
        spi.write(hxcod_c)
        cs1.value(1)

        time.sleep_ms(550)

        cs1.value(0)
        spi.write(b'\x98')
        spi.write(b'\x52') # 82=hundreds
        cs1.value(1)

        time.sleep_ms(550)

    if cod_d>54 :
       cs1.value(0)
       spi.write(b'\x98')
       spi.write(hxcod_d)
       cs1.value(1)

       time.sleep_ms(550)

    if cod_u>54:    #!=54: #>0:
       cs1.value(0)
       spi.write(b'\x98')
       spi.write(hxcod_u) #unit
       cs1.value(1)
       time.sleep_ms(550)

    if decimale==1:

       cs4.value(0)
       time.sleep_ms(350)
       spi.write(b'\x98')
       spi.write(b'\x47') # 71=point
       cs4.value(1)

       time.sleep_ms(550)

       #if cod_dec>54:
       cs1.value(0)
       spi.write(b'\x98')
       spi.write(hxcod_dec)
       cs1.value(1)

       time.sleep_ms(550)

       if cod_cen>54:
          cs1.value(0)
          spi.write(b'\x98')
          spi.write(hxcod_cen)
          cs1.value(1)

       time.sleep_ms(550)

def wifi_connect(net_n,net_psw) :
    wlan.connect(net_n, net_psw)
    start = time.ticks_ms() # get millisecond counter
    while not wlan.isconnected() and time.ticks_diff(time.ticks_ms(),start) < 7000:
          pass
    if wlan.isconnected()==True:
       connect_flg=True
    else:
       connect_flg=False
    return connect_flg

# Connect ESP8266 to router .


# ****** start piece of code that generate the memory error:
##cs2.value(0)
##spi.write(b'\x98')
##spi.write(b'\xF9')   #sequence
##cs2.value(1)
##
##time.sleep_ms(650)
##
##cs2.value(0)
##spi.write(b'\x98')
##spi.write(b'\xFB')   #start
##cs2.value(1)
# ******  end piece of code that genarate the memory error

net_name="Offline"
connect_flg=False

NetName1 = 'xxxx'
NetPSW1  = '......'
NetName2 = 'xxxx'
NetPSW2  = '......'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)


print("Cerco G4 net.")
oled.text("Cerco G4 net." , 0, 0)
oled.show()


status=wifi_connect(NetName1,NetPSW1)

if status==True:
   net_name = "G4"

else:
   print("Cerco Home net")
   oled.fill(0)
   oled.text("Cerco Home net. ", 0, 0)
   oled.show()
   wlan.disconnect()
   status=wifi_connect(NetName2,NetPSW2)

   if status==True:
      net_name = "Home"
print("Conn.: "+ net_name)

# connessione ad Adafruit IO via MQTT
if status==True:
    myMqttClient = "termoAdaIO"  # assegnare un nome qualsiasi
    AdaF_IO_urls = "io.adafruit.com"
    AdaF_IO_UserName = "ddddd"  #  account adafruit.com

# vedi "VIEW AIO KEYS" Adafruit IO Feed

    AdaF_IO_Key = "kkkkkkkkkkkkkkkkkkkkkkkkkkkk"
    c = MQTTClient(myMqttClient, AdaF_IO_urls, 0, AdaF_IO_UserName, AdaF_IO_Key)
    c.connect()

while True:
     print("Memory free :"+str(gc.mem_free()))

     t_obj_ir=irsensor.read_object_temp()
     # t_ambiente_ir=irsensor.read_ambient_temp()

     t_ambiente=bme.values[3]
     pressure=bme.values[4]
     humidity=bme.values[5]

     oled.fill(0)
     oled.text("Temp : " + (bme.values[0]), 0, 0)
     oled.text("Pres : " + (bme.values[1]), 0, 10)
     oled.text("Hum  : " + (bme.values[2]), 0, 20)
     oled.text("Obj  : " + str(t_obj_ir),0,40)
     oled.text("Conn.: " + net_name , 0, 50)
     oled.show()



    # Translate value

     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\x8A')   #temperature
     cs1.value(1)

     time.sleep_ms(350)

     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\xDB')   #object
     cs1.value(1)

     time.sleep_ms(550)
     print("temp.Obj",str(t_obj_ir))
     num_convert(t_obj_ir)

     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\x68')   #degree
     cs1.value(1)

     time.sleep_ms(650)

     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\x8A')   #temperature ambient
     cs1.value(1)

     time.sleep_ms(550)

     print("t ambiente "+str(t_ambiente))
     num_convert(t_ambiente)

     time.sleep_ms(550)

     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\x68')   #degree
     cs1.value(1)

     time.sleep_ms(650)


     cs1.value(0)
     spi.write(b'\x98')
     spi.write(b'\x72')   #humidity
     cs1.value(1)

     time.sleep_ms(550)
     print("Humidity :",str(humidity))
     num_convert(humidity)

     time.sleep_ms(350)

     cs4.value(0)
     spi.write(b'\x98')
     spi.write(b'\x3F')   #percent
     cs4.value(1)

     time.sleep_ms(850)

     cs4.value(0)
     spi.write(b'\x98')
     spi.write(b'\x4E')   #pressure
     cs4.value(1)

     time.sleep_ms(550)
     print("Pressure : ",str(pressure))
     num_convert(pressure)

     time.sleep_ms(450)

     cs3.value(0)
     spi.write(b'\x98')
     spi.write(b'\xbc')   #hecto
     cs3.value(1)

     time.sleep_ms(450)

     cs4.value(0)
     spi.write(b'\x98')
     spi.write(b'\x3b')   #pascals
     cs4.value(1)

     time.sleep_ms(550)

    # to publish the topic on adafruit  :
    # "<adafruit-username>/feeds/<nome del feed sulla dashboard>" , dato

     if status==True:
        cs2.value(0)
        spi.write(b'\x98')
        spi.write(b'\xFD')
        cs2.value(1)

        c.publish("ddddd/feeds/t_object", str(bme.values[0]))
        c.publish("ddddd/feeds/pressione", str(bme.values[1]))
        c.publish("ddddd/feeds/t_ambiente", str(bme.values[2]))
        c.publish("ddddd/feeds/t_ir", str(str(t_obj_ir)))
        print(status)

     delta=0
     start = time.ticks_ms() # get millisecond counter
     while delta<2000:
           delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference
In the attached zipped file all other modudule used in the program.

BMEESP-TALK-Forum.zip
(7.94 KiB) Downloaded 208 times
Thanks. Roberto

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Memory error adding few line of code also if memory free are some kbytes..

Post by jickster » Thu Oct 04, 2018 10:08 pm

There's nothing you can do to fix the memory issue by any refactoring of the sequence of Python code that you say causes the memory error.

For example, if you were creating an array of size 1000 and then only using 5 elements . . . you could fix that.
However, nothing in your sequence of Python commands that are causing your memory issue are "unnecessary".

If you do not want to convert your .py to frozen mpy - which I highly recommend doing as it's really simple - the only other thing you can do is intersperse

Code: Select all

gc.collect()
throughout your code. This will prevent fragmentation which will result in more memory being available but each call to gc.collect() takes a few hundred milliseconds so be careful.

But this is very laborious and not scalable: are you gonna come up with a script to add gc.collect() throughout all your future .py scripts?

I highly recommend converting your .py to frozen mpy. You only have to place your .py in a certain folder as part of the compilation of the firmware and it'll be converted to a .c file which will be compiled into your firmware.

Place note there's two types of freezing: MICROPY_MODULE_FROZEN_STR merely pastes the .py text into a C-array and MICROPY_MODULE_FROZEN_MPY converts your .py to bytecode. It's the second one you want.

BOB63
Posts: 58
Joined: Sat Jul 25, 2015 8:24 pm
Location: Monza , Italy

Re: Memory error adding few line of code also if memory free are some kbytes..

Post by BOB63 » Fri Oct 05, 2018 9:42 am

Hi jickster,
ok , at this point I'll study some tutorials to learn how freeze some modules into the firmware.

I suppose that in my case I could start freezing the modules that are used to read the sensors or write on the LCD .
Can I freeze these modules as they are now or do I've to modify in such way ?
I short, a module to be frozen in the firmware must be written in a specific way ?
Must respect certain charecteristics /standars in the structure , or for instance I can bring the module ssd1306.py as it is and froze into the firmware?
Thanks. Roberto

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Memory error adding few line of code also if memory free are some kbytes..

Post by kevinkk525 » Fri Oct 05, 2018 9:56 am

You can freeze any module that works as you use it now. There is no need to change anything. Just add your modules to the folder micropython/ports/esp8266/modules and build your firmware.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

BOB63
Posts: 58
Joined: Sat Jul 25, 2015 8:24 pm
Location: Monza , Italy

Re: Memory error adding few line of code also if memory free are some kbytes..

Post by BOB63 » Fri Oct 05, 2018 10:31 am

Great ! I'll try.
Thanks for now.
Thanks. Roberto

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: Memory error adding few line of code also if memory free are some kbytes..

Post by jickster » Fri Oct 05, 2018 10:10 pm

BOB63 wrote:Great ! I'll try.
Thanks for now.

Yes please report on much RAM is free after you do the freezing. I’m curious how much RAM is saved.


Sent from my iPhone using Tapatalk Pro

Post Reply