Problema en NVIC STM32F100

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 de EXTI0_IRQHandler()todo se cuelga.

Respuestas (3)

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.

gracias por tu respuesta pero como?? ¿Puedes explicar más con un ejemplo relacionado con este proyecto?
Lo uso void EXTI0_IRQHandler(void) { NVIC->ICPR[0] |= BIT6; lcd_writechar('2'); }para borrar el indicador de fuente de interrupción, pero lcd_writechar('2')nunca se ejecuta y todo es igual.
Estoy pensando que siempre se quedará atascado en SysTick_Handler(), lea la última actualización.

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_PR6en 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] |= BIT6usted 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
@peymankhalili hay dos formas de ejecutar el isr por software. Llame a la función. O establezca el bit pendiente.
Sí, lo hice (configuré el bit pendiente) por 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.
@peymankhalili ¿Algún cambio activa el RCC_IRQHandler?
no, quiero activar EXTI0_IRQHandler. Creo que desea mencionar a asm ("B 0x58"), es la dirección de EXTI0_IRQHandler.
@peymankhalili El NVIC está desplazado de la tabla de vectores por las excepciones. Tal vez bit6 no es el IRQ que crees que es. Además, no puede ramificar sin enlace y esperar regresar. Busque el estándar de llamada de procedimiento.
de core_cm3.h tenemos 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_IRQnla 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?
@peymankhalili Cuando pruebo tus fragmentos dados. Funciona bien. Debes tener algo más en marcha.

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.