MPU

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks, would yous mind if I ask a few questions about the MPU in the UC3 controller.

 

dmpu_entries[REGION_2_STACK_INDEX].addr = (uint32_t)&_stack;
dmpu_entries[REGION_2_STACK_INDEX].size = MPU_REGION_SIZE_4KB;

Is the stack address set to the start of the stack memory block or does it point at the end.

Is the size field for example 4000 or 4096

 

Cheers Lads

This topic has a solution.
Last Edited: Sun. Dec 10, 2017 - 09:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do the datasheets really not provide such facts? 

 

(as you'll have spotted there aren't many UC3 users here to answer such questions, maybe just Mike and Greg?) 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you actually asking about the MPU itself, or is this just a question about the meaning of the  REGION_2_STACK_INDEX symbol in the code snippet you posted?

 

The former, as clawson said. would surely be answered in the Datasheet;

You should be able to answer the latter by browsing the code - as we don't know where that code came from, we can't help you there.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys, what does it mean when it says the base address must be aligned to the size of the region???

 

typedef struct {
  unsigned int addr; /*! Base address of the protection region. Must be aligned to the size of the region. */
  eRegionSize size;  /*! Size of the protection region */
  bool valid;        /*! Protection validity. One of SET(the protection region is valid) or CLR(the region is not considered in the protection testing). */
} mpu_entry_t;

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My guess is if the region is 4k, then the base addr must be a multiple of 4k
Eg: 0x12345000
If region is 64k
0x12340000

This makes sense if the hardware logic is simply a mask and compare. Otherwise the hardware would need to be two compares.

Last Edited: Sat. Dec 9, 2017 - 10:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Kartman, interesting observation but its way over my head.  How would I allocate memory for the stack that adheres to these specifications.

 

Thanks for the response mate.

Edited, thanks I get it now...  Now I need to think of away to allocate memory that fits the specification! Thanks again!

Last Edited: Sat. Dec 9, 2017 - 10:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any suggestions on allocating memory that aligns lads?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, you could allocate a large block, then with some pointer calculations, address aligned areas inside that block.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was thinking that El Tangas.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Far from an expert, but wouldn't setting up a specific memory section in the linker scripts do the trick?

 

El Tangas wrote:

Well, you could allocate a large block, then with some pointer calculations, address aligned areas inside that block.

Wouldn't that waste memory?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It will waste memory, of course. I hope there is memory to waste...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With the "allocate and pointer arithmetics" methos you'd need to allocate 4K + size of your variable(s). If my hunch about a separate memory section is correct you'd need a section the size of your variable(s). Correct?

 

Since this thing with memory sections, linker scripts etc is not specific for e.g. AVR(8)s or UC32s but more generic to the GCC tool chain maybe some of the gurus on the subject could be lured into this thread?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The memory is to be allocated for tasks on a RTOS, may be if I could allocate one huge block at the start and split it up then the waste will be kept to a min.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 3

Don't ever do that! I was once involved in a system that had about 5MB of RAM available. One software component would allocate 2MB at start up then operate a "private" heap within that. This led to silly situations where either the heap in the remaining 3MB "ran out" while the 2MB heap still had plenty of space or the converse where the 2MB heap ran out while there was still plenty in the 3MB. If they had all just allocated from the 5MB the system could have continued for much longer so "private" heaps are a terrible idea.

 

(in this case it was done for "security" as that software block was a "secure module")

 

Unless you are employing virtualization then you are going to hit all kinds of problems with heap fragmentation anyway. (which is why Win32 and Linux use an MMU!). You only have to play with uCLinux for a while to realise why non-MMU beased memory allocation is a terrible idea.

 

Slowly but surely you will end up reimplementing Linux or Win32 but there's a reason why those are hugely complex operating systems!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

EDITED, yes, the alignment required is 0x1234000.  I've followed the code through and it should be okay but it returns MPU_SETUP_ENTRY_INVALIDBASEADDR

 

Hi freaks, I'm trying to work out how the MPU expects the memory to be aligned, we suspect it is "0x1234000" or "0x2468000".  The Test function that is reporting an invalid size is as follows: mpu_entry->size is 11;

  // Check the base address: it must be aligned to the size of the region.
  // This test is written carefully to also work for the 4-GB case.
  if(!Test_align(mpu_entry->addr, 2 << (U32)mpu_entry->size))
    // ERROR: the input base address is not aligned to the size of the region.
    return(MPU_SETUP_ENTRY_INVALIDBASEADDR);

Test_align is as follows:

/*! \brief Tests alignment of the number \a val with the \a n boundary.
 *
 * \param val Input value.
 * \param n   Boundary.
 *
 * \return \c 1 if the number \a val is aligned with the \a n boundary, else \c 0.
 */
#define Test_align(val, n     ) (!Tst_bits( val, (n) - 1     )   )

Tst_bits is:

/*! \brief Tests the bits of a value specified by a given bit-mask.
 *
 * \param value Value of which to test bits.
 * \param mask  Bit-mask indicating bits to test.
 *
 * \return \c 1 if at least one of the tested bits is set, else \c 0.
 */
#define Tst_bits( value, mask)  (Rd_bits(value, mask) != 0)​

Any help will be much appreciated, thanks guys.

 

 

Last Edited: Tue. Dec 12, 2017 - 01:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Found the error, my math for calculating the alignment is of.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay, the MPU is validating my aligned address, but it is still not working.  I'll posts yous tomorrow when I get a chance to look into it.  It's 5am here. ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right Freaks, could you have a look t the following code for the MPU I have written. First I set the privileged​ mode first using the following code:

void setup_mpu_permissions(void){
   
   /* Set Access Permission A to Read access in privileged mode and to None in
 * unprivileged mode.
 */
 set_access_permissions(REGION_0_STACK_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX); 
   
 /*
 * Set Access Permission B to Read/Write access in privileged mode and to
 * None in unprivileged mode.
 */
 set_access_permissions(REGION_0_STACK_INDEX, MPU_APRB_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
 * Set all subregions of the stack to Read/Write access
 * (i.e. use the Access Permissions B).
 */
 select_subregion(REGION_0_STACK_INDEX, 0x0ffff);
}

When I create a task I align the stack address with the following function:

unsigned int * configure_stack_mpu(struct task_ctrl_obj * tcb, unsigned char mpu_mem){
 
 
 // Security Check...
 if((mpu_mem > 30) || (mpu_mem < 11))
   mpu_mem  = MPU_REGION_SIZE_4KB;
  
  
 unsigned int allignment = mpu_allignment(mpu_mem);
 unsigned int memory_size = mpu_memory(mpu_mem);
 
 unsigned int * ptr = api_malloc(sizeof(int) * memory_size * 2);
 
 tcb->stack_allocation = ptr;
 tcb->ergonRegion = mpu_mem;
 
 unsigned int allignment_offset = (unsigned int)ptr & allignment; allignment_offset = (allignment + 1) - allignment_offset;
 
 if((allignment_offset + (unsigned int)ptr) & mpu_allignment(mpu_mem))
  gpio_set_gpio_pin(AVR32_PIN_PB22);
 
 
 return((unsigned int *)(allignment_offset + (unsigned int)ptr));
}

I lad the MPU settings during the context switch:

void setup_mpu(struct task_ctrl_obj * tcb){
 
 internal_set_cpu_mode(Supervisor_Mode);
 
 dmpu_entries[REGION_0_STACK_INDEX].addr = (uint32_t)tcb->mpu_base_mem_addr;
 dmpu_entries[REGION_0_STACK_INDEX].size = tcb->ergonRegion;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_0_STACK_INDEX].valid = true;
 
 if (set_mpu_entry(&dmpu_entries[REGION_0_STACK_INDEX], REGION_0_STACK_INDEX) == MPU_SETUP_ENTRY_OK) {
  gpio_set_gpio_pin(AVR32_PIN_PB22);
 }
}

It returns MPU_SETUP_ENTRY_OK!!!!

 

And the Context switch is as follows:

static void OperationSupervisor(void * CallFunction, void * SupervisorFunctionVariable){
 
 
 disable_mpu();
 
 // Note the System Time that the Task was switched to Execution Mode
 Delay_Queue.accumulator = -1 * tc_read_tc(&AVR32_TC, 0);
 
 if(Delay_Queue.accumulator == 0){ Delay_Queue.accumulator = 1;
 }
 
 // Assign function to supervisor call
 SupervisorCallFunction = CallFunction; 
 
 // Ensure the system is ready to perform a Supervisor Call
 int localMode = internal_get_cpu_mode(); internal_set_cpu_mode(Supervisor_Mode);
 
 asm volatile ( "PUSHM  R11-R12\n\t"
     "MOV     R12, %[PrologueVariable]\n\t"
      "LD.W    R12, R12  [0]\n\t"
     "SCALL\n\t" 
     "POPM  R11-R12" :: [PrologueVariable] "r" (&SupervisorFunctionVariable));  
   
 setup_mpu((struct task_ctrl_obj *)Core_Executing_Task);
 enable_mpu();

 internal_set_cpu_mode(localMode);
}

 

 

 

 

So basically, I've tested the alignment and it works, when I load the alignment address it also works.  But when I enable the MPU it freezes.  Wonder what Exception it throws, does anyone know?

 

 

 

 

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What does the debugger say?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll have a look at it tomorrow Kartman and let you know.  Bit late here in Ireland.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys, what's the start address of external SDRAM on the 

 

EDITED:

Is this correct:

 

evk1100SDRAM (wxa!ri) : ORIGIN = 0xD0000000, LENGTH = 0x02000000

Last Edited: Tue. Dec 19, 2017 - 01:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was going to say RTFM., but the EVK1000 user-blurb is *******.
Working backwards from the schematics, the SRAM is a 16Mx16 which is agrees with that linker-script directive LENGTH=
The SRAM CS is connected to NCS[1] which according to the Memories section of the datasheet agrees with the ORIGIN=

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And the solution is as follows, ignore the comments.

/*
 * mpu.h
 *
 * Created: 09/12/2017 02:26:22
 *  Author: wmjen
 */ 


#ifndef MPU_H_
#define MPU_H_

#include "asf.h"


void configure_task_mpu(void);
unsigned int * configure_stack_mpu(struct task_ctrl_obj *, unsigned char);
void configure_task_mpu_permissions(void);



// Number of regions considered in this example.
#define NB_CONFIG_MPU_ENTRIES       5
// Region Index
#define REGION_0_FLASH_INDEX        0
#define REGION_1_RAM_INDEX          1
#define REGION_2_STACK_INDEX        2
#define REGION_3_PERIPHERALS_INDEX  3
#define REGION_4_SDRAM_INDEX        4


// Allocation for NB_CONFIG_MPU_ENTRIES DMPU entries
mpu_entry_t dmpu_entries[NB_CONFIG_MPU_ENTRIES];

static unsigned int mpu_allignment(eRegionSize memory){
 
 unsigned int allign;
 
 switch(memory){
  case MPU_REGION_SIZE_4KB: allign = 0xfff;
  break;
  
  case MPU_REGION_SIZE_8KB: allign = 0x1fff;
  break;
  
  case MPU_REGION_SIZE_16KB: allign = 0x3fff;
  break;
  
  case MPU_REGION_SIZE_32KB: allign = 0x7fff;
  break;
  
  case MPU_REGION_SIZE_64KB: allign = 0xffff;
  break;
  
  case MPU_REGION_SIZE_128KB: allign = 0x1ffff;
  break;
  
  case MPU_REGION_SIZE_256KB: allign = 0x3ffff;
  break;
  
  case MPU_REGION_SIZE_512KB: allign = 0x7ffff;
  break;
  
  case MPU_REGION_SIZE_1MB: allign = 0xfffff;
  break;
  
  case MPU_REGION_SIZE_2MB: allign = 0x1fffff;
  break;
  
  case MPU_REGION_SIZE_4MB: allign = 0x3fffff;
  break;
  
  case MPU_REGION_SIZE_8MB: allign = 0x7fffff;
  break;
  
  case MPU_REGION_SIZE_16MB: allign = 0xffffff;
  break;
  
  case MPU_REGION_SIZE_32MB: allign = 0x1ffffff;
  break;
  
  case MPU_REGION_SIZE_64MB: allign = 0x3ffffff;
  break;
  
  case MPU_REGION_SIZE_128MB: allign = 0x7ffffff;
  break;
  
  case MPU_REGION_SIZE_256MB: allign = 0xfffffff;
  break;
  
  case MPU_REGION_SIZE_512MB: allign = 0x1fffffff;
  break;
  
  case MPU_REGION_SIZE_1GB: allign = 0x3fffffff;
  break;
  
  case MPU_REGION_SIZE_2GB: allign = 0x7fffffff;
  break;
  
  default: allign = 0x00000fff;
  break;
 }
 return(allign);
}

static unsigned int mpu_memory(eRegionSize memory){
 
 unsigned int memory_size;
 
 switch(memory){
  case MPU_REGION_SIZE_4KB: memory_size = 4096;
  break;
  
  case MPU_REGION_SIZE_8KB: memory_size = 8192;
  break;
  
  case MPU_REGION_SIZE_16KB: memory_size = 16348;
  break;
  
  case MPU_REGION_SIZE_32KB: memory_size = 32768;
  break;
  
  case MPU_REGION_SIZE_64KB: memory_size = 65536;
  break;
  
  case MPU_REGION_SIZE_128KB: memory_size = 131072;
  break;
  
  case MPU_REGION_SIZE_256KB: memory_size = 262144;
  break;
  
  case MPU_REGION_SIZE_512KB: memory_size = 524288;
  break;
  
  case MPU_REGION_SIZE_1MB: memory_size = 1048576;
  break;
  
  case MPU_REGION_SIZE_2MB: memory_size = 2097152;
  break;
  
  case MPU_REGION_SIZE_4MB: memory_size = 4194304;
  break;
  
  case MPU_REGION_SIZE_8MB: memory_size = 8388608;
  break;
  
  case MPU_REGION_SIZE_16MB: memory_size = 16777216;
  break;
  
  case MPU_REGION_SIZE_32MB: memory_size = 33554432;
  break;
  
  case MPU_REGION_SIZE_64MB: memory_size = 67108864;
  break;
  
  case MPU_REGION_SIZE_128MB: memory_size = 134217728;
  break;
  
  case MPU_REGION_SIZE_256MB: memory_size = 268435456;
  break;
  
  case MPU_REGION_SIZE_512MB: memory_size = 536870912;
  break;
  
  case MPU_REGION_SIZE_1GB: memory_size = 1073741824;
  break;
  
  case MPU_REGION_SIZE_2GB: memory_size = 2147483648;
  break;
  
  default: memory_size = 4096;
  break;
 }
 return(memory_size);
}

unsigned int * configure_stack_mpu(struct task_ctrl_obj * tcb, unsigned char mpu_mem){
 
 /*
  * Configuring Region 2: the memory used by the stack.
  * According to the linker script and to the linker step, the stack is
  * placed in INTRAM (internal RAM memory) after the RAM area explicitly
  * used by the application.
  * The stack is used upon exceptions (some registers are saved on the
  * stack; See "AVR32 Architecture Manual Complete" section 7.1 Event
  * Handling in AVR32A); the stack may be used when doing function calls
  * also. Since this application intends to generate exceptions, we must
  * make sure that the memory area used by the stack is Read/Write!
  */
 
 // Security Check...
 if((mpu_mem > 30) || (mpu_mem < 11))
   mpu_mem  = MPU_REGION_SIZE_4KB;
  
  
 unsigned int allignment = mpu_allignment(mpu_mem);
 unsigned int memory_size = mpu_memory(mpu_mem);
 
 unsigned int * ptr = api_malloc(sizeof(int) * memory_size * 2);
 
 tcb->stack_allocation = ptr;
 tcb->ergonRegion = mpu_mem;
 
 unsigned int allignment_offset = (unsigned int)ptr & allignment; 
     allignment_offset = (allignment + 1) - allignment_offset;
 
 if((allignment_offset + (unsigned int)ptr) & mpu_allignment(mpu_mem))
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 
 return((unsigned int *)(allignment_offset + (unsigned int)ptr));
}

inline void configure_task_mpu(void){
 
 /**
  * \note WARNING NOTE: there are limitations concerning the region size;
  * See doc32002 "AVR32UC Technical Reference Manual Complete" Table 6-1.
  * "Protection region sizes implied by the Size field".
  * The mpu_convert_kbsize_to_eregionsize() makes sure this part of the
  * spec is respected.
  */
 dmpu_entries[REGION_2_STACK_INDEX].addr = Core_Executing_Task->mpu_base_mem_addr;
 dmpu_entries[REGION_2_STACK_INDEX].size = Core_Executing_Task->ergonRegion;

 if (set_mpu_entry(&dmpu_entries[REGION_2_STACK_INDEX], REGION_2_STACK_INDEX) == MPU_SETUP_ENTRY_OK) {
  enable_mpu();
 }
 else{
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }
}

void configure_task_mpu_permissions(void){
 
 eRegionSize region_size;    // Region size
 uint32_t region_size_value; // A region size expressed in kB
 
 extern void _stack;         // Start address of the stack.
 extern void __stack_size__; // Size of the stack.

/*
  * Configuring Region 0: the Flash memory area occupied by this
  * application. Since this program is linked into flash, we want to define
  * the Flash memory protection scheme as being Readable and Executable(RX).
  * The flash memory starts at address 0x80000000 (this info is found in the
  * part specific header file found in the compiler installation tree;
  * e.g. in uc3a0512.h for an AT32UC3A0512 part).
  */
 dmpu_entries[REGION_0_FLASH_INDEX].addr = AVR32_FLASH_ADDRESS;

 /*
  * We estimate the size of this application to be less than 64kB. So we
  * define region 0 size as being 64kB.
  */
 dmpu_entries[REGION_0_FLASH_INDEX].size = MPU_REGION_SIZE_512KB;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_0_FLASH_INDEX].valid = true;
 
 // set the mpu configuration for Region 0
 if (set_mpu_entry(&dmpu_entries[REGION_0_FLASH_INDEX], REGION_0_FLASH_INDEX)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }
 /*
  * Set Access Permission A to Read/Execute access in both privileged
  * and unprivileged mode.
  */
 set_access_permissions(REGION_0_FLASH_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
  * Each region is divided into 16 sub-regions. So in the case of this
  * region (region 0) we are currently setting up, each sub-region is
  * 4kB in size.
  * All subregions that hold our application should be in EXECUTE access;
  * except for the ForbiddenFunc function which we implicitly put towards
  * the end of the .text section, for test purpose.
  * We estimated that our application should fit in much less that 64kB. So
  * we configure the subregions 0 to 11 to use the permission access
  * Read/eXecute as defined in the MPUAPRA register and the remaining
  * subregions (12 to 15) to use the permission access Read. Each subregion
  * is mapped to a bit: when the bit is set to 0, the subregion permission
  * access is taken from the MPUAPRA register (previously defined as
  * MPU_PRIVRX_UNPRIVRX for region 0); if the bit is set to 1; the subregion
  * permission access is taken from the MPUAPRB register (previously set to
  * MPU_PRIVR_UNPRIVNONE for region 0).
  * We purposely placed the ForbiddenFunc function in one of the subregion
  * 12 to 15; so that when the code jumps to this location, we should get an
  * ITLB exception.
  */
 select_subregion(REGION_0_FLASH_INDEX, 0x0000);

 /*
  * Configuring Region 1: the internal RAM memory used by this application.
  * The RAM memory starts at address 0x00000000 (this info is found in the
  * part specific header file found in the compiler installation tree;
  * e.g. in uc3a0512.h for an AT32UC3A0512 part).
  */
 dmpu_entries[REGION_1_RAM_INDEX].addr = AVR32_SRAM_ADDRESS;

 /*
  * We estimate the RAM footprint of this application to be less than 4kB.
  * So we define region 1 size as being 4kB in size.
  */
 dmpu_entries[REGION_1_RAM_INDEX].size = MPU_REGION_SIZE_64KB;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_1_RAM_INDEX].valid = true;
 
 // set the mpu configuration for Region 1
 if (set_mpu_entry(&dmpu_entries[REGION_1_RAM_INDEX], REGION_1_RAM_INDEX)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }

 /*
  * Set Access Permission A to Read/Write access in privileged mode and to
  * None in unprivileged mode.
  */
 set_access_permissions(REGION_1_RAM_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
  * Each region is divided into 16 sub-regions. So in the case of region 1
  * we are currently setting up, each sub-region is 256B in size.
  * All subregions that our application uses should be in Read/Write access;
  * except for the last subregion (in [0x00000F00, 0x00001000[)
  * (for test purpose).
  * We estimated that our application should use much less than 4kB. So we
  * configure the subregions 0 to 14 to use the permission access Read/Write
  * as defined in the MPUAPRA register and the remaining subregion (15) to
  * use the permission access Read.
  * Each subregion is mapped to a bit: when the bit is set to 0, the
  * subregion permission access is taken from the MPUAPRA register
  * (previously defined as MPU_PRIVRW_UNPRIVNONE for region 1); if the  bit
  * is set to 1; the subregion permission access is taken from the MPUAPRB
  * register (previously set to MPU_PRIVR_UNPRIVNONE for region 1).
  * For the sake of this example, the application will try to do a write
  * access at an address in the range [0x00000F00, 0x00001000[: we should
  * then get a DTLB exception.
  */
 select_subregion(REGION_1_RAM_INDEX, 0x0000);

 /*
  * Configuring Region 2: the memory used by the stack.
  * According to the linker script and to the linker step, the stack is
  * placed in INTRAM (internal RAM memory) after the RAM area explicitly
  * used by the application.
  * The stack is used upon exceptions (some registers are saved on the
  * stack; See "AVR32 Architecture Manual Complete" section 7.1 Event
  * Handling in AVR32A); the stack may be used when doing function calls
  * also. Since this application intends to generate exceptions, we must
  * make sure that the memory area used by the stack is Read/Write!
  */
 dmpu_entries[REGION_2_STACK_INDEX].addr = (uint32_t)&_stack;

 /**
  * \note WARNING NOTE: there are limitations concerning the region size;
  * See doc32002 "AVR32UC Technical Reference Manual Complete" Table 6-1.
  * "Protection region sizes implied by the Size field".
  * The mpu_convert_kbsize_to_eregionsize() makes sure this part of the
  * spec is respected.
  */
 region_size_value = (uint32_t)&__stack_size__ >> 10;

 if (!mpu_convert_kbsize_to_eregionsize(&region_size, region_size_value)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }

 dmpu_entries[REGION_2_STACK_INDEX].size = region_size;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_2_STACK_INDEX].valid = true;
 
 // set the mpu configuration for Region 2
 if (set_mpu_entry(&dmpu_entries[REGION_2_STACK_INDEX], REGION_2_STACK_INDEX)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }

 /*
  * Set Access Permission A to Read access in privileged mode and to None in
  * unprivileged mode.
  */
 set_access_permissions(REGION_2_STACK_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
  * Set all subregions of the stack to Read/Write access
  * (i.e. use the Access Permissions B).
  */
 select_subregion(REGION_2_STACK_INDEX,0x0000);


 /*
  * Configuring Region 3: the peripherals memory mapping.
  * We're using the DEBUG module to output traces to USART, we're using the
  * GPIO module => we have to define access permissions to the region where
  * the USART & GPIO peripherals registers are mapped. We'll set this region
  * as Read/Write because we don't want to generate MPU exceptions when
  * using a peripheral.
  * The USART & GPIO peripherals are on the same Peripheral Bus (PBA). We
  * configure all peripherals on PBA with the same access rights.
  * The PBA physical memory map starts at address 0xFFFF0000 (this info is
  * found in the data sheet in the table "AT32UC3x Physical Memory Map".
  * The PDCA module happens to be the module that is mapped at the start of
  * the PBA memory map in all devices except AT32UC3C series(INTC module).
  */
 dmpu_entries[REGION_3_PERIPHERALS_INDEX].addr = AVR32_PDCA_ADDRESS;

 // The size of the PBA memory map is 64kB.
 dmpu_entries[REGION_3_PERIPHERALS_INDEX].size = MPU_REGION_SIZE_64KB;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_3_PERIPHERALS_INDEX].valid = true;

 // set the mpu configuration for Region 3
 if (set_mpu_entry(&dmpu_entries[REGION_3_PERIPHERALS_INDEX], REGION_3_PERIPHERALS_INDEX)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }

 /*
  * Set Access Permission A to Read/Write access in privileged mode and to
  * None in unprivileged mode.
  */
 set_access_permissions(REGION_3_PERIPHERALS_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
  * We don't set the Access Permission B because we won't use it.
  * Set all 16 subregions of the PBA memory map to Read/Write access.
  */
 select_subregion(REGION_3_PERIPHERALS_INDEX, 0x0000);

 /*
  * Configuring Region 1: the internal RAM memory used by this application.
  * The RAM memory starts at address 0x00000000 (this info is found in the
  * part specific header file found in the compiler installation tree;
  * e.g. in uc3a0512.h for an AT32UC3A0512 part).
  */
 dmpu_entries[REGION_4_SDRAM_INDEX].addr = 0xD0000000;

 /*
  * We estimate the RAM footprint of this application to be less than 4kB.
  * So we define region 1 size as being 4kB in size.
  */
 dmpu_entries[REGION_4_SDRAM_INDEX].size = MPU_REGION_SIZE_32MB;

 // Deem this protection scheme as valid.
 dmpu_entries[REGION_4_SDRAM_INDEX].valid = true;
 
 // set the mpu configuration for Region 1
 if (set_mpu_entry(&dmpu_entries[REGION_4_SDRAM_INDEX], REGION_4_SDRAM_INDEX)) {
  gpio_set_gpio_pin(AVR32_PIN_PB20);
 }

 /*
  * Set Access Permission A to Read/Write access in privileged mode and to
  * None in unprivileged mode.
  */
 set_access_permissions(REGION_4_SDRAM_INDEX, MPU_APRA_ID, MPU_PRIVRWX_UNPRIVRWX);

 /*
  * Each region is divided into 16 sub-regions. So in the case of region 1
  * we are currently setting up, each sub-region is 256B in size.
  * All subregions that our application uses should be in Read/Write access;
  * except for the last subregion (in [0x00000F00, 0x00001000[)
  * (for test purpose).
  * We estimated that our application should use much less than 4kB. So we
  * configure the subregions 0 to 14 to use the permission access Read/Write
  * as defined in the MPUAPRA register and the remaining subregion (15) to
  * use the permission access Read.
  * Each subregion is mapped to a bit: when the bit is set to 0, the
  * subregion permission access is taken from the MPUAPRA register
  * (previously defined as MPU_PRIVRW_UNPRIVNONE for region 1); if the  bit
  * is set to 1; the subregion permission access is taken from the MPUAPRB
  * register (previously set to MPU_PRIVR_UNPRIVNONE for region 1).
  * For the sake of this example, the application will try to do a write
  * access at an address in the range [0x00000F00, 0x00001000[: we should
  * then get a DTLB exception.
  */
 select_subregion(REGION_4_SDRAM_INDEX, 0x0000);
}