I am using an ATSAMS70 (Cortex M7) microcontroller equipped with DMA and an ARM Memory Protection Unit (MPU). I have a high-speed serial interface coming in on a USART and being DMA'd into RAM. I need to disable caching of that region so the CPU will actually see the data that the DMA just wrote. Microchip's documentation and the Atmel START tool support DMA configuration but not the MPU as far as I can see. So I don't have an API to work with and have to configure the MPU via registers.
I got the DMA working fairly easily. And I've been able to create a region with the MPU and verify that it handling accesses to that region. The DMA can write to this memory, but if the CPU tries to read or write this in this area, the MPU throws a data access violation. I've tried various combinations of the region attributes but can't seem to crack it. It's not supposed matter but the code that trips the exception is running in privileged mode.
Can anyone help? Here is the function that configures the MPU region. This is the only region I am configuring so all other accesses are following the default mapping.
I got the DMA working fairly easily. And I've been able to create a region with the MPU and verify that it handling accesses to that region. The DMA can write to this memory, but if the CPU tries to read or write this in this area, the MPU throws a data access violation. I've tried various combinations of the region attributes but can't seem to crack it. It's not supposed matter but the code that trips the exception is running in privileged mode.
Can anyone help? Here is the function that configures the MPU region. This is the only region I am configuring so all other accesses are following the default mapping.
Code:
/*
* Configure the specified region, 1..16
* Returns the region size in bytes, which may be more than the requested size
*/
unsigned MPU_SetRegion(unsigned Region, u32 BaseAddress, unsigned BytesRequested, bool Cacheable, bool Executable)
{
u16 size_exponent;
// MPU uses an exponent of 2 to specify the region size.
// Find the lowest exponent which will satisfy the request.
size_exponent = 0;
if (BytesRequested < 32)
{
BytesRequested = 32;
}
while (BytesRequested > 1)
{
size_exponent += 1;
BytesRequested /= 2;
}
// Set base address and select region for configuration
// Writing the RNR selects the region which the RBAR and RASR control
MPU->MPU_RNR.Register = (Region-1);
MPU->MPU_RBAR.Register = (BaseAddress & MPU_REGION_ADDRESS_MASK);
// Configure the region
MPU->MPU_RASR.Size = size_exponent - 1;
MPU->MPU_RASR.XN = Executable ? 0 : 1;
MPU->MPU_RASR.AP = 0b011; /* no privilege restriction */
MPU->MPU_RASR.B = Cacheable ? 1 : 0;
MPU->MPU_RASR.C = Cacheable ? 1 : 0;;
MPU->MPU_RASR.TEX = Cacheable ? 0b000 : 0b001;
MPU->MPU_RASR.SRD = 0; // enable all sub-regions
MPU->MPU_RASR.S = 1; // region is shareable
// Enable the region
MPU->MPU_RASR.Enable = 1;
// Return actual size of the region
return(1 << size_exponent);
}
Last edited: