Cortex-M33 FVP Register Access Hard Fault Due to Memory Map Mismatch
The issue at hand involves a hard fault occurring during register access while debugging a Cortex-M33-based firmware using the Fixed Virtual Platform (FVP). The firmware is developed for the LPCXpresso55S28 board, which features an NXP LPC55S28 microcontroller with a Cortex-M33 core. The hard fault is triggered when attempting to access specific registers, such as the BODVBAT register in the Power Management Controller (PMC). This issue is observed exclusively during FVP-based debugging, while the same code runs without issues on the actual hardware.
The root cause of this problem lies in the mismatch between the memory map of the LPC55S28 microcontroller and the memory map of the FVP. The FVP, specifically the FVP_MPS2_Cortex-M33_MDK model, has a predefined memory map that does not align with the peripheral addresses used in the LPC55S28. This misalignment causes the FVP to interpret the register accesses as invalid memory operations, leading to a hard fault.
Memory Map Misalignment Between LPC55S28 and FVP_MPS2_Cortex-M33
The LPC55S28 microcontroller has a specific memory map where peripherals are mapped to addresses starting from 0x40020000. For instance, the PMC registers, including BODVBAT and RESETCTRL, are located at specific offsets from this base address. However, the FVP_MPS2_Cortex-M33 model has a different memory map, which is documented in the Arm Developer documentation. The FVP’s memory map does not include the peripheral addresses used by the LPC55S28, leading to a situation where the FVP cannot resolve the addresses being accessed by the firmware.
The FVP’s memory map is designed to simulate a generic Cortex-M33 system, and it does not include the specific peripheral configurations of the LPC55S28. This is a common issue when using FVPs for debugging, as they are not tailored to match the memory maps of specific microcontrollers. The FVP’s memory map is static and cannot be dynamically reconfigured to match the LPC55S28’s memory map without significant modifications.
Remapping Peripheral Addresses and Debugging Strategies for FVP Compatibility
To resolve the hard fault issue, the peripheral addresses in the firmware must be remapped to align with the FVP’s memory map. This can be achieved by modifying the header files that define the peripheral addresses. In the case of the LPC55S28, the peripheral addresses are defined in the LPC55S28.h header file, which contains over 27,000 lines of definitions. The following steps outline the process of remapping the peripheral addresses for FVP compatibility:
-
Identify the Peripheral Addresses: The first step is to identify the peripheral addresses used in the firmware. In this case, the PMC registers, such as BODVBAT and RESETCTRL, are accessed at specific offsets from the base address 0x40020000. These addresses must be identified and documented.
-
Create a Modified Header File: A copy of the LPC55S28.h header file should be created specifically for the FVP target. This modified header file will contain the remapped peripheral addresses that align with the FVP’s memory map. For example, the PMC registers can be remapped to addresses within the FVP’s RAM region, which is typically located at a different base address.
-
Replace Peripheral Addresses with RAM Addresses: In the modified header file, the peripheral addresses should be replaced with addresses within the FVP’s RAM region. For instance, if the FVP’s RAM region starts at 0x20000000, the PMC registers can be remapped to addresses within this region. This allows the firmware to access the "registers" without causing a hard fault, as the FVP can resolve these addresses.
-
Update the Firmware to Use the Modified Header File: The firmware must be updated to include the modified header file instead of the original LPC55S28.h file. This ensures that the firmware uses the remapped peripheral addresses during FVP-based debugging.
-
Verify the Remapped Addresses: After remapping the peripheral addresses, the firmware should be recompiled and loaded into the FVP for debugging. The debugger should be used to verify that the remapped addresses are being accessed correctly and that no hard faults occur during register access.
-
Implement a Mechanism for Output Redirection: Since the FVP does not simulate the actual behavior of the LPC55S28 peripherals, a mechanism should be implemented to redirect the output of the firmware to a location that can be monitored during debugging. This could involve redirecting stdout to a simulated UART or a memory buffer that can be inspected during debugging.
By following these steps, the firmware can be adapted to run on the FVP without encountering hard faults due to memory map mismatches. This approach allows for effective debugging and unit testing of the firmware using the FVP, even though the FVP does not fully simulate the LPC55S28 microcontroller’s peripherals.
Detailed Analysis of the FVP Memory Map and Peripheral Remapping
The FVP_MPS2_Cortex-M33 model has a predefined memory map that is documented in the Arm Developer documentation. This memory map includes regions for RAM, ROM, and peripherals, but it does not match the memory map of the LPC55S28 microcontroller. The following table provides a comparison of the memory maps for the LPC55S28 and the FVP_MPS2_Cortex-M33:
Memory Region | LPC55S28 Address Range | FVP_MPS2_Cortex-M33 Address Range |
---|---|---|
RAM | 0x20000000 – 0x2001FFFF | 0x20000000 – 0x2001FFFF |
ROM | 0x00000000 – 0x0007FFFF | 0x00000000 – 0x0007FFFF |
Peripherals | 0x40020000 – 0x400FFFFF | Not Available |
FVP Peripherals | Not Available | 0x40000000 – 0x400FFFFF |
As shown in the table, the LPC55S28’s peripheral region starts at 0x40020000, while the FVP’s peripheral region starts at 0x40000000. This mismatch means that the FVP cannot resolve the peripheral addresses used by the LPC55S28 firmware, leading to hard faults during debugging.
To remap the peripheral addresses, the following steps can be taken:
-
Identify the FVP’s RAM Region: The FVP’s RAM region is located at 0x20000000 – 0x2001FFFF. This region can be used to simulate the peripheral registers by remapping the LPC55S28’s peripheral addresses to this region.
-
Create a Memory-Mapped Structure in RAM: A memory-mapped structure can be created in the FVP’s RAM region to simulate the peripheral registers. For example, a structure representing the PMC registers can be defined as follows:
typedef struct {
uint32_t BODVBAT;
uint32_t RESETCTRL;
} PMC_Type;
- Map the Structure to the FVP’s RAM Region: The structure can be mapped to the FVP’s RAM region by defining a pointer to the structure at the desired address:
#define FVP_RAM_BASE 0x20000000
#define PMC_BASE (FVP_RAM_BASE + 0x1000) // Example offset
PMC_Type *PMC = (PMC_Type *)PMC_BASE;
- Update the Firmware to Use the Remapped Addresses: The firmware should be updated to use the remapped addresses. For example, the
POWER_SetBodVbatLevel
function can be modified as follows:
static inline void POWER_SetBodVbatLevel(power_bod_vbat_level_t level, power_bod_hyst_t hyst, bool enBodVbatReset)
{
// Use the remapped PMC registers
PMC->BODVBAT = (PMC->BODVBAT & (~(PMC_BODVBAT_TRIGLVL_MASK | PMC_BODVBAT_HYST_MASK))) | PMC_BODVBAT_TRIGLVL(level) |
PMC_BODVBAT_HYST(hyst);
PMC->RESETCTRL =
(PMC->RESETCTRL & (~PMC_RESETCTRL_BODVBATRESETENABLE_MASK)) | PMC_RESETCTRL_BODVBATRESETENABLE(enBodVbatReset);
}
By following these steps, the firmware can be adapted to run on the FVP without encountering hard faults due to memory map mismatches. This approach allows for effective debugging and unit testing of the firmware using the FVP, even though the FVP does not fully simulate the LPC55S28 microcontroller’s peripherals.
Conclusion
The hard fault issue during FVP-based debugging of a Cortex-M33 firmware is caused by a mismatch between the memory map of the LPC55S28 microcontroller and the FVP_MPS2_Cortex-M33 model. This mismatch can be resolved by remapping the peripheral addresses to align with the FVP’s memory map. By creating a modified header file and updating the firmware to use the remapped addresses, the firmware can be successfully debugged using the FVP. This approach provides a practical solution for running unit tests and debugging firmware on the FVP, even when the FVP does not fully simulate the target microcontroller’s peripherals.