Microcontroller Driver - arenaudineau/AwesomeArray-PythonDriver Wiki
For now, the lib is part of the Awesome Array Driver. You can import it with
from aad import mcd
If error messages appear, please refer to the Awesome Array Driver Wiki
Initialization
m = mcd.MCDriver()
Several errors may occur:
Microcontroller not found
Exception: µc not found, please verify its connection or specify its PID
Make sure the microcontroller is connected. There are two USB port on the board:
PWR
is used to power and program it and is NOT used by the driver, it may be connected to the PC the driver is run from, or another one ;USER
is used for serial communication and IS used by the driver, it must be connected to the PC the driver is run from ;
By default, the driver is looking for a USB device with a Product IDentifier (PID
): 22336
.
For some reason the board may not have this one. You can either change it by reprogramming the microcontroller (in STM32Cube, in the project, ioc
file, search for USB_DEVICE
on the left panel, go down, Device Descriptor
panel, PID (Product IDentifier)
) or provide it to the driver:
mcd.MCDriver.print_ports()
will show every device connected and its associated PID. (⚠️ This is NOT STMicroelectronics STLink Virtual COM Port
)
You can then use:
m = mcd.MCDriver(pid={correct_pid})
Microcontroller port already open
serial.serialutil.SerialException: could not open port '{PORT}': PermissionError(13, 'Access is denied.', None, 5)
The serial connection is already opened somewhere else, check if there are no other instance of MCDriver running (for example in another Jupyter Notebook ; you may want to interrupt/restart the kernel)
Lost microcontroller connection
serial.serialutil.SerialException: WriteFile failed (PermissionError(13, 'The device does not recognize the command.', None, 22))
This error will not happen right after the initialization but can appear when using it. It means the USB cable have been plugged out or that the connection has timed out.
Usage for the Awesome Array Driver
rv = m.cmd(argument0, argument1, ...) # with rv = None if cmd is a 'procedure' command
Commands reference
-
set_sr
: ['procedure' command]
Set Shift Register input bit- Argument 0: Shift Register identifier (see SR_LIST)
- Argument 1: Input bit state (State.RESET or State.SET)
-
fill_srs
: ['procedure' command]
Fill the five Shift Registers- Arguments 0->7: Value of SR.WLE, encoded with little endianness
- Arguments 8->15: Value of SR.WLO, encoded with little endianness
- Arguments 16->23: Value of SR.SL , encoded with little endianness
- Arguments 24->31: Value of SR.BL , encoded with little endianness
- Arguments 32->39: Value of SR.BLB, encoded with little endianness
-
set_cs
: ['procedure' command]
Set a Control Signal- Argument 0: Control Signal identifier (see CS_LIST)
- Argument 1: Input bit state (State.RESET or State.SET)
-
set_adr_r
: ['procedure' command]
Set Row address- Argument 0: The 5-bit address (int or bytes)
-
set_adr_c
: ['procedure' command]
Set Column address- Argument 0: The 5-bit address (int or bytes)
-
get_ctl
: ['function' command]
Get Shift Registers sanity bit- Argument 0: Shift Register identifier (see SR_LIST)
- Returns the bit state (init a State with it for easier manipulation)
-
clk
: ['procedure' command]
Clock once -
clk_sr
: ['procedure' command]
Clock once the shift registers -
clock_xnor
: ['procedure' command]
Clock once the XNOR -
ack_mode
: [special command]
Specify the commands which should send acknowledge after completion.- Argument 0: Flag of the commands (
ACK.NONE
,ACK_ALL
or combinaison ofACK.{CMD_NAME_UPPERCASE}
enum, see ACK_LIST) - Returns ack for
ACK_MODE
, if Argument 0 !=ACK.NONE
- Details The ack sent is the two bytes [
0xAA
,{CMD_CODE}
] - Details There is no ack for commands that already returns data.
- Argument 0: Flag of the commands (
-
debug_echo
: ['function' command]
Sends back the provided argument- Argument 0: byte (only one) to echo
- Returns the byte provided
-
debug_led
: ['function' command]
Turn on the three board LEDs for 2s- Returns b'Hello, C2N!'
General Usage
This driver is designed to be a generic interface between the microcontroller that will control the chip to test, and Python. Therefore each of its components are made to be extended very easily.
Every Python enumerations (in aad/mcd.py
) used in the driver must exactly match the ones on the µc.
The main one is the commands (CMD
) enum which are the instructions programmed on the microcontroller itself:
class CMD(IntEnum):
SET_SR = 0
FILL_SRs = en_auto() # Will return the next enum val, i.e. 1
SET_CS = en_auto() # 2
SET_ADR_R = en_auto() # 3
SET_ADR_C = en_auto() # etc...
GET_CTL = en_auto()
CLK = en_auto()
CLK_SR = en_auto()
CLK_XNOR = en_auto()
ACK_MODE = en_auto()
DEBUG_ECHO = en_auto()
DEBUG_LED = en_auto()
For any item of this enumeration, MCDriver
will generate a function of the exact same name, in lower case (e.g. MCDriver.set_adr_c
for CMD.SET_ADR_C
) taking any argument(s) (no verification is done, it is up to the user to respect the commands reference) and may return a value.
The parameters can either be integers - that will be converted into little-endian bytes (Least Significant Bit at the beginning) using the function mcd.as_bytes({int_param})
- or directly raw bytes.
The return value (if there is one) is a (an array of) byte(s), the endianness is µc-implementation-defined (refer to the reference again) but may be converted to integer afterward when they are little-endian bytes with mcd.as_int({little_endian_bytes})
.
Whether the command will return a value or not depend on the nature of it:
A command that returns something is called a function
command, one that does not is called a procedure
command. For the MCDriver to know what type the command is, one must add the procedure
commands to the ACK
flag (with again, an exact match to the C equivalent):
class ACK(IntFlag):
NONE = 0x00
SET_SR = en_auto() # For a flag, the next values are 1, 2, 4, 8, 16, ...
FILL_SRs = en_auto()
SET_CS = en_auto()
SET_ADR_R = en_auto()
SET_ADR_C = en_auto()
CLK = en_auto()
CLK_SR = en_auto()
CLK_XNOR = en_auto()
⚠️ There is a TODO: for now, the max count of
procedure
command is 7 because the ACK is coded on 8 bits
If a command is defined as a function
(i.e. not defined as a procedure
), calling it will block until Python actually receive the return value from the microcontroller.
If a command is defined as a procedure
, calling it will block until Python receive an ACKnowledgment if it has been asked for, and wont block otherwise.
ACK
s are messages sent from the microcontroller to Python to acknowledge the complete execution of the procedure, in order not to call another one before the µc can handle it.
By default, ACK is not asked for any command (except when initialized with the AwesomeArrayDriver
which activate them all). To change this setting, you must use the command ACK_MODE
:
m.ack_mode(mcd.ACK.SET_SR | mcd.ACK.FILL_SRs) # Will now ask ACKs for the cmds SET_SR and FILL_SRs
m.ack_mode(mcd.ACK_ALL) # Will now ask ACKs for every cmds
m.ack_mode(mcd.ACK_NONE) # Will now never ask for ACKs
ℹ️
ACK_MODE
will itself send an ACK if and only if its parameter is not mcd.ACK_NONE. It is all handled by the driver.