Tutorial: Building a HelloWorld Application (Step 3)

Define the Hardware Platform

In order to be able to integrate the embedded application's source code unmodified with the redBlocks Simulator as well as the actual hardware target, the application's source code needs to access all peripherals via a hardware abstraction layer. It must provide a clean programming interface that is independent from the specifics of the underlying hardware. We call this hardware abstraction layer the low level platform. We certainly need one low level platform implementation for each target (e.g. redBlocks Simulator and real hardware target). If you use the programming language C++, we recommend to implement the low level platform in a class template TLowLevelPlatform. For the implementation of the redBlocks Simulator's TLowLevelPlatform you can easily use the code fragments, generated by the redBlocks Simulator, like shown on this page. Refer to this tutorial in order to learn how to build the low level platform for the real target hardware.

The hardware platform for our application consists of a single digital output (that drives an LED) and a digital input (that is connected to a push button). We have already defined these hardware elements in the redBlocks Simulator and can thus use its simulation stub generation facilities: Select "Project -> Generate Code Fragments" in the redBlocks Simulator in order to display the following dialog:

 

Dialog  Platform Code Fragments

 

Copy the generated code snippets to the file project/sim/LowLevelPlatform.h, so it looks like this:

template<unsigned int T = 0>
class TLowLevelPlatform: public redBlocks::Core::NoInstanceBase
{
  public:
    typedef redBlocks::HAL::Drivers::TDigitalInputDriverStub<0> DiPushButton; // (1)
    typedef redBlocks::HAL::Drivers::TDigitalOutputDriverStub<0> DoLed;       // (2)

    static void initLowLevelDrivers()
    {
      typedef redBlocks::Simulators::SimulationStubs SimulationStubs; // (3)

      SimulationStubs::DigitalInput::add<DiPushButton>( SimulationStubs::DigitalInput::TRIGGER_EDGE_FALLING ); // (4)
      SimulationStubs::DigitalOutput::add<DoLed>( false );                    // (5)
    }
};

typedef TLowLevelPlatform<> LowLevelPlatform;

In line (1) the identifier DiPushButton is defined. In our simulation environment it refers to the simulated digital input with logical index 0 (in the simulation environment, numbers are used to distinguish different peripheral interfaces of the same kind).

In line (2) the identifier DoLed is introduced. In our simulation environment it refers to the simulated digital output with logical index 0. Our application will later use the type definitions DoLed and DiPushButton in order to access the peripherals. It does not need to know, whether they are represented by a driver stub or a real driver.

The type definition in line (3) is needed, so the following lines may refer to the identifier SimulationStubs instead of the completely qualified name redBlocks::Simulators::SimulationStub.

In line (4), our digital input driver stub is initialized with the desired parameters: We want it to simulate an interrupt callback, upon each falling edge of the signal. For this, we manually need to change the generated value SimulationStubs::DigitalInput::TRIGGER_EDGE_BOTH to SimulationStubs::DigitalInput::TRIGGER_EDGE_FALLING

In line (5) our digital output driver stub's reset value is configured, i. e. to output is initially set to low (parameter false).

This is all we need to do in order to define our hardware platform for the simulation environment. For porting the application to the target later, only the definition of LowLevelPlatform needs to be replaced.

If you wonder why LowLevelPlatform.h defines a class template TLowLevelPlatform and a typedef LowLevelPlatform after that: This approach is chosen in order to get around dependency issues that would otherwise occur when defining the callbacks for the driver stubs. Please take that for given at the moment.

High-level Platform Definitions

There is a file src/Platform.h, with the class Platform. This class defines the high-level driver functionality (e. g. buffering of incoming and outgoing data of a UART) and is located in the directory src as it is target independent, i. e. it does not need to be changed, when replacing the low-level hardware platform definition. It is derived from LowLevelPlatform, i. e. our definitions that are introduced within LowLevelPlatform.h can be accessed as Platform::DiPushButton and Platform::DoLed.

For our simple "Hello World" application we do not need to define any high level driver functionality, so the file src/Platform.h can be left unmodified.