Estoy usando la placa de descubrimiento STM32VL (STM32f100rb6). Escribí el siguiente código para NVIC:
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');
}
y
int main(void)
{
Interrupt_Init();
while (1)
{
}
}
void EXTI0_IRQHandler(void)
{
//NVIC->ICPR[0] |= BIT6;
lcd_writechar('2');
}
como puede ver en la frase Interrupt_Init()
de usuario I NVIC->ISPR[0] |= BIT6;
para habilitar suavemente exti0-IRQ. entonces void EXTI0_IRQHandler(void)
la subrutina debe ejecutarse y obtuve '2' en la pantalla LCD. pero como NVIC->ISPR[0] |= BIT6;
ejecutar la siguiente línea ( lcd_writechar('1');
) nunca se ejecuta ... pero cuando comenté ( NVIC->ISPR[0] |= BIT6;
) obtuve '1' en la pantalla LCD ... ¿qué está pasando?
Actualizar:
Busco más en el archivo "startup_stm32f10x_md_vl.s" en mi proyecto como archivo de inicio:
.section .text.Default_Handler,"ax",%progbits Default_Handler: Infinite_Loop: b Infinite_Loop .size Default_Handler, .-Default_Handler
y:
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 ...
y:
.weak EXTI0_IRQHandler .thumb_set EXTI0_IRQHandler,Default_Handler
Parece que "EXTI0_IRQHandler" siempre es igual a "Default_Handler" en mis proyectos, por lo que provoca un bucle infinito como definimos anteriormente.
Creo que esta parte:
void EXTI0_IRQHandler(void) { NVIC->ICPR[0] |= BIT6; lcd_writechar('2'); }
nunca influye en la definición "EXTI0_IRQHandler". ¿por qué?
Actualizar:
¿Hay alguna forma de saltar a EXTI0_IRQHandler sin implementar nada en el periférico? ¿Como asm("B 0x58")? ¿Mi propósito es estar seguro de las configuraciones centrales y luego trabajar en configuraciones periféricas?
Actualizar:
Estuve a punto de encontrar un problema, pero necesito ayuda para solucionarlo... después de muchos exámenes y uso de funciones de depuración, encontré que este fragmento de código es defectuoso:
void EXTI0_IRQHandler() { lcd_writechar('2'); LED_ON(); NVIC->ICPR[0] |= BIT6; }
en detalle,
lcd_writechar('2');
la causa del problema porque dentro de la función estoy usando la función de retraso (). Esta es esa pieza de código que involucra el retraso por la función SycTick:
/*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; }
como puede ver, estoy tratando de borrar el bit pendiente de SysTick,
SCB->ICSR |= BIT25;
pero claramente después de ejecutar la función de retraso () desde el interior deEXTI0_IRQHandler()
todo se cuelga.
Cuando ingresa a la rutina de interrupción, debe borrar el indicador de fuente de interrupción. Si no borra la bandera, cuando salga de la rutina de interrupción, simplemente volverá a ingresar a la rutina. De esta manera, siempre estará atascado en EXTI0_IRQHandler.
El NVIC->ICPR
único elimina el bit pendiente en el NVIC.
Pero, si la señal IRQ al NVIC todavía está activa (el registro EXTI PR), el borrado de bit pendiente en el NVIC no tendrá efecto.
En su lugar, debe borrar la fuente de solicitud de interrupción, EXTI->PR = EXTI_PR_PR6
en el ISR. De lo contrario, estará encadenando esta rutina de interrupción hasta que llegue una de mayor prioridad.
Las definiciones que encuentra en startup.s son débiles , las anula cuando escribe la función real.
Usando NVIC->ISPR[0] |= BIT6
usted genera una solicitud de interrupción de software. Se borra al entrar en el ISR.
Sugerencia general, al depurar rutinas de interrupción faltantes, establezca un punto de interrupción aquí:
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop <-------- breakpoint
.size Default_Handler, .-Default_Handler
NVIC->ISPR[0] |= BIT6
, por lo que void EXTI0_IRQHandler(void)
se supone que la función debe ejecutarse... pero no sucede... porque no obtuvimos '1' en la pantalla LCD como lcd_writechar('1');
lo admitimos.static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) { NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */ }
y de stm32f10x.h tenemos typedef enum IRQn{...EXTI0_IRQn = 6, ...}
si haces ese cálculo llegamos a NVIC->ISER[0] |= BIT6;
para activar EXTI0_IRQn
la Interrupción, así que para pendientes de acuerdo con esos archivos obtenemos NVIC->ISPR[0] |= BIT6;
. así que sé exactamente que estoy habilitando el bit pendiente de "EXTI0_IRQn", por lo que debemos ejecutar "void EXTI0_IRQHandler (void)", ¿dónde está el problema?Finalmente, encontré el error. La prioridad es el problema.
Úselo NVIC_SetPriority(EXTI0_IRQn, 1);
para establecer SysTick en un nivel de prioridad más alto que EXTI0_IRQn. Entonces todo va bien.
peyman khalili
peyman khalili
void EXTI0_IRQHandler(void) { NVIC->ICPR[0] |= BIT6; lcd_writechar('2'); }
para borrar el indicador de fuente de interrupción, perolcd_writechar('2')
nunca se ejecuta y todo es igual.peyman khalili