Organization of the Software Platform
Introduction to the Software Platform
Organization of the Software Platform
Using the Software Platform Builder
Glossary
The Software Platform consists of device stacks and software services. This section describes both parts and how they are related to each other.
Device Stacks
Device stacks is all about making hardware peripherals available to application code through abstract and generic software interfaces. Normally you build device stacks bottom-up. You start with the lowest level modules which are specific for a particular hardware device on your schematic design. On top of that, you can stack higher level modules that provide more generic functionality to access the device.
Device stacks may be composed of three types of modules: hardware wrappers, drivers and contexts.
Hardware Wrappers
Hardware wrappers (the green stack items) are the lowest level modules. They encapsulate the peripherals which are hooked up to your processor, and provide information for the higher layers of the stack to access the device. Information such as the base address, interrupt assignment and any soft peripheral configuration is all stored in the hardware wrapper.
Peripherals are not necessarily physical hardware devices on the NanoBoard, they can also live inside the FPGA only, such as a JPEG decoder which has no connectors to the physical world but only performs complex calculations inside the FPGA.
Normally, the hardware wrapper will not be visible to your application because in most cases the application will access it through the driver's interface on top of it. In some cases of extremely simple hardware wrappers, the driver and the peripheral could be combined (for example, a simple hardware wrapper with merely some control registers like I/O ports or LEDs). Such hardware wrappers simply do not require a driver and in this case, your application will have direct access to the peripheral interface.
Drivers
Drivers (the yellow stack items) provide the link between hardware wrappers and contexts. They provide the next level of abstraction and are stacked upon hardware wrappers. Drivers provide access to the peripheral via the hardware wrapper or via another driver.
The difference between a driver and a hardware wrapper is well defined. In general, the software at the level of the hardware wrapper must remain unaware of the software complexity of the application that runs on top. In other words, the hardware wrappers only define basic information about the peripheral but provide no further functionality. This basic information can be used by a driver which you can place on top of the hardware wrapper.
Each driver module fits on just one hardware wrapper. In other words, drivers (like hardware wrappers) are hardware specific and so are the interfaces they offer. Hence, if your application contains code that accesses a driver's API, your application will be hardware dependent. Drivers still operate at a low abstraction level, and using a device at the driver level requires knowledge of that particular driver's interface.
Contexts
Contexts (the blue stack items) are the highest level modules of device stacks and provide the most abstract layers of functionality. Contexts provide standardized, hardware independent access to devices. Contexts are instantiations of automatic services (see next section).
Contexts ensure portability of your application. For example, if you run an application with a generic mouse service, the application remains the same if you replace a PS/2 mouse with a USB mouse. A portable mouse application will work exactly the same, whether linked to a PS/2 or a to a USB hardware project, since the Software Platform will handle lower level details.
Some stacks may be small - for example a JPEG Decoder hardware wrapper and a JPEG Decoder Driver on top of it - while others may be more complex and provide truly hardware independent access to the device. For example a generic Storage System Context that accesses either a S29 Parallel Flash Memory or a SPI Master Controller via several other contexts and drivers. Note that the interface of the top-level interface will remain exactly the same, whether you want to access the S29 Parallel Flash Memory device or the SPI Master Controller.
Altium Designer comes supplied with drivers for all of hardware devices available on the NanoBoard, as well as many high level services. These services include:
- Storage Services for accessing files and folders on SD cards, IDE drives, Compact Flash cards and flash memory
- Networking Services to provide access to Ethernet networking
- Kernel Services providing POSIX compliant multithreading capabilities
- GUI Services allowing the quick construction of modern graphical interfaces
- Multimedia Services for audio and video functionality
Software Services
A software service is a set of functionality - that is, types, defines, structures and functions. This functionality is accessible from your application. Different services are brought into the software platform in different ways:
- System Services are always present in the software platform.
- Automatic Services are brought into the software platform automatically, depending on what stacks you create.
- Optional Services are services that you can select manually to be part of your project.
System Services
System services are always present in the software platform and include Software Platform Configuration, Interrupt Management and Software Timing Services. System services are not related to a specific device.
Software Platform Configuration
The software platform configuration service provides global settings for the software platform. One important setting to keep in mind is the frequency of the processor clock. An incorrect value may cause to unexpected behavior of some peripherals or timer functions.
Interrupt Management
The interrupt management services module provides standard services to disable, enable, mask, configure and acknowledge interrupts. In addition it provides extra mechanisms to register or associate native, standard, and kernel interrupt service routines (ISRs) to interrupts. These utilities are mostly used by interrupt-driven drivers but you can also use the module's API in your application.
Software Timing Services
The timing software services provides standard timing (frequency, delay and elapse) services that you can use for timing purposes. In addition they provide a simple way to install periodic software timers in the system.
The Software Platform makes sure interrupts and timers are handled in a processor independent way. The Processor Abstraction Layer (PAL), which is also implemented as software modules, are always linked with your C application but are only used by other modules to ensure that they work regardless of the processor used. All this happens beneath the surface and is not visible in the Software Platform Builder.
Automatic Services
Automatic services are brought into the software platform automatically when you create stacks that require such a services. Most automatic services are related to contexts. After all, each context is an instantiation of an automatic service.
POSIX device I/O (C library)
The POSIX device I/O service is the only automatic service that is not directly related to contexts. The POSIX device I/O module provides basic device I/O functionality that enables you to access intrinsically non-standard I/O devices in a standard way. These services include all services defined in the POSIX_DEVICE_IO unit of functionality of the POSIX standard. The greater part of the module's interface are C library interfaces. The following I/O C library interfaces are provided:
|
|
|
|
Devices that require other control operations than common operations such as read(), write(), open() and close(), are called special devices in the POSIX standard. For these special devices, the device I/O module provides the posix_devctl() function. With this function you can send any control command to a specific device.
Finally, this module provides four non-POSIX functions for memory mapping and memory sharing: mmap(), munmap(), shm_open() and shm_unlink().
Optional Services
POSIX is a set of well-established standards that define a standardized way for an application to interface to the operating system. Thus, POSIX is a set of books specifying APIs, it is neither a piece of code nor an operating system. The POSIX standards do not specify how kernel services must be implemented, but only defines their semantics. So, internally POSIX services may be implemented in a different way, on the outside they always must follow the specification of the interface.
The complete set of POSIX services as defined in the standard may be useful for large applications, but the set is considered to be too large for most embedded systems. Embedded systems usually have tight memory requirements, may not have memory management capabilities, and may not even have a secondary memory for implementing the UNIX file system.
For these reasons the POSIX standard recognizes the need for the creation of subsets of the operating system services. The IEEE Std 1003.13-2001 edition (POSIX.13) describes four real-time application environment profiles and their minimum hardware requirements. All generic software services modules in the Application Stack software framework conform to the PSE51 profile for Minimal Real-time Systems.
To access the interfaces of the generic software services modules from your application, you need to manually include the corresponding service.
Multithreading Support
The POSIX multithreading module provides all services defined in the POSIX_THREADS_BASE unit of functionality of the POSIX standard. The basic assumption in this software module is that the system consists of a single (implicit) process (corresponding to the processor's hardware address space) with multiple threads.
The programming model is that of a single (implicit) POSIX process, containing one or more threads of control (POSIX.1 threads or Ada tasks). Devices can be operated and controlled either by memory-mapped I/O or by the basic I/O interface, which provides a standard way to access non-standard I/O hardware and its non-portable control code.
The hardware model for the PSE51 profile assumes a single processor with internal memory. A memory management unit (MMU) is not required. Note that in multi-process systems, typically also multiple instantiations of the operating system exist, possibly communicating via shared memory or a backplane channel, or perhaps isolated.
Two synchronization primitives are defined for threads: mutexes and condition variables. Mutexes are used to synchronize threads for mutually exclusive access to shared resources (for example, if two threads are trying to write to the same device), while condition variables are used to signal and wait for events among threads. Waiting for a condition variable to be signaled can be specified with a time-out.
More specifically, the POSIX multithreading module supports functions to:
- create a thread
- wait for thread termination
- terminate a thread in a normal way
- detach a thread, that is, indicate to the implementation that the storage associated with a thread may be reclaimed when the thread terminates
- create a particular thread only if it has not been created already
Other functions allow you to handle thread identifiers and to manage thread creation attributes such as the size of the thread's stack, to define whether the thread storage is detachable from creation time, and more.
Signaling Support
The POSIX signals module provides all services defined in the POSIX_SIGNALS unit of functionality of the POSIX standard. Signal services are a basic mechanism within POSIX-based systems and are required for error and event handling.
Real-time systems typically have several logically concurrent software elements executing. Each such entity must respond to several cyclic and/or a-cyclic stimuli, often in a time-critical manner. Purely synchronous models can supply such functionality via the use of additional processes or threads. However, the current real-time practice for asynchronous notification for events (like a message arrival) and hardware interrupts, offers higher performance and lower latency.
For this reason the usage of POSIX signals is somehow restricted here in comparison with desktop systems (the kernel prefers mutex and conditional variables over signals for its internal synchronization). But analogous to UNIX processes that send signals to other processes, in this embedded environment threads may send signals to other threads.
Message Queues Support
This POSIX message queues module implements the POSIX_MESSAGE_PASSING unit of functionality of the POSIX standard.
In the PSE51 profile of IEEE Std 1003.13-1998, message queues were required because commercial real-time kernels available at that time, with similar functionality to the Minimal Real-time System Profile, typically included some form of message queuing mechanism for communication between threads. However, many embedded real-time applications for small systems do not require message queues. Because message queues can be easily implemented by the application using mutexes and condition variables, this version of the standard, IEEE Std 1003.13-2003, has dropped the requirement to support message queues. Despite the above reasoning, the Altium POSIX includes these services as an extra alternative for inter-thread communication.
Summary
The Software Platform contains modules at various abstraction levels. You can stack higher level modules on lower level modules working towards a situation in which your application becomes portable and independent of the hardware it accesses.
In addition, the Software Platform contains modules that offer extra functionality. Extra functionality may be required by other modules and automatically added, or you can add this functionality manually to your project.
In case of stacked modules, only the API of the highest level module is visible to your application (except from some extraordinary cases). The table below summarizes the advantages and possible disadvantages of using higher level APIs compared to lower level APIs.
Using the API of higher level modules | Using the API of lower level modules |
---|---|
Advantages | Disadvantages |
Your application becomes more portable / hardware independent | Your application becomes less portable |
Less developing effort needed since lower level modules take care of many hardware specific details | You will need to have better understanding of the lower level processes and developing efforts increase |
It is possible to modify the hardware design without having to change your application | Each modification in the hardware design forces you to adapt your application to the new hardware design |
Disadvantages | Advantages |
More overhead | Less overhead |
Your application may execute slower | Your application may execute faster |
May provide less control over the device | May provide more control over the device |