Skip to content
Damien George edited this page Aug 23, 2015 · 115 revisions

The aim is to make the pyb module obsolete, make all its functionality cleaner and more board-generic, and move such functionality elsewhere. Below is the current proposal, very much a work in progress.

Design goals and priciples

The main aim is to provide Python modules/functions/classes that abstract the hardware in a Pythonic way.

The API should be Pythonic and obvious. There should be a close mapping from functions to hardware and there should be as little magic as possible. The API should be as consistent across peripherals (Pin, UART, I2C, ADC, etc) as possible.

Use cases

These use-cases need to be written:

  • Basic I/O on a pin
  • PWM on a pin
  • ADC on a pin
  • Using a Timer to do a one-shot callback
  • Using a Timer to do a repeated callback

New hardware module

The classes to control the peripherals of the board will reside in a new module called hardware, therefore, by doing:

import hardware
dir(hardware)

one can easily see what's supported on the board.

The Pin class

Create and init a pin

pin = Pin(id, mode, pull=Pin.PULL_NONE, *, value, drive, slew, alt, ...)

  • id, and mode are mandatory and positional (mode can kw).
  • pull is optional and positional (also can be named).
  • The rest of args are kwonly.
  • Only value is required for a port to implement (initial value if given).
  • The rest are optional, and a port can define them and also define others.

Besides Pin.IN and Pin.OUT, mode can also take Pin.ALT and Pin.ALT_OPEN_DRAIN, but the alternate function itself cannot be configured via the Pin class, since this will be done via the other hardware classes (UART, SPI, I2C, etc.). However, Pin.ALT and Pin.ALT_OPEN_DRAIN exist to allow custom control of the pin settings after it has been taken by another peripheral. For example:

# create and initialize UART1 with TX and RX on GP1 and GP2 respectively.
UART(1, 9600, pins=['GP1', 'GP2']) 
# enable the pull-ups on both UART1 pins
Pin('GP1', mode=Pin.ALT, pull=Pin.PULL_UP)
Pin('GP2', mode=Pin.ALT, pull=Pin.PULL_UP)

Methods

  • pin.init(...) re init.
  • pin.high() set high.
  • pin.low() set low.
  • pin.value() get value.
  • pin.value(x) set value.
  • pin() fast method to get the value of the pin.
  • pin(value) fast method to set the value of the pin.
  • pin.toggle()

Getters and setters

  • pin.id() get only.
  • pin.mode([mode])
  • pin.pull([pull])
  • pin.drive([drive])
  • pin.slew([slew])

Constants

  • for mode: Pin.IN, Pin.OUT, Pin.OPEN_DRAIN, Pin.ALT, Pin.ALT_OPEN_DRAIN
  • for pull: Pin.PULL_UP, Pin.PULL_DOWN, Pin.PULL_NONE, optional: Pin.PULL_UP_STRONG, Pin.PULL_DOWN_WEAK, ...
  • for drive: Pin.LOW_POWER, Pin.MED_POWER, Pin.HIGH_POWER
  • for slew: Pin.FAST_RISE, Pin.SLOW_RISE
  • for interrupt (callback) mode: pin.INT_RISING, pin.INT_FALLING, pin.INT_RISING_FALLING, pin.INT_HIGH_LEVEL, pin.INT_LOW_LEVEL

Attributes

  • Pins list: Pin.board (mandatory) and Pin.cpu (optional).

The UART class

uart = UART(id, baudrate=9600, bits=8, parity=None, stop=0, *, pins, ...)

  • pins is a 4 or 2 item list indicating the TX, RX, RTS and CTS pins (in that order). Any of the pins can be None if one wants the UART to operate with limited functionality. If the RTS pin is given the the RX pin must be given as well. The same applies to CTS. When no pins are given (or all are None), then the default set of TX and RX pins is taken, and hardware flow control will be disabled. Example
uart = UART(1, 9600, 8, pins=['GP1', 'GP2'])  # No hardware flow control
uart = UART(1, 9600, 8, pins=['GP1', 'GP2', 'GP7', 'GP6']) # RTS/CTS flow control
uart = UART(1, 9600, 8, pins=['GP1', None]) # Tx only
uart = UART(1, 9600, 8, pins=[None, 'GP2']) # Rx only

uart = UART(1, 9600, 8, pins=['GP1']) # Raise 
uart = UART(1, 9600, 8, pins=['GP1', 'GP2', 'GP7']) # Raise
uart = UART(1, 9600, 8, pins=['GP1', 'GP2', 'GP7', None]) # OK, RTS only

uart = UART(1, 9600, 8) # Default pins are used. No flow control
  • uart.init(...)
  • uart.read([nbytes])
  • uart.readinto(buf[, nbytes])
  • uart.readall()
  • uart.readline([max_size])
  • uart.readchar()
  • uart.write(buf)
  • uart.writechar(char)
  • uart.sendbreak()

The ADC class

adc = ADC(id, *, bits, ...)

  • adc.init(...) re-init
  • adc.readchannel(channel) read a specific channel
  • apin = adc(pin) make an analog pin (will choose the correct channel for the pin)
  • apin.read()
  • apin.readtimed(buf, timer)

machine module

  • machine.freq([freq, ...]) get or set CPU and/or bus frequencies
  • machine.idle([... options]) idle the CPU, may require external event to leave idle mode
  • machine.sleep([... options]) enter sleep mode that retains RAM and continues execution when woken
  • machine.deepsleep([... options]) enter sleep mode that may not retain RAM and may reset when woken

sys module additions

The sys module has uPy specific functions:

  • sys.dup_stdio([stream_obj]) get or set duplication of global stdio, so that REPL can be redirected to UART or other (note: could allow to duplicate to multiple stream objs but that's arguably overkill and could anyway be done in Python by making a stream multiplexer)

time module additions

The time module has uPy specific functions:

  • time.sleep_ms(ms)
  • time.sleep_us(us)
  • time.ticks_ms()
  • time.ticks_us()
  • time.ticks_cpu()
  • time.ticks_diff(t0, t1)

os module additions

The os module has uPy specific functions:

  • os.mount(block_dev, mount_point, *, readonly)
  • os.mkfs(device or path, *, options...)

Clone this wiki locally