ARM PL390 GIC Interrupt Priority Handling in Cyclone V SoC

The ARM PL390 Generic Interrupt Controller (GIC) is a critical component in the Cyclone V SoC for managing interrupt priorities and ensuring that high-priority tasks are handled appropriately. The PL390 GIC is responsible for receiving interrupts from various sources, prioritizing them based on configured settings, and forwarding the highest-priority interrupt to the CPU. In a bare-metal multi-tasking environment, understanding how the PL390 GIC handles interrupt priorities is essential for achieving deterministic behavior in real-time systems.

In the Cyclone V SoC, the PL390 GIC supports up to 256 interrupt sources, each of which can be assigned a unique priority level. The GIC uses these priority levels to determine which interrupt should be serviced first when multiple interrupts are pending. The GIC also supports preemption, allowing higher-priority interrupts to interrupt lower-priority ones. However, the GIC does not inherently support nested interrupts of the same priority level, which can lead to challenges in systems where multiple tasks with different timing requirements must coexist.

The specific scenario involves three FPGA-generated interrupts: a base tick timer interrupt (IRQ 74) every 50 microseconds, a fast task interrupt (IRQ 75) every 1 millisecond, and a slow task interrupt (IRQ 76) every 5 milliseconds. The desired behavior is that the base tick timer interrupt should always have the highest priority and should be able to interrupt both the fast and slow task interrupts. The fast task interrupt should be able to interrupt the slow task interrupt but should not be interrupted by it. The slow task interrupt should be the lowest priority and should be interruptible by both the base tick timer and the fast task interrupts.

Priority Configuration and Preemption Limitations in PL390 GIC

The PL390 GIC allows for the configuration of interrupt priorities through its priority registers. Each interrupt source has an associated priority field, typically 5 to 8 bits wide, depending on the implementation. In the Cyclone V SoC, the priority field is 5 bits wide, allowing for 32 distinct priority levels. The lower the numerical value of the priority field, the higher the priority of the interrupt. For example, an interrupt with a priority value of 0 has the highest priority, while an interrupt with a priority value of 31 has the lowest priority.

One of the key limitations of the PL390 GIC is that it does not support dynamic priority adjustment during runtime. Once the priority levels are set, they remain fixed unless explicitly modified by software. This can be problematic in systems where the priority of tasks may need to change dynamically based on system conditions. Additionally, the PL390 GIC does not support nested interrupts of the same priority level. If two interrupts with the same priority are pending, the GIC will service them in the order in which they were received, which may not always align with the desired behavior.

In the given scenario, the base tick timer interrupt (IRQ 74) should be assigned the highest priority, followed by the fast task interrupt (IRQ 75), and then the slow task interrupt (IRQ 76). However, the PL390 GIC does not inherently support the concept of task-based preemption. Instead, it relies on the priority levels assigned to each interrupt to determine which interrupt should be serviced first. This means that if the fast task interrupt (IRQ 75) is currently being serviced, the base tick timer interrupt (IRQ 74) can preempt it, but the slow task interrupt (IRQ 76) cannot.

Another potential issue is the handling of interrupt masking and enabling. The PL390 GIC provides interrupt enable and disable controls at both the global and individual interrupt levels. If an interrupt is disabled, it will not be forwarded to the CPU, even if it has a high priority. This can lead to situations where critical interrupts are missed if they are inadvertently disabled. Additionally, the GIC supports interrupt masking, which can be used to temporarily block lower-priority interrupts while a higher-priority interrupt is being serviced. However, improper use of interrupt masking can lead to deadlock or priority inversion, where a lower-priority task blocks a higher-priority task from executing.

Implementing Interrupt Priority and Preemption in Cyclone V SoC

To achieve the desired interrupt behavior in the Cyclone V SoC, the following steps should be taken:

  1. Assigning Priority Levels: The first step is to assign appropriate priority levels to each of the three interrupts. The base tick timer interrupt (IRQ 74) should be assigned the highest priority (e.g., priority level 0), the fast task interrupt (IRQ 75) should be assigned a medium priority (e.g., priority level 10), and the slow task interrupt (IRQ 76) should be assigned the lowest priority (e.g., priority level 20). This ensures that the base tick timer interrupt can preempt both the fast and slow task interrupts, and the fast task interrupt can preempt the slow task interrupt.

  2. Configuring the PL390 GIC Priority Registers: The priority levels for each interrupt should be written to the corresponding priority registers in the PL390 GIC. This can be done during the initialization phase of the system. The priority registers are typically memory-mapped, and their addresses can be found in the Cyclone V SoC documentation. For example, the priority register for IRQ 74 might be located at address 0xFFFED400 + (74 * 4), and the priority value can be written to this address.

  3. Enabling Interrupts: After assigning priority levels, the interrupts should be enabled in the PL390 GIC. This involves setting the corresponding bits in the interrupt enable registers. The global interrupt enable bit should also be set to allow the GIC to forward interrupts to the CPU. The interrupt enable registers are also memory-mapped, and their addresses can be found in the Cyclone V SoC documentation.

  4. Handling Interrupt Preemption: The PL390 GIC supports interrupt preemption by default, meaning that a higher-priority interrupt can interrupt a lower-priority interrupt that is currently being serviced. However, it is important to ensure that the interrupt service routines (ISRs) for the base tick timer and fast task interrupts are designed to handle preemption correctly. This includes saving and restoring the CPU context, as well as ensuring that any shared resources are properly protected.

  5. Avoiding Priority Inversion: To avoid priority inversion, where a lower-priority task blocks a higher-priority task, it is important to use interrupt masking judiciously. Interrupt masking should only be used when absolutely necessary, and the duration of masking should be kept as short as possible. Additionally, any shared resources accessed by multiple interrupts should be protected using appropriate synchronization mechanisms, such as spinlocks or semaphores.

  6. Testing and Validation: Once the interrupt priorities and preemption settings are configured, the system should be thoroughly tested to ensure that the desired behavior is achieved. This includes testing scenarios where multiple interrupts occur simultaneously, as well as scenarios where interrupts are nested. The system should also be tested under heavy load to ensure that it can handle the maximum expected interrupt rate without missing any critical interrupts.

By following these steps, the desired interrupt behavior can be achieved in the Cyclone V SoC using the PL390 GIC. However, it is important to note that the PL390 GIC has certain limitations, such as the lack of support for dynamic priority adjustment and nested interrupts of the same priority level. These limitations should be taken into account when designing the system, and alternative approaches may need to be considered if the desired behavior cannot be achieved with the PL390 GIC alone.

In conclusion, the PL390 GIC in the Cyclone V SoC provides a flexible and powerful mechanism for managing interrupt priorities and preemption. However, achieving the desired behavior requires careful configuration of the GIC registers, proper handling of interrupt preemption, and thorough testing and validation. By following the steps outlined above, the desired interrupt behavior can be achieved, ensuring that the base tick timer interrupt can always preempt the fast and slow task interrupts, and the fast task interrupt can preempt the slow task interrupt.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *