cancel
Showing results for 
Search instead for 
Did you mean: 

Different triggers on the same clock

matteo
Associate II
Posted on March 28, 2014 at 21:35

Hello,

For a project I am working on I would like to generate interrupts on both edges of the HSI clock, for synchronization purposes. The sysclk is based on the main PLL, sourced from HSE. I output HSI on the MCO1 (pin PA8), and I am able to generate interrupts on either or both edges on the EXTI line 8 from that pin. However, if I do it like that I have found no way to distinguish between rising and falling transitions. My workaround (that does not work) would be to wire the PA8 pin (on which I output the clock) to the PC9 pin (I use a jumper between them). I would then detect falling edge transitions on PA8 through EXTI line 8, and rising edge transitions on PC9 through EXTI line 9. However, with my configuration I only detect the falling edge transitions on PA8. Here is my code:

/*Initialization*/
//MCO1 outputs the HSI clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource8,GPIO_AF_MCO);
//With a jumper, I also wire MCO1 to the PC9 pin.
//Using two pins I can discriminate between clock edges
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*Interrupt settings*/
NVIC_InitTypeDef NVIC_InitStructure;
/*Configure the mask bits for the interrupt on MCO1 */
EXTI->IMR |= 0x1 << 
8
;
/*Configure trigger selection bits for the interrupt on MCO1 */
EXTI->RTSR &= EXTI8_RISING_EDGE_NO; //Disable rising edge as trigger EXTI8_RISING_EDGE_NO == (uint32_t)0xFFFFFEFF
EXTI->FTSR |= EXTI8_FALLING_EDGE_YES; //Enable falling edge as trigger EXTI8_FALLING_EDGE_YES == (uint32_t)0x100
/*Configure the mask bits for the interrupt on PC9 (externally wired to MCO1)*/
EXTI->IMR |= 0x1 << 
9
;
//Configure trigger selection bits for interrupt on PC9
EXTI->RTSR |= EXTI9_RISING_EDGE_YES; //Enable rising edge as trigger EXTI9_RISING_EDGE_YES == (uint32_t)0x200
EXTI->FTSR &= EXTI9_FALLING_EDGE_NO; //Disable falling edge as trigger EXTI9_FALLING_EDGE_NO == (uint32_t)0xFFFFFDFF
/*Configure the enable and mask bits on the NVIC IRQ channel
* HSI on pin PA8, goes to EXTI line 8
* PC9 goes to EXTI line 9*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

And here is the handler:

void EXTI9_5_IRQHandler(void)
{
if(EXTI->PR & PR_EXTI8) //Interrupt on EXTI line 8, on which we registered the SCLK falling edge
{
if(debug_led_count++ == 5000000)
{
STM_EVAL_LEDToggle(LED3); //blinks correctly
debug_led_count = 0;
}
}
else if(EXTI->PR & PR_EXTI9) //Interrupt on EXTI line 9, on which we registered the SCLK rising edge
{
if(debug_led_count2++ == 5000000)
{
STM_EVAL_LEDToggle(LED4); //does not blink ever
debug_led_count2 = 0;
}
}
}

Could anyone point me in the direction of a solution? Is there some configuration I am missing? O perhaps my approach is entirely wrong? Cheers, Matteo
14 REPLIES 14
Posted on March 28, 2014 at 21:41

Or perhaps my approach is entirely wrong?

Interrupting millions of times a second is a woefully bad idea.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
matteo
Associate II
Posted on March 28, 2014 at 21:49

Fair enough.

However I am trying to read from a bank of external SAR ADCs, and I can readily see no other way to synch with them.

matteo
Associate II
Posted on March 28, 2014 at 21:49

Fair enough.

However I am trying to read from a bank of external SAR ADCs, and I can readily see no other way to synch with them.

Posted on March 28, 2014 at 22:05

So how does interrupting the STM32 synchronize external ADCs?

You don't clear the EXTI interrupts, and the 'if/else if' construct seems to assume the interrupt can't be executing with both pending.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
matteo
Associate II
Posted on March 28, 2014 at 22:27

The interrupts allow me to count the passing clock cycles for readout from the adcs.

I edited my interrupt handling code to clear the bit in the EXTI_PR register. ALso, I removed the 'else', but still only the EXTI8 interrupt is handled/triggered. My reasoning for the 'else' clause would be that I can't have both edges at the same time.

void EXTI9_5_IRQHandler(void)
{
if(EXTI->PR & PR_EXTI8) //Interrupt on EXTI line 8, on which we registered the SCLK falling edge
{
if(debug_led_count++ == 5000000)
{
STM_EVAL_LEDToggle(LED3);
debug_led_count = 0;
}
//clear pending
EXTI->PR |= PR_EXTI8;
}
if(EXTI->PR & PR_EXTI9) //Interrupt on EXTI line 9, on which we registered the SCLK rising edge
{
if(debug_led_count2++ == 5000000)
{
STM_EVAL_LEDToggle(LED4);
debug_led_count2 = 0;
}
//clear pending
EXTI->PR |= PR_EXTI9;
}
}

PR_EXTI8 ==(uint32_t)0x100 PR_EXTI9 == (uint32_t)0x200 Cheers, Matteo
Posted on March 28, 2014 at 23:24

Yeah, there has to be a better solution to this than banging interrupts at 16 MHz or more. I'm not clear on what STM32 model you're attempting this on.

As the processor reaches saturation it's quite possible for both edges to have occurred while in the interrupt service routine.

I'd ponder further, but you're trying to solve the wrong problem.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on March 28, 2014 at 23:29

void EXTI9_5_IRQHandler(void)
{
if (EXTI->PR & PR_EXTI8) //Interrupt on EXTI line 8, on which we registered the SCLK falling edge
{
EXTI->PR = PR_EXTI8; //clear pending, do it early, not RMW
if(debug_led_count++ == 5000000)
{
STM_EVAL_LEDToggle(LED3);
debug_led_count = 0;
}
}

 

if (EXTI->PR & PR_EXTI9) //Interrupt on EXTI line 9, on which we registered the SCLK rising edge
{
EXTI->PR = PR_EXTI9; //clear pending, do it early, not RMW
if (debug_led_count2++ == 5000000)
{
STM_EVAL_LEDToggle(LED4);
debug_led_count2 = 0;
}
}
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jpeacock2399
Associate II
Posted on March 28, 2014 at 23:31

Your data collection is too fast for an interrupt.  Set up a timer triggered circular DMA to read your ADCs (assuming they are wired parallel on the FSMC bus, given the data collection speed).  That eliminates the interrupt overhead and your data magically appears in memory.  Use the DMA HT and TC flags to process your data to ensure you get the section of the buffer not in use.

  Jack Peacock
matteo
Associate II
Posted on March 29, 2014 at 18:02

Set up a timer triggered circular DMA to read your ADCs (assuming they are wired parallel on the FSMC bus, given the data collection speed)

 

I am learning about setting up DMAs and such. However I am kinda stuck at something conceptual.

I have 8 sar ADCs, each one wired to a pin. It would be simpler to not have all these pins being in the same bank/port (e.g. some pins would be GPIOA, some GPIOC, some GPIOD, some GPIOG). It might be feasible to wire them differently if it is a requirement to read the data.

It is not clear to me if I can use a peripheral-to-memory DMA to load a buffer from a single pin, synched with a clock. And if it is possible, I've still to find how to do it.

Any help would be appreciated.

Cheers,

Matteo