Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python on bare metal

Python on bare metal

Fast & efficient MicroPython

Jessica Greene

February 23, 2019
Tweet

More Decks by Jessica Greene

Other Decks in Technology

Transcript

  1. Python on bare metal
    fast & efficient code with MicroPython
    Jessica Greene @sleepypioneer

    View Slide

  2. MicroPython
     A complete reimplementation of Python
     Designed to be efficient with resources
     Designed to run bare metal
    Includes:
     A compiler, runtime & familiar REPL
     Support for basic libraries
     Extra modules to control hardware

    View Slide

  3. PyBoard, ESP32, ESP8266 & more...

    View Slide

  4. Challenges of working on microcontrollers
    BATTERY POWERED VERY LITTLE MEMORY
    (RAM, ROM)
    NORMALLY REQUIRE
    LOW LEVEL LANGUAGE

    View Slide

  5. How does MicroPython solve the issue of having a low
    amount of RAM?
    Interned strings, most already in ROM
    Small integers stuffed in a pointer to avoid using heap (trick from lisp)
    Optimised method calls to not use heap
    Garbage collection

    View Slide

  6. Normal python uses
    megabytes RAM if
    not 100s
    MicroPython can run
    with only 8 kilobytes
    & it runs without an
    OS, so on bare
    metal
    Python Vs MicroPython

    View Slide

  7. How you can impact
    this with your code?

    View Slide

  8. Tips: Memory allocation
    Doesn’t use heap Uses Heap
    Expressions Importing
    If, while, for and try statements Defining functions & classes
    Local variables Assigning global variables for the first time
    Small integer arithmetic Creating data structures
    Inplace operations on existing data structures
    Calling functions/ methods with positional or
    keyword args

    View Slide

  9. Tips: CPU time
    USE FUNCTIONS TO
    AVOID GLOBAL
    SCOPES
    USE LOCAL
    VARIABLES
    CACHE MODULE
    FUNCTIONS &
    OBJECT METHODS
    AS LOCALS
    PREFER LONGER
    EXPRESSIONS NOT
    SPLIT UP ONES
    RUNTIME IS FAST!
    E.G. STR.STARTSWITH

    View Slide

  10. Tips: RAM usage
    DON'T USE HEAP
    WHEN POSSIBLE
    SHORTER VARIABLE
    NAMES, REUSE
    THEM; EG X,Y,I, LEN,
    VAR
    DON'T USE * OR **
    ARGS
    SCRIPT
    MINIFICATION
    ULTIMATE SOLUTION:
    FREEZE SCRIPTS INTO
    THE FIRMWARE (AT
    COMPILE TIME)

    View Slide

  11. Code example

    View Slide

  12. LED Blink script
    import time, machine
    led = machine.Pin('LED_BLUE')
    for i in range(N):
    led.on()
    led.off()
    50kHz
    @dpgeorge

    View Slide

  13. Inside a function - removes global variables 60kHz
    import time, machine
    led = machine.Pin('LED_BLUE')
    def blink_simple(n):
    for i in range(n):
    led.on()
    led.off()
    @dpgeorge

    View Slide

  14. Preload methods & range() optimisation
    def blink_preload(n):
    on = led.on # returns a bound method
    off = led.off
    r = range(n) # optimise the range
    for i in r:
    on()
    off()
    180kHz
    @dpgeorge

    View Slide

  15. Loop unrolling
    def blink_preload_unrolled8(n):
    n //= 8
    on = led.on
    off = led.off
    r = range(n)
    for i in r:
    on()
    off()
    on()
    off()
    ....
    220kHz
    @dpgeorge

    View Slide

  16. Native mode
    @micropython.native
    def blink_preload_unrolled8_native(n:int):
    n //= 4
    on = led.on
    off = led.off
    r = range(n)
    for i in r:
    on()
    off()
    on()
    off()
    ....
    290kHz
    @dpgeorge

    View Slide

  17. Viper mode
    @micropython.viper
    def blink_unrolled8_viper(n:int):
    n //= 8
    p = ptr16(stm.GPIOB + stm.GPIO_BSRR)
    for i in range(n):
    p[0] = 1 << 4 # high
    p[1] = 1 << 4 # low
    p[0] = 1 << 4 # high
    p[1] = 1 << 4 # low
    ....
    12890kHz
    @dpgeorge

    View Slide

  18. In assembler
    @micropython.asm_thumb
    def blink_asm(r0):
    lsr(r0, r0, 3)
    movwt(r1, stm.GPIOB + stm.GPIO_BSRR)
    mov(r2, 1 << 4)
    label(loop)
    strh(r2, [r1, 0]) # high
    strh(r2, [r1, 2]) # low
    strh(r2, [r1, 0]) # high
    strh(r2, [r1, 2]) # low
    ....
    27359.25kHz
    @dpgeorge

    View Slide

  19. Takeaways
    ○ If your code runs faster it can sleep
    for longer and that saves battery!
    ○ ROM everything that you can
    ○ Use runtime methods!
    ○ Local not global variables!

    View Slide

  20. THANK YOU!
    www.github.com/sleepypioneer/fast_and_efficient_micropython
    www.micropython.org
    www.github.com/micropython

    View Slide