At first sight, micropython is seemingly unable to guarantee realtime execution of two subsequent lines of code, which is crucial for exact timing sequences. Random time delays occur between the exectution, possibly to micropython higher priority interrupts, garbage collection and USB console.
This can be illustrated on the following example:
I am creating two timers, 1 and 8, each with exactly same parameters and observing both on oscilloscope.
The aim is to get them in sync.
It seems there is no way from current micropython to get them into sync.
Code: Select all
clk_src = pyb.freq()[2]*2
clk_freq=0.01 # kHz
t1_n=1 # timer 1
t2_n=8 # timer 2
t1_freq=clk_freq*1000*2
t2_freq=clk_freq*1000*2
t1_ch=2
t2_ch=3
t1 = pyb.Timer(t1_n, freq=t1_freq, mode=pyb.Timer.UP, deadtime=256)
#t2 = pyb.Timer(t2_n, freq=t2_freq, mode=pyb.Timer.UP, div=1, , deadtime=2)
t2 = pyb.Timer(t2_n, freq=t2_freq, mode=pyb.Timer.UP, div=1)
ch1 = t1.channel(t1_ch, pyb.Timer.PWM, pin=pyb.Pin.board.B0, pulse_width=(t1.period() + 1) // 2)
ch2 = t2.channel(t2_ch, pyb.Timer.PWM_INVERTED, pin=pyb.Pin.board.B1, pulse_width=(t2.period() + 1) //2)
What is the easiest way to synchronise two timers?
I have found the following in micropython STM HAL drivers in C:
Code: Select all
#define __TIM1_CLK_ENABLE() (RCC->APB2ENR |= (RCC_APB2ENR_TIM1EN))
#define __TIM1_CLK_DISABLE() (RCC->APB2ENR &= ~(RCC_APB2ENR_TIM1EN))
- or alternatively, how can this be implemented in micropython assembler?
I have found ARM THUMB assembly functions for enabling / disabling RCC timer peripherals, but am lost in translation into
@micropython.asm_thumb
Here is the relevant ASM THUMB code :
Code: Select all
791 /**
// 792 * @brief Enables or disables the Low Speed APB (APB1) peripheral clock.
// 793 * @param RCC_APB1Periph: specifies the APB1 peripheral to gates its clock.
// 794 * This parameter can be any combination of the following values:
// 795 * RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4,
// 796 * RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7,
// 797 * RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14,
// 798 * RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3,
// 799 * RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_UART4,
// 800 * RCC_APB1Periph_UART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2,
// 801 * RCC_APB1Periph_I2C3, RCC_APB1Periph_CAN11, RCC_APB1Periph_CAN12,
// 802 * RCC_APB1Periph_PWR, RCC_APB1Periph_DAC
// 803 * @param NewState: new state of the specified peripheral clock.
// 804 * This parameter can be: ENABLE or DISABLE.
// 805 * @retval None
// 806 */
SECTION `.text`:CODE:NOROOT(1)
CFI Block cfiBlock24 Using cfiCommon0
CFI Function RCC_APB1PeriphClockCmd
THUMB
// 807 void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
// 808 {
// 809 /* Check the parameters */
// 810 assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph));
// 811 assert_param(IS_FUNCTIONAL_STATE(NewState));
// 812 if (NewState != DISABLE)
RCC_APB1PeriphClockCmd:
UXTB R1,R1 ;; ZeroExt R1,R1,#+24,#+24
CMP R1,#+0
BEQ.N ??RCC_APB1PeriphClockCmd_0
// 813 {
// 814 RCC->APB1ENR |= RCC_APB1Periph;
LDR.N R1,??DataTable43_22 ;; 0x40023840
LDR R1,[R1, #+0]
ORRS R0,R0,R1
LDR.N R1,??DataTable43_22 ;; 0x40023840
STR R0,[R1, #+0]
B.N ??RCC_APB1PeriphClockCmd_1
// 815 }
// 816 else
// 817 {
// 818 RCC->APB1ENR &= ~RCC_APB1Periph;
??RCC_APB1PeriphClockCmd_0:
LDR.N R1,??DataTable43_22 ;; 0x40023840
LDR R1,[R1, #+0]
BICS R0,R1,R0
LDR.N R1,??DataTable43_22 ;; 0x40023840
STR R0,[R1, #+0]
// 819 }
// 820 }
??RCC_APB1PeriphClockCmd_1:
BX LR ;; return
CFI EndBlock cfiBlock24