Microchip® Advanced Software Framework

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
SAM Peripheral Access Controller (PAC) Driver

This driver for Atmel® | SMART ARM®-based microcontroller provides an interface for the locking and unlocking of peripheral registers within the device.

When a peripheral is locked, accidental writes to the peripheral will be blocked and a CPU exception will be raised.

The following peripherals are used by this module:

The following devices can use this module:

The outline of this documentation is as follows:

Prerequisites

There are no prerequisites for this module.

Module Overview

The SAM devices are fitted with a Peripheral Access Controller (PAC) that can be used to lock and unlock write access to a peripheral's registers (see Non-Writable Registers). Locking a peripheral minimizes the risk of unintended configuration changes to a peripheral as a consequence of Run-away Code or use of a Faulty Module Pointer.

Physically, the PAC restricts write access through the AHB bus to registers used by the peripheral, making the register non-writable. PAC locking of modules should be implemented in configuration critical applications where avoiding unintended peripheral configuration changes are to be regarded in the highest of priorities.

All interrupt must be disabled while a peripheral is unlocked to make sure correct lock/unlock scheme is upheld.

Locking Scheme

The module has a built in safety feature requiring that an already locked peripheral is not relocked, and that already unlocked peripherals are not unlocked again. Attempting to unlock and already unlocked peripheral, or attempting to lock a peripheral that is currently locked will generate a CPU exception. This implies that the implementer must keep strict control over the peripheral's lock-state before modifying them. With this added safety, the probability of stopping runaway code increases as the program pointer can be caught inside the exception handler, and necessary countermeasures can be initiated. The implementer should also consider using sanity checks after an unlock has been performed to further increase the security.

Recommended Implementation

A recommended implementation of the PAC can be seen in the figure below.

Why Disable Interrupts

Global interrupts must be disabled while a peripheral is unlocked as an interrupt handler would not know the current state of the peripheral lock. If the interrupt tries to alter the lock state, it can cause an exception as it potentially tries to unlock an already unlocked peripheral. Reading current lock state is to be avoided as it removes the security provided by the PAC (Reading Lock State).

Note
Global interrupts should also be disabled when a peripheral is unlocked inside an interrupt handler.

An example to illustrate the potential hazard of not disabling interrupts is shown in the diagram below.

Run-away Code

Run-away code can be caused by the MCU being operated outside its specification, faulty code, or EMI issues. If a runaway code occurs, it is favorable to catch the issue as soon as possible. With a correct implementation of the PAC, the runaway code can potentially be stopped.

A graphical example showing how a PAC implementation will behave for different circumstances of runaway code in shown in the first and second figures below.

In the example, green indicates that the command is allowed, red indicates where the runaway code will be caught, and the arrow where the runaway code enters the application. In special circumstances, like example 4 above, the runaway code will not be caught. However, the protection scheme will greatly enhance peripheral configuration security from being affected by runaway code.

Key-Argument

To protect the module functions against runaway code themselves, a key is required as one of the input arguments. The key-argument will make sure that runaway code entering the function without a function call will be rejected before inflicting any damage. The argument is simply set to be the bitwise inverse of the module flag, i.e.

system_peripheral_<lock_state>(SYSTEM_PERIPHERAL_<module>,
~SYSTEM_PERIPHERAL_<module>);

Where the lock state can be either lock or unlock, and module refer to the peripheral that is to be locked/unlocked.

Faulty Module Pointer

The PAC also protects the application from user errors such as the use of incorrect module pointers in function arguments, given that the module is locked. It is therefore recommended that any unused peripheral is locked during application initialization.

Use of __no_inline

Using the function attribute __no_inline will ensure that there will only be one copy of each functions in the PAC driver API in the application. This will lower the likelihood that runaway code will hit any of these functions.

Physical Connection

The diagram below shows how this module is interconnected within the device.

Special Considerations

Non-Writable Registers

Not all registers in a given peripheral can be set non-writable. Which registers this applies to is showed in List of Non-Write Protected Registers and the peripheral's subsection "Register Access Protection" in the device datasheet.

Reading Lock State

Reading the state of the peripheral lock is to be avoided as it greatly compromises the protection initially provided by the PAC. If a lock/unlock is implemented conditionally, there is a risk that eventual errors are not caught in the protection scheme. Examples indicating the issue are shown in the diagram below.

In the left figure above, one can see the runaway code continues as all illegal operations are conditional. On the right side figure, the runaway code is caught as it tries to unlock the peripheral.

Extra Information

For extra information, see Extra Information for PAC Driver. This includes:

Examples

For a list of examples related to this driver, see Examples for PAC Driver.

API Overview

Macros

#define SYSTEM_PERIPHERAL_ID(peripheral)   ID_##peripheral
 Retrieves the ID of a specified peripheral name, giving its peripheral bus location. More...
 

Peripheral Lock and Unlock

__no_inline enum status_code system_peripheral_lock (const uint32_t peripheral_id, const uint32_t key)
 
__no_inline enum status_code system_peripheral_unlock (const uint32_t peripheral_id, const uint32_t key)
 

APIs available for SAM L21/L22/C20/C21.

__no_inline enum status_code system_peripheral_lock_always (const uint32_t peripheral_id, const uint32_t key)
 
static void system_pac_enable_interrupt (void)
 Enable PAC interrupt. More...
 
static void system_pac_disable_interrupt (void)
 Disable PAC interrupt. More...
 
static void system_pac_enable_event (void)
 Enable PAC event output. More...
 
static void system_pac_disable_event (void)
 Disable PAC event output. More...
 

#define SYSTEM_PERIPHERAL_ID (   peripheral)    ID_##peripheral

Retrieves the ID of a specified peripheral name, giving its peripheral bus location.

Parameters
[in]peripheralName of the peripheral instance
Returns
Bus ID of the specified peripheral instance.

Referenced by dsu_crc32_cal(), and main().

static void system_pac_disable_event ( void  )
inlinestatic

Disable PAC event output.

Disable PAC event output on peripheral access error.

static void system_pac_disable_interrupt ( void  )
inlinestatic

Disable PAC interrupt.

Disable PAC interrupt on peripheral access error.

static void system_pac_enable_event ( void  )
inlinestatic

Enable PAC event output.

Enable PAC event output on peripheral access error.

static void system_pac_enable_interrupt ( void  )
inlinestatic

Enable PAC interrupt.

Enable PAC interrupt so can trigger execution on peripheral access error, see SYSTEM_Handler().

Referenced by main().

__no_inline enum status_code system_peripheral_lock ( const uint32_t  peripheral_id,
const uint32_t  key 
)

Referenced by dsu_crc32_cal(), and main().

__no_inline enum status_code system_peripheral_lock_always ( const uint32_t  peripheral_id,
const uint32_t  key 
)
__no_inline enum status_code system_peripheral_unlock ( const uint32_t  peripheral_id,
const uint32_t  key 
)

Referenced by dsu_crc32_cal(), and main().