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. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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)
  7. LED Blink script import time, machine led = machine.Pin('LED_BLUE') for

    i in range(N): led.on() led.off() 50kHz @dpgeorge
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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!