The complete FTS project is documented on a github website: https://FirstTestStation.github.io/FTS_Website/
On this deposit, we have the firmware used to create the Master Pico load to control the interconnectIO board.
The hardware support for the firmware is on github location: https://github.com/FirstTestStation/InterconnectIO_Board
The Master Pico software is the earth of interconnectIO board. The software receive SCPI command from the serial port, execute the action requested by the command and return answer to the user.
This project is licensed under the BSD 3-Clause License. See the LICENSE file for more details.
This project was initially developed in 2020 on a Raspberry Pi 4, following the installation instructions from Getting Started with Pico_C.pdf Version 1.4.
The current version has been developed on a Raspberry Pi 5 using Visual Studio with the Raspberry Pi Pico extension, following the instructions in Getting Started with Pico_C.pdf dated 15 October 2024.
For debugging, we utilize a Pico board as debugger with a special software debug probe software (debugprobe_on_pico.uf2)
Initially based on https://github.com/cronologic-de/webusb, the project has evolved to be a complete SCPI instrument without frontend interface (next phase).
The compilation is performed using Visual Studio and the extension installed are:
- Raspberry Pi Pico Visual Studio Code extension 0.17.2
- Doxygen Documentation Generator v1.4.0
- Doxygen runner v1.8.0
Build of this cmake project is performed with Visual Studio
master.cis the main source file for the firmware.CMakeLists.txtcontains build instructions for CMake, including how to build the SCPI library.pico_sdk_import.cmakewas (as usual) copied verbatim from the Pico SDK and allows CMake to interact with the SDK’s functionality.
- When software loaded, the Pico board should be installed on the location marked MASTER on interconnectIO Board.
- On board Pico Led will flash slowly (heartbeat) on power ON.
- Loading new firmware will trigger the watchdog, resulting in a burst of beeps during the boot sequence to signal the watchdog timeout. Only cycling the power ON/OFF will reset the watchdog trigger flag.
The boot sequence performs basic diagnostics. A failure in the tests will result in a burst of beeps. The error codes are as follows:
- 1 Beep Burst: Master Pico's temperature is too high
- 2 Beep Burst: Master Pico's system voltage (VSYS) is out of limits
- 3 Beep Burst: Error in the internal I2C communication
- 4 Beep Burst: Error reading parameters from I2C EEPROM; default values will be used
- 5 Beep Burst: A watchdog timeout has occurred on the Master Pico.
The main communication for the InterconnectIO Board is based on the SCPI standard, developed by Jan Breuer [https://www.jaybee.cz/scpi-parser/]. According to the SCPI standard, some commands are mandatory, while others can be developed by the designer. In this section, we provide a list of the required SCPI commands as well as those developed specifically to control the InterconnectIO Board.
| SCPI_COMMAND | COMMENT |
|---|---|
| *IDN? | Identification string (Project, Hardware, PartNumber SN Serial Number, Version) |
| *RST | Reset Command |
| *CLS | Clear Status |
| *ESE | Standard Event Status Enable Register |
| *ESR | Standard Event Status Register |
| *OPC | Operation Complete |
| *SRE | Service Request Enable |
| *STB | Read Status Byte |
| *TST | Internal SelfTest |
| *WAI | Wait-to-Continue (Do nothing on this parser) |
| SYSTem:ERRor[:NEXT]? | Read actual error on the error FIFO |
| SYSTem:ERRor:COUNt? | read number of errors in the FIFO |
| SYSTem:VERSion? | read SCPI version used |
| STATus:QUEStionable[:EVENt]? | queries the event register (QUES) for the Questionable Data register |
| STATus:QUEStionable:CONDition? | queries the condition register (QUESC) for the Questionable Data register |
| STATus:QUEStionable:ENABle | set the status enable register (QUESE) for the Questionable Data register |
| STATus:QUEStionable:ENABle? | queries the status enable register (QUESE) for the Questionable Data register |
| STATus:OPERation[:EVENt]? | queries the event register (OPER) for the operation Data register |
| STATus:OPERation:CONDition? | queries the condition register (OPERC) for the operation Data register |
| STATus:OPERation:ENABle | set the status enable register (OPERE) for the operation Data register |
| STATus:OPERation:ENABle? | queries the status enable register (OPERE) for the operation Data register |
| SCPI_COMMAND | PARAMETER | COMMENT |
|---|---|---|
| ROUTe:CLOSe | (@<ch_list>) | Close relay based on number |
| ROUTe:CLOSe:EXCLusive | (@<ch_list>) | open relay already closed on the bank and close relay listed |
| ROUTe:CLOSe:Rev | {BANK1-BANK4} | Close reverse relay to move the contact from HIGH side to LOW side of differential relay |
| ROUTe:OPEN | (@<ch_list>) | Open relay from the channel list |
| ROUTe:OPEN:Rev | {BANK1-BANK4} | Open reverse relay to move the contact to HIGH side of differential relay |
| ROUTe:OPEN:ALL | {BANK1-BANK4|ALL} | Open all relays from a particular Bank or all relays from all banks |
| ROUTe:CHANnel:STATe? | (@<ch_list>) | Return state of the relay in the channel list, 0: open relay, 1: Close relay |
| ROUTe:BANK:STATe? | {BANK1-BANK4} | Read decimal value of relays state on the particular bank. Each bank is a byte long |
| ROUTe:REV:STATe? | {BANK1-BANK4} | Read contact side of reverse relay, LOW Side = 0, HIGH side = 1 |
| ROUTe:CLOSe:PWR | {LPR1|LPR2|HPR1|SSR1} | Close the designated power relay |
| ROUTe:OPEN:PWR | {LPR1|LPR2|HPR1|SSR1} | Open the designated power relay |
| ROUTe:STATe:PWR? | {LPR1|LPR2|HPR1|SSR1} | Read state of the power relay, 0: Open, 1:Closed |
| ROUTE:CLOSe:OC | {OC1|OC2|OC3} | Close or activate the designated open collector transistor |
| ROUTE:OPEN:OC | {OC1|OC2|OC3} | Open or deactivate the designated open collector transistor |
| ROUTE:STATe:OC? | {OC1|OC2|OC3} | Read state of the the designated open collector transistor, 0: Open, 1:Closed |
| DIGital:In:PORTn? | {0-1} | Read Decimal value of the designated digital port (port0: 8 bits, port1: 8 bits) |
| DIGital:In:PORTn:BITn? | {0-1} | Read value of the bit position at the designated port |
| DIGital:Out:PORTn | {0-1}{<value>} | At the designated digital port, set the output to the value (byte) |
| DIGital:Out:PORTn:BItn | {0-1} {0-7} {<value>} | At the designated digital port and the designated bit, set the output to the value |
| DIGital:DIRection:PORTn | {0-1}{|value|} | Set the direction of the designated port to the value (byte), 0: input, 1: output |
| DIGital:DIRection:PORTn:BITn | {0-1} {0-7} {<value>} | At the designated digital port and the designated bit, set the direction to the value |
| DIGital:DIRection:PORTn? | {0-1} | Read the direction value for the designated port |
| DIGital:DIRection:PORTn:BITn? | {0-1} {0-7} | Read the direction value for the designated port and the designated bit position |
| GPIO:DIRection:DEVice#:GP# | {0-3} {0-28} {0-1} | At the designated device and defined gpio number, set the direction to input (0) or output (1). DEVice0: Master_Pico (SCPI interpreter) DEVice1: Slave1_Pico (Digital Port 0 & 1) DEVice2: Slave2_Pico (relay bank 1 & 3) DEVice3: Slave3_Pico (relay bank 2 & 4) |
| GPIO:DIRection:DEVice#:GP#? | {0-3} {0-28} {0-1} | At the designated device and defined gpio number, read the direction to input (0) or output (1). |
| GPIO:Out:DEVice#:GP# | {0-3} {0-28} {0-1} | At the designated device and defined gpio number, set the output to the value. |
| GPIO:In:DEVice#:GP#? | {0-3} {0-28} | At the designated device and defined gpio number, read the value of the GPIO. |
| GPIO:SETPad:DEVice#:GP# | {0-3} {0-28} {<Value>} | At the designated device and defined gpio number, set the pad value. |
| GPIO:GETPad:DEVice#:GP#? | {0-3} {0-28} | At the designated device and defined gpio number,read the pad value. PAD REGISTER DEFINITION Bit 7: OD Output disable Bit 6: IE Input enable Bit 5:4 DRIVE Strength 0x0: 2mA, 0x1: 4mA, 0x2: 8mA, 0x3: 12mA Bit 3: PUE Pull up enable Bit 2: PDE Pull down enable Bit 1: SCHT Enable schmidt trigger Bit 0: SLF Slew rate control 1=fast 0 = slow |
| ANAlog:DAC:Volt | <value> | Set DAC output to the value |
| ANAlog:DAC:Save | <Value> | Save a default value for startup |
| ANAlog:ADC0:Volt? | Read Voltage at ADC input 0 | |
| ANAlog:ADC1:Volt? | Read Voltage at ADC input 1 | |
| ANAlog:ADC:Vsys? | Read system voltage from Pico Master | |
| ANAlog:ADC:Temp? | Read Pico Master internal temperature in Celsius | |
| ANAlog:PWR:Volt? | Read voltage at load using power monitoring device | |
| ANAlog:PWR:Shunt? | Read voltage at the shunt resistor (0.1 ohm) using power monitoring device | |
| ANAlog:PWR:Ima? | Read current(mA) passing in the shunt resistor (calculation I = E/R) | |
| ANAlog:PWR:Pmw? | Read power(mW) at the load (calculation P = VI) | |
| ANAlog:PWR:Cal | <actualValue,expectedValue> | calibrate current(mA) on full range to get more precision |
| SYSTem:DEVice:VERSion? | Return firmware version of Pico for Master, Slave1, Slave2 and Slave3 | |
| SYSTem:BEEPer | Generate beep pulse | |
| SYSTem:LED:ERRor | {0|1|OFF|ON} | Manual control of the read error led |
| SYSTem:LED:ERRor? | Status of the error led | |
| SYSTem:OUTput | {0|1|OFF|ON} | Turn ON/OFF internal 5V available to UUT. |
| SYSTem:OUTput? | Read output status 0: OFF, 1: ON | |
| SYSTem:SLAves | {0|1|OFF|ON} | Turn ON/OFF Pico slaves controller (run signals) |
| SYSTem:SLAves? | 0: All Pico Slaves disabled, 1: All Pico Slaves enabled | |
| SYSTem:SLAves:STAtus? | read Pico device 'status byte' for slaves 1 to 3 | |
| SYSTem:TESTboard | {0-5} | Selftest execute from menu below 0 Input test number to execute (0 to exit) 1 Selftest using only selftest board, no check of onewire 2 Selftest run only if selftest board is installed, onewire validation 3 Selftest using selftest board and loopback connector 4 Selftest of instruments in manual mode using selftest board 5 Test of SCPI command,selftest board is required |
| CFG:Write:Eeprom:STR | 'varname string ,value string' | valid varname = 'partnumber': partnumber of the InterconnectIO board, default: '500-1000-010' 'serialnumber' : serial number of the InterconnectIO board, default: '00001' 'mod_option' : optional module installed on the InterconnectIO board, default: 'DAC,PWR' 'com_ser_speed' : baudrate used by the SCPI command serial port, default: '115200' 'com_ser_echo' : Serial port echo ON (1) or OFF (0), default: '0' 'pico_slaves_run' : flag to control the slaves RUN pin actuation. 0: Pico Slaves reset at each boot(disable USB), 1: Do not reset slaves at boot, default: '0' 'testboard_num' : partnumber of the selftest board written on the onewire device , default: '500-1010-020' |
| CFG:Write:Eeprom:Default | Special command to write all default value to eeprom | |
| CFG:Read:Eeprom:Full? | Special command to read all data on eeprom | |
| CFG:Read:Eeprom:STR? | 'varnames string' | Reads string value from the designated parameter |
| SCPI_COMMAND | PARAMETER | COMMENT |
|---|---|---|
| COM:OWire:Check? | <value> | value = Number of expected Onewire devices on a link, normally 1 or 2, Check if devices are detected |
| COM:OWire:Write | {String 64 chars maximum starting with 64bits lasered ROM} | example: 2D4CE282200000CC, SELFTEST, 500-1010-020, 000001, J1 |
| COM:OWire:Read? | [Nb of Onewire devices] | read string of all the 1-Wire devices on the link, specify number of onewire to be read |
| COM:INITialize:ENAble | {SPI|SERIAL|I2C} | Configure designated communication port |
| COM:INITialize:DISable | {SPI|SERIAL|I2C} | Configure designated communication port to GPIO |
| COM:INITialize:STATus? | {SPI|SERIAL|I2C} | Read if the designated communication is enable or disable |
| COM:SERIAL:WRITE | <svalues> | send string, don't wait for answer |
| COM:SERIAL:READ? | <svalues> | send string, wait for answer |
| COM:SERIAL:Baud | <value> | set baudrate speed |
| COM:SERIAL:Baud? | read baudrate speed | |
| COM:SERIAL:Protocol | <svalues> | exa: {N81 O72 E61 8N1 etc ..}. Three character to define protocol to be use |
| COM:SERIAL:Protocol? | read the used protocol | |
| COM:SERIAL:Handshake | {0|1|OFF|ON} | set the RTS-CTS handshake according to the value |
| COM:SERIAL:Handshake? | read value corresponding to the handshake state, 0: disabled, 1: enabled | |
| COM:SERIAL:Timeout | <values> | Timeout in ms (32bits), default is 1000 |
| COM:SERIAL:Timeout? | read value of the timeout | |
| COM:SPI:WRIte | <data> | Spi write data (byte if databit =8 or word if databits = 16) |
| COM:SPI:REAd:LENx? | <opt:register> | Spi read x bytes |
| COM:SPI:Baudrate | <value> | Set baudrate speed in Hz |
| COM:SPI:Baudrate? | read SPI speed in Hz | |
| COM:SPI:CS | <gpio> | Set Chipselect gpio,default is 5, valid num = {0,1,5,6,7,12,13,14,15,16,17} |
| COM:SPI:CS? | Get Chipselect gpio number | |
| COM:SPI:Databits | <value> | // number of data bits to read or write during SPI communication, normally 8 (byte long) or 16 (word long) |
| COM:SPI:Databits? | read databit value | |
| COM:SPI:Mode | {0|1|2|3|4|5|6|7} | Set SPI mode + ChipSelect toggle mode (0:End of transmit, 1: At each byte) mode 0: Cs=0, Cpol=0, CPha=0 mode 1: Cs=0, Cpol=0, Cpha=1 mode 2: Cs=0, Cpol=1, Cpha=0 mode 3: Cs=0, Cpol=1, Cpha=1 mode 4: Cs=1, Cpol=0, CPha=0 mode 5: Cs=1, Cpol=0, Cpha=1 mode 6: Cs=1, Cpol=1, Cpha=0 mode 7: Cs=1, Cpol=1, Cpha=1 |
| COM:SPI:Mode? | read mode number used | |
| COM:I2C:WRIte | <data> | Spi write data |
| COM:I2C:REAd:LENx? | <opt:register> | Spi read x bytes from optional register |
| COM:I2C:ADDRress | <Device address> | I2C Address to use to talk to the device |
| COM:I2C:ADDRress? | read address value | |
| COM:I2C:Baudrate? | read I2C speed in Hz | |
| COM:I2C:Baudrate | <value> | Set speed in Hz |
| COM:I2C:Databits | <value> | Number of databits to write or read. Normally 8 (bytes) or 16 (word) |
| COM:I2C:Databits? | read number of databits used on I2C communication |
| SCPI_COMMAND | COMMENT |
|---|---|
| ROUTe:CLOSe(@101) | Close relay 101, Signal on High side |
| ROUTe:CLOSe:EXC(@102) | open relay on bank1 (101) and close relay 102 |
| ROUTe:CLOSe (@108,115) | close relay 108 and 115, signal on low side |
| ROUTe:CLOSe (@100:104) | close relay 100,101,102,103, and 104 |
| ROUTe:OPEN:ALL BANK1,BANK2 | open relay on bank1 and bank2 |
| ROUTe:OPEN:ALL ALL | open relay on all banks |
| ROUTe:REV:STATe? BANK1 | read which side of diff relay we are connected (0 = H or 1 = L) |
| ROUTe:CHAN:STATe? (@100) | read relay state ( 0 = Open or 1 = close) |
| DIGital:DIRection:PORT0 #HFF | set the 8 bit of port0 to output ( 0 = in, 1 = out) |
| DIGital:Out:PORT1 #H55 | Write hex value 0x55 to port 1 |
| DIGital:DIRection:PORT1? | Read direction on port 1 for the 8 bits ( 0 = in, 1 = out) |
| DIGital:In:PORT0? | Read the 8 bits on port 0 |
| GPIO:DIRection:DEVice0:GP22 1 | Set gpio 22 on Device 0 (Master) to direction out (1 = out) |
| GPIO:Out:DEVice1:GP8 0 | Set gpio 8 on Device 1 (Slave_1) to 0 (0 = low level) |
| GPIO:In:DEVice2:GP9? | Read value of gpio 9 on device 2 (Slave_2) |
| GPIO:SETPad:DEVice3:GP22 | Set PAD value (8 bits) on gpio 22 on Device 3 (Slave_3) |
| GPIO:GETPad:DEVice1:GP8? | Read PAD value (8 bits) on gpio 8 on Device 1 (Slave_1) |
| SYSTem:BEEPer | Turn ON momentary the beeper |
| SYSTEM:DEVice:VERsion? | Read version of each Pico devices [0,1,2,3], return string ex: 1.0, 1.0, 1.0 1.0 |
| COM:1WIRE:WRITE "2D4CE282200000CC, SELFTEST,500-1010-020, 000001, J1" | Lasered ROM + Board#+ Serial + Location |
Relay bank 1 Differential: 10 @ 17 Single: 100 @ 107 (High) 108 @ 115 (Low)
Relay bank 2 Differential: 20 @ 27 Single: 200 @ 215 (High) 208 @ 215 (Low)
Relay bank 3 Differential: 30 @ 37 Single: 300 @ 315 (High) 308 @ 315 (Low)
Relay bank 4 Differential: 40 @ 47 Single: 400 @ 415 (High) 108 @ 415 (Low)
- Relay type are DPDT (Double Pole Double Throw). Relay could be connected in differential mode or configured in single ended mode
- Relay address used reflect the difference between the differential and single mode.
- Relay @10, @100 and @108 are the same physical relay.
- If relay @10 is closed, the high side of the relay (BK1_CH0_H) will be connected on high side of the common point (BK1_COM_H). The low side of the relay (BK1_CH0_L) will be connected on the low side of the common point (BK1_COM_L)
- If relay @100 is closed, the high side of the relay (BK1_CH0_H) will be connected on high side of the common point (BK1_COM_H). The low side of the relay (BK1_CH0_L) will be connected on the low side of the common point (BK1_COM_L)
- If relay @108 is closed, the high side of the relay (BK1_CH0_H) will be connected on low side of the common point (BK1_COM_L) because the reverse relay will be actuated on the same time of the relay @108. The low side of the relay (BK1_CH0_L) will be connected on the high side of the common point (BK1_COM_H)
- The 4 relay banks are identical and follow the same rules