0

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
}

Arduino IDE config

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 of void(). This only caused Simulink to complain that a .c type wrapper file is missing.
C. Matr
  • 3
  • 2

1 Answers1

0

You need to include stm32 CMSIS header for your micro:

#include "stm32l476xx.h"

and the HAL driver as well

#include "stm32l4xx_hal.h"

But for HAL you will need more headers and source files.

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Thanks for the hint - I've included both headers and added their paths so the compiler knows where to look for them. No new errors pop-up but the same errors persists. I thought it'd be helpful to share the full log of the code generator on pastebin: [https://pastebin.com/S1HezgSV](https://pastebin.com/S1HezgSV) – C. Matr Mar 14 '23 at 12:07
  • @C.Matr You need also to have proper definitions showing what micro you are using and HAL configuration file. It cant be done by a cargo-cult programming (https://en.wikipedia.org/wiki/Cargo_cult_programming) attempt. Read the CMSIS and HAL documentation to learn what you need to make it working – 0___________ Mar 14 '23 at 13:22