I am trying to implement some logic which is meant to be enforcing an MIT constraint in the way some specific interrupt is handled in a stm32f429
board (so building against the ravenscar-full-stm32f429disco
runtime).
For context, I have configured the MC01
pin of this board to pulsate at a rate of 3.2MHz (so actually period and not sporadic but probably somewhat irrelevant to my question) and have then jumpered this pin to another one which has been configured as an interrupt receiver for the EXTI4_Interrupt
interrupt. The AHB bus is running at the default 16MHz.
The MIT enforcer is implemented by way of the following protected object:
with Ada.Interrupts.Names;
with System; use System;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;
use Ada.Real_Time;
package Interrupt_Controllers with Elaborate_Body is
protected MIT_Controller with
Interrupt_Priority => Interrupt_Priority'Last
is
procedure Handle_Interrupt with
Attach_Handler => Ada.Interrupts.Names.EXTI4_Interrupt;
entry Wait_For_Next_Interrupt;
private
Event: Timing_Event;
procedure Handle_Timeout(E: in out Timing_Event);
Arrived: Boolean;
MIT: Time_Span := Milliseconds(100);
end MIT_Controller;
task type Interrupt_Action;
end Interrupt_Controllers;
with the body being:
with EXTI; use EXTI;
with Common_Types; use Common_Types;
package body Interrupt_Controllers is
protected body MIT_Controller is
procedure Handle_Interrupt is
begin
EXTI_IMR_Register.MR4 := Off; -- disable interrupt
EXTI_PR_Register.PR4 := On; -- clear pending status (bit needs to be set HIGH in order to do that)
Set_Handler(Event, Clock + MIT, Handle_Timeout'Access); -- setup interrupt-enable event to fire after MIT
Arrived := True;
end Handle_Interrupt;
entry Wait_For_Next_Interrupt when Arrived is
begin
Arrived := False;
end Wait_For_Next_Interrupt;
procedure Handle_Timeout(E: in out Timing_Event) is
begin
EXTI_IMR_Register.MR4 := On; -- enable the interrupt
end Handle_Timeout;
end MIT_Controller;
type Count is mod Natural'Last;
task body Interrupt_Action is
C: Count := 0;
begin
loop
MIT_Controller.Wait_For_Next_Interrupt;
C := C + 1;
end loop;
end Interrupt_Action;
IA: Interrupt_Action;
end Interrupt_Controllers;
and in the “main” procedure I just:
with Interrupt_Controllers;
pragma Elaborate(Interrupt_Controllers);
which then just enters an infinite loop i.e.
loop
null;
end loop;
Now when I run this in gdb and put a few brakepoints inside Handle_Interrupt
, Handle_Timeout
and the Interrupt_Action
task I only get hits for the first two but not the task. I.e. if the execution is constantly continue
d breakpoint hitting alternates between the interrupt handler and the timeout handler but never goes inside the task.
One thought I had was that something is incomplete with regards to program elaboration so I added the with Elaborate_Body
to the package specification but also the Elaborate
pragma in “main” as shown above but that didn’t change much (gdb was hitting the interrupt handler breakpoints anyway even without these).
Running info threads
whilst inside Handle_Interrupt
yields:
Id Target Id Frame
* 1 Thread <main> interrupt_controllers.mit_controller.handle_interrupt (<_object>=...) at /home/...
which is somewhat interesting as it kinda indicates the runtime somehow hijacks the “main” thread to run the interrupt handler?
Another thought was that maybe Interrupt_Action
running on the default priority gets constantly preempted by the interrupt handler so never gets a chance to run. But that seems somewhat unlikely as there’s an MIT of 100ms
and the AHB bus is running at a much higher rate than the interrupt rate.
Obviously, I can’t declare the task object inside “main” because of the No_Task_Hierarchy
restriction in Ravenscar but isn’t the above what at library level
means? (i.e. declare within the declarative part of a package specification/body)
I’m clearly missing something basic here.
Any pointers would be much appreciated. - Thanks.