cancel
Showing results for 
Search instead for 
Did you mean: 

compensating latencies on STM32F4 interrupts

xavier2399
Associate II
Posted on September 14, 2012 at 14:29

I'm working on a project on a STM32F4 CPU, generating signals (VGA) with DMA.

I have a generic timer on CPU clock (no prescaler) on a STM32 triggering interrupts on overflow, to generate a periodic signal with GPIO afterwards.

I need to trigger thr GPIO at a very regular time (basically down to a CPU cycle precision). I've managed to reduce this jitter to +-5 cycles by setting priorities & al, but this jitter exists, depending on what the CPU was doing and the interrupted instruction.

I need to compensate this few cycles jitter. Adding a few cycles more latency isn't a problem as long as I toggle GPIOs always at the same counter cycle.

My idea was to read the current value of the counter after the interrupt, and have an active loop of (FIXED_NUMBER-CNT->VAL) time, ensuring I would exit the loop at precise times.

However, doing a simple loop in C - being a FOR loop, or a while(counter->value < TARGET); doesn't work as it ADDS jitter instead of reducing it.

I ensured with empty, non optimized but not hitting memory loop body (asm(''''))

See this example on AVR (more predictable timings) See by example

http://lucidscience.com/pro-vga video generator-7.aspx

(search for ''jitter'')

I tried a simple loop in assembly such as (r0 has the number of cycles to wait to compensate counter value)

loop : SUBS r0,#1 ; tried with 2 also BGE loop 

and, again, jitter is better without it.

To sum it up, I already know how much I should delay. Unfortunately, branches alone don't seem to work (nondeterminisctic pipeline refill ?) and IT conditional expressions don't either because they always take the same number of cycles (sometimes doing nothing).

Would running from RAM instead of flash improve consistency ?

Maybe I'm out of my league here ... any help would appreciated, thanks! (crosspost from stackoverflow as I think I'd have more success here than there, sorry) #interrupts-counter
23 REPLIES 23
henryryq
Associate II
Posted on May 27, 2013 at 16:11

:D i found the attach link after klik the ok button, maybe next time i use it option. 

thx for your replay... im try your suggest..

The one with modulated signal does not appear to get low enough to read a zero state.

my opinion why it can be, because the pin on output mode and previous signal is high.

what about you?

ricky

henryryq
Associate II
Posted on May 28, 2013 at 03:48

solved, 

change Port E to Port C.. and the data receive normaly....

ricky

haythem
Associate II
Posted on March 19, 2014 at 00:08

Not work for me this is my own code can you help me 

/**

  ******************************************************************************

  * @file    IO_Toggle/main.c 

  * @author  MCD Application Team

  * @version V1.0.0

  * @date    19-September-2011

  * @brief   Main program body

  ******************************************************************************

  * @attention

  *

  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS

  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE

  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY

  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING

  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE

  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.

  *

  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>

  ******************************************************************************  

  */ 

/* Includes ------------------------------------------------------------------*/

#include ''stm32f4_discovery.h''

/** @addtogroup STM32F4_Discovery_Peripheral_Examples

  * @{

  */

/** @addtogroup IO_Toggle

  * @{

  */ 

/* Private typedef -----------------------------------------------------------*/

GPIO_InitTypeDef  GPIO_InitStructure;

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

void TimingDelay(unsigned int tick);

void EnableTiming(void);

/* Private functions ---------------------------------------------------------*/

/**

  * @brief  Main program

  * @param  None

  * @retval None

  */

int main(void)

{

  /*!< At this stage the microcontroller clock setting is already configured, 

       this is done through SystemInit() function which is called from startup

       file (startup_stm32f4xx.s) before to branch to application main.

       To reconfigure the default setting of SystemInit() function, refer to

        system_stm32f4xx.c file

     */

  /* GPIOD Periph clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  /* Configure PD12, PD13, PD14 and PD15 in output pushpull mode */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

  GPIO_Init(GPIOD, &GPIO_InitStructure);

  while (1)

  {

    /* PD15 to be toggled */

    GPIO_SetBits(GPIOD, GPIO_Pin_15);

    

    /* Insert delay */

   TimingDelay(10);

    

    GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

    

    /* Insert delay */

    TimingDelay(1000);

  }

}

/**

  * @brief  Delay Function.

  * @param  nCount:specifies the Delay time length.

  * @retval None

  */

volatile unsigned int *DWT_CYCCNT   = (volatile unsigned int *)0xE0001004; //address of the register

volatile unsigned int *DWT_CONTROL  = (volatile unsigned int *)0xE0001000; //address of the register

volatile unsigned int *SCB_DEMCR        = (volatile unsigned int *)0xE000EDFC; //address of the register

 

//******************************************************************************

 

void EnableTiming(void)

{

    static int enabled = 0;

 

    if (!enabled)

    {

        *SCB_DEMCR = *SCB_DEMCR | 0xF42400;

        *DWT_CYCCNT = 0; // reset the counter

        *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter

 

        enabled = 1;

    }

}

 

//******************************************************************************

 

void TimingDelay(unsigned int tick)

{

    unsigned int start, current;

 

    start = *DWT_CYCCNT;

 

    do

    {

        current = *DWT_CYCCNT;

    } while((current - start) < tick);

}

 

//******************************************************************************

#ifdef  USE_FULL_ASSERT

/**

  * @brief  Reports the name of the source file and the source line number

  *         where the assert_param error has occurred.

  * @param  file: pointer to the source file name

  * @param  line: assert_param error line source number

  * @retval None

  */

void assert_failed(uint8_t* file, uint32_t line)

  /* User can add his own implementation to report the file name and line number,

     ex: printf(''Wrong parameters value: file %s on line %d\r\n'', file, line) */

  /* Infinite loop */

  while (1)

  {

  }

}

#endif

/**

  * @}

  */ 

/**

  * @}

  */ 

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

Posted on March 19, 2014 at 01:36

Not work for me this is my own code can you help me 

You'd need to be calling EnableTiming() prior to entering the loop.

For 1 us, use TimingDelay(SystemCoreClock / 1000000), ideally computing the constant outside the loop.

For 1 ms, use TimingDelay(SystemCoreClock / 1000)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..