I observed the traces when instantiating the Picarx class.
To do this, I inserted “print” statements in a specific format.
The logs are formatted as follows:
" {format } ::= {Num_Line} {key} {level} {method name} { data} "
{Num_Line} ::= num line off log, not num line off code Python
{key} ::= “code” for using the Linux ‘grep’ function
{level} ::= The length of the underlines depends on the depth of the method calls
{method name} ::= PWM, I2C, ARR, PSC, SRVO, PICAR, etc
{data} ::= Information Sought
Example

By following the Python code for creating an instance of the Picarx class, the logs let you see what’s happening.
I’m interested in the part where the servo motors are declared (not the motors themselves, not the ultrasonic part, etc.)
Let’s start by instantiating the Picarx class.

- Line 0 to 1: Instantiation of the Picarx class for the “P0” servo motor
- Lines 2–3: Instantiation of the Servo class for the “P0” servo motor, which will instantiate the PWM class for the “P0” servo, which in turn will call its freq() method
- Line 4 : Creation of the “timer” class variable
- Lines 5 and … : Determining the address of the I2C port on bus 1 → 0x14 found
- Lines 6 to 10 Call to the method self.freq( 50 )
Calculation of the prescaler and arr values
for the frequency self._freq == 50 Hz
The freq() method calls the prescaler() method, i.e., PSC
- Lines 11 to 13 Call (PCS) the method self.prescaler( 1200 )
- Lines 14 to 16 For canal “P0” timer_index === 0
Therefore, timer[0][arr] === 1
This will result in a rather surprising calculation for
the variable self._freq - Line 17 Frequency calculation: self._freq == 60000 Hz
That makes sense, since timer[0][arr] should be equal to 1200 as
calculated previously, not one
- Line 18 … Storing the value of (prescaler - 1) = (1200 - 1) == 1199 == 0x4AF in memory location 0x40
- Line 19 to 20 End of methode prescaler()
I have more data to provide, but I’m stuck because the editor won’t accept more than 5 documents linked to the text.
21 code_______FREQ:
22 code___________ARR
23 code___________ARR: -------- self.periode(arr=1200)
24 code___________ARR: timer_index=0
25 code___________ARR: timer = [{‘arr’: 1200}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]
26 code___________ARR: timer[self.timer_index][arr] = 1200
27 code_______I2CW: _i2c_write(reg=0x44, value=0x4b0)
code___________I2C-write( self, data=[68, 4, 176]==[0x44, 0x4, 0xb0, ]
28 code___________ARR: -------- self.periode( ) OUT
29 code___________ARR
30 code_______FREQ: -------- self.freq( ) OUT
31 code_______FREQ
32 code____PWM: ---------- pwm.init OUT ( )
33 code____PWM
- Line 21 Return to the freq() method and call the period() method (ARR)
- Line 22 to 23 The calculations will be based on the value arr=1200
- Lines 24 to 26 For canal “P0” timer_index === 0
Therefore, timer[0][arr] === 1200
This time, this value is consistent. - Lines 27 … Then writes this value to memory address 0x44
This method does not modify the variable self._freq - Lines 28 to 31 Return to the freq() method, and end of the freq() method
- Lines 32 to 32 End of the PWM class instantiation for channel “P0”
*At this point in the code, we return to the “init” method of the Servo class. The period(4095) method will be called.
*
34 code_SRVO: call self.period(self.PERIOD = 4095)
35 code___________ARR
36 code___________ARR: -------- self.periode(arr=4095)
37 code___________ARR: timer_index=0
38 code___________ARR: timer = [{‘arr’: 4095}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]
39 code___________ARR: timer[self.timer_index][arr] = 4095
40 code_______I2CW: _i2c_write(reg=0x44, value=0xfff)
code___________I2C-write( self, data=[68, 15, 255]==[0x44, 0xf, 0xff, ]
41 code___________ARR: -------- self.periode( ) OUT
42 code___________ARR
- Lines 34 to 36 Call the “periode” method (ARR), which will update the “timer” variable of the PWM class.
- Lines 37 to 39 For canal “P0” timer_index === 0
Therefore, timer[0][arr] === 4095
This time, this value is consistent.
But all the calculations made during the instantiation phase of the PWM class will be discarded, as we will see.Surprising, isn’t it? - Lines 40 … Then writes this value to memory address 0x44
This method does not modify the variable self._freq - Lines 41 to 42 Return to the “init” method of the Servo class
43 code_SRVO: self.ClOCK=72000000.0, self.FREQ=50, self.PERIOD=4095
44 code_SRVO: call self.prescaler(prescaler = 351.64835164835165)
45 code___________PSC
46 code___________PSC: -------- self.prescaler( prescaler=351.64835164835165 )
47 code___________PSC: self._prescaler = 352
48 code___________PSC: timer_index=0
49 code___________PSC: timer = [{‘arr’: 4095}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]
50 code___________PSC: timer[self.timer_index][arr] = 4095
51 code___________PSC: self._freq = 49.95004995004995 <?<?<?<?<?<?<?<?<?<?<?<? != 50
52 code_______I2CW: _i2c_write(reg=0x40, value=0x15f)
code___________I2C-write( self, data=[64, 1, 95]==[0x40, 0x1, 0x5f, ]
53 code___________PSC: -------- self.prescaler( ) OUT
54 code___________PSC
55 code_SRVO:----------Servo.init() OUT
56 code_SRVO
57 code_____PICAR: initialisation SERVO P1
- Lines 43 to 47 Using the three constants
self.ClOCK=72000000
self.FREQ=50,
self.PERIOD=4095
The prescaler calculation gives → prescaler = 351.64835164835165 - Lines 48 to 50 For canal “P0” timer_index === 0
Therefore, timer[0][arr] === 4095
This time, this value is consistent. - Line 51 Calculation of the value of the variable “_freq” = 49.95…Hz.
This value does not match 50 Hz, but that is normal since the value
of the variable “_prescaler” has been rounded.
Everything is consistent. - Lines 52 … Storing the value of (prescaler - 1) = (352 - 1) == 351 == 0x15F in memory location 0x40
- Lines 53 to 56 The Servo class has been instantiated for channel “P0”
- Line 57 The instantiation of the Picarx class continues by instantiating the Servo class for the “P1” channel.
For “P1” chanel, The process will be the same as the previous one.
There will be a new instance of the PWM class for “P1”, and everything
that was surprising will once again be just as surprising to me.
In summary:
- Why does instantiating the PWM class perform calculations that will be ignored, and which, moreover, introduce an error because timer[self.timer_index][arr] has not been initialised before the calculations of self._freq 50 Hz requested, 60KHz calculated.
- Why does the instantiation of the PWM class call the freq() method, rather than simply determining the active port on the I2C bus?
Leaving it up to the Servo or Motor class instance to choose the optimal calculation methods:
i.e self.period( ) or self.prescaler( ) or self.freq()


