Welcome to scaffold’s documentation!¶

Getting started¶
Scaffold is a FPGA board made for security research on hardware embedded devices. It is capable of communicating with many circuits using standard protocols. It can be easily extended with new protocols by writing new transceivers in VHDL or Verilog language, and integrating it in the proposed scaffold global architecture. When exchanging messages with the devices under tests, Scaffold can generate triggers for chosen commands, spy data on a bus or intercept and traffic.
Scaffold board also embeds special electronics tailored for hardware attacks:
- Sense resistor and analog amplifier for real-time current measurement
- FPGA safety protections against voltage glitch attacks
- Controllable power switches
- Fast power tearing capability, for emergency shutdown of the device under test
- Delay and pulse generators, allowing firing glitches or laser pulses.
An easy-to-use python API is provided to control the board.
Board tour¶
- A: USB2 link with host computer. Also used to power the board.
- B: Main board power switch.
- C: Switch the jumper to the right to power the board from an external 5 V power supply and not from the USB.
- D: External power supply for the platform socket.
- E: External power supply for the DUT socket.
- F: Adjustable voltage regulator for the platform socket. When the jumper is set on top position, this power source is not used and the platform socket is powered from the external power supply.
- G: Adjustable voltage regulator for the DUT socket. When the jumper is set on top position, this power source is not used and the DUT socket is powered from the external power supply.
- H: Adjustable voltage regulator for the I/O bank of the FPGA connected to the platform and DUT sockets. This allows setting the correct voltage depending on the connected device. Supported voltage range goes from 1.5 V up to 3.3 V.
- I: FPGA active serial connector for bitstream programmation. An USB blaster can be used to update the bitstream.
- J: FPGA reset button. Push if the board enters error state.
- K: Switches to select Spy or Intercept mode for each I/O of the FPGA. In intercept mode, the signals of the platform and DUT sockets are not connected anymore and the FPGA can act as a man in the middle circuit.
- L: Switches to enable 1 KOhm series protection resistors on the I/Os (at the cost of slew-rate). Shall be enabled when there is a risk to damage the FPGA, with high-voltage glitches for instance.
- M: Tearing input. Any positive edge will power-off the DUT immediately and shunt all I/Os to ground.
- N: A, B, C I/Os voltage standard selection between 3.3 V or 5 V.
- O: A, B, C I/O groups. Each group can be configured to have 3.3 V or 5 V I/Os. 5 V is suited to drive Alphanov TTL 50 Ohm laser sources (other 3.3 V I/Os can’t). All the I/Os of a same group are either in output or input mode.
- P: D I/O group. Maximum voltage is 3.3 V. Those I/Os are connected to the platform and DUT sockets and are usually used to communicate with the target device and generate triggers. SMA connectors are provided for D0 to D6.
- Q: Platform socket and power state LED.
- R: DUT socket and power state LED.
- S: Adjustable shunt resistor for power trace measurement.
- T: Output of the analog 11 X amplifier for power trace measurement.
Connecting the board¶
Connect the board with a micro-USB cable to your computer. Power-on the board using the power switch. The operating system shall detect the board as a USB-To-Serial device (COMx on Windows, /dev/ttyUSBx on linux). It may be necessary to install FTDI driver for some Windows versions.
Using the Python API¶
The file scaffold.py
is the library which can be used to interact with
Scaffold board.
from scaffold import Scaffold
# Connect to the board.
# This will open the serial device and check for hardware version
scaffold = Scaffold('/dev/ttyUSB0')
# Configure UART0 for operation
uart = scaff.uart0
uart.baudrate = 115200
# Connect UART0 signals to board pins
# << operator connects signals. Left operand is the destination, right operand
# is the source (the order is important)
# In this example, D0 and D1 are configured as outputs, D2 is configured as an
# input.
scaffold.d0 << uart.tx
scaffold.d1 << uart.trigger
uart.rx << scaffold.d2
# UART is now ready to use
uart.send('Hello world !')
Kits¶
Some kits for specific applications with Scaffold are available.
Breadboard kit¶
The Scaffold breadboard provides solderable test points for all the DUT socket pins. It can be used to mount a setup with any target.

STM32F2 QFP64 kit¶
This kit allows communicating with the embedded ST bootloader of STM32F2 devices. It is possible to write the Flash memory to load code, and then execute it after reset.

The socket FLIPPED-QPF64 can be used to mount a STM32F2 device on its backside. All pins of the package must be returned before inserting the device in the socket. Pin 1 of the target device is as shown in the figure above. Make sure the device is correctly inserted and all the needles of the socket touch their corresponding PIN.
Python API example¶
The class scaffold.stm32.STM32
of the Python API provides methods to
communicate with the circuit and setup tests very quickly.
from scaffold import Scaffold
from scaffold.stm32 import STM32
stm = STM32(Scaffold('/dev/ttyUSB0'))
# Load some code into Flash memory
stm.startup_bootloader()
stm.extended_erase()
stm.write_memory(0x08000000, open('program.bin', 'rb').read())
# Run the program
stm.startup_flash()
Example script¶
An example file in examples/stm32.py can be used to load and execute code onto a STM32F2 device.
$ python3 stm32.py -d /dev/ttyUSB0 --load program.bin --run
Communication initiated
Product ID: 0x0411
Possible device match: stm32f2xxxx
Get: 310001021121314463738292
Bootloader version: 3.1
Option bytes: ffaa0055ffaa0055ffff0000ffff0000
RDP: no protection
Erasing Flash memory...
Programming...
Verifying...
Flash memory written successfully!
Rebooting from Flash memory...
Smartcard kit¶
This kit allows communicating with any smartcard using 7816 protocol.
The class scaffold.iso7816.Smartcard
of the Python API provides
methods to communicate with an ISO7816 Smartcard and setup tests very quickly.
Currently, only T=0 protocol is supported by the API and it has not been tested
extensively yet.

Pinout¶
D0 | I/O. This signal is pulled up with a resistor on the daughter board |
D1 | nRST |
D2 | CLK |
D3 | Socket card presence contactor |
Scaffold peripherals¶
I/Os¶
The Scaffold Python API allows controlling and reading the I/Os of the board. This can be useful, for instance, to control the reset signal of a device under test. The following example shows how easy this can be done.
# Toggle D0 every second.
for i in range(10):
scaffold.d0 << 0
time.sleep(1)
scaffold.d0 << 1
time.sleep(1)
# Put D0 in high impedance state
scaffold.d0 << None
time.sleep(1)
# Connect the output to the internal UART peripheral TX signal, and send a
# message !
scaffold.d0 << scaffold.uart0.tx
scaffold.uart0.send('Hello world!')
It is also possible to read the current electrical state of an input of the board:
if scaffold.d0.value == 1:
print('Input is high!')
Finally, you can watch for events on an input. The event will be asserted if a 1 is detected. This works for short pulses (> 10 ns).
# Reset event flag
scaffold.d0.event = 0
# Wait some time
time.sleep(1)
# Lookup event register to know if a pulse has been received
if scaffold.d0.event == 1:
print('Event detected!')
scaffold.d0.clear_event()
Warning
I/Os internals have been refactored in 0.3. Registers are not the same as in 0.2. Current API supports both 0.2 and 0.3 versions.
Internal registers¶
a0 | 0xe000 |
a1 | 0xe010 |
b0 | 0xe020 |
b1 | 0xe030 |
c0 | 0xe040 |
c1 | 0xe050 |
dn | 0xe060 + 0x10 * n |
base + 0x0000 | value | R/W |
base + 0x0001 | config | W |
value register¶
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | event | value |
- value
- Reading this bit will return current logical state on the I/O. Setting this bit has no effect.
- event
- This bit is set to 1 when the I/O logical state changes. It can be reset by writing 0 to it.
config register¶
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | mode |
This register allows customizing the output mode of an I/O.
mode | Description |
0 | Auto The pin is driven by the routed peripheral. |
1 | Open-drain The pin is driven by the routed peripheral, but always acts as an open-collector. |
2 | Push-only The pin is driven by the routed peripheral, but is active only when a one is outputed. |
Power module¶
The power module controls two power supplies: the “platform” socket power supply and the “dut” socket power supply. Each power supply can be turned on and off.
A positive input pulse on the “tearing” input of the board (SMA connector on the left side) will automatically power-off both power supplies.
Python API example¶
# Turn DUT on
scaffold.power.dut = 1 # True is also valid
# Check current power supply status
# (it may be off due to external tearing)
if scaffold.power.dut: # Will return 0 or 1
print('DUT is still ON')
# Turn DUT off
scaffold.power.dut = 0 # False is also valid
The following example controls both power supplies at the same time.
# Turn on all power supplies
scaffold.power.all = 0b11
# Check current power status of both power supplies
if (scaffold.power.all == 0b11):
print('Both power supplies are ON')
# Turn off all power supplies
scaffold.power.all = 0b00
It is also possible to output the power enable signal to one of the IOs, for triggering or monitoring:
scaffold.d0 << scaffold.power.dut_trigger
For more API documentation, see scaffold.Power
Internal registers¶
control | 0x0600 |
control register¶
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | platform | dut |
- dut
- Write 1 to enable the DUT socket power supply. Write 0 to disable. This bit is cleared when the tearing input is high.
- platform
- Write 1 to enable the platform socket power supply. Write 0 to disable. This bit is cleared when the tearing input is high.
LEDs module¶
The LEDs module allows controlling the LEDs of the board.
Python API example¶
# Adjust LEDs brightness
# 0 is minimum
# 1 is maximum
scaffold.leds.brightness = 0.5
# Toggle a LED every second
scaffold.leds.d0.mode = LEDMode.VALUE
for i in range(10):
time.sleep(1)
scaffold.d0 << 1
time.sleep(1)
scaffold.d0 << 0
# Now flash the LED every second
scaffold.leds.d0.mode = LEDMode.EVENT
for i in range(10):
time.sleep(1)
scaffold.d0 << 1
time.sleep(1)
scaffold.d0 << 0
LEDs mode¶
A/B/C/D LEDs can be lit according to two different modes:
- Event mode: the LED will flash when an rising or falling edge occurs on the monitored signal. This is the default mode. This mode allows seeing activity on the LED even when very short pulses happen.
- Value mode: the LED is ON when the monitored signal is high. When using this mode, a user may not be able to catch very short pulses. This mode is more appropriate for watching slow signals.
Registers¶
0x0200 | control | W |
0x0201 | brightness | W |
0x0202 | leds_0 | W |
0x0203 | leds_1 | W |
0x0204 | leds_2 | W |
0x0205 | mode | W |
control register¶
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | override | disable |
- disable
- Write 1 to disable TLC5927 drivers output. Default is 0 (enabled).
- override
- Sets the LEDs of the board to the values defined in led_n registers.
brightness registers¶
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | brightness |
- brightness
- 7-bits word which controls the brightness of the LEDs. See TLC5952 datasheet for more details.
leds_n registers¶
leds_n registers define the state of the LEDs of the board when override bit is set. Set a bit to 1 to turn the corresponding LED on, 0 to turn it off. Value on reset is 0x00.
mode register¶
23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
reserved | d5 | d4 | d3 | d2 | d1 | d0 | c1 | c0 | b1 | b0 | a1 | a0 | reserved |
mode register is a 24-bit register. Write three times to update all the bits of this register.
Each bit of this register sets the lighting mode of a LED. When bit is 0, the corresponding LED will blink on a falling or rising edge of the monitored signal. When the bit is 1, the LED will be lit as long as the monitored signal is high. Default mode is 0 (event mode) for all LEDs.
Version module¶
This module helps the software identifying the board. When
scaffold.Scaffold
connects to the board, the version string is
automatically queried and cached in the version attribute.
Python API example¶
# Read cached version string
# Shall return something like 'scaffold-1.0'
print(scaffold.version)
Python API¶
Main Scaffold API¶
This page documents the main classes and methods of the Scaffold Python API.
Manipulating the attributes of the different modules of a Scaffold
instance will read or write in the FPGA registers. Some registers may be cached
by the Python API, so reading them does not require any communication with the
board and thus can be fast.
-
class
scaffold.
Scaffold
(dev='/dev/scaffold')¶ This class connects to a Scaffold board and provides access to all the device parameters and peripherals.
Variables: - uarts – list of
scaffold.UART
instance managing UART peripherals. - i2cs – list of
scaffold.I2C
instance managing I2C peripherals. - iso7816 –
scaffold.ISO7816
instance managing the ISO7816 peripheral. - pgens – list of four
scaffold.PulseGenerator
instance managing the FPGA pulse generators. - power –
scaffold.Power
instance, enabling control of the power supplies of DUT and platform sockets. - leds –
scaffold.LEDs
instance, managing LEDs brightness and lighting mode. - [a0,a1,b0,b1,c0,c1,d0,d1,d2,d3,d4,d5] –
scaffold.Signal
instances for connecting and controlling the corresponding I/Os of the board.
-
__init__
(dev='/dev/scaffold')¶ Create Scaffold API instance.
Parameters: dev – If specified, connect to the hardware Scaffold board using the given serial device. If None, call connect method later to establish the communication.
- uarts – list of
-
class
scaffold.
Signal
(parent, path)¶ Base class for all connectable signals in Scaffold. Every
Signal
instance has a Scaffold board parent instance which is used to electrically configure the hardware board when twoSignal
are connected together.-
__init__
(parent, path)¶ Parameters: - parent – Scaffold instance which the signal belongs to.
- path – Signal path string. Uniquely identifies a Scaffold board internal signal. For instance ‘/dev/uart0/tx’.
-
__lshift__
(other)¶ Feed the current signal with another signal.
Parameters: other – Another Signal
instance. The other signal must belong to the sameScaffold
instance.
-
__str__
()¶ Returns: Signal path. For instance ‘/dev/uart0/tx’.
-
name
¶ Signal name (last element of the path). For instance ‘tx’. Read-only.
-
path
¶ Signal path. For instance ‘/dev/uart0/tx’. Read-only.
-
-
class
scaffold.
IO
(parent, path, index)¶ Board I/O.
-
clear_event
()¶ Clear event register.
Warning: If an event is received during this call, it may be cleared without being took into account.
-
event
¶ I/O event register.
Getter: Returns 1 if an event has been detected on this input, 0 otherwise. Setter: Writing 0 to clears the event flag. Writing 1 has no effect.
-
mode
¶ I/O mode. Default is AUTO, but this can be overriden for special applications.
Type: IOMode
-
value
¶ Current IO logical state.
Getter: Senses the input pin of the board and return either 0 or 1. Setter: Sets the output to 0, 1 or high-impedance state (None). This will disconnect the I/O from any already connected internal peripheral. Same effect can be achieved using << operator.
-
-
class
scaffold.
GroupIO
(parent, path, index)¶ Board I/O in group A, B or C. Those I/Os are special since their operating voltage can be configured to either 3.3 V or 5.0 V by switching an on-board jumper. Voltage configuration applies to groups of I/Os, and as a side effect, all I/Os of a same group are in input only mode, or output only mode. This class allows setting the direction of the I/O and will check for conflicting configurations in a same group of I/Os.
-
dir
¶ Current I/O direction.
Getter: Returns IODir.INPUT
if the I/O is in input mode,IODir.OUTPUT
if the I/O is in output mode, or None if it is undecided (thus the mode will be the same as the other I/O of the same group).Setter: Changes the direction of the I/O. The API will verify that the new configuration does not conflict with the other I/O of the same group. Accepted values are IODir.INPUT
,IODir.OUTPUT
or None.
-
-
class
scaffold.
UART
(parent, index)¶ UART module of Scaffold.
-
baudrate
¶ Target UART baudrate.
Getter: Returns current baudrate, or None if no baudrate has been previously set during current session. Setter: Set target baudrate. If baudrate cannot be reached within 1% accuracy, a RuntimeError is thrown. Reading the baudrate attribute after setting it will return the real effective baudrate.
-
flush
()¶ Discard all the received bytes in the FIFO.
-
receive
(n=1)¶ Receive n bytes from the UART. This function blocks until all bytes have been received or the timeout expires and a TimeoutError is thrown.
-
reset
()¶ Reset the UART to a default configuration: 9600 bps, no parity, one stop bit, trigger disabled.
-
transmit
(data, trigger=False)¶ Transmit data using the UART.
Parameters: - data – Data to be transmitted. bytes or bytearray.
- trigger – True or 1 to enable trigger on last byte, False or 0 to disable trigger.
-
-
class
scaffold.
ISO7816
(parent)¶ ISO7816 peripheral of Scaffold. Does not provide convention or protocol management. See
scaffold.iso7816.Smartcard
for more features.-
clock_frequency
¶ Target ISO7816 clock frequency. According to ISO7816-3 specification, minimum frequency is 1 Mhz and maximum frequency is 5 MHz. Scaffold hardware allows going up to 50 Mhz and down to 195312.5 Hz (although this may not work with the smartcard).
Getter: Returns current clock frequency, or None if it has not been set previously. Setter: Set clock frequency. If requested frequency cannot be reached within 1% accuracy, a RuntimeError is thrown. Reading this attribute after setting it will return the real effective clock frequency.
-
empty
¶ True if reception FIFO is empty.
-
etu
¶ ISO7816 ETU parameter. Value must be in range [1, 2^11-1]. Default ETU is 372.
-
flush
()¶ Discard all the received bytes in the FIFO.
-
parity_mode
¶ Parity mode. Standard is Even parity, but it can be changed to odd or forced to a fixed value for testing purposes. :type: ISO7816ParityMode
-
receive
(n=1)¶ Receive bytes. This function blocks until all bytes have been received or the timeout expires and a TimeoutError is thrown.
Parameters: n – Number of bytes to be read.
-
reset_config
()¶ Reset ISO7816 peripheral to its default configuration.
-
transmit
(data)¶ Transmit data.
Parameters: data (bytes) – Data to be transmitted.
-
trigger_long
¶ Enable or disable long trigger (set on transmission, cleared on reception). When changing this value, wait until transmission buffer is empty.
Type: bool
-
trigger_rx
¶ Enable or disable trigger upon reception. :type: bool
-
trigger_tx
¶ Enable or disable trigger upon transmission. :type: bool
-
-
class
scaffold.
I2C
(parent, index)¶ I2C module of Scaffold.
-
clock_stretching
¶ Enable or disable clock stretching support. When clock stretching is enabled, the I2C slave may hold SCL low during a transaction. In this mode, an external pull-up resistor on SCL is required. When clock stretching is disabled, SCL is always controlled by the master and the pull-up resistor is not required.
Type: bool or int.
-
flush
()¶ Discards all bytes in the transmission/reception FIFO.
-
frequency
¶ Target I2C clock frequency.
Getter: Returns current frequency. Setter: Set target frequency. Effective frequency may be different if target cannot be reached accurately.
-
raw_transaction
(data, read_size, trigger=None)¶ Executes an I2C transaction. This is a low-level function which does not manage I2C addressing nor read/write mode (those shall already be defined in data parameter).
Parameters: - data (bytes) – Transmitted bytes. First byte is usually the address of the slave and the R/W bit. If the R/W bit is 0 (write), this parameter shall then contain the bytes to be transmitted, and read_size shall be zero.
- read_size (int) – Number of bytes to be expected from the slave. 0 in case of a write transaction.
- trigger (int or str.) – Trigger configuration. If int and value is 1, trigger is asserted when the transaction starts. If str, it may contain the letter ‘a’ and/or ‘b’, where ‘a’ asserts trigger on transaction start and ‘b’ on transaction end.
Raises: I2CNackError – If a NACK is received during the transaction.
-
read
(size, address=None, trigger=None)¶ Perform an I2C read transaction.
Parameters: address (int or None) – Slave device address. If None, self.address is used by default. If defined and addressing mode is 7 bits, LSB must be 0 (this is the R/W bit). If defined and addressing mode is 10 bits, bit 8 must be 0. Returns: Bytes from the slave. Raises: I2CNackError – If a NACK is received during the transaction.
-
reset_config
()¶ Reset the I2C peripheral to a default configuration.
-
write
(data, address=None, trigger=None)¶ Perform an I2C write transaction.
Parameters: address (int or None) – Slave device address. If None, self.address is used by default. If defined and addressing mode is 7 bits, LSB must be 0 (this is the R/W bit). If defined and addressing mode is 10 bits, bit 8 must be 0. Raises: I2CNackError – If a NACK is received during the transaction.
-
-
class
scaffold.
PulseGenerator
(parent, index)¶ Pulse generator module of Scaffold. Usually abreviated as pgen.
-
count
¶ Number of pulses to be generated. Minimum value is 1. Maximum value is 2^16.
-
delay
¶ Delay before pulse, in seconds. float.
-
fire
()¶ Manually trigger the pulse generation.
-
interval
¶ Delay between pulses, in seconds. float.
-
width
¶ Pulse width, in seconds. float.
-
-
class
scaffold.
LEDs
(parent)¶ LEDs module of Scaffold.
-
brightness
¶ LEDs brightness. 0 is the minimum. 1 is the maximum.
Type: float
-
disabled
¶ If set to True, LEDs driver outputs are all disabled.
-
override
¶ If set to True, LEDs state is the value of the leds_n registers.
-
reset
()¶ Set module registers to default values.
-
-
class
scaffold.
Power
(parent)¶ Controls the platform and DUT sockets power supplies.
-
all
¶ All power-supplies state. int. Bit 0 corresponds to the DUT power supply. Bit 1 corresponds to the platform power-supply. When a bit is set to 1, the corresponding power supply is enabled. This attribute can be used to control both power supplies simultaneously.
-
dut
¶ DUT power-supply state. int.
-
platform
¶ Platform power-supply state. int.
-
STM32 API¶
This API is for STM32 experimental daughter boards.
-
class
scaffold.stm32.
STM32
(scaffold)¶ Class for instrumenting STM32 devices using Scaffold board and API. The following Scaffold IOs are used:
- D0: STM32 UART MCU RX pin, Scaffold UART TX
- D1: STM32 UART MCU TX pin, Scaffold UART RX
- D2: STM32 NRST pin for reset
- D6: STM32 BOOT0 pin
- D7: STM32 BOOT1 pin
The uart0 peripheral of Scaffold board is used for serial communication with the ST bootloader.
This class can communicate with the ST bootloader via USART1. This allows programming the Flash memory and then execute the loaded code.
-
__init__
(scaffold)¶ Parameters: scaffold – An instance of scaffold.Scaffold
which will be configured and used to communicate with STM32 daughter board.
-
assert_device
()¶ Raise a RuntimeError is device is unknown (None).
-
checksum
(data)¶ Calculate the checksum of some data, according to the STM32 bootloader protocol.
Parameters: data – Input bytes. Returns: Checksum byte. This is the XOR of all input bytes.
-
command
(index)¶ Send a command and return the response.
Parameters: index – Command index. Returns: Response bytes.
-
extended_erase
()¶ Execute the Extended Erase command to erase all the Flash memory of the device.
-
get
()¶ Execute the Get command of the bootloader, which returns the version and the supported commands.
-
get_id
()¶ Execute the Get ID command. The result is interpreted and the class will try to find information if the ID matches a known device.
-
go
(address, trigger=0)¶ Execute the Go command.
Parameters: - address – Jump address.
- trigger – 1 to enable trigger on command transmission.
-
read_memory
(address, length, trigger=0)¶ Tries to read some memory from the device. If requested size is larger than 256 bytes, many Read Memory commands are sent.
Parameters: - address – Memory address to be read.
- size – Number of bytes to be read.
- trigger – 1 to enable trigger on command transmission.
-
read_option_bytes
()¶ Read the option bytes of the device. The method get_id must have been called previously for device identification.
Returns: Memory content of ‘option_bytes’ section.
-
readout_protect
()¶ Execute the Readout Unprotect command.
-
readout_unprotect
()¶ Execute the Readout Unprotect command. If the device is locked, it will perform mass flash erase, which can be very very long.
-
startup_bootloader
()¶ Power-cycle and reset target device in bootloader mode (boot on System Memory) and initiate serial communication. The byte 0x7f is sent and the response byte 0x79 (ACK) is expected. If the device does not respond, a Timeout exception is thrown by Scaffold. The device will not respond if it is locked in RDP2 state (Readout Protection level 2).
-
startup_flash
()¶ Power-cycle and reset target device and boot from user Flash memory.
-
wait_ack
(tag=None)¶ Wait for ACK byte.
Parameters: tag – Tag which is set when NACKError are thrown. Useful for error diagnostic.
-
wait_ack_or_nack
()¶ Wait for ACK or NACK byte.
Returns: True if ACK has been received, False if NACK has been received.
-
write_memory
(address, data, trigger=0)¶ Write data to device memory. If target address is Flash memory, this function DOES NOT erase Flash memory prior to writing. If data size is larger than 256 bytes, many Write Memory commands are sent.
Parameters: - address – Address.
- data – Data to be written. bytes or bytearray.
- trigger – 1 to enable trigger on each command transmission.
ISO7816 API¶
This API provides support for ISO7816 support with Scaffold.
-
class
scaffold.iso7816.
Smartcard
(scaffold)¶ Class for smartcard testing with Scaffold board and API. The following IOs are used:
- D0: ISO7816 IO
- D1: ISO7816 nRST
- D2: ISO7816 CLK
- D3: Socket card contactor sense
scaffold.Scaffold
class has ISO7816 peripheral support, but it is very limited. This class adds full support to ISO7816 by managing ATR, convention convertion, etc.Variables: - atr (bytes) – ATR received from card after reset.
- convention (Convention) – Communication convention between card and terminal. Updated when first byte TS of ATR is received.
- protocols (set) – Communication protocols found in ATR. This set contains integers, for instance 0 if T=0 is supported, 1 if T=1 is supported…
-
__init__
(scaffold)¶ Configure a Scaffold board for use with smartcards. :param scaffold:
scaffold.Scaffold
instance.
-
apdu
(the_apdu, trigger='')¶ Send an APDU to the smartcard and retrieve the response.
Parameters: - the_apdu (bytes or str) – APDU to be sent. str hexadecimal strings are allowed,
but use should consider using the
apdu_str()
method instead. - trigger (str) – If ‘a’ is in this string, trigger is raised after ISO-7816 header is sent, and cleared when the following response byte arrives. If ‘b’ is in this string, trigger is raised after data field has been transmitted, and cleared when the next response byte is received.
Raises: ValueError – if APDU data is invalid.
Return bytes: Response data, with status word.
- the_apdu (bytes or str) – APDU to be sent. str hexadecimal strings are allowed,
but use should consider using the
-
apdu_str
(the_apdu)¶ Same as
apdu()
function, with str argument and return type for convenience.Parameters: the_apdu (str) – APDU to be sent, as an hexadecimal string. Return str: Response from the card, as a lowercase hexadecimal string without spaces.
-
find_info
()¶ Parse the smartcard ATR list database available at http://ludovic.rousseau.free.fr/softwares/pcsc-tools/smartcard_list.txt and try to match the current ATR to retrieve more info about the card.
The database file cannot be embedded in the library because it uses GPL and not LGPL license. On debian systems, this file is provided in the pcsc-tools package.
Returns: A list of str, where each item is an information line about the card. Return None if the ATR did not match any entry in the database.
-
inverse_byte
(byte)¶ Inverse order and polarity of bits in a byte. Used for ISO7816 inverse convention decoding.
-
receive
(n)¶ Use the ISO7816 peripheral to receive bytes from the smartcard, and apply direct or inverse convention depending on what has been read in the ATR.
Parameters: n – Number of bytes to be read.
-
reset
()¶ Reset the smartcard and retrieve the ATR. If the ATR is retrieved successfully, the attributes
atr
convention
andprotocols
are updated.Returns: ATR from the card. Raises: ProtocolError – if the ATR is not valid.
-
class
scaffold.iso7816.
Convention
¶ Possible ISO7816 communication convention. This is given by the first byte of the ATR returned by the card.
-
DIRECT
= 59¶
-
INVERSE
= 63¶
-
-
class
scaffold.iso7816.
ProtocolError
(message)¶ Exception raised when a protocol error between the terminal and the smartcard occurs.
Architecture¶
The following documentation describes in details the architecture of Scaffold. The targeted audience is the developer who wish fixing bugs in the architecture or extend its functionalities. Reading this documentation may help understanding what’s under the hood.
Communication protocol¶
General architecture¶
The FPGA has many embedded peripherals. Each peripheral has registers which can be read/written to receive/send data and perform actions. Each register is assigned a unique 16-bits address and is connected to the system data bus.
A bridge controller, inside the FPGA, controls the read and write operations on the system data bus. This controller can be driven by a host computer using the USB link, allowing the host computer to manipulate the registers connected to the system data bus.
Protocol¶
When connected to a host computer using a USB cable, the board is recognized as a USB-to-Serial device from FTDI manufacturer. Baudrate is 2 Mbits/s, with one stop bit and no parity check.
A very simple protocol is defined to perform read and write operations through the serial device. To perform an operation, the following data must be sent to Scaffold:
Command | 1 byte | Mandatory |
Address | 2 bytes | Mandatory |
Polling address | 2 bytes | When polling enabled |
Polling mask | 1 byte | When polling enabled |
Polling value | 1 byte | When polling enabled |
Size | 1 byte | When size enabled |
Data | N bytes | For write commands |
Bit 0 of command byte indicates if this is a read (0) or write (1) command. Bit 1 indicates if size parameter is present (1 to enable size). Bit 2 indicates if polling is requested for this command (1 to enable polling). All other bits must be set to zero, otherwise the command is considered invalid and Scaffold will enter error mode.
For write and read commands, a response is transmitted by the Scaffold board. This response starts by the data bytes (for register read commands) and terminates with a status byte. The status byte shall be equal to the size of the processed data. If a command times out during polling, the returned status byte will be lower than the size of the data.
Register polling¶
Read or write operations on registers can be conditioned to a given register
expected state. When polling is enabled, each read or write operation is
performed when the monitored register reaches a given value for some chosen
bits. Polling is enabled when bit 2 of command byte is 1. Read or write
operation is performed when (Register and Mask) = (Value and Mask)
.
Polling can be used for flow control when using a peripheral to process multiple bytes. For instance, when using a SPI peripheral, polling can be used to wait for incoming bytes.
The polled register can be different from the read or written register (two different addresses can be passed in the command parameters: address and polling address).
Polling timeout¶
Optionally, a timeout can be configured for polling operations. This is particularly useful if receiving bytes from a peripheral is not guaranteed. When the polling times out in a read operation, the remaining expected bytes are sent by the board as zero. When the polling times out in a write operation, the remaining bytes sent to the board are discarded by the bus bridge. The returned acknowledge byte indicates the number of successfully processed bytes and will be lower than the requested size in the command.
The timeout delay can be configured with a special command:
Command 0x08 | 1 byte | Mandatory |
Polling delay value | 4 bytes | MSB first |
No response is expected after this command. The new delay value will be applied for all the following commands. If the delay is set to zero, then the timeout is disabled (which is the default).
FPGA bus¶
The internal global bus connects all the peripherals together. This bus is controlled by the serial bridge which is connected to the host computer with the USB link. The bus can perform only two simple operations:
- Read a byte from a register,
- Write a byte to a register.
The bus works using many signals:
- 16-bits address: bus_address,
- Write assertion signal: bus_write
- 8-bits write data: bus_write_data,
- Read assertion signal: bus_read
- 8-bits read data: bus_read_data
Using different data wires for read and write operations makes conflicts between modules impossible. Also, some FPGA devices may not allow internal bidirectional wires.
All the signals of the bus are synchronized to the system clock, on rising edges.
Register write cycle¶
FPGA bus bridge¶
The bus bridge allows reading and writing bytes on the internal FPGA bus using commands sent in serial. This bridge is implemented in VHDL using a Finite State Machine. The state machine manages the commands parsing and execution.
The state machine has a lot of states and is a bit complex. However, the parsing and execution of a command is faster than the time required to receive an incoming new command - making it hard to saturate the commands queue. The only cases a command queue can be overflowed is when using polling commands - in such cases the application may wait for the response before sending further commands.
Overflowing the commands queue will usually lead to entering the error state as bytes will be discarded, resulting in data bytes being interpreted as invalid command codes. When in error state, the error LED on the board is lit. The only way to recover from the error state is pressing the reset button.
State machine¶
The following graph is the bus bridge finite state machine implemented in the FPGA. This document is an help for understanding FPGA internals.
![digraph {
graph [dpi = 55, bgcolor = "#ffffff00", fontname = "helvetica", fontsize = 16];
node [fontname = "helvetica", fontsize = 16, fixedsize = true, width = 0.8];
edge [fontname = "helvetica", fontsize = 12];
node [shape = doublecircle] CMD; ERR;
node [shape = circle];
CMD[group = g5];
CMD -> ADH [label = " data & rw_cmd"];
CMD -> ERR [label = " invalid command"];
ADH[group = g5];
ADH -> ADL [label = " data"];
ADL[group = g5];
ADL -> PADH [label = " data ∧\n has_polling"];
ADL -> SIZE [label = " data ∧\n ! has_polling"];
PADH[group = g6];
PADH -> PADL [label = " data"];
PADL[group = g6];
PADL -> PMSK [label = " data"];
PMSK[group = g6];
PMSK -> PVAL [label = " data"];
PVAL[group = g6];
PVAL -> SIZE [label = " data"];
SIZE[group = g5];
SIZE -> LOOP [label = " data ∨ ! has_size"];
RD[group = g1];
RD -> WAIT1 [label = " 1"];
WAIT1[label = "WAIT", group = g1];
WAIT1 -> SEND [label = " ready"];
SEND[group = g1];
SEND -> LOOP [label = " 1"];
VAL[group = g2];
VAL -> WR [label = " data"];
WR[group = g2];
WR -> LOOP [label = " 1"];
LOOP[group = g5];
LOOP -> P1 [label = " size ≠ 0"];
P1[group = g3];
P1 -> P2 [label = " 1"];
P2[group = g3];
P2 -> P3 [label = " 1"]
P3[group = g3];
P3 -> P4 [label = " poll_ok"]
P3 -> P1 [label = " ! poll_ok"]
P4[group = g3];
P4 -> RD [label = " read_command"];
P4 -> VAL [label = " write_command"];
LOOP -> WAIT2 [label = " size = 0"];
WAIT2[label = "WAIT", group = g4];
WAIT2 -> SEND2 [label = " ready"];
SEND2[label = "SEND", group = g4];
SEND2 -> CMD [label = " 1"];
TOC1 [group = g7]
CMD -> TOC1 [label = " data & timeout_config"]
TOC2 [group = g7]
TOC1 -> TOC2 [label = " data"]
TOC3 [group = g7]
TOC2 -> TOC3 [label = " data"]
TOC4 [group = g7]
TOC3 -> TOC4 [label = " data"]
TOC4 -> CMD
TO [group=g8]
P3 -> TO [label = " timeout"]
WAIT3[label="WAIT", group=g8]
WAIT3 [label="WAIT", group=g8]
TO -> WAIT3 [label = " read_command"]
SEND3 [label="SEND", group=g8]
WAIT3 -> SEND3 [label = " ready"]
SEND3 -> TO [label=" 1"]
POP4 [label="POP", group=g9]
TO -> POP4 [label=" write_command"]
POP4 -> TO [label=" data"]
TO -> WAIT2 [label=" size = 0"]
}](_images/graphviz-64264a116a0d79f969f6ea3969522e156eb9078d.png)
Details on states:
CMD
: Idle state, awaiting for command byte.ADH
: Awaiting for read/write address high nibble.ADL
: Awaiting for read/write address low nibble.PADH
: Awaiting for polling address high nibble.PADL
: Awaiting for polling address low nibble.PMSK
: Awaiting for polling mask.PVAL
: Awaiting for polling value.SIZE
: Read/write size fetch. If the command does not require size parameter, use 1. Otherwise, wait and store next byte received on UART.LOOP
: Preload polling address on the bus for P1 and P2 states. Return to initial state if all bytes have been read or written.WAIT
: Wait for UART to be ready to transmit a byte. This also acts as a delay cycle required for data bus to be available (due to pipelining).SEND
: Send result byte on UART (command acknowledge or register value).P1
: First polling state. Assert bus read signal. Due to pipelining, the data read from the bus is available to the rest of the logic atP2
.P2
: Second polling state. Used for pipelining (registers the data read from the bus).P3
: Polling test. If polling value matches, leave polling by going toP4
. Otherwise, return toP1
for a new polling read cycle.P4
: End of polling. Load register address on the bus.RD
: Register read cycle.VAL
: Read from UART the byte to be written in register.WR
: Register write cycle.TO
: Timeout state. Loops until all unprocessed bytes have been discarded (write operation) or returned as zeros (read operation).POP
: Cycle used to discard a byte from the input FIFO during a write operation which has timed out.
Details on transition conditions:
1
: Unconditionally pass to the next state at the next clock cycle.data
: True when the UART FIFO has a byte available.size
: Number of remaining bytes to be read or written.ready
: True when the UART of the bus bridge is ready to transmit a byte.read_command
: True when the fetched command byte corresponds to a bus read cycle command.write_command
: True when the fetched command byte corresponds to a bus write cycle command.
Polling timeout configuration¶
A special command bit allows reconfiguring the polling timeout delay. The delay parameter is stored in an internal 32 bits register and encodes a number of clock cycles to wait during polling state (1 unit equals to 3 clock cycles). When this register is set to 0, the timeout is disabled. Note that disabling the timeout is not recommended since the FSM may stuck in a polling operation forever or until general reset.
The maximum possible timeout duration is approximately 128 seconds.
Output module¶
The available I/Os of the scaffold board can be internally connected to any module output. The “right matrix” controls which module output signals are connected to which I/Os. Each I/O has a register storing its multiplexer selecting the source signal.
Multiplexers selection table¶
Index | Signal name |
---|---|
0 | z |
1 | 0 |
2 | 1 |
3 | /power/dut_trigger |
4 | /power/platform_trigger |
5 | /uart0/tx |
6 | /uart0/trigger |
7 | /uart1/tx |
8 | /uart1/trigger |
9 | /iso7816/io_out |
10 | /iso7816/clk |
11 | /iso7816/trigger |
12 | /pgen0/out |
13 | /pgen1/out |
14 | /pgen2/out |
15 | /pgen3/out |
Building and flashing the FPGA bitstream¶
Advanced users may want to modify the architecture of the FPGA of Scaffold to support more peripherals, implement new features or even fix bugs. This section briefly describe how to build the FPGA bitstream with Intel (Altera) tools, and flash the board.
Prerequisites¶
Quartus II software from Intel (Altera) must be used to build the FPGA bitstream. The version of Quartus must have support for Cyclone IV devices; version 14.1 can be used. Although Quartus is a proprietary tool, the free Quartus Web Edition can be used and shall not require any license. Quartus can run on linux and Windows (but we did not give a try on Windows).
For flashing the FPGA, a programmer supporting Active Serial mode must be used. Altera USB Blaster is a good one.
Building the bitstream¶
Under Quartus software, load the fpga-arch/scaffold.qpf
project file with
the File > Open Project menu. Build the design with Start context-menu of
Compile Design task as highlighted below.

Hopefully the compilation should succeed. If you modified the original design, we recommand you to check in the compilation report that the max frequency of the system clock of the compiled design is at least 110 MHz (100 MHz plus some security margin). If this constraint is not respected, then your design may not work properly and need to be optimized.

Flashing the FPGA¶
Power-on the board and connect the programmer as shown below:

In Quartus, open the programmer window with the Tools > Programmer menu.
- Setup your programmer with the Hardware Setup button.
- Switch to Active Serial Programming mode.
- Click on Add File… and select the file
confware.pof
. The setup shall represent an EPCS16 device, which is the on-board Flash memory storing the bitstream and read by the FPGA when powering-up Scaffold. - Check the Program/Configure and Verify boxes.
- Click on the Start button.
Remove the programmer cable to test your new design!
