Electronics > Microcontrollers
Wobbling signal generated by Output Compare output
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
Go to full version