API Interface
The API interface is managed over the X2CScope class.
Simplest example
1"""The simplest usage of the pyX2Cscope library.
2
3The script initializes the X2CScope class with a specified serial port and ELF file,
4retrieves specific variables, reads their values, and writes new values to them.
5"""
6
7from pyx2cscope.x2cscope import X2CScope
8
9# initialize the X2CScope class with serial port, by default baud rate is 115200
10x2c_scope = X2CScope(port="COM8")
11# instead of loading directly the elf file, we can import it after instantiating the X2CScope class
12x2c_scope.import_variables(r"..\..\tests\data\qspin_foc_same54.elf")
13
14# Collect some variables.
15speed_reference = x2c_scope.get_variable("motor.apiData.velocityReference")
16speed_measured = x2c_scope.get_variable("motor.apiData.velocityMeasured")
17
18# Read the value of the "motor.apiData.velocityMeasured" variable from the target
19print(speed_measured.get_value())
20# Write a new value to the "motor.apiData.velocityReference" variable on the target
21speed_reference.set_value(1000)
Further examples in the repository: https://github.com/X2Cscope/pyx2cscope/tree/main/pyx2cscope/examples
X2CScope class
Import the X2Cscope class:
from pyx2scope import X2CScope
X2CScope class needs one parameter to be instantiated:
port: The desired communication port name, i.e.:”COM3”, “dev/ttyUSB”, etc.
X2CScope will support multiple communication interfaces. Currently, only Serial is supported: CAN, LIN, and TCP/IP are coming in near future. For serial, the only parameter needed is the desired port name, by default baud rate is set to 115200. If there’s a need to change the baud rate, include the baud_rate parameter with your preferred baud rate.
Instantiate X2CScope with the port:
x2c_scope = X2CScope(port="COM16")
Import variables
X2Cscope needs the location of the variables inside the controller firmware. The list of variables can be loaded from multiple sources: .elf file, pickle binary and YML text file.
See more details at Import and Export variables section.
x2c_scope.import_variables(r"..\..\tests\data\qspin_foc_same54.elf")
Variable class
X2CScope class handles variables, either for retrieving and writing values as well for plotting graphics. The next step is to get a variable object that will represent the variable inside the microcontroller. Use the method get_variable to link to a desired variable. The only parameter needed for that method is a string containing the variable name.
Create a Variable object for the variable you want to monitor:
variable = x2c_scope.get_variable('variable_name')
Replace ‘variable_name’ with the name of the variable you want to monitor. You can create multiple variable objects as required. To get variables that are underneath a struct, use the “dot” convention: “struct_name.variable”. It is only possible to link to final variables, i.e., it is not possible to link to a structure directly, only to its members.
Reading values
4. Once you have gone through these steps, you can use the method get_value() to retrieve the actual value of the variable:
variable.get_value()
Writing values
To set the value for the respective variable use the method set_value():
variable.set_value(value)
Import and Export variables
Easiest way to assembly a variable list is to import it from an elf file. The elf file is the output of the firmware compilation and contains all the information about the variables, their addresses, and sizes. Once the list of variables are available from the elf file, it can be exported to a pickle binary file or a YML text file. It is possible to export selected variables or the whole list of variables. Having the exported file (yml or pickle) it is possible to import it back to the X2CScope object. YML is human readable and can be edited with any text editor, while pickle is a binary file and can be used to store the variables in a more secure way.
See the example below:
1"""Example of importing and exporting variable.
2
3The script initializes the X2CScope class with a specified serial port,
4retrieves specific variables, reads their values, export them to a yaml file
5and also export all the variables available as a pickle binary file.
6
7We define a new instance of X2Cscope, and we reload the variables over the exported
8files instead of the elf file.
9"""
10import os
11
12from pyx2cscope.x2cscope import X2CScope
13from pyx2cscope.variable.variable_factory import FileType
14
15# initialize the X2CScope class with serial port, by default baud rate is 115200
16com_port = "COM32"
17x2c_scope = X2CScope(port=com_port)
18# instead of loading directly the elf file, we can import it after instantiating the X2CScope class
19x2c_scope.import_variables(r"..\..\tests\data\qspin_foc_same54.elf")
20
21# Collect some variables, i.e.: from QSPIN on SAME54 MCLV-48V-300W
22angle_reference = x2c_scope.get_variable("mcFocI_ModuleData_gds.dOutput.elecAngle")
23speed_measured = x2c_scope.get_variable("mcFocI_ModuleData_gds.dOutput.elecSpeed")
24
25# Read the value of the "motor.apiData.velocityMeasured" variable from the target
26print(speed_measured.get_value())
27
28# you can export only these two variables as yaml file (plain text)
29x2c_scope.export_variables(filename="my_two_variables", items=[angle_reference, speed_measured])
30# you can export all the variables available. For a different file format, define 'ext' variable, i.e. pickle (binary)
31x2c_scope.export_variables(filename="my_variables", ext=FileType.PICKLE)
32
33# disconnect x2cscope so we can reconnect with another instance
34x2c_scope.disconnect()
35
36# Instantiate a different X2Cscope to ensure we have an empty variable list, i.e. x2c
37x2c = X2CScope(port=com_port)
38# instead of loading the elf file, we load our exported file with all variable
39x2c.import_variables("my_variables.pkl")
40# or we can load only our two variables
41# x2c.import_variables("my_two_variables.yml")
42# or we can load our elf file again
43# x2c.import_variables(filename=r"..\..\tests\data\qspin_foc_same54.elf")
44
45# Collect some variables, i.e.: from QSPIN on SAME54 MCLV-48V-300W
46angle_ref2 = x2c.get_variable("mcFocI_ModuleData_gds.dOutput.elecAngle")
47speed_ref2 = x2c.get_variable("mcFocI_ModuleData_gds.dOutput.elecSpeed")
48
49# Read the value of the "speed_ref2" variable from the target
50print(speed_ref2.get_value())
51
52# housekeeping
53os.remove("my_variables.pkl")
54os.remove("my_two_variables.yml")
55
Scope Channel
X2CScope class provide means to retrieve scope data, i.e., instead of getting the current value of a variable, collect the values during a time frame, triggering according some trigger values or not, and return and array that could be plotted with any available python graphic framework as matplotlib, seaborn, etc.
1. To use the scope functionality, first you need to link a variable as previously explained, and add this variable to the scope by means of the method: add_scope_channel(variable: Variable) :
variable1 = x2c_scope.get_variable("variable1") variable2 = x2c_scope.get_variable("variable2") x2c_scope.add_scope_channel(variable1) x2c_scope.add_scope_channel(variable2)
2. To remove a variable from the scope: remove_scope_channel(variable: Variable), to clear all variables and reset the scope use instead: clear_all_scope_channel()
x2c_scope.remove_scope_channel(variable2)
or
x2c_scope.clear_all_scope_channel()
Up to 8 channels can be added. Each time you add or remove a variable, the number of channels present on the channel are returned.
Getting Data from Scope
To get data from scope channel you need to follow this sequence:
Request data
- Check if data is ready (sampling is done)
Data is ready? Yes, get the data and handle it.
Data is not ready? Execute some delay and check again.
After handling the data, start from the beginning requesting new data.
Step-by-step you need:
Request to X2CScope to collect data for the variables registered on the scope channels.
x2c_scope.request_scope_data()
2. Check if the data is ready: Returns Scope sampling state. Returns: true if sampling has completed, false if it’s yet in progress.
while not x2c_scope.is_scope_data_ready(): time.sleep(0.1)
Get the scope data once sampling is completed
data = x2c_scope.get_scope_channel_data()
A simple loop request example to get only 1 frame of scope data is depicted below:
# request scope to start sampling data x2c_scope.request_scope_data() # wait while the data is not yet ready for reading while not x2c_scope.is_scope_data_ready(): time.sleep(0.1) for channel, data in x2c_scope.get_scope_channel_data().items(): # Do something with the data. # channel contains the variable name, data is an array of values
Triggering
To Set up Trigger, any available variable can be selected, by default works on no trigger configuration. To set any trigger configuration, you need to pass a TriggerConfig imported from from pyx2cscope.x2cscope
trigger_config = TriggerConfig(Variable, trigger_level: int, trigger_mode: int, trigger_delay: int, trigger_edge: int) x2cscope.set_scope_trigger(trigger_config)
TriggerConfig needs some parameters like the variable and some trigger values like:
Variable: the variable which will be monitored
Trigger_Level: at which level the trigger will start executing
Trigger_mode: 1 for triggered, 0 for Auto (No trigger)
Trigger_delay: Value > 0 Pre-trigger, Value < 0 Post trigger
Trigger_Edge: Rising (1) or Falling (0)
Additional information on how to change triggers, clear and change sample time, may be found on the API documentation.