Author Topic: Wobbling signal generated by Output Compare output  (Read 879 times)

0 Members and 1 Guest are viewing this topic.

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Wobbling signal generated by Output Compare output
« on: April 24, 2025, 09:18:30 am »
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: [Select]
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
}
}


DISASSEMBLED CODE:
Code: [Select]
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: }



 

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Re: Wobbling signal generated by Output Compare output
« Reply #1 on: April 24, 2025, 09:21:58 am »
It appears that the GIF is not moving at all. Here's a link to the video: https://youtu.be/5fmkvsD-KEA
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3469
  • Country: gb
Re: Wobbling signal generated by Output Compare output
« Reply #2 on: April 24, 2025, 10:27:29 am »
Do you have any other interrupts running, or any code in the main loop that may be disabling interrupts for a brief period?
 

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Re: Wobbling signal generated by Output Compare output
« Reply #3 on: April 24, 2025, 10:57:08 am »
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: [Select]
/*
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
}
}
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 4464
  • Country: Earth
Re: Wobbling signal generated by Output Compare output
« Reply #4 on: April 24, 2025, 12:32:46 pm »
try something like this:
Code: [Select]
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
}
« Last Edit: April 24, 2025, 12:38:28 pm by radiolistener »
 

Offline wek

  • Frequent Contributor
  • **
  • Posts: 562
  • Country: sk
Re: Wobbling signal generated by Output Compare output
« Reply #5 on: April 24, 2025, 09:47:48 pm »
As you've found out already, it's always better to use hardware  when it comes to timing.

Also, not directly related to your initial question, but don't RMW TIM_SR. Strangely enough, you had it correctly in your first post... (moreover, |= into SR is straight wrong).

JW

 

Offline PCB.Wiz

  • Super Contributor
  • ***
  • Posts: 2368
  • Country: au
Re: Wobbling signal generated by Output Compare output
« Reply #6 on: April 24, 2025, 10:06:58 pm »
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.

Yes, this is the least jitter / 'correct' approach.
Jitter occurs in any software pin toggle as the time to arrive at that line of code varies.

If you have other interrupts that are long, and the next-compare update is high frequency, then interrupt priority can be required.
The granularity should be 1 Peripheral CLK, and there should not be any added jitter?  What is your sampling jitter here?
eg if your edge distance is 2000 perclks, it should always be exactly 2000 perclks, as HW sets the toggle distance.
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 368
  • Country: au
Re: Wobbling signal generated by Output Compare output
« Reply #7 on: April 25, 2025, 06:29:04 am »

Code: [Select]
/*
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.
*/
...

The code as presented does not reference K. Maybe that part is yet to be added, but how is the first output kept in phase with the received signal at all?

 

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Re: Wobbling signal generated by Output Compare output
« Reply #8 on: April 25, 2025, 08:25:36 am »
In the code I posted K and TXpulseWidth are not shown because are defined and updated in another file. The first output is in phase with the reference signal because one of its edges triggers the timer 1, which then provides the two square signals. K gives me a way to delay the generation of both in phase and quadrature signals in respect to the reference signal, while TXpulseWidth gives me infos about the precise period of the reference signal.
In the video I posted in a previous answare you can see the two generated signal. The reference signal is not shown because I have just a 2 ch oscilloscope, but I used it as esternal trigger. The lag between the trigger and the square wave generation is due to K, which in fact allows me to shift both square waves at the same time.
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 368
  • Country: au
Re: Wobbling signal generated by Output Compare output
« Reply #9 on: April 25, 2025, 10:45:58 am »
A two channel scope - what luxury! For years, well decades actually, I got by with a single channel CRO, so I learned all the tricks making use of the trigger input. At least you are able to see the received signal and one of your generated signals at the same time.

It must be doing what you want, but I'm always keen to learn something new.

How does the external signal "trigger" timer 1? I can see that demodulatorClocksInit() does not enable the TIM1 counter (via CEN bit in CR1), so presumably something must turn that on. You also said that you don't have any other interrupt routines, so that leaves one less possible way of doing that.
 

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Re: Wobbling signal generated by Output Compare output
« Reply #10 on: April 26, 2025, 08:03:02 am »
Hi,
in order to make it clearer to you I draw a simple schematic of how the system works. Also, vou can find the whole code attached.

Code: [Select]
/*
File name: TXfrequencyMeasure.c

This code reads the TX signal and automatically updates TXpulseWidth
with the period of the signal. It is possible to evaluate the TX
frequency with a desired step, stored in REP. It means that the
actual measurement is taken only after REP periods. It is useless
to measure it every cycle since if it changes, it changes very slowly.


TEST: PASSED.
*/

#include "TXfrequencyMeasure.h"

#define REP 100
#define CAPTURE_BUFFER_SIZE 2 // One for rising and one for falling edge

volatile uint32_t capture_buffer[CAPTURE_BUFFER_SIZE]; // DMA buffer
extern int TXpulseWidth; // Pulse width in ticks
extern int K;
extern int nextI, nextQ;
int n = 0;

void TXfrequencyMeasureInit(void){

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;      // GPIOA clock enable
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;    // TIM2 clock enable
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;      // DMA clock enable

    GPIOA->MODER &= ~(3U << (0 * 2)); // GPIOA0 in alternate function
    GPIOA->MODER |=  (2U << (0 * 2));     
    GPIOA->AFR[0] &= ~(0xF << (0 * 4)); // Alternate function is TIM2 CHANNEL 1
    GPIOA->AFR[0] |=  (1U << (0 * 4));     

    TIM2->PSC = 0;                      // No prescaler for maximum resolution
    TIM2->ARR = 0xFFFFFFFF;            // Auto reload set to MAX

    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S; // CC1 channel is input, mapped on TI1
    TIM2->CCMR1 |= TIM_CCMR1_CC1S_0;   
    TIM2->CCER &= ~(TIM_CCER_CC1P);    // Sensitive to rising edge
    TIM2->CCER |= TIM_CCER_CC1E;        // Enable Input Capture CH1

    TIM2->DIER |= TIM_DIER_CC1DE;      // Enable DMA request on CH1 capture
    TIM2->CR1 |= TIM_CR1_CEN;          // TIM2 starts

    // --------------------------
    // Configure DMA1 Channel 5
    // TIM2_CH1 DMA is on DMA1_Channel5
    // --------------------------
    DMA1_Channel5->CPAR = (uint32_t)&TIM2->CCR1;
    DMA1_Channel5->CMAR = (uint32_t)capture_buffer;
    DMA1_Channel5->CNDTR = CAPTURE_BUFFER_SIZE;
    DMA1_Channel5->CCR =
        DMA_CCR_MINC      |     // Memory increment
        DMA_CCR_PSIZE_1   |     // Peripheral size: 32-bit
        DMA_CCR_MSIZE_1   |     // Memory size: 32-bit
        DMA_CCR_CIRC      |     // Circular mode
        DMA_CCR_PL_1      |     // High priority
        DMA_CCR_EN;             // Enable DMA channel

DMA1_Channel5->CCR |= DMA_CCR_TCIE; // Enable transfer complete interrupt

    NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}

void DMA1_Channel5_IRQHandler(void){

if(DMA1->ISR & DMA_ISR_TCIF5){
DMA1->IFCR |= DMA_IFCR_CTCIF5; // Clear transfer complete flag

if(n>=REP){

TIM1->CCR1 = K; // When to rise I
TIM1->CCR2 = TXpulseWidth/4+K; // When to rise Q

uint32_t t1 = capture_buffer[0]; // Assign the values to two variables
uint32_t t2 = capture_buffer[1];

if (t2 >= t1) TXpulseWidth = t2 - t1; // If we did not overflow the timer the width is the difference of times
else TXpulseWidth = (0xFFFFFFFF - t1 + t2 + 1); // If we overflew it, we fix it
}
else{
if(n<REP) n++;
else n = 0;
}

TIM1->CNT = 0; // Reset TIM1
TIM1->CR1 |= 1<<0; // Start TIM1
  }

}

Code: [Select]
/*

File name: demodulatorClocks.c

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 | 1<<2; // Interrupt enable on CC1 and CC2
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 | 1<<4; // CC1 and CC2 channel 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
}
}

As you can see TIM1 is started by the DMA interrupt that provides the measure of the input signal frequency
 
The following users thanked this post: ozcar

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 368
  • Country: au
Re: Wobbling signal generated by Output Compare output
« Reply #11 on: April 27, 2025, 06:26:26 am »
Thanks for providing that.

So, you do have another interrupt routine, but if things work correctly, the DMA and timer interrupts should be separated by your "K" offset, so should not interfere with each other.

I tried it on a STM32F303 "Black Pill" board, with CPU and timers running at 72MHz. Not knowing what frequency you are working with, I used a 20kHz input. It looked like it was working, but I did notice a few things.

Occasionally, the "in phase" output on PA8 would get inverted for a while. I managed to capture it changing over from being "OK" to "NOT OK" - see below. But then maybe I messed something up in getting it to work on my board, or maybe just running at different cycle time upsets something.

Secondly, the comments in the code say that your intention is to measure the period of the input waveform only every "REP" times, with REP set at 100 in the code as posted. However, "n" will count up to 100 and then get stuck at that value:

Code: [Select]
if(n>=REP){
                       (calculate new TXpulseWidth etc)
}
else{
if(n<REP) n++;
else n = 0;
}

So from then onwards, it does the calculation every time. I tried changing it so that it really only does that processing every 100th time through, and that totally messed things up! It was just not working at all for even values of REP much smaller than 100. I think that setting the timer counter to zero after it has been free-running for a few cycles could be to blame. Note that the DMA interrupt only occurs every second cycle of the input, so if you did want to measure the period of each cycle of the input signal, you'd have to turn on the interrupt for DMA transfer half-complete as well.

So, it may appear to be working, but I've got a feeling that there could be something there that will come out to bite you at some point.
 

Offline ppTRNTopic starter

  • Regular Contributor
  • *
  • Posts: 169
  • Country: it
Re: Wobbling signal generated by Output Compare output
« Reply #12 on: April 27, 2025, 12:51:23 pm »
Thank you for taking such interest.

1. Yes there is actually another ISR, and several other will be implemented. Given the timing syncronization of the system, they are expected to fire at certain time instant such that they should not interfere to much with one another. That's why I neglected the DMA interrupt.

2. The typical frequencies goes from 3 to 25kHz;

3. I also noticed the strange inversion of the in phase signal. I have no idea why it happends but after resetting it behaves correctly. I suspect this happend when the input signals is subjected to a big frequency change, which will not normally happend;

4. Yes, there is a bug that makes the measurement of the input period continous. If correctly implemented it does not work because it does not set the first threshold for the compare register of TIM1. Thank you for spotting it, I just fixed it and it works quite well, expecially for REP = 100 to 500. For higher values i find that it takes too much to adapt to the changes in the signal

Code: [Select]
void DMA1_Channel5_IRQHandler(void){

if(DMA1->ISR & DMA_ISR_TCIF5){
DMA1->IFCR |= DMA_IFCR_CTCIF5; // Clear transfer complete flag

TIM1->CCR1 = K; // When to rise I
TIM1->CCR2 = TXpulseWidth/4+K; // When to rise Q

if(n>=REP){
n = 0;
uint32_t t1 = capture_buffer[0]; // Assign the values to two variables
uint32_t t2 = capture_buffer[1];

if (t2 >= t1) TXpulseWidth = t2 - t1; // If we did not overflow the timer the width is the difference of times
else TXpulseWidth = (0xFFFFFFFF - t1 + t2 + 1); // If we overflew it, we fix it
}
else n++;

TIM1->CNT = 0; // Reset TIM1
TIM1->CR1 |= 1<<0; // Start TIM1
  }

}

Yet another change I made was to make te input capture for the input frequency measure sensitive to the falling edge. It is just more convenient for the kind of proccess that is made afterward. So now the Inphase signal is actually out of phase with the input one
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 368
  • Country: au
Re: Wobbling signal generated by Output Compare output
« Reply #13 on: April 28, 2025, 08:17:53 pm »
I look at things like this wondering "How would I do that?". Or maybe just as a puzzle in the same way some people might try to solve Sudoku, but the difference with something like this is that when you start you don't know that there even is a solution.

Using the toggle mode with the interrupt routine just continually incrementing the CCR values looks like a good way to keep two (or more) output signals in locked phase, as long as the frequency is not too high, as is the case here. I had not seen that before, but when I go looking now, I do see this suggested elsewhere. It does worry me a bit that when using toggle mode, maybe you could lose track of whether the output is high or low, and I was wondering if that could somehow be why the one output occasionally got inverted.

For what it is worth, my test signal was generated by PWM on another STM32, and seems pretty stable. If I set TIM1 going and never touch it again in the DMA interrupt, I can see the two outputs maintain the phase difference for as long as I like, but with nothing to maintain the phase relationship with the input signal, the DSO shows the two output signals drifting slowly relative to the input. The DSO said that the input signal was 20001.1Hz, and the generated signals were 20001.5Hz.

Locking the phase of the outputs to the input signal seems to be the tricky bit. For me, even with the DMA interrupt adjusting the TIM1 CNT and CCR values every time (so once for every two cycles of the input), I was seeing strange things happening.

I was thinking about trying to gradually steer the outputs in the right direction.  To that end, I was contemplating using another channel on TIM1 to capture the input signal instead of using another timer. That might make it a bit easier to know what CCR values are required to lock the outputs to the input. I have not had a chance to look at that though.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf