Ich habe zwei externe Interrupt-Quellen, die in einen STM32F105 kommen. Ich möchte, dass einer von ihnen (nennen Sie ihn "IRQHigh") den anderen ("IRQLow") vorwegnimmt. Wenn IRQHigh während der IRQLow-ISR ausgelöst wird, wartet der Programmablauf derzeit, bis ich das IRQLow-ITPending-Bit lösche, bevor er in die IRQHigh-ISR verzweigt.
Der STM32F105 ist ein Cortex-M3-basierter Mikrocontroller. Es unterstützt verschachtelte Interrupts. Meine Anwendung ist in C geschrieben, mit GCC (arm-none-eabi-gcc) in Eclipse, mit der STM32F1 Standard Peripheral Library.
Ich denke, ich habe die Prioritäten richtig konfiguriert, aber mir muss etwas fehlen.
Hier ist der entsprechende Initialisierungscode. Ich habe AFB-Uhrbefehle, GPIO-Konfiguration usw. entfernt, da jedes Subsystem für sich allein gut zu funktionieren scheint:
#define IRQHIGH_EXTI_PORT GPIO_PortSourceGPIOA
#define IRQHIGH_EXTI_PIN GPIO_PinSource3
#define IRQHIGH_EXTI_LINE EXTI_Line3
#define IRQHIGH_EXTI_IRQn EXTI3_IRQn
#define IRQLOW_EXTI_PORT GPIO_PortSourceGPIOC
#define IRQLOW_EXTI_PIN GPIO_PinSource11
#define IRQLOW_EXTI_LINE EXTI_Line11
#define IRQLOW_EXTI_IRQn EXTI15_10_IRQn
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
// Sixteen levels of pre-emption priority, no subpriorities
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// IRQHigh
// Connect EXTI Line to GPIO Pin
GPIO_EXTILineConfig(IRQHIGH_EXTI_PORT, IRQHIGH_EXTI_PIN);
// Configure EXTI line
EXTI_InitStructure.EXTI_Line = IRQHIGH_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// Configure and enable EXTI Interrupt
NVIC_InitStructure.NVIC_IRQChannel = IRQHIGH_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// IRQLow
// Connect EXTI Line to GPIO Pin
GPIO_EXTILineConfig(IRQLOW_EXTI_PORT, IRQLOW_EXTI_PIN);
// Configure EXTI line
EXTI_InitStructure.EXTI_Line = IRQLOW_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
// Configure, but do not enable, EXTI Interrupt
NVIC_InitStructure.NVIC_IRQChannel = IRQLOW_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);
Die IRQ-Handler sind wie folgt eingerichtet:
void EXTI3_IRQHandler(void)
{
IRQHigh();
EXTI_ClearITPendingBit(IRQHIGH_EXTI_LINE);
}
void EXTI15_10_IRQHandler(void)
{
if (EXTI_GetITStatus(IRQLOW_EXTI_LINE) == SET)
{
if (IRQLow()) // This returns a non-zero value if an overflow happened
{
CleanUpOverflow();
}
// Clear interrupt bit.
EXTI_ClearITPendingBit(IRQLOW_EXTI_LINE);
}
else // unknown EXTI source
{
ErrorHandler(ERR_UNKNOWN_EXTI15_10_IRQ); // This never happens
}
}
Ein paar Dinge zu beachten:
IRQHigh() und IRQLow() nehmen jeweils viel Zeit in Anspruch (weshalb ich möchte, dass einer den anderen unterbricht).
IRQLow ist anfänglich nicht aktiviert, wird aber später mit aktiviertNVIC_EnableIRQ(IRQLOW_EXTI_IRQn);
Innerhalb von EXTI15_10_IRQHandler() erhalte ich einen Rückgabewert von IRQLow().
Ich habe die xxx_IRQHandler() Funktionen mit und ohne deklariert __attribute__ ((interrupt ("IRQ")))
. Ich verstehe, dass dieses Attribut bei Cortex-M3 nicht erforderlich ist, aber ich habe es trotzdem versucht (und die gleichen Ergebnisse erhalten).
Was mache ich falsch?
Update: Mit Hilfe eines Kommentars von @Jeroen3 habe ich entdeckt, dass IRQLow IRQHigh unterbricht. Jetzt muss ich herausfinden warum...
Die Prioritäten werden nicht korrekt initialisiert.
Der Code in der Frage initialisiert das NVIC wie folgt:
// IRQHigh, enabled immediately
NVIC_InitStructure.NVIC_IRQChannel = IRQHIGH_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// IRQLow, to be enabled later:
NVIC_InitStructure.NVIC_IRQChannel = IRQLOW_EXTI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);
Später wird IRQLow dann explizit mit aktiviert NVIC_EnableIRQ()
.
Das Problem ist, dass die NVIC_Init()
Funktion (aus der SPL) nichts (!) Initialisiert, wenn IRQChannelCmd = DISABLE . Es setzt einfach das ICER-Register, um diesen Interrupt zu deaktivieren.
Das scheint mir ein Bug zu sein, aber sei es so. Jetzt muss ich die anderen xxx_Init()
Funktionen in der SPL überprüfen und sehen, ob mich später etwas anderes beißen könnte :)
Es gibt ein paar Lösungen. Ich ziehe es vor, alle fünf Zeilen der IRQLow-Init-Sequenz wegzulassen und durch diese zu ersetzen:
NVIC_SetPriority(IRQLOW_EXTI_IRQn, 5);
Dann, wenn es Zeit ist, NVIC_EnableIRQ()
kann es wie vorgesehen verwendet werden.
Beachten Sie, dass dies funktioniert, weil das NVIC mit NVIC_PriorityGroup_4
(keine Unterprioritäten) konfiguriert ist. Bei unterschiedlichen PriorityGroup-Einstellungen müssten Sie auch die Unterpriorität konfigurieren.
Jeroen3
Tut
bitsmack
Tut
Tut
bitsmack
bitsmack
bitsmack
0___________