1

I'm trying to create my own servo.write block in Simulink for Arduino DUE deployment (and External Mode). Before you ask why if there is one available inside the Simulink Arduino Support Package, generally my final goal is to create a block that will use Arduino servo.writeMicroseconds function (there is no out of the box block for this one) but first i want to try with something simple to debug to see if i can get it to work....

I've been using this guide (https://www.mathworks.com/matlabcentral/fileexchange/39354-device-drivers) and one of working examples in there as a template and started modifying it (originally it implemented Digital Output driver). I took the LCT approach.

The the original digitalio_arduino.cpp/h files from the guide (example with digital read/out) were the files I modified as they were working without any issues out-of-the-box. Step by step i made following modifications:

  1. Remove DIO read (leave only write) from CPP and H files

  2. Change StartFcnSpec to digitalIOSetup and make changes in H file so port is always in OUTPUT mode

  3. Include Servo.h library within CPP file and create Servo object

Up to this point, all edits went fine, no compile errors, all header files were detected by Simulink and diode kept blinking as it should so the code actually worked (i ran it in External Mode).

But as soon as i made the final modification and replaced pinMode() with myservo.attach() and digitalWrite() with myservo.write() (of course i changed the data type in writeDigitalPin function from boolean to uint8_T) the code, despite compiling and building without any issue didn't work at all. Specified servo port was completely dead, as it even wasn't initialised. Changing value on S-Function input didn't yield any results.

Of course If i replaced custom block with built in Servo Write block from Hardware Support Package, everything worked fine so its not hardware issue.

I'm completely out of ideas what could be wrong, especially that there are no errors so not even a hint where to look.

Here is the LCT *.m script used for generating S-Function:

def = legacy_code('initialize');
def.SFunctionName  = 'dout_sfun';

def.OutputFcnSpec  = 'void NO_OP(uint8 p1, uint8 u1)';
def.StartFcnSpec   = 'void NO_OP(uint8 p1)';
legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def, '-DNO_OP=//') 

def.SourceFiles     = {fullfile(pwd,'..','src','digitalio_arduino.cpp')};
def.HeaderFiles     = {'digitalio_arduino.h'};
def.IncPaths        = {fullfile(pwd,'..','src'), 'C:\ProgramData\MATLAB\SupportPackages\R2021b\aIDE\libraries\Servo\src'};
def.OutputFcnSpec  = 'void writeDigitalPin(uint8 p1, uint8 u1)';
def.StartFcnSpec   = 'void digitalIOSetup(uint8 p1)';
legacy_code('sfcn_cmex_generate', def);
legacy_code('sfcn_tlc_generate', def);
legacy_code('rtwmakecfg_generate',def);
legacy_code('slblock_generate',def);

Here is digitalio_arduino.CPP file

#include <Arduino.h>
#include <Servo.h>
#include "digitalio_arduino.h"
Servo myservo;

// Digital I/O initialization
extern "C" void digitalIOSetup(uint8_T pin) 
{
    //pinMode(pin, OUTPUT);
    myservo.attach(pin);
}

// Write a logic value to pin
extern "C" void writeDigitalPin(uint8_T pin, uint8_T val)
{
    //digitalWrite(pin, val);
    myservo.write(val);
}

// [EOF]

And here is digitalio_arduino.H file

#ifndef _DIGITALIO_ARDUINO_H_
#define _DIGITALIO_ARDUINO_H_
#include "rtwtypes.h"

#ifdef __cplusplus
extern "C" {
#endif

void digitalIOSetup(uint8_T pin);
void writeDigitalPin(uint8_T pin, uint8_T val);

#ifdef __cplusplus
}
#endif
#endif //_DIGITALIO_ARDUINO_H_

As I mentioned I've been using a working example as a reference. So I've modified it step by step to see if maybe there is a point when suddenly some error comes up but everything compiles yet does not work :/

I was wondering maybe if there is an issue with the Servo.h library or the Servo object and did some tinkering with these, like i removed Servo myservo; line of code to see if anything happens and just like expected, i started receiving errors that Servo is not defined. If I did not include Servo.h at all or forget to add IncPath to Servo.h as before compile errors about Servo not being supported symbol or not being able to find Servo.h library - so actually the code seems to be "working" in a way, it seems to have everything it needs to work :/

I also looked at the MathWorks implementation of Servo Write block, the MWServoReadWrite to see how Arduino API is being used and no surprise, it's being used in the same way as I've been trying to. They include Servo.h, they are using servo.attach() and servo.write() to control the servo port. And that's it. Yet for them it works, for me does not :/

When I inspect generated C code that runs on Arduino (with my custom S-Function block in it), it seems that all the functions are placed exactly where they are supposed to be, they receive correct arguments. I expected at least that I'll find a hint in there, i.e. missing code or anything else.

  • Does your C/C++ code work outside of the MATLAB/Simulink environment (i.e. if you were to implement a standalone application that does digital write with nothing to do with MATLAB)? I always find it better to first have working functions before I ship the code into MATLAB/Simulink. Also, why use LCT instead of System Object blocks (just a matter of preference, but I found the templates they give for System Object blocks extremely good and much more simple than LCT). – Tommy Wolfheart Mar 24 '22 at 20:15
  • When i run that code in Arduino Sketch, stripped out of CPP wrappers (so basically its just Servo myservo; Servo.Attach and Servo.Write) it works correctly. The original example i used also worked correctly with most of my modification. As for why LCT, It's because it seemed to be easier to modify and i have more experience with that. Wanted to make sure it works with LCT before i start trying out System Objects (which are completely new to me). – Multiplexer Mar 24 '22 at 20:59
  • I see. Yeah sorry not too familiar with LCT. My suspicion is there may be a step missing or the order of the steps differs from what's defined [here](https://www.mathworks.com/help/simulink/sfg/integrating-existing-c-functions-into-simulink-models-with-the-legacy-code-tool.html) and it's causing a problem. I don't know, but I feel like there should be a compile line after your last generate. – Tommy Wolfheart Mar 24 '22 at 21:32
  • If you get really stuck, give System Objects a go. It is very simple and straight forward if you follow this [guide](https://www.mathworks.com/help/supportpkg/arduino/device-driver-blocks.html) and then 'at' me if it's not working and I may have some two cents on the matter. – Tommy Wolfheart Mar 24 '22 at 21:32
  • @TommyWolfheart Hey, I've been tinkering with this issue and I think i found the cause. I became curious what will happen if I were to place both my custom Servo Block in model alongside with Simulink Arduino Support Package built in Servo Block And guess what, suddenly my own block started to work. So apparently it seems that If Simulink does not detect any built in Arduino Block in model it omits some routine responsible for enabling interrupt/timers in Arduino being placed in main() (so servos are dead). I'll have to compare the codes and put that in my custom code too. – Multiplexer Mar 27 '22 at 20:18
  • Oh nice. Glad it worked out. Will keep that in mind in my own project as well. – Tommy Wolfheart Mar 28 '22 at 10:04
  • @TommyWolfheart After today I think the problem still may be somewhere within the code. I've noticed that the only difference between code with my custom block and code with built-in block is that my code generates no errors but some warnings in the compile diagnostics view – Multiplexer Mar 28 '22 at 18:34
  • @TommyWolfheart I think these are Linker warnings? customservo_arduino.o: In function 'customServoAttach': customservo_arduino.cpp:(.text.customServoAttach+0x4): warning: undefined reference to 'Servo::attach(int)' customservo_arduino.o: In function 'customServoWrite': customservo_arduino.cpp:(.text.customServoWrite+0x2): warning: undefined reference to 'Servo::write(int)' customservo_arduino.o: In function '_GLOBAL__sub_I_myservo': customservo_arduino.cpp:(.text.startup._GLOBAL__sub_I_myservo+0x2): warning: ndefined reference to 'Servo::Servo()' – Multiplexer Mar 28 '22 at 18:36

0 Answers0