ARM Cortex-M33 Execution Halt When Running Code from DDR4 Memory
The Corstone SSE-300 platform, based on the ARM Cortex-M33 processor, is designed to provide a secure and efficient environment for embedded applications. One of its key features is the inclusion of Tightly Coupled Memory (TCM), which includes Instruction TCM (ITCM) and Data TCM (DTCM). These memory regions are optimized for low-latency access, making them ideal for critical code and data. However, the limited size of ITCM (typically 512 KB) can pose challenges when dealing with larger executables that exceed this capacity. In such cases, developers may attempt to place their code in external memory, such as DDR4, to accommodate the larger size.
When attempting to execute code from DDR4 memory starting at address 0x6000000, the Cortex-M33 halts after executing only two instructions. This behavior is unexpected, especially since the same code executes successfully when loaded into ITCM. The issue is further complicated by the fact that the program runs correctly when a debugger is connected, a hardware reset is performed, and the program is manually started. This suggests that the problem is related to the initialization or configuration of the memory subsystem, rather than the code itself.
The Cortex-M33 relies on a Memory Protection Unit (MPU) to enforce memory access permissions and attributes. The MPU is crucial for ensuring that code and data are accessed in a manner consistent with the system’s security and performance requirements. When code is placed in DDR4, the MPU must be configured to allow execution from this region. Additionally, the DDR4 memory controller must be properly initialized to ensure that the memory is accessible and that the correct timing parameters are applied. Failure to configure these components correctly can result in the processor being unable to fetch and execute instructions from the external memory, leading to the observed halt.
MPU Misconfiguration and DDR4 Initialization Timing Issues
The most likely cause of the execution halt is a misconfiguration of the Memory Protection Unit (MPU). The MPU is responsible for defining the memory regions and their attributes, such as access permissions, cacheability, and executability. By default, the Cortex-M33 may not allow execution from external memory regions like DDR4 unless explicitly configured to do so. If the MPU is not properly set up to mark the DDR4 region as executable, the processor will generate a fault when attempting to fetch instructions from this area, resulting in a halt.
Another potential cause is improper initialization of the DDR4 memory controller. DDR4 memory requires precise timing and configuration to function correctly. The memory controller must be programmed with the correct parameters, such as refresh rates, CAS latency, and voltage levels, before the memory can be accessed. If the DDR4 controller is not initialized or is configured incorrectly, the memory may not be ready when the processor attempts to fetch instructions, leading to a failure in execution.
Additionally, the Cortex-M33’s bus matrix and memory interfaces must be configured to allow access to the DDR4 region. The AHB (Advanced High-performance Bus) and APB (Advanced Peripheral Bus) interfaces must be set up to route memory accesses to the correct destination. If the bus matrix is not configured to map the DDR4 region correctly, the processor will be unable to access the memory, resulting in a halt.
The fact that the program runs successfully when a debugger is connected and a hardware reset is performed suggests that the issue may be related to the timing of the DDR4 initialization. When the debugger is connected, it may introduce additional delays or perform steps that ensure the DDR4 memory is ready before the processor starts executing code. Without the debugger, the processor may attempt to access the DDR4 memory before it is fully initialized, leading to the observed halt.
Configuring MPU for DDR4 Execution and Ensuring Proper DDR4 Initialization
To resolve the issue of the Cortex-M33 halting when executing code from DDR4, the following steps should be taken:
1. Configure the MPU to Allow Execution from DDR4:
The MPU must be configured to mark the DDR4 region as executable. This involves defining a memory region that covers the DDR4 address space (starting at 0x6000000) and setting the appropriate attributes. The region should be marked as executable, and the access permissions should be set to allow privileged and unprivileged access. The MPU configuration can be done using the ARM CMSIS (Cortex Microcontroller Software Interface Standard) MPU functions or by directly writing to the MPU registers.
For example, the following code snippet demonstrates how to configure the MPU to allow execution from the DDR4 region:
#include "arm_mpu.h"
void configure_mpu() {
ARM_MPU_Disable();
ARM_MPU_SetRegion(
0, // Region number
ARM_MPU_RBAR(0x6000000, ARM_MPU_SH_NON, 0, 1, 0), // Base address and attributes
ARM_MPU_RLAR(0x6000000 + DDR4_SIZE - 1, 1) // Limit address and enable region
);
ARM_MPU_Enable(ARM_MPU_CTRL_PRIVDEFENA_Msk);
}
2. Initialize the DDR4 Memory Controller:
The DDR4 memory controller must be properly initialized before the processor attempts to access the memory. This involves programming the controller with the correct timing parameters, such as refresh rates, CAS latency, and voltage levels. The initialization sequence typically involves writing to the controller’s configuration registers and waiting for the memory to stabilize. The exact steps will depend on the specific DDR4 memory controller used in the system.
For example, the following code snippet demonstrates a basic DDR4 initialization sequence:
void initialize_ddr4() {
// Set DDR4 timing parameters
DDR4_CONTROLLER->TIMING1 = 0x12345678;
DDR4_CONTROLLER->TIMING2 = 0x9ABCDEF0;
// Enable the DDR4 controller
DDR4_CONTROLLER->CTRL |= DDR4_CTRL_ENABLE;
// Wait for the DDR4 memory to stabilize
while (!(DDR4_CONTROLLER->STATUS & DDR4_STATUS_READY));
}
3. Configure the Bus Matrix and Memory Interfaces:
The AHB and APB interfaces must be configured to route memory accesses to the DDR4 region. This involves setting up the bus matrix to map the DDR4 address space to the correct memory controller. The configuration can be done using the system control registers or through a configuration tool provided by the SoC vendor.
For example, the following code snippet demonstrates how to configure the bus matrix to map the DDR4 region:
void configure_bus_matrix() {
BUS_MATRIX->DDR4_MAPPING = 0x6000000; // Map DDR4 region to memory controller
BUS_MATRIX->CTRL |= BUS_MATRIX_CTRL_ENABLE;
}
4. Ensure Proper Timing of DDR4 Initialization:
To ensure that the DDR4 memory is ready before the processor starts executing code, it may be necessary to introduce a delay or wait for a specific signal indicating that the memory is stable. This can be done by polling a status register in the DDR4 memory controller or by using a hardware timer to introduce a delay.
For example, the following code snippet demonstrates how to wait for the DDR4 memory to stabilize:
void wait_for_ddr4_ready() {
while (!(DDR4_CONTROLLER->STATUS & DDR4_STATUS_READY)) {
// Wait for DDR4 memory to be ready
}
}
5. Verify the Configuration with a Debugger:
After configuring the MPU, DDR4 memory controller, and bus matrix, it is important to verify the configuration using a debugger. The debugger can be used to inspect the MPU settings, DDR4 controller registers, and bus matrix configuration to ensure that everything is set up correctly. Additionally, the debugger can be used to step through the initialization sequence and verify that the DDR4 memory is accessible before the processor starts executing code.
By following these steps, the Cortex-M33 should be able to execute code from the DDR4 memory region without halting. The key is to ensure that the MPU is configured to allow execution from the DDR4 region, the DDR4 memory controller is properly initialized, and the bus matrix is configured to route memory accesses correctly. Additionally, proper timing of the DDR4 initialization is crucial to ensure that the memory is ready before the processor attempts to access it.
In conclusion, executing code from DDR4 memory on the Corstone SSE-300 platform requires careful configuration of the MPU, DDR4 memory controller, and bus matrix. By addressing these components and ensuring proper initialization timing, developers can successfully run large executables from external memory, overcoming the limitations of the ITCM region.