Ich verwende das STM32VL Discovery Board (STM32f100rb6). Ich habe folgenden Code für NVIC geschrieben:
void Interrupt_Init(void)
{
__enable_irq();
/*Core Base(NVIC)*/
//set priority to 0
//NVIC->IP[6] &= ~((uint32_t)0xff00);
//Activate Interrupts
NVIC->ISER[0] |= BIT6;
//Enable Pending BIT for Interrupt 6
NVIC->ISPR[0] |= BIT6;
lcd_writechar('1');
}
Und
int main(void)
{
Interrupt_Init();
while (1)
{
}
}
void EXTI0_IRQHandler(void)
{
//NVIC->ICPR[0] |= BIT6;
lcd_writechar('2');
}
wie Sie unter Interrupt_Init()
I user NVIC->ISPR[0] |= BIT6;
phrase sehen, um exti0-IRQ weich zu aktivieren. Also void EXTI0_IRQHandler(void)
muss das Unterprogramm ausgeführt werden und ich habe '2' auf dem LCD. aber als NVIC->ISPR[0] |= BIT6;
execute next line( ) läuft es lcd_writechar('1');
nie.NVIC->ISPR[0] |= BIT6;
Aktualisieren:
Ich schaue weiter in die Datei "startup_stm32f10x_md_vl.s" in meinem Projekt als Startdatei:
.section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop .size Default_Handler, .-Default_Handler
Und:
g_pfnVectors: .word _estack .word Reset_Handler .word NMI_Handler .word HardFault_Handler .word MemManage_Handler .word BusFault_Handler .word UsageFault_Handler .word 0 .word 0 .word 0 .word 0 .word SVC_Handler .word DebugMon_Handler .word 0 .word PendSV_Handler .word SysTick_Handler .word WWDG_IRQHandler .word PVD_IRQHandler .word TAMPER_IRQHandler .word RTC_IRQHandler .word FLASH_IRQHandler .word RCC_IRQHandler .word EXTI0_IRQHandler ...
Und:
.weak EXTI0_IRQHandler .thumb_set EXTI0_IRQHandler,Default_Handler
Es scheint, dass "EXTI0_IRQHandler" in meinen Projekten immer gleich "Default_Handler" ist, so dass es eine Endlosschleife verursacht, wie wir oben definiert haben.
Ich denke dieser Teil:
void EXTI0_IRQHandler(void) { NVIC->ICPR[0] |= BIT6; lcd_writechar('2'); }
nie die "EXTI0_IRQHandler"-Definition beeinflusst. Warum?
Aktualisieren:
Gibt es eine Möglichkeit, zu EXTI0_IRQHandler zu springen, ohne etwas in der Peripherie zu implementieren? Wie asm ("B 0x58")? Mein Ziel ist es, sicher zu sein, von Kernkonfigurationen dann an peripheren Konfigurationen zu arbeiten?
Aktualisieren:
Ich habe das Problem fast gefunden, brauche aber Hilfe, um es zu beheben. Nach vielen Untersuchungen und der Verwendung von Debug-Funktionen habe ich festgestellt, dass dieser Codeabschnitt fehlerhaft ist:
void EXTI0_IRQHandler() { lcd_writechar('2'); LED_ON(); NVIC->ICPR[0] |= BIT6; }
im Detail
lcd_writechar('2');
Grund zum Problem, weil ich innerhalb der Funktion die Funktion delay () verwende. Dies ist das Stück Code, das die Verzögerung durch die SycTick-Funktion beinhaltet:
/*Enable SysTick*/ //Processor clock (AHB) SysTick->CTRL |= BIT2; //Counting down to zero to asserts the SysTick exception request. SysTick->CTRL |= BIT1; SysTick->LOAD = 8000 - 1; void SysTick_Handler(void) { SysTick_Tick++; //lcd_writechar('7'); SCB->ICSR |= BIT25; } void delay(int ms) { SysTick_Tick = 0; //Enable Systick Counter SysTick->CTRL |= BIT0; while (SysTick_Tick < ms) {} //Disable Systick Counter SysTick->CTRL &= ~BIT0; SCB->ICSR |= BIT25; return; }
Wie Sie sehen, versuche ich, das ausstehende Bit von SysTick zu löschen,
SCB->ICSR |= BIT25;
aber nach dem Ausführen der Funktion delay () von innenEXTI0_IRQHandler()
hängt eindeutig alles.
Wenn Sie in die Interrupt-Routine eintreten, müssen Sie das Interrupt-Quell-Flag löschen. Wenn Sie das Flag nicht löschen, wird es beim Verlassen der Interrupt-Routine einfach wieder in die Routine eintreten. Auf diese Weise bleiben Sie immer im EXTI0_IRQHandler hängen.
Das NVIC->ICPR
entfernt nur das Pending-Bit im NVIC.
Wenn jedoch das IRQ-Signal zum NVIC noch aktiv ist (das EXTI PR-Register), hat das anstehende Bit-Löschen im NVIC keine Wirkung.
Stattdessen müssen Sie die Interrupt-Anforderungsquelle EXTI->PR = EXTI_PR_PR6
in der ISR löschen. Andernfalls verketten Sie diese Interrupt-Routine, bis eine mit höherer Priorität eintrifft.
Die Definitionen, die Sie in startup.s finden, sind schwach , Sie überschreiben diese, wenn Sie die eigentliche Funktion schreiben.
Mit NVIC->ISPR[0] |= BIT6
generieren Sie eine Software-Interrupt-Anforderung. Es wird beim Betreten des ISR gelöscht.
Allgemeiner Tipp, beim Debuggen fehlender Interrupt-Routinen hier einen Haltepunkt setzen:
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop <-------- breakpoint
.size Default_Handler, .-Default_Handler
NVIC->ISPR[0] |= BIT6
, also void EXTI0_IRQHandler(void)
sollte die Funktion laufen ... aber es passiert nicht ... weil wir keine '1' auf dem LCD bekommen haben, wie lcd_writechar('1');
es zugegeben wird.static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) { NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */ }
und von stm32f10x.h haben wir typedef enum IRQn{...EXTI0_IRQn = 6, ...}
, wenn Sie diese Berechnung durchführen, kommen wir zum NVIC->ISER[0] |= BIT6;
Aktivieren EXTI0_IRQn
von Interrupt, also für ausstehend gemäß diesen Dateien erhalten wir NVIC->ISPR[0] |= BIT6;
. Ich weiß also genau, dass ich das ausstehende Bit von "EXTI0_IRQn" aktivieren muss, also müssen wir "void EXTI0_IRQHandler (void)" zum Laufen bringen, wo ist das Problem??Endlich habe ich den Fehler gefunden. Priorität ist das Problem.
Wird verwendet NVIC_SetPriority(EXTI0_IRQn, 1);
, um SysTick auf eine höhere Prioritätsstufe als EXTI0_IRQn einzustellen. Dann geht alles OK.
peyman khalili
peyman khalili
void EXTI0_IRQHandler(void) { NVIC->ICPR[0] |= BIT6; lcd_writechar('2'); }
zum Löschen des Interrupt-Quell-Flags,lcd_writechar('2')
läuft aber nie und alles ist gleich.peyman khalili