My goal
I'm building a Simulink based application for Nucleo L476RG using Mathworks' code generation support packages. These packages include basic blocks to control the peripherals of the controller but when it comes to external hardware (f.e. an SPI based SD card writer) I do not want to implement the communication protocol from scratch.
I have experience with using Arduino IDE with STM32 board support to program the Nucleo board and have found a few sources describing the process of integrating such Arduino code straight into Simulink using S-functions, see the following links:
https://www.ee-diary.com/2020/11/How-to-create-Arduino-S-Function-in-Simulink.html
https://www.mathworks.com/matlabcentral/fileexchange/39354-device-drivers
My goal is to combine create an S-function "driver" which would utilize the Arduino STM package and libraries and which I'd be able to include along my other Simulink functions and generate + deploy the final code onto the Nucleo board using Mathworks toobloxes.
My approach
First I tested a simple LED blink function in Arduino IDE, uploaded it onto the board and verified that everything works as expected. This is the default Arduino blink code plus the project settings:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Then I wanted to replicate the same functionality using the S-function builder block. This is the S-func. source:
/* Includes_BEGIN */
#include <math.h>
#ifndef MATLAB_MEX_FILE
#include <Arduino.h>
#include <variant_NUCLEO_L476RG.h>
#endif
/* Includes_END */
/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */
void blink_sfunc_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
/*
* Custom Start code goes here.
*/
/* Start_END */
}
void blink_sfunc_Outputs_wrapper(const real_T *xD)
{
/* Output_BEGIN */
if (xD[0]==1){
# ifndef MATLAB_MEX_FILE
digitalWrite(LED_BUILTIN,ledinp[0]);
# endif
}
/* Output_END */
}
void blink_sfunc_Update_wrapper(const uint8_T *led_in,
real_T *xD)
{
/* Update_BEGIN */
if (xD[0]!=1){
# ifndef MATLAB_MEX_FILE
pinMode(LED_BUILTIN,OUTPUT);
# endif
xD[0]=1;}
/* Update_END */
}
void blink_sfunc_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
* Custom Terminate code goes here.
*/
/* Terminate_END */
}/* Includes_BEGIN */
#include <math.h>
#ifndef MATLAB_MEX_FILE
#include <Arduino.h>
#include <variant_NUCLEO_L476RG.h>
#endif
/* Includes_END */
/* Externs_BEGIN */
/* extern double func(double a); */
/* Externs_END */
void blink_sfunc_Start_wrapper(real_T *xD)
{
/* Start_BEGIN */
/*
* Custom Start code goes here.
*/
/* Start_END */
}
void blink_sfunc_Outputs_wrapper(const real_T *xD)
{
/* Output_BEGIN */
if (xD[0]==1){
# ifndef MATLAB_MEX_FILE
digitalWrite(LED_BUILTIN,ledinp[0]);
# endif
}
/* Output_END */
}
void blink_sfunc_Update_wrapper(const uint8_T *led_in,
real_T *xD)
{
/* Update_BEGIN */
if (xD[0]!=1){
# ifndef MATLAB_MEX_FILE
pinMode(LED_BUILTIN,OUTPUT);
# endif
xD[0]=1;}
/* Update_END */
}
void blink_sfunc_Terminate_wrapper(real_T *xD)
{
/* Terminate_BEGIN */
/*
* Custom Terminate code goes here.
*/
/* Terminate_END */
}
The S-function generates the C source without any issues. The next step is to build the Simulink model containing the S-function and this is where I fail. A great number of errors pops up in the Arduino library files including unkown type names, undefined variables etc. Just an example:
C:/Users/tomru/AppData/Local/Arduino15/packages/STMicroelectronics/hardware/stm32/2.4.0/cores/arduino/stm32/digital_io.h:57:37: error: unknown type name 'GPIO_TypeDef'
57 | static inline void digital_io_write(GPIO_TypeDef *port, uint32_t pin, uint32_t val)
| ^~~~~~~~~~~~
C:/Users/tomru/AppData/Local/Arduino15/packages/STMicroelectronics/hardware/stm32/2.4.0/cores/arduino/stm32/backup.h:67:3: warning: implicit declaration of function '__HAL_RCC_BACKUPRESET_RELEASE' [-Wimplicit-function-declaration]
67 | __HAL_RCC_BACKUPRESET_RELEASE();
- I tried to include all necessary header files and define their path in the S-function builder block and there is no error about unknown or missing includes.
- As per the linked tutorial, I tried changing the S-function wrapper to .cpp and redefining the object methods to
extern "C" void(..)
instead ofvoid()
. This only caused Simulink to complain that a .c type wrapper file is missing.