![]() |
Synergy Software Package User's Manual
|
Learn how to develop applications with the Synergy Software Package (SSP) using the SSP's module-based architecture and the functional software layers. Integrate SSP applications with multiple boards and Synergy devices using the Board Support Package (BSP).
The following pages describe the fundamental SSP architecture:
The Renesas Synergy™ Software Package (SSP), part of the Renesas Synergy™ Platform, is a complete integrated software package designed to provide easy to use, scalable, high quality software for embedded system design. Using the Synergy Software Platform will reduce time to market by providing a completely integrated and qualified embedded software platform comprising of an industry leading, completely optimized and hardened Real-time Operating System (RTOS), middleware, communication stacks, function libraries, application framework and hardware abstracted low-level device drivers.
The SSP is divided into four main layers:
The SSP provides uniform and intuitive APIs that are well documented. Each module is supported with detailed user documentation and software datasheet including code size and execution time for each function.
Users have the choice to integrate with the platform capabilities using either the Framework Interface or HAL layer, depending on which best meets the needs of the application. To further scale each module, build time options such as parameter checking may be compiled out for smaller, more efficient code.
This section describes the Renesas Synergy Software Package (SSP) architecture and how to use the SSP Application Programming Interface (API).
As microcontrollers increase in complexity, so does the breadth of knowledge required to make them operate in the desired way. The SSP provides an innovative approach to embedded software for IoT applications. With the SSP, you have a new and extremely powerful software interface from the ground up, making coding fast and providing you with a robust development processes. With this software, you can create differentiated application code instead of spending months developing baseline code to interface at the hardware level.
| Term | Description | Reference |
|---|---|---|
| Module | Modules can be peripheral drivers, purely software, or anything in between. Each Module consists of a folder with source code, documentation, and anything else that the customer needs to use the code effectively. Modules are independent units, but they may depend on other Modules. Example SSP Modules are the UART driver (UART Interface), Audio Playback Framework, which relies on timer, DMA, and DAC drivers (Audio Framework Interface), or the Messaging Framework (Messaging Framework Interface). Applications can be built by combining multiple modules to provide the user with the features they need. | SSP Modules |
| BSP | Short for Board Support Package. In the SSP the BSP provides just enough foundation to allow other SSP modules to work together without issue. | BSP Architecture |
| Callback Function | This term refers to a function that is called when an event occurs. For example, the bus error interrupt handler is implemented in the r_bsp. The user will likely want to know when a bus error occurs. To alert the user, a callback function can be supplied to the r_bsp. When a bus error occurs the r_bsp will jump to the provided callback function and the user can handle the error. Interrupt callback functions should be kept short and be handled carefully because when they are called the MCU will still be inside of an interrupt and therefore will be delaying any pending interrupts. | - |
| Interface | See SSP Interfaces section: SSP Interfaces. All interfaces in the SSP are listed here: Framework Interfaces and HAL Interfaces | SSP Interfaces |
| Instance | See SSP Instances section: SSP Instances | SSP Instances |
| Module Instance | Single and independent configuration of a Module. | - |
| Application | Code that is owned and maintained by the user. Application code may be based off sample application code provided by Renesas, but is the responsibility of the user. | An example for a simple application is included as tutorial in this manual: ref application-wdt |
| Driver | A Driver is a specific kind of Module that directly modifies registers on the MCU. | - |
| Stacks | The SSP architecture is designed such that Modules work together to form a Stack. Starting with the uppermost Module and going to the bottommost dependency forms a specific Stack. | SSP Stacks |
| Layer/Level | Stacks are made of multiple layers of Modules. A Layer can consist of one or multiple Modules depending on the requirements of the next Layer up. Layer and Level are used interchangeably. | ref ssp-predefined-layers |
Modules are the core building block of SSP. Modules can do many different things, but all Modules share the basic concept of providing functionality upwards and requiring functionality from below.
The amount of functionality provided by a Module is not limited though there are usually points where separation makes sense. If too much functionality is provided, then reuse of the Module can become difficult in the future. If not enough functionality is provided, then unnecessary complexity and overhead may be added in order to make the Modules work as expected.
The simplest SSP application consists of one Module with the user application on top.
For simplicity, ignore the Board Support Package (BSP) for now because it is a requirement of any SSP project. In the picture above, the BSP is located underneath the bottom layer, SSP Layer 0.
When modules are layered atop one another, an SSP stack is formed. The stacking process is performed by matching what one module provides with what another module requires. For example, the Audio Playback Framework Module requires a Transfer Interface, which can be fulfilled by the Data Transfer Controller (DTC) Driver Module. Instead of including the DTC code in the Audio Playback Module, we split these into two modules. This allows for reuse of the underlying modules, which has many benefits.
By continuing to add layers to the Stack using SSP Modules, you can interface with the Synergy hardware at a high level.
The ability to stack modules has great benefit because it ensures the flexibility of the architecture as a whole. If modules are directly dependent upon other modules, then issues arise when application features must work across different user designs. To ensure that modules are reusable the modules must be capable of being swapped out for other modules that provide the same features. The SSP architecture provides this flexibility to swap modules in and out through the use of SSP Interfaces.
At the architecture level, Interfaces are the way that Modules provide common features. This commonality allows Modules that adhere to the same Interface to be used interchangeably. Interfaces can be thought of as a contract between two Modules. The Modules agree to work together using the information that was agreed upon in the contract.
On Synergy hardware there is occasionally an overlap of features between different peripherals. For example, I2C communications can be achieved through use of the IIC peripheral or the SCI peripheral in its Simple I2C mode. There is a difference in the level of features provided by both peripherals. In I2C mode the SCI peripheral will only support a subset of the features of the full-featured IIC.
Interfaces aim to provide support for the common features that most users would expect. This means that some of the advanced features of a peripheral, such as the IIC, might not be available in the Interface. In most cases these features are still available through Interface Extensions.
In design, Interfaces are implemented as header files. All Interface header filenames end with '_api.h'. The following sections detail what makes up an Interface.
Whenever possible, Interfaces use typed enumerations for function parameters and structure members.
Enumerations remove any uncertainty when deciding what values are available for a parameter. Also note that enumeration options follow a strict naming convention where the name of the type is prefixed on the available options. Combining the naming convention with the autocomplete feature available in e2 studio provides the benefits of rapid coding while maintaining highly readable code.
At a minimum, all SSP Interfaces include three data structures: a control structure, a configuration structure, and an instance structure.
The control structure is used as a unique identifier for using the module. If SSP modules were only peripheral drivers then this control structure might be replaced with a channel number. All function calls for that module would then take a channel number so that the code could determine which peripheral channel to operate on. SSP modules are not restricted to device drivers and therefore the control structure is used. The user allocates storage for a control structure and then sends a pointer to it into the open() call for a Module. At this point, the Module initializes the structure as needed. You must then send in a pointer to the control structure for all subsequent module calls. The contents of the control structure are used by the module and must not be altered. Reading data from a control structure should also be avoided as the data structure is not guaranteed to remain the same between SSP releases. In general, you should treat control structures like a black box.
The contents of a control structure are specific to an instance. This means that two instances of the same interface will have two completely different control structure types. The control structures that exist in an interface are named <interface>_ctrl_t. Below is an example of the interface control structure for I2C:
Since all interface control structures are of type void, they cannot be allocated. Instead, these types are placeholders for instance control structures. Instance control structures are defined in instance header files and are named <instance>_instance_ctrl_t. Below are examples of I2C Instance control structures for the IIC (r_riic) and SCI (r_sci_i2c) peripherals:
When using an interface, the instance control structure should be allocated and used in place of the interface control structure. Using the example above, if the SCI-I2C Instance was being used then you would allocate a structure of type sci_i2c_instance_ctrl_t and use it wherever i2c_ctrl_t is referenced in the Interface. The ISDE will take care of allocating the correct control structure for you.
Dynamic memory allocation through use of the malloc() and free() functions are not used in SSP modules.
The configuration structure is used for the initial configuration of a module during the open() call. The structure consists of members such as: channel, interrupt priority, bitrate, and operating mode. The structure is used purely for input into the module. This structure does not have to be unique and could be discarded by you after initialization, if desired.
Above is an example configuration structure for the I2C Interface. The last three structure members (p_callback, p_context, and p_extend) are common to almost all module configurations.
The p_callback and p_context members are described in the SSP Interface Callback Functions section.
The p_extend member is used for extending the current Interface for a specific Instance. Interfaces are designed to support the most common features. There are cases where an Instance of an Interface requires extra information to properly configure itself. There are also cases where the extra information is not required, but users might need it to adjust the module for their specific application. When this is the case, the user can provide the underlying Instance with more configuration information by passing it through the p_extend member. The information that is passed through this member is defined by the underlying Instance, and therefore the user must adhere to its structure. If invalid information is passed to the underlying driver, then the Instance is not able to successfully use the data and proper operation cannot be guaranteed. Refer to the Interface Extensions section for more information.
It is also important that configuration structures only have members that apply to the current Interface. If multiple layers in the same stack define the same configuration parameters then it becomes difficult to know where to modify the option. For example, the baud rate for a UART is only be defined at the Driver layer. Any layers that use the UART Interface rely on the baud rate being provided at the Driver layer and do not offer it in their own configuration structures.
Callback functions allow Modules to asynchronously alert the user application when an event has occurred. An example for an event is when a byte has been received over a UART channel. Callbacks are required to allow user application code to react to interrupts. SSP Modules define and handle the interrupts for Synergy MCU peripherals. If the user tries to define the interrupt service routine at the same time as a SSP Module, then the code does not build. Therefore SSP Modules allow the user application to respond to interrupts by registering a function to be called when an interrupt occurs.
Callback functions must be defined in the user application. They always return void and take a structure for their one parameter. The structure typedef is provided in the Interface for the Module and is named * _callback_args_t*. The contents of the structure may vary depending on the Interface, but two members are common: event and p_context.
The event member is used by the application to determine why the callback was called. Using the UART example again, the callback could have been triggered because a byte was received, all bytes had been transmitted, or a framing error has occurred. The event member is an enumeration provided by the Interface.
The p_context member is used for providing user-specified data to the callback function. In many cases a callback function is shared between multiple channels or Module Instances. When the callback occurs, the code handling the callback needs context information so that it can figure out which Module Instance the callback is for. For example, if the callback wanted to make a SSP API call in the callback, then at a minimum the callback must use the control structure. To make this easy, the user can provide a pointer to the control structure as the p_context. When the callback occurs, the control structure is available as it will be passed in the callback structure.
Callback functions are called from within an interrupt service routine. For this reason callback functions should be kept as short as possible so they do not affect the real time performance of the user's system. An example skeleton function for the Flash Interface callback is shown below.
When a Module is not directly used in the user application (it is not the top layer of the stack) then its callback function will be handled by the Module above. If there is a Console Interface Module that requires a UART Interface Module then the Console Module will control and use the UART's callback function. In this case the user does not need to create a callback function for the UART Module in their application code.
All Interfaces include an API structure which contains function pointers for all the supported Interface functions. An example structure, with the comments removed, for the Digital to Analog Convert (DAC) is shown below.
The API structure is what allows for Modules to easily be swapped in and out for other Modules that are Instances of the same Interface. Let's look at an example application using the DAC Interface above.
Synergy MCUs have an internal DAC peripheral. If the DAC API structure in the DAC Interface were not used, then the application could make calls directly into the module. In the example below the application is making calls to the R_DAC_Write function which is provided in the r_dac module.
Now let's assume that the user needs more DAC channels than are available on the MCU by adding a new external DAC module named r_dac_external. The external DAC uses I2C for communications. The application must now distinguish between the two modules, which adds complexity and further dependencies to the application.
The use of Interfaces and the API structure allows for the use of an abstracted DAC. This means that no extra logic is needed and the application no longer depends upon certain hard-coded Modules. Instead the application now depends on the DAC Interface API which can be implemented by any number of Modules.
Functions inside of the API structures follow common names. Most Modules will have a pair of open() and close functions. The open() function must be called before any of the other functions. The only exception is the versionGet() function which is not dependent upon any user provided information.
Other functions that will commonly be found are read(), write(), get(), and set(). Function names are designed to be a noun followed by a verb. Example names include:
All Interfaces supply a versionGet() function. This function fills in a structure of type ssp_version_t. This structure is made up of two versions: one for the Interface (the API) and one for the underlying Instance that is currently being used.
The API version ideally never changes, and only rarely if it does. A change to the API may require users to go back and modify their code. The code version, the version of the current Instance, may be updated more frequently. Bug fixes, enhancements, and additional features may all bump the code version. Changes to the code version will only require changes to the user code if the user code is using extended features provided by the Instance.
While Interfaces dictate the features that are provided, Instances actually implement those features. Each Instance is tied to a specific Interface. Instances use the enumerations, data structures, and API prototypes from the Interface. This allows for an application that uses an Interface to swap out the Instance when needed.
On Synergy MCUs some peripherals will have a one-to-one mapping between the Interface and Instance, while others will have a one-to-many. In the example below the IIC and SPI peripherals map to only one Interface each while the SCI peripheral implements three Interfaces.
Each Instance includes a constant global structure with its functions that implement the Interface's API. The name of this structure is standardized as g__on_. Examples include g_spi_on_spi, g_transfer_on_dtc, and g_adc_on_adc. This structure is available to be used through an extern in the instances header file (r_spi.h, r_dtc.h, and r_adc.h respectively).
All modules have a build-time configuration header file. Most configuration options are supplied at run time. Some options that are rarely used, or apply to all instances of a module, may be moved to build time. The advantage of using a build-time configuration option is to potentially reduce code size reduction by removing an unused feature. Performance enhancements are also possible. All modules have at least one build time option, which is whether to enable or disable parameter checking for the module. SSP modules check function arguments for validity when possible. You may want to disable this feature when your testing has concluded to save code space and to speed up execution.
In some cases, Instances require more information than is provided in the Interface. This situation can occur in the following two cases:
The configuration structure for the Block Media Interface is intentionally sparse. This allows for nearly endless Instances. Possible Instances include SD card, SPI Flash, SDRAM, USB, and many more. Different configuration information is needed for each Instance. This is accomplished by supplying the information through the p_extend parameter. While the configuration data provided in the p_extend is not the same between Instances, the API calls thereafter will be. This means that the change is only required in one place.
Use of Interface extensions is not always necessary. Some Instances do not offer an extension since all functionality is provided in the Interface. In many cases the p_extend member can be set to NULL. If NULL is provided and the Instance does offer an extension then the Instance will take this to mean that the default options should be used. The documentation for each Instance indicates whether an Interface extension is provided and whether its use is mandatory or optional.
The SSP comes with two predefined layers: the Driver layer and the Framework layer. The layers are easily identifiable because the modules reside in different folders and have different prefixes. Driver layer modules are located in the ssp/src/driver folder, while Framework level modules are located in the ssp/src/framework folder. Modules in the Driver layer start with an r_ prefix, while Framework level modules start with a sf_ prefix.
The core difference in the functionality between the layers is that Driver layer modules are restricted to being peripheral drivers that are RTOS aware, but do not use any RTOS objects or make any RTOS API calls. This means that Driver layer modules can be used in applications with, or without, an RTOS.
Framework layer modules are free to use RTOS objects such as semaphores, mutexes, or event flags. Framework modules may also create their own when needed. Framework layer modules that need to access hardware typically do so through a Driver layer Interface. Exceptions can be granted in special cases where multiple peripherals need to be used together in a way that would not be practical through multiple individual Interfaces.
The high-level file structure of the SSP is shown below.
Directly underneath the base ssp folder the folders are split into the source and include folders. Include folders are kept separate from the source for easy browsing and easy setup of include paths. The same set of folders are located in the ssp/inc and ssp/src folders: bsp, driver, and framework.
Apart from the BSP, the SSP's two predefined layers, Driver and Framework, are present. Driver layer modules are located in the ssp/src/driver folder and Framework layer modules are located in ssp/src/framework. Under the include tree, the Driver and Framework layer folders contain two folders each: api and instances. The api folder contains the Interface header files for that layer. The instances folder contains the Instance header files for that layer. Both layers are flat internally which limits the number of include paths required for a project.
The ssp_cfg folder is where configuration header files are stored for each module. Its layout is the same as the ssp folder where the BSP, Driver, and Framework layers have separate flat directories. See the Build Time Configuration section for information on what is provided in these header files.
SSP modules are meant to be both reusable and stackable. It is important to remember that modules are not dependent upon other modules, but upon other Interfaces. The user is then free to fulfill the Interface using the Instance that best fits their needs.
In the image above Interface Y is a dependency of Interface X and has its own dependency on Interface Z. Interface X only has a dependency on Interface Y. Interface X has no knowledge of Interface Z. This is a requirement for ensuring that layers can easily be swapped out. This is shown in the diagram below:
In this example we are using the Azure RTOS. FileX file system on two storage mediums: SDMMC and SPI Flash. The SPI Flash Interface takes care of the SPI flash protocol but requires a SPI Interface for actual SPI bus communications. The SDMMC Interface takes care of the protocol and the bus communications meaning that it does not have any dependencies.
Each layer in the SSP Stack is responsible for calling the API functions of its dependencies. This can also be described by saying that users are only responsible for calling the API functions at the layer at which they are interfacing. Using the FileX example above, the user is only responsible for calling FileX functions in the application code. Internally, FileX then calls FileX I/O, which in turn calls a Block Media Interface Module. The Block Media Interface can call multiple drivers. At a minimum an upper layer Module calls the open() function of the Interface it depends upon.
To write an application using a Module, you must determine the following:
1) Determine which open() function to call. Dependencies are based upon Interfaces which means that a Module must have some way of discerning which Instance to call.
2) Determine the configuration parameters. The Module also needs to know what configuration information to pass down. In some cases the Module requires certain configuration parameters to be set. If this is the case then the module sets these configuration structure members itself before passing on the rest of the structure. The rest of the configuration structure members must be provided outside of the Module.
3) Provide a control structure which is Module Instance specific and therefore can be allocated by the upper layer module.
Putting this all together means that to interact with a Module Instance, the following is needed:
This information is sufficient to use any module. Notice that the API structure is the only structure that is Instance specific; not Module Instance specific. This is because the API structure will not vary between multiple uses of the same Instance. If SPI is being used on SCI channels 0 and 2 then both Module Instances will use the same API structure while the configuration and control structures will vary.
To make Module Instances easier to use, all of these pieces are encapsulated in instance structures found in each Interface. These structures have a standardized name of <interface>_instance_t. An example from the WDT interface is shown below.
Upper layer modules that have a dependency on an Interface can then use the instance structure to hold everything needed to interact with an Instance of that Interface. Continuing with the WDT example above, below is the Thread Monitor Framework Interface configuration structure. The Thread Monitor Interface is dependent upon the WDT Interface.
The Thread Monitor module has everything it needs to work with the WDT Interface in the p_lower_lvl_wdt structure member.
In some cases module dependencies are not be defined in the Interface, but instead in the Instance. An example is the Block Media Interface could be implemented on SDMCC, SPI Flash, or many other Instances (also see API Reference section). Because of the wide range of implementations, the instance structure for a particular Interface cannot be used directly in the Block Media Interface's configuration structure. The Block Media Interface's configuration structure is shown again below.
Notice there are Instance structure pointers provided. The reason for this, as previously mentioned, is that the Block Media Interface is too generic to enforce a dependency upon a particular Interface. When a Module is an Instance of a generic Interface, such as Block Media, and it has dependencies on other Modules, the module puts the lower-layer pointers in an extension structure that is referenced through the Interface's p_extend configuration member. This is required to allow Module stacking while not forcing Interfaces to expand and have many optional configuration members.
This section will give general information on how to use a SSP module.
Start by picking an Interface for the functionality that is required. For example, for UART communications use the UART Interface.
After picking an Interface, choose a suitable Instance. The list of known Instances of an Interface is listed in the documentation comments for an Interface. Include the header file of the selected Instance in the source file of the application that uses the Instance.
The e2 studio ISDE provides a graphical user interface for setting the parameters of the Interface and Instance configuration structures. The ISDE also automatically includes those structures, once they are configured in the GUI, in application-specific header files that you can include into your application code.
To see how the ISDE handles the configuration, see Configuring a Project in the ISDE User’s Guide: Using the e2 studio ISDE
The configuration and control structure types follow standard names of <interface>_ctrl_t and <interface>_cfg_t respectively. The ISDE allocates storage for both structures in the application specific header files, which the ISDE creates. Use the ISDE Properties view to set the values for the members of the configuration structure as needed. Many members will be typed enumerations in which case the enumeration can be referenced for available options.
If the Interface has a callback function option, then you first need to declare and define the function in their source code. The return value is always of type void and the parameter to the function is a typed structure of name <interface>_callback_args_t. Once the function has been defined, assign its name to the p_callback member of the configuration structure. If any context information is required in the callback, then the user can provide a pointer to the p_context member. You can assign callback function names through the ISDE Properties window for the selected Module.
Refer to the Instance documentation to see if an Interface extension is provided. If so, then it will be found in the Instance's header file and named <interface>_on__cfg_t. It may have several members just like the Interface's configuration structure. When you select a driver with a specific Instance, you can select any parameter in the configuration structure of the instance in the ISDE property.
Once the instance structure has been defined, you can interact with the Instance as needed. Below is code that builds up an instance structure for the UART Interface as implemented on SCI. Please note that when using e2 studio for Synergy, the following code is automatically generated for the user.
Now that the instance structure is ready, you can interact with the UART Interface. In e2 studio, the name of the instance structure is the *Name* that you provide when configuring the Module Instance in the ISDE Properties window.
SSP uses the ISO/IEC 9899:1999 (C99) C programming language standard. Specific features introduced in C99 that are used include standard integer types (stdint.h), booleans (stdbool.h), designated initializers, and the ability to intermingle declarations and code.
The const qualifier is used with API parameters whenever possible. An example case is shown below:
While not fool-proof by any means, this does provide some extra checking inside the SSP code to ensure that arguments that should not be altered are treated as such.
Weak symbols are used occasionally in and with SSP. They are used to ensure that a project builds even when you have not defined an optional function.
This section describes the BSP or Board Support Package. For the API Reference see Board Support Package. The BSP is board specific and as a result also MCU specific.
The BSP is responsible for getting the MCU from reset to the user's application (that is, the main() function). Before reaching the user's application the BSP sets up the stacks, heap, clocks, interrupts, and C runtime environment. The BSP also configures and sets up the port I/O pins and performs any board specific initializations.
| Term | Meaning |
|---|---|
| system_xxxx.c or startup_xxxx.c | The ‘xxxx’ refers to the MCU type. For example, system_S7G2.c when referencing the S7G2 MCU. |
| BSP | Short for Board Support Package. BSP’s usually have source files related to a specific board. |
| Callback Function | This term refers to a function that is called when an event occurs. For example, the NMI interrupt handler is implemented in the BSP. The user will likely want to know when an NMI system exception occurs. To alert the user, a callback function can be configured for the group interrupts (a group of exceptions all of which are tied to the NMI). When an NMI occurs the BSP will jump to the provided callback function and the user can handle the error. Interrupt callback functions should be kept short and be handled carefully because when they are called the MCU will still be inside of an interrupt and therefore will be delaying any pending interrupts. |
The BSP is organized into folders containing MCU, board specific and CMSIS information.
Synergy is CMSIS-compliant and based on the CMSIS-Core. This requires that we follow CMSIS requirements and naming standards.
The BSP directory structure is shown below:
The BSP is heavily data driven with most features and functionality being configured based on the content from configuration files. Configuration files represent the settings specified by the user and are generated by the ISDE when the Generate Project Content button is clicked.
The table below describes each of the configurable BSP settings. Many of these settings are MCU specific and there are differences between the settings available for each of the supported MCUs.
Table: BSP Configuration options
| BSP Property | Description |
|---|---|
| Part number | MCU part number |
| ram_size_bytes | Available RAM in this MCU package |
| rom_size_bytes | Available ROM in this MCU package |
| data_flash_size_bytes | Available Data Flash in this MCU package |
| package_style | Style of package (ie. BGA) |
| package_pins | Number of pins in this MCU package |
| series | MCU part series |
| Main stack size (bytes) | Size of the Main Stack. Must be > 0. |
| Process stack size (bytes) | Size of the Process Stack. Use of this stack is optional. If 0, then PSP use is disabled |
| Heap size (bytes) | Size of the heap in bytes. If 0, the heap is disabled. |
| OFS0 register settings: IWDT Start Mode, IWDT Timeout Period, IWDT Dedicated Clock Frequency Divisor, IWDT Window End Position, IWDT Window Start Position, IWDT Reset Interrupt Request Select, IWDT Stop Control, WDT Start Mode Select , WDT Timeout Period, WDT Clock Frequency Division Ratio, WDT Window End Position, WDT Window Start Position, WDT Reset Interrupt Request, WDT Stop Control | The option-setting memory determines the state of the MCU after a reset. It is allocated to the configuration setting area and the program flash area of the flash memory. See the MCU user manual for details. |
| OFS1 register settings: Voltage Detection 0 Circuit Start, Voltage Detection 0 Level, HOCO Oscillation Enable. S3 MPU has MPU configuration settings. | See the MCU user manual for details. |
| MPU - Enable or disable PC Region 0 | Start block address for access window protection |
| MPU - PC0 Start, MPU - PC0 End, MPU - Enable or disable PC Region 1, MPU - PC1 Start, MPU - PC1 End, MPU - Enable or disable Memory Region 0, MPU -Memory Region 0 Start, MPU - Memory Region 0 End, MPU - Enable or disable Memory Region 1, MPU - Memory Region 1 Start, MPU - Memory Region 1 End, MPU - Enable or disable Memory Region 2, MPU - Memory Region 2 Start, MPU - Memory Region 2 End, MPU - Enable or disable Memory Region 3, MPU - Memory Region 3 Start, MPU - Memory Region 3 End | Secure MPU ROM register settings. See user manual for details. |
| ID code 1, ID code 2, ID code 3, ID code 4 | Sets the ID Code for boot mode and debugger access protection. |
| MCU Vcc (mV) | Some Modules (e.g. LVD) need to know the voltage supplied to the MCU. This information is obtained from here. |
| Parameter checking | Defines whether the global setting for parameter checking is enabled or disabled. Local modules will take this value by default but can be locally overridden. |
| Assert Failures | Defines what happens when an assertion failure occurs. |
| Error Log | Defines whether or not errors are logged to ssp_error_log. |
Configuration files are used by the BSP to set up ROM registers, clocks, interrupts, ELC events and initial pin configurations. These configuration files can be found in ssp_cfg\bsp.
Bsp_cfg.h
This configuration file contains the values for BSP system settings. These are the settings that can be modified from the ISDE BSP properties tab. They include ROM register settings, stack and heap size, parameter checking and control of error logging.
Some registers are located in ROM and therefore must be set at compile-time. These include some option-setting memory (OFS) registers as well as certain memory protection registers.
Option-setting memory determines the state of the MCU after a reset. For example, the IWDT can be configured and enabled, voltage detection can be enabled, and HOCO oscillation can be enabled. When these registers are set the operations are completed before the MCU’s reset vector is fetched and execution begins.
Some Synergy MCUs include a Memory Protection Unit (MPU). The MPU is a programmable device that can be used to define memory access permissions (i.e. privileged access only or full access) and memory attributes (for example, bufferable, cacheable) for different memory regions. The MPU can support up to eight programmable memory regions, each with their own programmable starting addresses, sizes and settings.
The ISDE configures these memory areas by setting values for the provided MPU settings. You must be careful when setting these registers. Incorrect settings can prevent access to required memory areas or prevent access to the MCU entirely.
You can configure the pins used in your application through the ISDE pin configurator. See Configuring Pins.
Bsp_pin_cfg.h
This configuration file contains an array of pin configurations. During start-up, and before main() is executed, the BSP iterates over this array and initializes the MCU's port pins based on the settings in the array. Initially, before any pin configuration by the user, the ISDE Pins tab displays the initial reference configuration defined for the selected board type (see Configuring Pins). Once the user modifies the pin configuration and clicks Generate Project, a new bsp_pin_cfg.h file is generated containing the new pin configuration. The BSP always uses the bsp_pin_cfg.h file from ssp_cfg\bsp as the source for its pin configuration information, but the pin information generated by clicking Generate Project is written to a bsp_pin_cfg.h file in the hidden folder ssp_cfg\bsp\.out.
In this way, the user can manually edit the bsp_pin_cfg.h in ssp_cfg\bsp without the fear of the file being overwritten by the project generation, while the Pin Configuration information generated by the ISDE also remains available for view or merging with the user’s config file.
All system clocks are set up during BSP initialization based on the settings in bsp_clock_cfg.h. These settings are derived from clock configuration information provided from the ISDE Clocks tab setting.
Bsp_clock_cfg.h
This configuration file represents the values for system clock settings. These are the settings that can be modified from the ISDE **Clocks** tab. See: Configuring Clocks
As Synergy MCU’s are based on the Cortex-M ARM architecture, the NVIC Nested Vectored Interrupt Controller (NVIC) handles exceptions and interrupt configuration, prioritization and interrupt masking. In the ARM architecture, the NVIC handles exceptions. Some exceptions are known as System Exceptions. System exceptions are statically located at the top of the vector table and occupy vector numbers 1 to 15. Vector zero is reserved for the MSP Main Stack Pointer (MSP). The remaining 15 system exceptions are shown below:
NMI and Hard Fault exceptions are enabled out of reset and have fixed priorities. Other exceptions have configurable priorities and some can be disabled.
Group interrupt is the term used to describe the 12 sources that can trigger the Non-Maskable Interrupt (NMI). When an NMI occurs the NMI Handler examines the NMISR (status register) to determine the source of the interrupt. NMI interrupts take precedence over all interrupts, are usable only as CPU interrupts, and cannot activate the Synergy peripherals Data Transfer Controller (DTC) or Direct Memory Access Controller (DMAC).
Possible group interrupt sources include:
A user may enable notification for one or more group interrupts by registering a callback using the BSP API function R_BSP_GroupIrqWrite. When an NMI interrupt occurs, the NMI handler checks to see if there is a callback registered for the cause of the interrupt and if so calls the registered callback function.
As mentioned earlier, the first 16 slots in the vector table are already accounted for by the system exceptions. Beginning with slot 16 are user configurable interrupts. These may be external, or peripheral generated interrupts.
The size of the NVIC interrupt table varies across Synergy MCU types (shown below).
Although the number of available slots for the NVIC interrupt vector table may seem small, the BSP defines up to 512 events that are capable of generating an interrupt. By using Event Mapping, the BSP maps user enabled events to NVIC interrupts. For an S7G2 MCU, only 96 of these events may be active at any one time, but the user has flexibility by choosing which events generate the active event.
The diagram below shows the interrupt vector table for the S7G2:
By allowing the user to select only the events they are interested in as interrupt sources, we are able to provide an interrupt service routine that is fast and event specific.
For example, on other microcontrollers a standard NVIC interrupt vector table might contain a single vector entry for the SCI0 (Serial Communications Interface) peripheral. The interrupt service routine for this would have to check a status register for the 'real' source of the interrupt. In the Synergy implementation there is a vector entry for each of the SCI0 events that we are interested in. The difference between a standard NVIC table and the Synergy S7G2 NVIC table is shown below:
Configuration of interrupts is handled by the ISDE. Selecting an interrupt to be used by a module will generate the code necessary to allocate its entry in the vector table, as well as link it to the proper ICU ELC event.
When an interrupt occurs one of the very first operations must be to call R_BSP_IrqStatusClear() with the interrupt number corresponding to the NVIC interrupt slot that was assigned by the BSP. R_BSP_ IrqStatusClear() clears the interrupt status flag (IR) for the given interrupt. When an interrupt is triggered the IR bit is set. If it is not cleared in the ISR then the interrupt will trigger again immediately.
Entries that have been assigned a priority (i.e. BSP_IRQ_CFG_ICU_IRQ0) in our example, have their corresponding ‘weak handler’ address placed in the next available vector slot. All of the possible interrupt sources are iterated over in this manner. Defined interrupts are entered into the vector table.
Bsp_irq_cfg.h is a legacy file that is no longer used and will be removed in the future. Interrupt configuration is now completely handled by the ISDE.
System exceptions such as the HardFault_Handler, are defined as weak references. This allows the user to override the default handler for a particular exception and define their own handler.
All other entries in the vector table are generated by the ISDE using a macro which defines the vector and a corresponding vector information structure to generate an entries in ROM table linker sections (.vector.* for vectors and .vector_info.* for vector information).
Note that in CMSIS system_xxxx.c, there is also a weak definition (and a function body) for the Warm Start callback function R_BSP_WarmStart(). Because this function is defined in the same file as the weak declaration, it will be called as the ‘default’ implementation. The function may be overridden by you by copying the body into your application and modifying it as necessary. The linker identifies this as the ‘strong’ reference and uses it.
As the BSP is in the process of bringing up the board out of reset, there are two points where the user can request a callback. These are defined as the 'Pre C' and 'Post C' warm start callbacks.
As described above, this function is already weakly defined as R_BSP_WarmStart(), so it is a simple matter of redefining the function or copying the existing body from CMSIS system_xxxx.c into the application code to get a callback. R_BSP_Warmstart() takes an event parameter which describes the type of warm start callback being made.
This function is not enabled/disabled and is always called for both events as part of the BSP startup. Therefore it needs a function body, which will not be called if the user is overriding it. The function body is located in system_xxxx. To use this function just copy this function into your own code and modify it to meet your needs.
This callback occurs almost immediately after reset and at this point no C runtime environment, clocks, or IRQs have been setup.
Why would you be interested in a 'Pre C' warm start callback?
Below are a few examples.
This callback occurs after clocks and the C runtime environment have been setup.
Why would you be interested in a 'Post C' warm start callback?
Below are a few examples.
Creating a Custom BSP for your own board is not supported in this version of the SSP. For information on creating a Custom BSP with earlier versions, see application note R11AN0071EU, Creating a Custom Board Support Package for SSP v1.2.0 or Later.
The BSP provides public functions, available to any project using the BSP, that allow access to functionality that is common across BSP supported MCUs and boards.
The BSP register protection functions utilize reference counters to ensure that an application which has specified a certain register and subsequently calls another function does not have its register protection settings inadvertently modified.
Both functions will only modify the protection state if their reference counter is zero.
As the example below shows, without reference counters, MODULE2 would re-protect the registers that MODULE 1 had un-protected, preventing MODULE1 from writing them.
This section describes the key features
Detailed CMSIS library details can be found on Github: https://github.com/ARM-software/CMSIS_5/releases/tag/5.8.0
Detailed CMSIS library details can be found on Github: https://github.com/ARM-software/CMSIS_5/releases/tag/5.8.0