General
In the following steps we create a very simple project using the semf library. We assume you already set up a microcontroller project which uses an Eclipse based IDE. We set this up for an STM32F4 microcontroller and used STM32CUBEMX / STM32CUBEIDE for hardware initialization.
C++ Project
Convert your project to a C++ project by a right mouse click -> Convert to C++. Copy the semf library to a new 'semf' folder in the root directory of your project.
Library Linkage
Link the semf library to your project by adding the library and include path and the library itself. You can find these settings in Project -> Settings -> C/C++ General -> Paths and Symbols. Make sure you add both to the C++ language and all configurations:
- Go to Includes and add the semf library path.
- Go to Library Paths and add the semf library path.
- Go to Libraries and add the name of the semf library file with a „:“ in front of the name (e.g. :semf_cortex-m4_fpv4-sp-d16.a).
STM32 Systick
Setting up a new project with STM32CUBEMX / STM32CUBEIDE the systick callback is never called.
We add this callback in the stm32f4xx_it.c file.
void SysTick_Handler(void)
{
HAL_IncTick();
HAL_SYSTICK_Callback();
}
C to Cpp Bridge
maincpp.h
Create the following maincpp.h file in the same directory as the main.h.
#ifndef CPPMAIN_H_
#define CPPMAIN_H_
void cppInit();
void cppMainLoop();
#endif
maincpp.cpp
Create the following maincpp.cpp file in the same directory as the main.c.
#include "bsp.h"
#include "app.h"
extern "C" {
void cppInit()
{
static msp::Msp myMsp;
static bsp::Bsp myBsp(myMsp);
static app::App myApp(myBsp);
msp.init();
}
void cppMainLoop()
{
app.mainLoop();
}
}
main.c Changes
Add following code in the main.c to enter the cpp part of the project.
#include "maincpp.h"
int main(void)
{
cppInit();
while (1)
{
cppMainLoop();
}
}
Microcontroller and Board Support Package
semf makes applications hardware independent. Somewhere in the project we need to define all the hardware dependent stuff. To do that, let’s create a Msp and Bsp class.
In the following example we make the semf::app::Timer, one semf::Gpio and a semf::AnalogIn (adc) accessable from the application.
msp.h
Create the following msp.h file in the same directory as the main.h.
#ifndef MSP_H_
#define MSP_H_
#include "main.h"
#include "stm32f4xx_hal.h"
namespace msp
{
class Msp
{
public:
Msp();
explicit Msp(const Msp& other) = delete;
~Msp() = default;
semf::Timer& systick1ms();
void init();
private:
semf::Stm32F4Gpio m_gpio1;
semf::Stm32F4Systick m_systick1ms;
semf::Stm32F4AnalogIn m_analogIn1;
};
}
#endif
Interface for using ADC (Analog to Digital Conversion) hardware in interrupt mode.
Interface class for using a GPIO pin of the microcontroller.
msp.cpp
Create the following msp.cpp file in the same directory as the main.c.
#include "msp.h"
extern ADC_HandleTypeDef hadc1;
namespace msp
{
Msp::Msp()
:m_gpio1(B1_GPIO_Port, B1_Pin),
m_analogIn1(hadc1)
{
}
{
return m_gpio1;
}
semf::Timer& Msp::systick1ms()
{
return semf::Stm32F4Systick::instance();
}
{
return m_analogIn1;
}
void Msp::init()
{
}
}
bsp.h
Create the following bsp.h file in the same directory as the main.h.
#ifndef BSP_H_
#define BSP_H_
#include "msp.h"
namespace bsp
{
class Bsp
{
public:
explicit Bsp(msp::Msp& myMsp);
explicit Bsp(const Bsp& other) = delete;
~Bsp() = default;
void init();
private:
};
}
#endif
Class for handling a digital output.
A TimeBase is the bridge between e.g. a hardware timer (interrupt service routine) and TickReceiver o...
bsp.cpp
Create the following bsp.cpp file in the same directory as the main.c.
#include "bsp.h"
namespace bsp
{
Bsp::Bsp(msp::Msp& myMsp)
:m_timeBase1ms(myMsp.systick()),
m_digitalOut1(myMsp.gpio1)
{
}
{
return m_timeBase1ms;
}
{
return m_digitalOut1;
}
void Bsp::init()
{
}
}
Application
Now we can set up our micro application.
app.h
Create the following app.h file in the same directory as the main.h.
#ifndef APP_H_
#define APP_H_
#include "bsp.h"
namespace app
{
class App
{
public:
explicit App(bsp::Bsp& myBsp);
explicit App(const App& other) = delete;
~App() = default;
void init();
void mainLoop();
private:
void onTimeout();
SEMF_SLOT(m_onTimeoutSlot, App, *
this, onTimeout);
};
}
#endif
Software SoftwareTimer which can be added to a TimeBase or used singular.
Class for handling a digital output.
#define SEMF_SLOT(name, className, object, function,...)
Creates a semf slot.
app.cpp
Create the following app.cpp file in the same directory as the main.c.
#include "app.h"
namespace app
{
App::App(bsp::Bsp& myBsp)
:m_swTimer(myBsp.timeBase1ms()),
m_digitalOut(myBsp.digitalOut1())
{
}
void App::init()
{
}
void App::mainLoop()
{
}
void App::onTimeout()
{
m_digitalOut.toggle();
}
}