Electronics > Microcontrollers

Wobbling signal generated by Output Compare output

(1/3) > >>

ppTRN:
Hi everyone,

I'm working on generating two signals: one that is in phase, and another that's delayed by 90° relative to a reference input signal. I am using an STM32F303K8.

The code technically works, but the output signals are unstable. I've attached a video showing the issue.

I’ve tried reorganizing the code to make it as efficient as possible, but unfortunately, I haven’t seen any improvement. I even considered implementing the logic in assembly, as mentioned in a previous thread, but that approach clearly isn’t feasible.

Has anyone encountered similar behavior? I understand I'm not working with a real-time processor or any high-end hardware, but a 400ns jitter at 72MHz suggests a timing uncertainty of about 30 clock cycles—which seems significant.

Could the issue be related to the PLL? I'm using a 6MHz crystal oscillator that's boosted to 72MHz. Or could it be tied to the code running inside the ISR? After all, 30 clock cycles can be consumed pretty quickly in there.

I'd really appreciate any insights or suggestions on how to improve this. Thanks in advance!

CODE THAT GENERATES THE TWO SQUARE WAVES:

--- Code: ---void TIM1_CC_IRQHandler(){

if(TIM1->SR & 1<<1){
TIM1->SR = ~(1<<1); // Clear flag
if(GPIOA->IDR & 1<<8) GPIOA->BSRR = 1<<(8+16); // Toggle pin
else GPIOA->BSRR = 1<<8;
TIM1->CCR1 = TIM1->CCR1 + TXpulseWidth/2; // Update compare match
}
else if(TIM1->SR & 1<<2){
TIM1->SR = ~(1<<2); // Clear flag
if(GPIOA->IDR & 1<<8) GPIOA->BSRR = 1<<(9+16); // Toggle pin
else GPIOA->BSRR = 1<<9;
TIM1->CCR2 = TIM1->CCR2 + TXpulseWidth/2; // Update compare match
}
}

--- End code ---


DISASSEMBLED CODE:

--- Code: ---0x08000A7C F6424010  MOVW          r0,#0x2C10
0x08000A80 F2C40001  MOVT          r0,#0x4001
    53:         if(TIM1->SR & 1<<1){
    54:                 TIM1->SR = ~(1<<1);                                                                      // Clear flag
    55:                 if(GPIOA->IDR & 1<<8)   GPIOA->BSRR = 1<<(8+16);   // Toggle pin
    56:                 else GPIOA->BSRR = 1<<8;
    57:                 TIM1->CCR1 = TIM1->CCR1 + TXpulseWidth/2;                            // Update compare match
    58:         }
0x08000A84 6801      LDR           r1,[r0,#0x00]
0x08000A86 0789      LSLS          r1,r1,#30
0x08000A88 F2400110  MOVW          r1,#0x10
0x08000A8C F6C40100  MOVT          r1,#0x4800
0x08000A90 D410      BMI           0x08000AB4
    59:         else if(TIM1->SR & 1<<2){
    60:                 TIM1->SR = ~(1<<2);                                                                      // Clear flag
    61:                 if(GPIOA->IDR & 1<<8)   GPIOA->BSRR = 1<<(9+16);   // Toggle pin
    62:                 else GPIOA->BSRR = 1<<9;
    63:                 TIM1->CCR2 = TIM1->CCR2 + TXpulseWidth/2;                            // Update compare match
    64:         }
0x08000A92 6802      LDR           r2,[r0,#0x00]
0x08000A94 0752      LSLS          r2,r2,#29
    65: }
0x08000A96 BF58      IT            PL
0x08000A98 4770      BX            lr
0x08000A9A F06F0204  MVN           r2,#0x04
    60:                 TIM1->SR = ~(1<<2);                                                                      // Clear flag
0x08000A9E F8402B28  STR           r2,[r0],#0x28
    61:                 if(GPIOA->IDR & 1<<8)   GPIOA->BSRR = 1<<(9+16);   // Toggle pin
    62:                 else GPIOA->BSRR = 1<<9;
    63:                 TIM1->CCR2 = TIM1->CCR2 + TXpulseWidth/2;                            // Update compare match
    64:         }
0x08000AA2 680A      LDR           r2,[r1,#0x00]
0x08000AA4 05D2      LSLS          r2,r2,#23
0x08000AA6 F04F7200  MOV           r2,#0x2000000
0x08000AAA BF58      IT            PL
0x08000AAC F44F7200  MOV           r2,#0x200
0x08000AB0 E00B      B             0x08000ACA
0x08000AB2 BF00      NOP           
0x08000AB4 F06F0202  MVN           r2,#0x02
    54:                 TIM1->SR = ~(1<<1);                                                                      // Clear flag
0x08000AB8 F8402B24  STR           r2,[r0],#0x24
    55:                 if(GPIOA->IDR & 1<<8)   GPIOA->BSRR = 1<<(8+16);   // Toggle pin
    56:                 else GPIOA->BSRR = 1<<8;
    57:                 TIM1->CCR1 = TIM1->CCR1 + TXpulseWidth/2;                            // Update compare match
    58:         }
    59:         else if(TIM1->SR & 1<<2){
    60:                 TIM1->SR = ~(1<<2);                                                                      // Clear flag
    61:                 if(GPIOA->IDR & 1<<8)   GPIOA->BSRR = 1<<(9+16);   // Toggle pin
    62:                 else GPIOA->BSRR = 1<<9;
    63:                 TIM1->CCR2 = TIM1->CCR2 + TXpulseWidth/2;                            // Update compare match
    64:         }
0x08000ABC 680A      LDR           r2,[r1,#0x00]
0x08000ABE 05D2      LSLS          r2,r2,#23
0x08000AC0 F04F7280  MOV           r2,#0x1000000
0x08000AC4 BF58      IT            PL
0x08000AC6 F44F7280  MOV           r2,#0x100
0x08000ACA 608A      STR           r2,[r1,#0x08]
0x08000ACC F2400280  MOVW          r2,#0x80
0x08000AD0 F2C20200  MOVT          r2,#0x2000
0x08000AD4 6801      LDR           r1,[r0,#0x00]
0x08000AD6 6812      LDR           r2,[r2,#0x00]
0x08000AD8 EB0272D2  ADD           r2,r2,r2,LSR #31
0x08000ADC EB010162  ADD           r1,r1,r2,ASR #1
0x08000AE0 6001      STR           r1,[r0,#0x00]
    65: }

--- End code ---



ppTRN:
It appears that the GIF is not moving at all. Here's a link to the video: https://youtu.be/5fmkvsD-KEA

mikerj:
Do you have any other interrupts running, or any code in the main loop that may be disabling interrupts for a brief period?

ppTRN:
There are no other interrupts, but I managed to fix it. I now use the toggle on match feature in order to automatically toggle the pin on match and in the ISR I just update the compare values. Also I increased the interrupt priority reducing the jitter to just 50ns.


--- Code: ---/*
This code generates two square waves, one in phase and one in quadrature
with the received signal. They can be shifted by adding a delay, stored in K.

TEST: PASSED.
PERFORMANCE: 50ns gitter

*/

#include "demodulatorClocks.h"

extern int K;
extern int TXpulseWidth;

void demodulatorClocksInit(){

RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // TIM1 clock enable
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // GPIOA clock enable

GPIOA->MODER &= ~(1<<16);          // GPIOA8 in AF mode
GPIOA->MODER |= 1<<17;         
GPIOA->MODER &= ~(1<<18);          // GPIOA9 in AF mode
GPIOA->MODER |= 1<<19;         

GPIOA->AFR[1] &= ~(0xF << 0);    // Clear PA8
GPIOA->AFR[1] |= (0x6 << 0);     // AF6 for TIM1_CH1

GPIOA->AFR[1] &= ~(0xF << 4);    // Clear PA9
GPIOA->AFR[1] |= (0x6 << 4);     // AF6 for TIM1_CH2

TIM1->CR1 |= 0; // Up counter
TIM1->CR2 |= 0; // No master mode
TIM1->SMCR |= 0; // No slave mode
TIM1->DIER |= 1<<1 // Interrupt enable on CCR1
| 1<<2 // Interrupt enable on CCR2
| 1<<3 // Interrupt enable on CCR3
| 1<<4; // Interrupt enable on CCR4
TIM1->SR |= 0; // Interrupt flag register
TIM1->EGR |= 0; // Software event generation

TIM1->CCMR1 |= (0b011 << 4); // CH1 toggle on match
TIM1->CCMR1 |= (0b011 << 12); // CH2 toggle on match

TIM1->CCMR2 |= 0; // CC2 and CC3 are in output mode with no effect on pins
TIM1->CCER |= 1<<0 // CC1 enable
| 1<<4 // CC2 enable
| 1<<8 // CC3 enable
| 1<<12; // CC4 enable
TIM1->CNT = 0; // TIM1 counter value
TIM1->PSC = 0; // Prescaler 1
TIM1->ARR = 0xFFFF; // Auto reload register at MAX
TIM1->RCR = 0; // Repetition counter
TIM1->CCR1 = TXpulseWidth/2; // When to lower I
TIM1->CCR2 = TXpulseWidth/4; // When to rise Q
TIM1->CCR3 = 3*TXpulseWidth/4; // When to lower Q

TIM1->BDTR |= TIM_BDTR_MOE; // OUTPUT COMPARE OUTPUT ENABLE

NVIC_SetPriority(TIM1_CC_IRQn, 1);
NVIC_EnableIRQ(TIM1_CC_IRQn);

}

void TIM1_CC_IRQHandler(){

if(TIM1->SR & 1<<1){
TIM1->SR &= ~(1<<1); // Clear flag
TIM1->CCR1 = TIM1->CCR1 + TXpulseWidth/2; // Update compare match
}
else if(TIM1->SR & 1<<2){
TIM1->SR &= ~(1<<2); // Clear flag
TIM1->CCR2 = TIM1->CCR2 + TXpulseWidth/2; // Update compare match
}
}

--- End code ---

radiolistener:
try something like this:

--- Code: ---void handleCC1IF(void) {
    uint32_t shiftAdd = (GPIOA->IDR >> 4) & 0x10;  // Based on PA8 state
    GPIOA->BSRR = 1 << (8 + shiftAdd);  // Toggle PA8
    TIM1->CCR1 += TXpulseWidth / 2;
    TIM1->SR &= ~1;  // Clear CC1IF
}

void handleCC2IF(void) {
    uint32_t shiftAdd = (GPIOA->IDR >> 4) & 0x10;  // Based on PA8 state
    GPIOA->BSRR = 1 << (9 + shiftAdd);  // Toggle PA9 in sync with PA8
    TIM1->CCR2 += TXpulseWidth / 2;
    TIM1->SR &= ~2;  // Clear CC2IF
}

void handleError(void) {
    // Handle the unexpected case (maybe log or assert)
}

void TIM1_CC_IRQHandler() {
    // Function pointer table for handling CC1IF and CC2IF
    void (*handlers[])(void) = { handleError, handleCC1IF, handleCC2IF, handleError };

    handlers[TIM1->SR & 3]();   // Call the corresponding handler
}

--- End code ---

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod