Firmware Release v1.20.1

  • Hello everyone, we have release a new Firmware release v1.20.1

    sources can be found on Github Here

    Release Notes:

    • SmartConfig (Smart provisioning of Wifi Credentials)
      • To disable Smart Provisioning use pybytes.smart_config(False)
    • IDF V3.2
    • Micropython V1.11
    • Secure BLE (Server side )
    • Pybytes v1.1.2
    • LittleFS v2.0
    • Light sleep support
    • RTC memory support
    • Wifi promiscuous mode
    • CoAp module
    • Esp32 touchpad functionality exposed to micropy
    • uasyncio module
    • Uzlib module
    • Add support for LoRa regions CN470 and IN865
    • Added support for LoRa Class C multicast
    • Increase App partition Size For FIPy, GPy and LoPy4 to 1980K
    • Updated Build ENV for detecting Flash Size
    • Update Make Environment for IDF version check and checkout
    • Support OTA from older v1.18 Firmwares through intermediate firmware v1.18.3
    • Updates / Bug fixes to Pycom module
    • Updates / bug fixes to UART module
    • Updates to machrmt module
    • Updates / bug fixes to machrtc module
    • Updates / Bug fixes to modlora
    • Updates / Bug Fixes to Bluetooth module
    • Updates / Bug fixes to WLAN module
    • Updates / Bug fixes to LTE module
    • Updates / Bug fixes to machine module
    • Updates / bug fixing for OS module
    • Updates / Bug fixing for modusocket module
    • General fixes and improvements to the LoRaWAN stack
    • General Makefile Updates
    • General Bug Fixing

    Here is the summary of changes which can cause compatibility issues updating from 1.18 FW along with new APIs added


    • "pulses_send()" API can be configured as non-blocking
      "wait_tx_done" parameter is added


    • ntp_sync() API has new parameter: "backup_server" -> not mandatory
      memory() API is added


    • RX Buffer length can be maximum of 512 byte on all boards
      • Previously it was 4096 bytes on FIPY and GPY
    • New parameter of UART constructor:
      • rx_buffer_size
      • New Exception is dropped if "rx_buffer_size" is bigger than 512 bytes


    • New API: LoRa.reset() to reset sx1272 chip on LoPy1 Boards


    • Bluetooth's constructor has new parameter: "modem_sleep”, “mtu”
      • Exception is dropped if sleep failed
    • New API of characteristic class: read_descriptor()
    • Bluetooth.deinit() closes all connections
    • Bluetooth.connect() from now drops TimeoutError and not OSError when timeout happens
    • New parameter of Bluetooth.connect()
      • Has a "timeout" parameter defining timeout for establishing connection
      • Previously it was set to 5ms
    • New API: Bluetooth.set_advertisement_params()
    • New API: Bluetooth.set_advertisement_raw()
    • New API: Bluetooth.modem_sleep()
    • New API: Bluetooth.gatts_mtu() to get mtu of the client connection to Pycom device
    • New API: Bluetooth.tx_power()


    New module


    • set_color() has new parameter: "wait_tx"
      • Can be used to make underlying RMT operation block


    • lte_iccid() API drops new OSError exception if SIM is not detected
    • send_at_cmd() API's "delay" parameter is removed
    • send_at_cmd() raises new TypeError exception if "cmd" is not passed
    • New Callback registering API for registering a callback function to be called when LTE coverage is Lost (Note: Depending on the Sequans modem FW it might be supported or not , if not the callback will not be triggered - an update on Sequans FW supporting this Feature will be announced later )


    • deepsleep_wakeup() API is renamed to sleep_wakeup
    • sleep() API is implemented for light sleep (it was an empty function)


    • New API: bootmgr()
    • New API: get_free_heap()
    • New APIs: related to Pybytes
    • New APIs for setting/getting stored Wifi Credentials for STA and AP mode
    • heartbeat() API drops new OSError excpetion if RGB_LED is disabled (can be disabled during build)
    • rgb_led() API drops new OSError excpetion if RGB_LED is disabled (can be disabled during build)
    • nvs_get() API returns user defined "NoExistValue" if the object does not exist in NVS. Otherwise it raises a ValueError!.
      * To maintain previous behaviour, use pycom.nvs_get('<item>', None)


    • New file system type is added: Little FS
    • Virtual File System concept is used
      • The /flash can be LittleFS or FatFS, the SD Card can be FatFS
      • Files System related functions are replaced, they are used via VFS
    • mkfs() API is removed and is replaced by fsformat()


    • queue_put() releases the GIL during operation -> REPL will work
    • queue_get() releases the GIL during operation -> REPL will work


    • readall() API is removed
      • read() without parameters does the same
    • connect() API can be set as Non-BLocking
      • Only if timeout is defined: new OSError exception is dropped if settimeout operation of lwip fails
      • Only if timeout is defined: new TimeoutError exception is dropped if connection times out
      • Only if timeout is defined: new OsError exception may dropped if SSL is configured and underlying ssl operation fails
    • recv() API drops TimeoutError exception if underlying lwip returns with SSL_TIMEOUT
      • Before it only dropped this exception if MP_EAGAIN is returned
    • recvfrom() API drops TimeoutError exception if underlying lwip returns with SSL_TIMEOUT
      • Before it only dropped this exception if MP_EAGAIN is returned
    • New API: sendto()


    • Parameters of ticks_diff() API are swapped
      • Was: start_in, end_in
      • New: end_in, start_in


    • New API: bandwidth()
    • New API: hostname()
    • New API: ap_sta_list()
    • New API: max_tx_power()
    • New API: country()
    • New API: joined_ap_info()
    • New API: wifi_protocol()
    • New API: send_raw()
    • New API: promiscuous()
    • New API: callback()
    • New API: events()
    • New API: smartConfig()
    • New API: Connected_ap_pwd
    • New API: wifi_packet()
    • New API: ctrl_pkt_filter()
    • WLAN's contructor/init():
      • New optional parameter: bandwidth
      • New optional parameter: max_tx_pwr
      • New optional parameter: country -> if not given as tuple TypeError is dropped
    • API scan() has new optional parameters:
      • ssid, bssid, channel, show_hidden, type, scantime -> drops exception if given incorrectly
    • API mac() may drop new exceptions depends on number of arguments and it returns Mac of both AP and STA
    • New Triggers for Wlan Callback

    MQTT aws lib

    • Removed from frozen code but can be found on Github Here

    Please Note Documentation for v1.20 FW is still being updated and can be found Here

    Issue submission and Collaboration:

    For better experience and support for Pycom community, we have restructured our GitHub public Repo to have a separate branches for 1.18 and 1.20 FWs (under Release) - Daily development will be done on a new default branch (Dev) (previously we used to do the main Dev privately and do weekly/monthly releases to public repo).
    This will make it easier for people to Contribute to Our Firmware plus better traceability of opened Issues.
    we recommend you open any pull request on that Branch (Dev).

    OTA to 1.20 FW from 1.18

    Between version 1.18.2 and 1.20 the partition table is changed, the OTA_0 partition, among several others, is relocated because the size of the firmware has been increased due to the extended functionality of the 1.20 version. Due to this reason when updating from version 1.18.2 to 1.20 via OTA, an update to an intermediate version, numbered as 1.18.3, must be performed.
    The intermediate version makes sure that when OTA update to 1.20 is requested, the partition table contains correct entries and the new image will be flashed to the proper location.

    The intermediate version, 1.18.3, contains the following EXTRA steps when OTA update is requested:

    • Updates bootloader
    • Moves the content of the "ota data" partition to its new location
    • Updates the partition table

    Note: Please note that if bootloader or partition table update fails (e.g.: due to a power-loss), the device will not boot and recover and a new image must be flashed via a cable.

    When the device is being updated to the 1.18.3 intermediate version it may be flashed onto "OTA_0" partition depending on the where current active image is loaded from. In this case on next boot it automatically copies itself from "OTA_0" to "Factory" partition as a preparation for being able to receive the 1.20 image in the future. Without this step when the 1.20 image is being flashed on the "Factory" partition due to its increased size it would overwrite the first segments of the curently running firmware (which is the 1.18.3 and located on "OTA_0" partition).

    Therefore the correct update chain from 1.18 to 1.20 via OTA looks like: 1.18.2 -> 1.18.3 -> 1.20

    Downgarding from 1.20 back to 1.18 is possible, however the target version must be 1.18.3. The 1.18.3 image able to detect whether a downgrade happened and in this case it will not perform the steps explained above, it behaves as the 1.18.2r7 image just with updated partition table and bootloader. Updating back again to 1.20 is possible and allowed.

    Note: Updating devices with encrypted flash is not supported.

    Note: Downgrading via OTA from 1.18.3 to 1.18.2.xx is not allowed as this might casuse further OTA operations to fail.

    Note: Before doing OTA to 1.20 firmware make sure that the Scripts on device are updated (if necessary) to be compatible with 1.20 FW to avoid exceptions once device is updated to 1.20 which might lead to loosing connection to the remote device.

    You can find firmware images for 1.18.3 here:


    Note: This new Release has support for LittleFS filesystem if you updated from 1.18 FW your Filesystem is set to FatFS and if you choose to switch to LittleFS this will cause the filesystem to be formatted .

    Note: previous stable and development firmware can now be found as “legacy” in the firmware updater, so the new firmware updater has the 3 firmware types pybytes, legacy and pybytes-legacy

    Note: Upgrading from legacy (1.18) FW also downgrading from 1.20 to 1.18 will cause Nvs data to be erased as formatting under new FW is updated

    Note: There is an issue regarding BLE connection from Pycom Device (client) to a mobile phone (tested on Iphone) acting as Server, where connection always times out - connection from Pycom Device to another does not have that issue - will keep you updated with the fix for that problem.

  • @robert-hh I am using a L01 (4MB SPIRAM + 8MB Flash)

  • @regiskiwi Are you using a LoPy1 w/o SPIRAM or Lopy4 with SPIRAM?

  • @robert-hh Just a note, the timer interrupt seems located in IRAM :
    timer_isr_register(TIMER_GROUP_0, TIMER_1, HAL_TimerCallback, NULL, ESP_INTR_FLAG_IRAM, NULL);

  • @robert-hh Thanks Robert. As far as I understand, cache is disabled by the CPU when SPI access is undertaken ( . If an ESP_INTR_FLAG_IRAM interrupt triggers during that time and it tries to access cache it will raise this exception. As far as I can see OnRxDone is called by SX1272RadioFlagsIrq and this timer interrupt is in IRAM so likely to be active during flash access.

  • @andreas said in Firmware Release v1.20.1:

    We experienced the same and went through all the jazz outlined within [1] to produce some m

    Thanks Andreas, Robert We have made modifications to the LOPY build so I can not easily use the vanilla one provided. I am looking forward to see the changes you made in github. In the meantime, I am using the latest toolchain from expressif (90) and mfix-esp32-psram-cache-dupldst flag. I have also added the attribute IRAM to the OnRadioRxError, OnRadioTxTimeout, OnRadioRxTimeout interrupt handlers and in a few functions called by OnRadioTxDone (I am using a class C device). The difficult bit is OnRadioRxDone. This handler logic is long and I think it should really need to be moved to a separate thread to keep the ISR logic small and fast. what do you think?
    I think I am hitting this caching issue a lot because we do make use of NVS (config variables)

  • @regiskiwi It is quite a while ago since I dug my way through the Lora stack. I had seen this IRAM/Not IRAM setting. But at that time it seemed plausible for me due to timing constraints. After TxDone, the device has to meet a very narrow time window for possible downlink messages. With caching needed that window may have been hard to hit. For the other events, timing is less critical. So I wonder more why caching is disabled. Did you do that intentionally in your code? Without caching, the firmware is hardly usable.
    Did you try to add the IRAM attribute to the other handlers?

    P.S.: I made also the experience that the internal WDT is not effective.

  • Dear @regiskiwi,

    @regiskiwi said in Firmware Release v1.20.1:

    I have been having the "Cache disabled but cached memory region accessed" exception in my custom (LOPY) build but it is hard to reproduce.

    I hear you. We experienced the same and went through all the jazz outlined within [1] to produce some more stable builds. However, I am sorry that we haven't been able to upstream the changes appropriately. As we recognized folks of Pycom have been pretty busy on their World Tour, I will try again to get through to @Xykon next week.

    If you can get by using unmodified builds in any way, you are welcome to try our Dragonfly builds in the meanwhile [2].

    As I am not using LoRa yet, I can't tell about any possible issues with the OnRadio* event handlers regarding IRAM.

    With kind regards,


  • @andreas I have been having the "Cache disabled but cached memory region accessed" exception in my custom (LOPY) build but it is hard to reproduce. When this happens in 1.20.r1 the CPU loops in the panic handler and hangs up there and only a POWEROFF reset will reboot the device ( WTG does not work). I made some minor changes in panic.c and got it to reboot if the exception happens. (the loop is caused by a call to rtc_wdt_set_time()).

    That's all good but I need to find what could be causing this exception and I wonder if you can help me there:
    In LoRaMAC.c there are radio 5 handlers defined but only one of them (OnRadioTxDone) is using the IRAM_ATTR attribute. It seems that all 5 of those handlers are called within an interrupt context so I think that they should be located in IRAM too. Any reason why they are not?

    The handlers are:
    RadioEvents.TxDone = OnRadioTxDone;
    RadioEvents.RxDone = OnRadioRxDone;
    RadioEvents.RxError = OnRadioRxError;
    RadioEvents.TxTimeout = OnRadioTxTimeout;
    RadioEvents.RxTimeout = OnRadioRxTimeout;

    Thanks a lot.

  • I'm trying to compile the pycom-micropython to use only one core.
    I compile the idf libs, I make menuconfig and select "component config->FreeRTOS-> Run FreeRTOS only on first core". the compilation runs ok.
    I move the libs to the pycom-micropython and compile the firmware, and program the wipy with no problems.
    After the programming completes, the pycom enter into a loop when loading the bootloader and don't go to the python shell.

    D (695) bootloader_flash: mmu set paddr=001e0000 count=1 size=20 src_addr=1ebab0 src_addr_aligned=1e0000
    D (704) bootloader_flash: mmu set paddr=001e0000 count=1 size=20 src_addr=1ebab0 src_addr_aligned=1e0000
    pycom-esp-idf/components/freertos/tasks.c:685 (xTaskCreateStaticPinnedToCore)- assert failed!
    abort() was called at PC 0x4009097b on core 0
    Backtrace: 0x40092c0f:0x3ffbab00 0x40092e15:0x3ffbab20 0x4009097b:0x3ffbab40 0x400de0b5:0x3ffbab80 0x400d2411:0x3ffbabb0

    If I disable Run FreeRTOS only on first core. The pycom boots.

    D (706) bootloader_flash: mmu set paddr=001e0000 count=1 size=20 src_addr=1ed800 src_addr_aligned=1e0000
    Pycom MicroPython 1.20.1.r1 [4c809f4e-dirty] on 2019-11-21; LoPy4 with ESP32
    Type "help()" for more information.

  • @iwahdan
    I am using Fipy and Lopy4 device which are getting data from a Ruuvitag by BLE connection. Since I have updated the firmware 1.20.1, pycom devices doesn't get any value from the ruuvi. Do you know if there is an issue with BLE connection with the new firmware ?

  • Dear @t0000899 and all others here,

    @t0000899 said in Firmware Release v1.20.1:

    Sometimes during FTP transfer there is an unhandled exception and flash memory is formatted.

    Memory dump at 0x4020234c: bad00bad bad00bad bad00bad
    Guru Meditation Error: Core  0 panic'ed (IllegalInstruction). Exception was unhandled.

    @andreas said in Firmware Release v1.20.1:

    We can confirm this after upgrading to 1.20.1 on FiPy and LoPy4 devices, with or without VARIANT=PYBYTES. We are also spuriously getting these core panics, see also bad00bad bad00bad.

    Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
    Guru Meditation Error: Core  1 panic'ed (IllegalInstruction). Exception was unhandled.
    Memory dump at 0x4020f958: bad00bad bad00bad bad00bad

    We have been working on mitigating these issues, so if you feel lucky, you might want to try one of our custom builds published to [1]. More background about this is available through [2].

    If we are lucky together, this will improve the stability significantly. If you will be still receiving the core dumps, I will be happy if you would share its content with us. Please just don't paste it into the comment itself but put it into a file which you will be able to upload by dragging it into the text area.

    Please be aware that when upgrading from a lower firmware version to the current 1.20.1.r1 development release these builds are based upon, you will have to erase your device completely before flashing in order to keep things straight as outlined within this topic already. Hint: Use a command like pycom-fwtool-cli --port /dev/ttyUSB0 erase_all, see also [3].

    Please also be aware that this procedure will also erase the LoRa MAC stored on the device. @robert-hh thankfully outlined the procedure to restore it appropriately:

    • If you still know the value the LoraMac had before, then you can follow the procedure explained at
    • If you do not know it, you will have to use the Pycom updater to restore it:
      • First, use the Pycom updater (GUI version) to install a recent image (like pybytes 1.20.1) from the Internet. You do not have to use it, the installation process itself already restores both the LoRa MAC and the Sigfox ID.
      • Then, use the Pycom updater to flash the custom image. Do not erase the flash in between.

    As it turned out to gain more robustness for others already [4,5], we will be happy to learn if this happens to you as well.

    Have fun!

    With kind regards,

    P.S.: For all people who want to go with Pybytes, we just published builds using VARIANT=PYBYTES at [6]. When going that way, you should probably save the pybytes_config.json before invoking the erase_all procedure and restore it to the device afterwards.

    P.P.S.: All these builds use the LittleFS filesystem to prevent filesystem corruption which works for us very well.


  • @crumble said in Firmware Release v1.20.1:


    The new firmware is only visible, if you select pybytes, If yiou are asked about your bybytes ID, you can simply skip the question.

    What is the between pybytes and pybytes/legacy?

  • @dabal221

    The new firmware is only visible, if you select pybytes, If yiou are asked about your bybytes ID, you can simply skip the question.

  • @andreas said in Firmware Release v1.20.1:

    @dabal221 said in Firmware Release v1.20.1:

    Because when I update Firmware using Pycom Firmware Update I have got 1.20.0.rc13 not 1.20.1

    Maybe the program will offer the newer releases after upgrading the Pycom Firmware Updater itself.

    @andreas I have got 1.16.1, it is said that it is the latest stable version.

  • @dabal221 said in Firmware Release v1.20.1:

    Because when I update Firmware using Pycom Firmware Update I have got 1.20.0.rc13 not 1.20.1

    Maybe the program will offer the newer releases after upgrading the Pycom Firmware Updater itself.

  • @andreas Where can I find Firmware Release v1.20.1? Because when I update Firmware using Pycom Firmware Update I have got 1.20.0.rc13 not 1.20.1

  • @serafimsaudade said in Firmware Release v1.20.1:

    I'm trying to connect gpy to wireless, but when I do wlan.scan() get this error:
    wlan = WLAN(mode=WLAN.STA_AP,ssid="teste", auth=(WLAN.WPA2, 'pass'))
    nets = wlan.scan()
    OSError: Scan operation Failed!

    This work on others fw version.

    @dabal221 said in Firmware Release v1.20.1:

    @serafimsaudade How do you solve this "OSError: Scan operation Failed!"?

    For us, this flow works

    import network
    station = network.WLAN()

    then, later, either



    station.connect(ssid, (auth_mode, password), timeout=int(timeout * 1000))

  • @serafimsaudade Unfortunately, it does not change anything. :(

  • @dabal221
    I put a time.sleep of 3sec before wlan.scan(). And the error don't happen.

    # Change the mode to both AP and station so we can connect to the network
    self.wlan.init(mode=WLAN.STA_AP, ssid=system.uniqueGwId, auth=(WLAN.WPA2, self.system.apKey))
    # Use internal antena
    # Use External antena
        self.nets = self.wlan.scan()
    except Exception as exception:
        print("error", 'startWLAN scan: {0}'.format(exception))

Log in to reply

Pycom on Twitter