PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : STM32F4 - Timer als Counter - ISR löst nach Initialisierung sporadisch aus.



erik_wolfram
09.08.2016, 14:47
Hallo,

ich merke schon, dass ich in diesen Forum sehr aktiv bin Fragen zu stellen.
Nun habe ich mal wieder ein neues Problem bei einem Interupt von verketteten Timern.

Grundsätzlich möchte ich einen umfangreichen Funktionsgenerator mit einem externen 16-Bit DAC realisieren. Dieser wird über einen DMA und SPI angesteuert.
Als Mikrocontroller kommt ein STM32F07VG Discovery zum Einsatz.

Der Programmablauf sieht wie folgend aus.

- ich verwende TIM8 für das Triggern des DMA-Vorgangs um die Werte koninuierlich auszugeben. (Der DMA funktioniert und wird daher nicht näher beschrieben)
- TIM8 wirkt als Master-Timer und gibt beim Überlauf (update) den internen Trigger aus
- TIM4 nutzt diesen Trigger (ITR3) als Slave als Taktquelle
- ein Überlauf-Interupt von TIM4 soll die Ausgabe von X Werten abfangen und den vollständigen Vorgang beenden

Da der DMA im Circular Mode arbeitet kann ich hier nicht die Werte mitzählen und wollte den TIM4 stattdessen nutzen.
Das Abfangen der X Werte funktioniert. Doch nach der Initialisierung von TIM4 und dem Interupt lösst dieses in variierenden Abständen einmal aus.
Das Mitzählen und Abbrechen der Ausgabevorganges funktiert nach dem einmaligen Auslösen des Interupts zuverlässig.

Der Code sieht so aus (vereinfacht):


void TIM8_init()
{
...
TIM_TimeBaseInit( TIM8, &TIM_TimeBaseStructure );

// Select the TRGO source
TIM_SelectOutputTrigger( TIM8, TIM_TRGOSource_Update );
TIM_SelectMasterSlaveMode( TIM8, TIM_MasterSlaveMode_Enable );
...
}


void TIM4_init()
{
RCC_APB1PeriphClockCmd( RCC_APB1ENR_TIM4EN, ENABLE );

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 5;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_DeInit( TIM4 );
TIM_TimeBaseInit( TIM4, &TIM_TimeBaseStructure );

TIM_SetCounter( TIM4, 0 );

// TIM2 durch TIM8 synchron starten
TIM_SelectInputTrigger(TIM4, TIM_TS_ITR3);
TIM_SelectSlaveMode( TIM4, TIM_SlaveMode_External1 );

TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );

TIM_Cmd( TIM4, ENABLE );
}


void TIM4_IRQHandler()
{
if( TIM_GetITStatus( TIM4, TIM_IT_Update ) == SET )
{
// ClearITPendigBit TIM8 Update
TIM_ClearITPendingBit( TIM4, TIM_IT_Update);

TIM_Cmd( TIM8, DISABLE );
}
}


main
{
...
TIM8_init();
TIM4_init();

TIM_Cmd( TIM8, ENABLE );
...

}


Wie kann das vorschnelle Ausösen des Überlauf-Interupts erfolgen? Ich habe auch schon den CNT-Wert mit Werten größer 0 initialisiert - trotzdem wird jedesmal das Überlaufinterupt einmal aufgerufen...

Gruß Erik

erik_wolfram
10.08.2016, 08:55
Nach längerem Suchen und einen ausführlichen Debugen bin ich dem Fehler auf die Schliche gekommen.

Ich verwende die StdPeriph-Driver Bibleothek. Zum Ende der Timer-Initialisierung wird im EGR-Register das Bit0 gesetzt und sollte laut Beschreibung ein Update-Event generieren, welches durch die Hardware automatisch gelöscht werden sollte.
Das erfolgt jedoch nicht, und sobald ich danach das Interupt aktiviere springt das Programm auf Grund des bestehenden ISR-Flags ins Interupt.

Abhilfe:

TIM_TimeBaseInit( TIM4, &TIM_TimeBaseStructure );
...
TIM_ClearITPendingBit( TIM4, TIM_IT_Update);
TIM_ITConfig( TIM4, TIM_IT_Update, ENABLE );


Den Fehler will ich den anderen Nutzern nicht vorenthalten. Die Verkettung der Timer, bzw. Zähler funktioniert jetzt so.