File Exchange

image thumbnail

Device Drivers

version 1.6.0.1 (1.88 MB) by Giampiero Campa
Developing Simulink Device Driver Blocks: Step-By-Step Guide and Examples

155 Downloads

Updated 01 Sep 2016

View License

Editor's Note: This file was selected as MATLAB Central Pick of the Week

This package contains a guide that explains, in a step-by-step fashion, how to develop device driver blocks (blocks that perform target-specific functions when executed on a target platform).
Example drivers for:
-) Arduino digital output
-) Arduino digital input
-) Arduino analog output
-) Arduino encoder read
are included.

While the examples are built using the Arduino as the hardware platform (specifically relying on the Simulink Support Package for Arduino), the method applies to any other supported target.

In this guide, the first method to develop device drivers is based on the S-Function Builder block. Following chapters also describe different methods based respectively on the Legacy Code tool, the MATLAB function block, and the System Object block. Advantages and disadvantages of each method are discussed in the guide.

Finally, note that for MATLAB 2013b you will need to apply a fix for the S-Function builder to develop blocks with no input. To do so, go to the following page: http://www.mathworks.com/support/bugreports/1006532 , scroll down to the bottom, and follow the instructions therein.

Comments and Ratings (135)

Perry, yes something similar should work provided you know which library to include and functions to call. For Simulink Real Time in general I would contact our Technical Support, and tell them exactly what you need to accomplish (with examples), they are in general better equipped to help you.

Perry

I am able to use the System Object block method to implement a driver for Raspberry Pi that links a static library. Will this method work with Simulink Realtime? One difference is compilation is done on the Pi whereas for Simulink Real Time, compilation is done on the host.

Amanda P

Hi,

I'm using the encoder S-Function and have modified it so that it'll only trigger on the rising edge of my reference signal to count pulses. I know this has less resolution, but I want to verify carry over functionality from my hand code, to the model I'm creating.

I'm finding that my output results in the same sign, no matter which direction the motor is turning.

Below is the modified code, if any one has thoughts as to why I'm getting the same sign, please share!

Modified "update" code:

if (xD[0]!=1) {

/* don't do anything for MEX-file generation */
# ifndef MATLAB_MEX_FILE

/* enc[0] is the encoder number and it can be 0,1 or 2 */
/* if other encoder blocks are present in the model */
/* up to a maximum of 3, they need to refer to a */
/* different encoder number */

/* store pinA and pinB in global encoder structure Enc */
/* they will be needed later by the interrupt routine */
/* that will not be able to access s-function parameters */

Enc[enc[0]].pinA=pinA[0]; /* set pin A */
Enc[enc[0]].pinB=pinB[0]; /* set pin B */

/* set encoder pins as inputs */
pinMode(Enc[enc[0]].pinA, INPUT);
pinMode(Enc[enc[0]].pinB, INPUT);

attachInterrupt(digitalPinToInterrupt(Enc[enc[0]].pinA), irsPinAEn0, RISING);

# endif

/* initialization done */
xD[0]=1;
}

Modified Library Code:

# ifndef MATLAB_MEX_FILE

# include <Arduino.h>

typedef struct { int pinA; int pinB; int pos; int del;} Encoder;
volatile Encoder Enc[3] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}};

/* auxiliary debouncing function */
void debounce(int del) {
for (int k=0;k<del;k++) {
/* can't use delay in the ISR so need to waste some time
perfoming operations, this uses roughly 0.1ms on uno */
k = k +0.0 +0.0 -0.0 +3.0 -3.0;
}
}

/* Interrupt Service Routine: change on pin A for Encoder 0 */
void irsPinAEn0(){

/* read pin B right away */
int drB = digitalRead(Enc[0].pinB);

/* possibly wait before reading pin A, then read it */
//debounce(Enc[0].del);
int drA = digitalRead(Enc[0].pinA);

/* this updates the counter */

if (drB == HIGH) { /* check pin B */
Enc[0].pos++; /* going clockwise: increment */
} else {
Enc[0].pos--; /* going counterclockwise: decrement */
}

/* end counter update */

} /* end ISR pin A Encoder 0 */

#endif

Hi, any one, who can guide me how to creat custom block for my code. I am totally new to custom Blocks.

unsigned long lastTime;
double errsum, E;
int j=0;
int a;

void setup() {
Serial.begin(9600);


PORTB=0x00;
DDRB=0x06;

ICR1=199;
OCR1A=100;
OCR1B=100;
TCNT1=0;
TCCR1A=0x50;
TCCR1B=0x19;
}

void loop() {


int sensorValue = analogRead(A4);

float val = sensorValue* (4.7 / 1023.0);

if(val>= 2.5){

Serial.println("Low to High");

unsigned long now=millis();
double timeChange = (double)(now-lastTime);

int sensorValue = analogRead(A1);

float voltage = sensorValue* (4.9 / 1023.0);
float voltage2 = (9.2*voltage);
Serial.println(voltage2);
float vr = 25;
double E=vr-voltage2;
errsum +=(E*timeChange);
errsum=abs(errsum);
E=abs(E);
if (errsum>50){
errsum=50;
}
j =2.5*E+(0.5*errsum);
if(j>199) j=199;
lastTime= now;

//update ocr registers with the value
TCCR1B=0x18;
if((PINB&0x02)!=00) TCCR1C=0x80;
if((PINB&0x04)!=00) TCCR1C=0x40;
TCNT1=0;
OCR1B = j;
if(j==0) TCCR1C=0x40;
TCCR1B=0x19;


Serial.println(j);


}
else{

Serial.println("High to Low");

unsigned long now=millis();
double timeChange = (double)(now-lastTime);

int sensorValue = analogRead(A2);

float voltage = sensorValue* (4.9 / 1023.0);
// float voltage2 = (9.2*voltage);
float voltage2 = (10.3*voltage);
Serial.println(voltage2);
float vr = 5 ;
double E=vr-voltage2;
errsum +=(E*timeChange);
errsum=abs(errsum);
E=abs(E);
if (errsum>50){
errsum=50;
}
j =2.5*E+(0.5*errsum);
if(j>199) j=199;
lastTime= now;

//update ocr registers with the value
TCCR1B=0x18;
if((PINB&0x02)!=00) TCCR1C=0x80;
if((PINB&0x04)!=00) TCCR1C=0x40;
TCNT1=0;
OCR1A = j;
if(j==0) TCCR1C=0x40;
TCCR1B=0x19;

Serial.println(j);

}

}

I am trying to include an s function builder block to perform an I2c communication with a BMP280 sensor. When i perform the simulation in external mode everything goes well. My problem arises when i try to include this block in a more complicated system that perform an autopilot for an UAV. Arduino seems blocking and i don't understand why. All the autopilot is perfectely loaded and executed without this change . I really have no idea of what is the cause of the block. Thanks in advance

Luca Cirillo

@Chee Teck Tam: I took advantage of the rollover block explained in the following link, check it out:
http://ctms.engin.umich.edu/CTMS/index.php?aux=Activities_DCmotorA

@Murat Belge: Thanks for your help. After modified the enc_output() function in cpp and header file to returns a long. The encoder position now can exceed 2^15-1. Thanks a lot.

Murat Belge

@Chee Teck Tam: The enc_output() function returns an int. Change the function to return a long.

Hi Murat Belge, Thanks for your reply. I had tried to changed the variable type for Enc.pos in encoder_arduino.cpp to "long" and "volatile long" as well. However, the encoder position still overflow after 2^15-1. Below attached my code, not sure what is going wrong. Kindly advise. Appreciate your help. ( I am using Arduino Mega2560 in this implementation)

code:
#include <Arduino.h>
#include "encoder_arduino.h"

typedef struct
{
int pinA;
int pinB;
volatile long pos;
int del;
} Encoder;
volatile Encoder Enc[3] = {{0,0,0,0}, {0,0,0,0}, {0,0,0,0}};

// Auxiliary function to handle encoder attachment
static int getIntNum(int pin)
{
// Returns the interrupt number for a given interrupt pin
// See http://arduino.cc/it/Reference/AttachInterrupt
switch(pin) {
case 2:
return 0;
case 3:
return 1;
case 21:
return 2;
case 20:
return 3;
case 19:
return 4;
case 18:
return 5;
default:
return -1;
}
}

// Auxiliary debouncing function
static void debounce(int del)
{
long k;
for ( k = 0; k < del; k++) {
// can't use delay in the ISR so need to waste some time
// perfoming operations, this uses roughly 0.1ms on uno
k = k +0.0 +0.0 -0.0 +3.0 -3.0;
}
}

// Interrupt Service Routine: change on pin A for Encoder 0
static void irsPinAEn0(void)
{
// Read pin B right away
int drB = digitalRead(Enc[0].pinB);

// Possibly wait before reading pin A, then read it
debounce(Enc[0].del);
int drA = digitalRead(Enc[0].pinA);

// this updates the counter
if (drA == HIGH)
{
// low->high on A?
if (drB == LOW) { // check pin B
Enc[0].pos++; // going clockwise: increment
}
else {
Enc[0].pos--; // going counterclockwise: decrement
}

}
else {
// must be high to low on A
if (drB == HIGH) { // check pin B
Enc[0].pos++; // going clockwise: increment
}
else {
Enc[0].pos--; // going counterclockwise: decrement
}
} // end counter update
} // end ISR pin A Encoder 0

// Interrupt Service Routine: change on pin B for Encoder 0
static void isrPinBEn0(void)
{
// read pin A right away
int drA = digitalRead(Enc[0].pinA);

// possibly wait before reading pin B, then read it
debounce(Enc[0].del);
int drB = digitalRead(Enc[0].pinB);

// this updates the counter
if (drB == HIGH) { // low->high on B?
if (drA == HIGH) { // check pin A
Enc[0].pos++; // going clockwise: increment
} else {
Enc[0].pos--; // going counterclockwise: decrement
}
} else { // must be high to low on B
if (drA == LOW) { // check pin A
Enc[0].pos++; // going clockwise: increment
} else {
Enc[0].pos--; // going counterclockwise: decrement
}
} // end counter update
} // end ISR pin B Encoder 0

// Interrupt Service Routine: change on pin A for Encoder 1
static void irsPinAEn1(void)
{
// read pin B right away
int drB = digitalRead(Enc[1].pinB);

// possibly wait before reading pin A, then read it
debounce(Enc[1].del);
int drA = digitalRead(Enc[1].pinA);

// this updates the counter
if (drA == HIGH) { // low->high on A?
if (drB == LOW) { // check pin B
Enc[1].pos++; // going clockwise: increment
} else {
Enc[1].pos--; // going counterclockwise: decrement
}
} else { // must be high to low on A
if (drB == HIGH) { // check pin B
Enc[1].pos++; // going clockwise: increment
} else {
Enc[1].pos--; // going counterclockwise: decrement
}
} // end counter update

} // end ISR pin A Encoder 1

// Interrupt Service Routine: change on pin B for Encoder 1
static void isrPinBEn1(void)
{
// read pin A right away
int drA = digitalRead(Enc[1].pinA);

// possibly wait before reading pin B, then read it
debounce(Enc[1].del);
int drB = digitalRead(Enc[1].pinB);

// this updates the counter
if (drB == HIGH) { // low->high on B?
if (drA == HIGH) { // check pin A
Enc[1].pos++; // going clockwise: increment
} else {
Enc[1].pos--; // going counterclockwise: decrement
}
} else { // must be high to low on B
if (drA == LOW) { // check pin A
Enc[1].pos++; // going clockwise: increment
} else {
Enc[1].pos--; // going counterclockwise: decrement
}
} // end counter update

} // end ISR pin B Encoder 1

// Interrupt Service Routine: change on pin A for Encoder 2
static void irsPinAEn2(void)
{
// read pin B right away
int drB = digitalRead(Enc[2].pinB);

// possibly wait before reading pin A, then read it
debounce(Enc[2].del);
int drA = digitalRead(Enc[2].pinA);

// this updates the counter
if (drA == HIGH) { // low->high on A?
if (drB == LOW) { // check pin B
Enc[2].pos++; // going clockwise: increment
} else {
Enc[2].pos--; // going counterclockwise: decrement
}
}
else { // must be high to low on A
if (drB == HIGH) { // check pin B
Enc[2].pos++; // going clockwise: increment
} else {
Enc[2].pos--; // going counterclockwise: decrement
}
} // end counter update

} // end ISR pin A Encoder 2

// Interrupt Service Routine: change on pin B for Encoder 2
static void isrPinBEn2(void)
{
// read pin A right away
int drA = digitalRead(Enc[2].pinA);

// possibly wait before reading pin B, then read it
debounce(Enc[2].del);
int drB = digitalRead(Enc[2].pinB);

// this updates the counter
if (drB == HIGH) { // low->high on B?
if (drA == HIGH) { // check pin A
Enc[2].pos++; // going clockwise: increment
} else {
Enc[2].pos--; // going counterclockwise: decrement
}
}
else { // must be high to low on B
if (drA == LOW) { // check pin A
Enc[2].pos++; // going clockwise: increment
} else {
Enc[2].pos--; // going counterclockwise: decrement
}
} // end counter update

} // end ISR pin B Encoder 2

// Initialization function called by Encoder System object
extern "C" void enc_init(int enc, int pinA, int pinB)
{
// enc is the encoder number and it can be 0,1 or 2
// if other encoder blocks are present in the model
// up to a maximum of 3, they need to refer to a
// different encoder number

// store pinA and pinB in global encoder structure Enc
// they will be needed later by the interrupt routine
// that will not be able to access s-function parameters

Enc[enc].pinA=pinA; // set pin A
Enc[enc].pinB=pinB; // set pin B

// set encoder pins as inputs
pinMode(Enc[enc].pinA, INPUT);
pinMode(Enc[enc].pinB, INPUT);

// turn on pullup resistors
digitalWrite(Enc[enc].pinA, HIGH);
digitalWrite(Enc[enc].pinB, HIGH);

// attach interrupts
switch(enc) {
case 0:
attachInterrupt(getIntNum(Enc[0].pinA), irsPinAEn0, CHANGE);
attachInterrupt(getIntNum(Enc[0].pinB), isrPinBEn0, CHANGE);
break;
case 1:
attachInterrupt(getIntNum(Enc[1].pinA), irsPinAEn1, CHANGE);
attachInterrupt(getIntNum(Enc[1].pinB), isrPinBEn1, CHANGE);
break;
case 2:
attachInterrupt(getIntNum(Enc[2].pinA), irsPinAEn2, CHANGE);
attachInterrupt(getIntNum(Enc[2].pinB), isrPinBEn2, CHANGE);
break;
}
}

// Output function called by Encoder System object
extern "C" int enc_output(int enc)
{
return (volatile long)Enc[enc].pos;
}
// [EOF]

Murat Belge

@Chee Teck Tam: Try changing the variable type for Enc.pos in encoder_arduino.cpp to "long". Current data type is int which is 16-bits in some Arduino boards like Uno. Encoder position will overflow after 2^15-1 if int is 16-bits. Changing the variable type for encoder position to long makes overflow less frequent though it'll still occur after encoder position exceeds 2^32-1. You can also correct for overflow in your Simulink model by detecting and compensating for it.

Read the following from Arduino language reference pages for more info on the subject: https://www.arduino.cc/reference/en/language/variables/data-types/int/

Hi everyone,

I am using the encoder_arduino_test.slx tried to acquire the encoder count. However, the encoder count will reset every 32768 count and return to -32768 count. Any solution to make the encoder continuous counting ? Appreciate your advise.

@Sudeshna Bhattacharya
Hi Sudeshna - I am using an Arduino Mega 2560 and have included Arduino.h, which includes wiring_constants.h.
My Arduino needs to interface with more than one SPI sensor device. These will have common MISO, MOSI, and SCK signals, but different chip select signals so that they can each be selected in turn. I think that this is normal.
One of the devices has a different SPI Mode to the others. I was assuming that I could change this Mode selection as I select each device in turn.
Justin

can someone help my use this device drivers to develop sfunction for sim900

@Justin Mellor
The error for SPI System Object blocks show that BitOrder is not defined anywhere. Assuming that you are using either Due or MKR1000, BitOrder is declared in wiring_constants.h as:

enum BitOrder {
LSBFIRST = 0,
MSBFIRST = 1
};

You can try including "Arduino.h" (from sam for Due and samd for MKR1000) which includes wiring_constants.h.

I also want to understand your use case of having different SPI modes for different slaves. Can you elaborate the same?

Does anyone know of an SPI driver based on a System Object?
The SPI blocks that come with the Arduino Support Package work OK, but don't allow you to use two SPI devices with different Modes and Clock Frequencies.

Saket Adhau

Hello Giampiero Sir,
Thanks for your kind help. Can you please tell me one more thing please.
The encoder function works like butter but when i increase the speed of my motor, the encoder graph goes downwards and the simulation stops.

Hi Qais - I guess you have seen the Encoder Device Driver that Giampiero has provided. This outputs position, so the value can easily be converted into a rate using something like the Discrete Difference block, that just subtracts a previous frame value from the present value, and then dividing by the time step value... or by using the Continuous Derivative block.
Justin

Qais if you divide the output of the block by time it should do what you need.

Thanks for sharing this !! I have a question, if i have a 600 ppr encoder and i want to use this block function to measure velocity, how do i do that if you would know??
Thanks in advance :D

Hi Giampiero - the Arduino Device Driver block guidance that is here and in the Mathworks documentation is excellent - thank you! I have successfully created DIO drivers for my Arduino. However I cannot work out how to generate drivers that will communicate with sensors via the SPI protocol.
I have added #include <SPI.h> to the top of the .cpp file and added the following at the beginning of the .cpp _setup function:
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));
The SPI.beginTransaction has been added to the beginning of the _step function in the .cpp file as well.

The first error I encounter is as follows:
C:/AlphaLoop/APMdrivers/include/SPI.h:49:31: error: 'BitOrder' has not been declared
SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {

I have MATLAB code that is correctly interfacing with the sensors using the MATLAB HW Support Package, and have also successfully used the SPI WriteRead block to communicate with them. Unfortunately, the provided SPI block will not allow me to communicate with multiple SPI devices that use different SPI modes. This is why I need to create a System Object based Device Driver.
If you could give me some guidance as to where to put these SPI configuration commands, that would be great! Alternatively, is there is an example you could point me to. Hopefully, in the future, the device driver examples could include SPI and I2C driver blocks.
Thanks in advance for your help - I hope to get this project flying in 2018! - Justin

and it worked perfectly for standard I/O System Object blocks. However I have tried to use this approach to sensor read data using SPI

Hi Saket, i thought i fixed that problem, anyhow, the solution is simple: move the "int k=0" part out of the loop, so that line looks like this:

int k;
for (k=0;k<del;k++) {

Saket Adhau

Hello Giampiero Campa,
I was working on arduino DUE controllerd motor and encoder setup for which i need RPM measurement and also the s_function is not working on adruino due.
The error is something like

"../sfcn_encoder_wrapper.c:48:3: error: 'for' loop initial declarations are only allowed in C99 mode
for (int k=0;k"

Can you please help ?

dgmcik

not clear with lots of bugs

@Morteza and @Mario
To include libraries in your device driver blocks,
1) Include the header file in your source file (C/C++). In this case, add #include <wiringpi.h>
2) If your library has a linker that needs to be used during code compilation, use the 'buildInfo.addLinkFlags('<name of the linker>') under the 'updateBuildInfo' function in your system object. In this case, the linker for the WiringPi library is '-lwiringPi'.

You can refer to the documentation help provided in the Simulink support package for Raspberry Pi to create a device driver block https://www.mathworks.com/help/supportpkg/raspberrypi/device-driver-blocks.html

Hi,i have same question like Mario Frischmann.
Anyone can help?

How can i add libraries which are stored on the raspberry Pi 3 like wiringPi.h?
#include </home/pi/wiringPi/wiringPi/wiringPi.h> does not work.
The path is correct.

Bruno Marin

any idea to get the temperature readings from DS18B20 in ARDUINO UNO using any of these files?
Thanks

I want to use the S function builder to get analogRead from arduino uno, however in my code generation report shown an error : cannot open source file "Arduino.h" for file: C:\MATLAB\SupportPackages\R2016a\toolbox\target\supportpackages\arduinotarget\scheduler\include\arduinoAVRScheduler.h
how can I add the source file "Arduino.h" in my model?

ali soltani

very very very good

Perry

Very nice guide that explains concepts well.....

I was trying to follow the Matlab System Object method for Raspberry Pi driver development. However, the example (digitalio_raspi_test.slx) failed to build with the error:
### Build procedure for model: 'digitalio_raspi_test' aborted due to an error.
Function TAR tried to add two files as "digitalio_raspi.h".

I am using 2016b and Raspberry Pi support package was downloaded about 1 month ago. I am interested in the System Object method since I will need to link several libraries.

Really helpful

Hi, anyone knows or have done a driver for the L3G gyroscope sensors from pololu?

Hi, anyone worked on encoder to read the speed in Raspberry Pi 3 using simulink blocks or SFunction?
Thanks.

@Murat Belge,
Works perfect! Thanks a lot :)

Murat Belge

@Mohamed: You can use a MATLAB function block to read temperature from a DS18B20. The MATLAB code is provided below. Note that it takes about 750ms for a single temperature conversion.

function temperature = readDS18B20()
%#codegen

persistent sensorPath;

if isempty(sensorPath)
path = '/sys/bus/w1/devices/28-031561e430ff';
fileSeperator = '/';
sensorPath = [path,fileSeperator,'w1_slave'];
end

% Open file, read, and close it
fid = fopen(sensorPath);
w1_slave = fread(fid,1024);
fclose(fid);

% Convert to text
w1_slave = char(w1_slave');

% Find raw temperature data in 1/1000th of a degree Celcius
stringToFind = 't=';
stringToFindLength = length(stringToFind);
temperatureIndices = strfind(w1_slave,stringToFind)+stringToFindLength;
temperatureIndexStart = temperatureIndices(end);
temperatureIndexEnd = temperatureIndexStart+5;
temperatureString = char(w1_slave(temperatureIndexStart:temperatureIndexEnd));

% Convert to Celcius
temperature = real(str2double(temperatureString))/1000;

any idea to get the temperature readings from DS18B20 in Raspberry Pi using any of these files?
Thanks

I can't download the file!

cjx1842

不错不错

zheng Hu

Why can I not downland?

Dzung

Hi, could anyone tell me how to develop my own hardware support packages? Thanks in advanced.

Hazem, maybe you forgot to build the S-Function, by clicking "Build" on the S-Function Builder ?

hazem saaad

I have a serious problem and I need help.When I run the simulink file,I get the following message "
Error in S-function 'encoder_slsp/Encoder': S-Function 'sfcn_encoder' does not exist".

olivier

Hello,

Thanks for the great job Giampiero! I've tried the samples on Uno with 2015a and it works perfectly.
Now I try to write a CAN driver for the CAN-BUS shield.
First, I'd like to make an init function to set the CAN speed with a Matlab system block. This block has no I/Os, but when I try to update the model, I get:
MATLAB System block 'can_test/MATLAB System' error occurred when invoking 'isOutputFixedSizeImpl' method of 'CANSetup'. The error was thrown from '
'C:\Program Files\MATLAB\R2015aSP1\toolbox\simulink\simulink\+SLStudio\ToolBars.p' at line 1175'.

Reported by CANSetup: Incorrect number of outputs for the isOutputFixedSize method; 1 were requested, but the method returns 0, as specified by the getNumOutputs method.

I don't understand, since I've put num = 0 for both getNumOutputsImpl and getNumInputsImpl functions.

Then I need to include the CAN and SPI libraries. How can I do that with the system block method?

Thank you.

Ok, great ! Thanks !
I'm going to try too then, at some point (maybe in a few weeks or so) just out of curiosity...

Thanks again.
G.

Marcell

Thanks for you response.

I tried it before I wrote the comment and it worked normally without the need to rebuild the S-Function every time the sample time or the parameters are changed.

However, just to make sure I checked it again right now but it works for me.

Hi Marcell, thanks for the feedback.

You can certainly place the S-Function Builder block in a subsystem and write a mask for it, and you can use it to pass "normal" parameters (the ones defined as such in the data properties pane). This will work as these parameters are read from the mask and passed down to the S-Function before each execution.

However, I'm pretty sure that both the Sample Time and the initial conditions, which are defined in the initialization pane, are hardcoded in the executable (and the TLC file) every time you press the "Build" button in the S-Function builder.

Therefore, if you encapsulate the S-Function Builder block in a subsystem, build a mask for it, and change the sample time in this mask, I am afraid that the change will NOT get propagated down until you rebuild the S-function (so you - or the user - have to look under the mask, double click the S-Function Builder block, and click on "Build".

I think that doing so is misleading for the user, who might think that the sample time gets propagated down without any problem every time it gets changed from the upper level mask.

Now, that being said, I haven't explicitly checked this in the last 2 or 3 years at least, so, just in case I'm wrong (which I don't think it's the case, but still), I invite you to try and double check for yourself, (and let me know).

Giampiero

Marcell

Wonderful package thank you it helped me a lot with my work.

I just wanted to point out, that one can actually use the S-function approach with user defined sample times from the mask. One just have to place the S-function block into a subsystem and define a sample time parameter in the subsystem’s mask. Then specify a parameter with the value of the name of the sample time parameter of the subsystem’s mask. Then write the parameter’s name in the sample time value field inside the initialization tab of the S-function.

This method also eliminates the need to right click the S-function in order to change the mask parameters.

lays25

I also tried using the method suggested earlier by Phil and MathWorks Classroom Resources Team (referencing to page 20 of the Guide) - adding "extern "C"" and renaming the wrapper file to .cpp but then I get another problem. The model is built and downloaded to my Arduino and... nothing happens. There is no communication, TX/RX diodes are off and I get the following error: Unable to connect to the 'Arduino Due' target for 'encoder_slsp'.

arman sani

The detail of the walk-through is exquisite. Thank you very very much.

Hi,
To start, excellent package, great info, lots of detail A+++.
I'm using R2013a, with Windows XP, Microsoft SDK 7.1, Arduino MEGA 2560.
I have been working on a LCD block using an S-function builder block. I spent a long time trying to get it to work but struggling due to an error. The start of the error is shown below. After trawling the internet searching and finding very little I tried changing the LiquidCrystal.h and .cpp files I had in my working directory to the ones from the MATLAB support package folder. This fixed the problem, briefly. On shut down, my computer did a Windows update. The day after, I had a go at adding more to the block, on opening the model file I got a load of warning messages about File I/O from "arduino.h" (I don't have the message to hand). Now my LCD block won't build and I get a java error to do with getting ports. So, started again, and it worked, added some inports to the S-function, and crash. I now get intermittent java errors when trying to build, or I get the realtime_make_rtw hook error shown below. Again.

This is extremely frustrating and I am running out of ideas. Any info/ help would be fantastic. Thanks in advance.

Rob

The call to realtime_make_rtw_hook, during the after_make hook generated the following error:
The build failed with the following message: "C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/tools/avr/bin/avr-gcc" -I"C:/ArduinoStuff/arduinoMEGA2560_LCD_02_rtt" -I"C:/ArduinoStuff" -I"C:/Program Files/MATLAB/R2013a/extern/include" -I"C:/Program Files/MATLAB/R2013a/simulink/include" -I"C:/Program Files/MATLAB/R2013a/rtw/c/src" -I"C:/Program Files/MATLAB/R2013a/rtw/c/src/ext_mode/common" -I"C:/Program Files/MATLAB/R2013a/rtw/c/ert" -I"C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/arduino/cores/arduino" -I"C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/arduino/variants/mega" -I"C:/MATLAB/SupportPackages/R2013a/arduino/include" -I"C:/MATLAB/SupportPackages/R2013a/arduino-1.0/libraries/Servo" -mmcu=atmega2560 -std=gnu99 -Wall -Wstrict-prototypes -g -Os -D"MODEL=arduinoMEGA2560_LCD_02" -D"NUMST=1" -D"NCSTATES=0" -D"HAVESTDIO=" -D"ONESTEPFCN=0" -D"TERMFCN=1" -D"MAT_FILE=0" -D"MULTI_INSTANCE_CODE=0" -D"INTEGER_CODE=0" -D"MT=0" -D"CLASSIC_INTERFACE=0" -D"TID01EQ=0" -D"F_CPU=16000000" -D"_RUNONTARGETHARDWARE_BUILD_=" -D"_ROTH_MEGA2560_=" -D"_RTT_NUMSERVOS_=0" -c -x none ./arduinoMEGA2560_LCD_02.c ./arduinoMEGA2560_LCD_02_data.c ./ert_main.c ./sfcn_LCD_wrapper.cpp ./HardwareSerial.cpp ./Print.cpp ./WInterrupts.c ./WMath.cpp ./WString.cpp ./new.cpp ./wiring.c ./wiring_analog.c ./wiring_digital.c ./io_wrappers.cpp
In file included from ./ert_main.c:18:
C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/arduino/cores/arduino/Arduino.h:24:1: warning: "true" redefined
In file included from ./arduinoMEGA2560_LCD_02.h:23,
from ./ert_main.c:17:
./rtwtypes.h:158:1: warning: this is the location of the previous definition
In file included from ./ert_main.c:18:
C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/arduino/cores/arduino/Arduino.h:25:1: warning: "false" redefined
In file included from ./arduinoMEGA2560_LCD_02.h:23,
from ./ert_main.c:17:
./rtwtypes.h:154:1: warning: this is the location of the previous definition
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
In file included from ./sfcn_LCD_wrapper.cpp:40:
C:/ArduinoStuff/LiquidCrystal.cpp:6:22: error: WProgram.h: No such file or directory
In file included from ./sfcn_LCD_wrapper.cpp:39:
C:/ArduinoStuff/LiquidCrystal.h:82: error: conflicting return type specified for 'virtual void LiquidCrystal::write(uint8_t)'
C:/MATLAB/SupportPackages/R2013a/arduino-1.0/hardware/arduino/cores/arduino/Print.h:48: error: overriding 'virtual size_t Print::write(uint8_t)'
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
./io_wrappers.cpp: In function 'void Serial_read(int, int, uint8_t*, int*)':
./io_wrappers.cpp:40: warning: 'libFcnOutput' may be used uninitialized in this function
make: *** [arduinoMEGA2560_LCD_02.o] Error 1

The build process will terminate as a result.

Rusty Boyd

Hi,

I'm having a problem with the LCT method. In both the example, I have problems with the 'DNO_OP=//' directive in the instruction,
legacy_code('compile', def, '-DNO_OP=//')
In the dout example, it only generates a warning. In my code, it generates a fatal error (the two warnings make sense in context of the error):
Error using mex
/Users/BOYD/Documents/Atmel_Studio/6.2/sl_TC_varfvarduty/sl_dd_tc1/src/tc1_sfun.c:168:9:
error: expected expression
NO_OP();
^
/Users/BOYD/Documents/Atmel_Studio/6.2/sl_TC_varfvarduty/sl_dd_tc1/src/tc1_sfun.c:190:10:
warning: expression result unused [-Wunused-value]
NO_OP( *u1, *u2);
^~~
/Users/BOYD/Documents/Atmel_Studio/6.2/sl_TC_varfvarduty/sl_dd_tc1/src/tc1_sfun.c:190:15:
warning: expression result unused [-Wunused-value]
NO_OP( *u1, *u2);
^~~
Error in legacycode.LCT/compile (line 375)
Error in legacycode.LCT.legacyCodeImpl (line 84)
Error in legacy_code (line 87)
[varargout{1:nargout}] = legacycode.LCT.legacyCodeImpl(action, varargin{1:end});

In the dout example, it generates only 3 warnings.

I've tried bypassing LCT and using mex directly with the exact same results. I've tried both 2015a and 2015b - no diff. I'm using OS X 10.10.5 (14F27) and Xcode Version 6.4 (6E35b).

I hope someone can help.
-Rusty

A bit complicated for a novice programmer but the detail the go through is amazing. Thanks.

Barza Nisar

Excellent tutorial, thank you!

Suytry KY

Hi everyone,
I use the s-function encoder block in the model to read encoder pulses. If i use only one encoder, it is fine. But the simulink stop working when i use 2 or 3 encoder to read from my robot motors. Can anyone help me to solve this problem because i am supposed to use simulink with arduino to read encoder for my thesis project. NOTE: I do as external mode for real-time test.
Thanks in advance!

Hi,

I also tried this guide with my raspberrypi.

Is there also a librarie for the raspberry?
# ifndef MATLAB_MEX_FILE
# include <Arduino.h>
# endif

Does this instruction works with a raspberry?

Giampiero, very very helpful information, thank you. Question for Nancy can you publish your SD code? i would find this very useful.
Thanks

huan xia

so great!

I bumped into the following error message and found a solution:

The call to realtime_make_rtw_hook, during the after_make hook generated the following error:
The build failed with the following message: make: *** No rule to make target `../../../../../../../../../../../../MATLAB/SupportPackages/R2014a/arduino-1.0.5/hardware/arduino/cores/arduino/HardwareSerial.h', needed by `HardwareSerial.o'. Stop.

The issue was that I was building the model from a directory where the path was too long. i.e. C:/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvxyz/

When I built the model in directory with a shorter path i.e. C:/Documents, I no longer experienced this error.

Sina

Also, I have done what you mentioned. But the main problem is to do with the C++ and C differences I suppose. I will email you the error description I get when building the simulink model on Arduino.
Thanks.
Sina

Sina

Thanks a lot Giampiero,
That helped a lot. How do I go about declaring global variables/ functions/ libraries? I know in the libraries pane there are 3 sections,
1. Library / Object / Source file
2. Includes
3. External Function Declarations

Can you make an example?
Alternatively, would you mind taking a quick look at my simple model? I can email it to you.

Cheers,
Sina

Hi Sina,
well, you can't just copy and paste all your code in the output pane, remember that the initialization and global variable and function definitions must go into the Library->Includes pane, the initialization code (that is the part contained in the "setup" function below) must go into the Discrete Update pane, and only the part contained into the "loop" function, which needs to be executed at every time step, must go into the Output pane.

I'd suggest you have another look at the guide, and start building up things gradually from a simple example that works.

Giampiero

Sina

Hi Giampiero and Everyone,
I have a question, I used this guide and built a block to be able to read some input numbers from simulink and pass the numbers to an arduino code so that using motor driver and encoder library it can run the motor. I have written this as my output:

/* wait until after initialization is done*/
if (xD[0]==1){
/*don't do anything for the Mex-file generation */

#ifndef MATLAB_MEX_FILE
/* MYCODE which is normally run on arduino and uses two libraries: Encoder and DualVNH5019MotorShield */

#include <Encoder.h>
#include <DualVNH5019MotorShield.h>

unsigned int DEBUG = 1;
unsigned int ms_delay = 200;

// setup pin variables
const int encoderChanA = 2; // pin2 for interrupt0 on timer2
const int encoderChanB = 3; // pin3 for interrupt1 on timer2
Encoder motorEncoder(encoderChanA,encoderChanB);
// setup pins for motor control and current sense
unsigned char INA1 = 8; // sets motor direction
unsigned char INB1 = 10; // sets motor direction
unsigned char EN1DIAGA = 5; // sets motor speed, pin5 for PWM on timer0 (to avoid problems with interrupts on timer2)
unsigned char CS1 = A1;
DualVNH5019MotorShield mdriver(INA1,INB1,EN1DIAGA,CS1,INA1,INB1,EN1DIAGA,CS1); // repeat arguments to simulate second driver (part of API but not actually used)
// setup global variables
float currentMotorSpeed = 0;
long currentEncoderPosition = 0;
int currentMotorCurrent = 0;
float desiredSpeed = 0;
int u = 0; // placeholder input variable 0-9
// Function declaration

void setup()
{
// setup code here
pinMode(encoderChanA, INPUT);
pinMode(encoderChanB, INPUT);
digitalWrite(encoderChanA, HIGH);
digitalWrite(encoderChanB, HIGH);
mdriver.init();
}

void loop()
{

// 2) read encoder position, and motor current
currentEncoderPosition = motorEncoder.read();
currentMotorCurrent = mdriver.getM1CurrentMilliamps();

// 3) Set speed for motor 1, speed is a number betwenn -400 and 400
mdriver.setM1Speed(in[0]);
}
#endif
}

This code uses functions that are declared in the included libraries. and I did include those in the supported libraries pane and added the libraries to current matlab folder.
It builds the block but the model cannot be built on my Arduino Uno. (there are some errors)
Would you please elaborate?
Thanks.
Sina

Carlos

Many thanks for your tutorial, now Simulink has become even more powerful to me. Is there a way to remove the tedious pasting the .cpp and .h at the current MATLAB directory for successful compilation?

Nebojsa

Does someone make a simulink block to use DS1302 real time clock?
I try it, but I did not succeed.
Please, help with some sugestions.

Simulink with arduino : data acquisition
--------------------------------------------
Hello all ,
i'm working on data acquisition from a sensor attached to the arduino : MPU6050 using a model in simulink , i have installed the hardware support in simulink but i don't know how to start building the model , the model must read the data from arduino by deploying it into the arduino
my connection arduino <=> MPU6050 is :

Arduino MPU 6050
3.3V VCC
GND GND
A5 SCL
A4 SDA
DIGITAL 2 INT
GND AD0

any help will be appreciated
thanks

Nancy

Solved! Thanks

Nancy

when I tried to deploy a simulink model that contains fuzzy logic controller block it didn't work :s . Is there a way to deploy it to Arduino Mega ?

amir

Great! after 1 month working on an encoder with 8400cpr to read the data by arduino mega2560 and NO answer, today I did it just using by this work.

Simon

Hi,

I built an own arduino Stepper library for arduino uno and now i want to embed it into simulink.
The problem i have is that i use:

main()
{
}

instead of the common:

setup(){}
loop(){}

structure, because the init() function in the common structure interferes my library functions.

I tried to use the s-function builder instruction with my library and i had the same issues as i had when writing functions of my library into the common(setup(),loop()) structure.

My question:

Is there a way to use the main() structure instead of the void(),loop() structure using the s-function builder {with arduino uno and the simulink support package of matlab}?

What i tried so far:
- deleting the init() function call in the main function of the s-function builder block created modelname_rtt folder.
- changing the init(){as a part of the wiring.c} so that it executes the setup for my library.

By the way thanks for your great tutorials.

Best Regards,
Simon

For Daniel and other interested, Nancy was able to solve the issue by doing 3 things:

1) Copying the utilities folder to the current directory In addition to copying its content in the same folder.

2) Including the SD.h in addition to the SD.cpp

3) Transfering the whole directory to a file path that has no spaces.

Note that #3 is always necessary to make things work due to the use of GCC. In this case i think #1 (and perhaps also #2) made the trick.

Minho,
i don't know how to make it work with external mode and i am sure is not easily doable with this method. It might be not even feasible. I'll let you know more if i find anything.

Also, if i don't know what error it is that you are finding, it's hard for me to have a clue :)

Minho

I have question. If i want sfcn_encoder bolck use external mode. How can I do?
I do wrapper.c -> wrapper.cpp and add extern "C".
But It has error.

I am having the same issue as Nancy.

Nancy

I'm trying to use the SD card library , I get this error when I build the model;

The call to realtime_make_rtw_hook, during the after_make hook generated the following error:
The build failed with the following message: make: *** No rule to make target `../../../../../../../../../../../../MATLAB/SupportPackages/R2014a/arduino-1.0.5/hardware/arduino/cores/arduino/HardwareSerial.h', needed by `HardwareSerial.o'. Stop.

Any help will be appreciated.

-Nancy

zhubo

1

MAMADOU

Hello i started with arduino (uno) and matlab by modeling a blinking model. But i have a problem to run the model with my arduino uno card. I go to the tools menu for 1st time for to Prepare to Run the model and at the 2nd time, i don't see the option : Run. That is my problem. Is someone can help me. Thanks

German

Nice work, very helpful

JimC

This is a great help to get started. I've been able to tweak the encoder block for speeds.
I can't seem to create a driver block that uses the serial comms commands though. I tried including the HardwareSerial.h and .cpp files in the library pane and ran renc2cpp.
Any trick needed?

EDUARDO

phil

Has anybody been able to make an interrupt block?

uavc

In case anyone wanted to compare the Output Driver S-Function Block to Arduino code, here is the arduino code:

#include <Arduino.h>

int xD[0];
int pin[] = {12};
int in[0];

void setup()
{
//xD[0]=0;
if (xD[0]!=1) {

/* don't do anything for MEX-file generation */
pinMode(pin[0],OUTPUT);

/* initialization done */
xD[0]=1;
}
}

void loop()
{
/* wait until after initialization is done */
if (xD[0]==1) {

/* don't do anything for mex file generation */
digitalWrite(pin[0],in[0]);
}
}

Mehmet

Hi,

I wonder,how overruns on Arduino Hardware affect software . Because all example drivers give ovverruns error without input and output drivers.

Regards
Mehmet

Neil

Hello thank you for the reply. I have finally got it working with much success. I'm still not sure where the "inlined" error came from but now it's gone.

I have a question for you. I'm trying to use global variables throughout the simulink model. It works if I call the variable within the same s-function as your guide said. However, if I call that variable in another S-function it gives me an error " error: <variable> undeclared (first use in this function)" pertaining to the wrapper file. I find this strange since all my calls to functions within the "#includes" headers work.

For example, my includes section looks as shown below:

# ifndef MATLAB_MEX_FILE
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int uart0_filestream = -1;

# endif

I can call all functions within the first 3 headers, however, if I call uart0_filestream in another block I get the error.

Neil

Neil

I have not been able to get this to work at all. I'm using MATLAB 2013a Student version. I generate C code using the steps provided. However, when I try to download it to the Arduino, it gives me an error that the function is not in-lined and therefore cannot be downloaded to the target. It tells me to go into the configurations->Simulink Coder and turn in-lining off but since I'm using the student version I don't see this option. Has anyone gotten this error before? I see no where in the documentation

phil

phil

has anybody been able to get the Arduino Ethernet library to work>? i keep getting errors which seems to be related to the IP adress class

C:/MATLAB/Targets/R2012b/arduino-1.0/hardware/arduino/cores/arduino/IPAddress.h:33: undefined reference to `vtable for IPAddress'

the code in this file:
class IPAddress : public Printable {
private:
uint8_t _address[4]; // IPv4 address
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address() { return _address; };

i havent even called any functions. at this point i am simply trying to include the ethernet library.

IMPORTANT UPDATE: For MATLAB 2013b you will need to apply a fix for the S-Function builder (otherwise an incorrect argument list will be generated for a block that has no inputs).

Go to the following page: http://www.mathworks.com/support/bugreports/1006532
scroll down to the bottom, and follow the instructions therein (it basically
comes down to saving the zip file, opening winzip as administrator, and
unzipping the file in the MATLAB folder (e.g. C:\Program Files\MATLAB\2013b).

Also note that another issue in MATLAB 2013b causes high memory usage on the
Arduino side, and thus prevents the upload of models that have many blocks
and/or high memory requirements. This might sometimes be a problem for boards
with smaller memory footprint like the Uno or Nano.

uavc

uavc

found the problem. the libraries I had to include in the simulink s-function builder was

# ifndef MATLAB_MEX_FILE
# include <Arduino.h>
# endif

in that order. I accidentally put the second line first as I thought these were just regular includes, without recognizing that the include was running an if loop (ifndef.... end if) to check:

#ifndef

The #ifndef operator checks whether something has not been defined using the #define keyword. It must be followed by#endif.

Problem solved. XD

uavc

SITUATION:

I'm trying to build the output block according to the tutorial. I'm sure this is a basic question but I couldn't quite build the S-function.

EXACT ERROR:

sfcn_exout_slsp_wrapper.c
c:\docs\avr/io.h(330) : fatal error C1021: invalid preprocessor command 'warning'

C:\PROGRA~1\MATLAB\R2013A\BIN\MEX.PL: Error: Compile of 'sfcn_exout_slsp_wrapper.c' failed.

EXPLANATION IN DETAIL:

I had earlier problems that the s-function builder wasn't compiling because it couldn't find Arduino.h, inttypes.h avr/io.h, avr/pgmspace.h, avr/sfr_defs

Arduino.h is the only .h file that is called directly from the s-function builder library so I guess the other files are being called by Arduino.h etc. I included the entire path of the Arduino library on the stock c:\program files(x86) directory but it didn't compile still. Hence, I just copied the whole folder into my working directory, still wouldn't work. What made it work was that I had to copy every single .h file (mentioned above) into the working directory (the answer to MATLAB command "pwd") before it would compile and then it led to this error above. I think it's an include error, so how do I ask the s-function builder to look everywhere within my working directory (which is especially important for the avr/xxx.h files.

any idea how to solve it? thanks!

Great introduction to learn how to build custom driver blocks. Congrats!

Joshua Hurst

Hi Christian,

If you were looking specifically for I2C, MPU6050, or other I2C devices/hardware I posted a simple C-based I2C solution using WirnigPiI2C and you can find this here:
http://www.mathworks.com/matlabcentral/fileexchange/43383-raspberry-pi-mpu6050-sfunction-with-i2c-communication-using-wiringpii2c

Let me know if this helps you!

Josh

Dan

amzaing one that works. Thanks.

Christian

Hi,
I have the same problem as Glen but with Arduino Mega and Support Package for Arduino. When i run the Target Hardware it does not include the wrapper .cpp in the _rtt folder, are there any solutions already?

thank you
Christian

Christian

Glen,
send me the files with the exact procedure that you are following and the error you are getting, i'll see if i can do anything.

Glen

Hi,

I have tried a number of different things to try and get the wrapper.cpp file included into the source_files listed in the .mk (make) file, rather than it being skipped. This has included editing the rtwmakecfg and trying to find the toolchain that is used to compile the .mk file. Editing the rtwmakecfg was unsuccessful. I did edit a Linux tool chain located in the "coder" directory. But I don't think it is the one that is used. The toolchain that is listed in the .mk file I cannot find - gmake, LinuxRemoteBuild.

Glen

Hi,

I have been trying again to get the MPU6050/HMC5883L model to build on the RPi. In the make file (.mk) which is included in the (_rtt) folder, when I rename the _wrapper.cpp file it is listed as a "SKIPPED_FILE". When I do not rename the wrapper.c is included in the "SOURCE_FILES". I have tried to get it included by editing the SFB.mat file but still no luck.

Joshua Hurst

Hi Glen,

I have a student working on the mpu6050 code for RasPi right now - getting it work in C and Python first. Then I will be porting it to Simulink most likely next week.

Feel free to send me an email directly and I can try to look at your files when I start start porting my students code: hurstj2@rpi.edu

In general for the Rpi you have to make sure the c-code compiles and on its own. If you look at the RPi examples I posted you have to make sure the #includes reference the local directory structure on the RPi - not your box. Just look at the Quadrature Encoder example for the RPi and you will see I had use: #include </home/pi/wiringPi/wiringPi/wiringPiI2C.h>. Which is where the files are on the RPi, not my actual computer. And don't forget to include the actual C files as well:
#include </home/pi/wiringPi/wiringPi/wiringPi.h>
#include </home/pi/wiringPi/wiringPi/wiringPi.c>

Let me know if this helps!

Josh

Glen

Hi Giampiero,

Many thanks for your reply. I should explain more. I am trying to incorporate the libraries for the MPU6050 and HMC5883L. The code I have previously compiled on the PI. I used the Arduino MPU6050 S-Function Builder Example from Joshua Hurst as a Starting point and replaced the Arduino Libraries with the Libraries I have for the PI - including the I2Cdev. The S-function builds successfully. I then change the _wrapper from .c to .cpp and apply the extern "C" changes. However, when I run on target hardware - using the MATLAB Pi Support Package - it does not include the wrapper .cpp or any .cpp file in the folder (_rtt) it downloads to the PI to compile and run. If I leave the wrapper.c unchanged it does get incorporated into the _rtt folder but then I have unreferenced .cpp files not included.

I can send you my work so far if it helps.

Many thanks for your support.

Best Wishes
Glen

Hi Glen, there are several RasPi drivers, i believe with external libraries too, linked in the Acknowledgement section of this page.

I (Giampiero) would suggest trying them first to see if you can make them work, if so, start from them to see if you can build your driver. That being said i'll investigate further this case to see if anyone has any idea.

Glen

Hi Giampiero,

I am trying build a model incorporating an S-Function Builder for my RaspPi. Because it includes C++ files I change the wrapper file extension to .cpp and at extern "C" infront of the Outputs and Update wrapper. However, when I run the model a further file is built with the extension _rtt and it does not include my wrapper file and other .cpp files within the file that gets downloaded to the RaspPi, hence I get undefined references.

I have tried a number of things but starting to go around in circles.

Any help would be appreciated.

Best Wishes
Glen

Mark,
you need to scroll up to see the upper part of the text. Maximizing the window might also help a little.

Mark

Within the "afmotor_slsp" model, there is a block containing instructions titled "Double Click for Explanations". When I double-click, the instructions start with step 3...what are the first two steps???

Hi,
Thank you for your step by step explanation. I have tried to create my own servo and I am getting the following error when I have changed the name of the wrapper file generated to .cpp from .c

The call to realtime_make_rtw_hook, during the after_make hook generated the following error:
The specified file "servornd_wrapper.c" does not exist on the IDE and MATLAB paths.

Could you help me resolve this error.
Thanks in advance.

Perfect!
helped me a lot

thank you for that tutorial

I'm glad that's working, Nathan.
Thanks Phil, that's great!

@Classroom Resources,
That was the trick. I can now use any library I wish in the S-Function builder. Thank you very much

@phil,
I added this line to my Library/Object/Source files pane in the s-function builder. It seems to take care of the path issue.

INC_PATH C:\arduino-1.0.3\libraries\Time

Nathan, if you include a .cpp file then you should rename the generated wrapper function from .c to .cpp, and also open it and write: ' extern "C" ' before the two function calls.

Please have a look at page 20 of the guide, which explains how to do this, and let me know if it works.

phil

@ Nathan...
did you put the included files in the current matlab folder?

Hello,
I tried to follow your example and it worked great for interfaces that are in Arduino.h such as digital and analog IO. I ran into problems when trying to include other Arduino Libraries.

I noticed that you had included "AFMotor.cpp" and "AFMotor.h" in your examples, which I guess is similar what I am attempting with "DS1307RTC.h" and "DS1307RTC.cpp" which are libraries for keeping time.

I can build the sfunction with the sfunction builder when it is structured like you have it in your examples. When I go to build the applicaiton, however, I run into an issue that seems to be related to cpp code when the compiler is expecting c code. I am using the Arduino integration package found here http://www.mathworks.com/matlabcentral/fileexchange/30277-embedded-coder-support-package-for-arduino

The compiler message I get when it attempts to build the header file with a class definition is this:

C:/ARDUIN~1.3/hardware/tools/avr/bin//avr-gcc -c -mmcu=atmega2560 -I. -DF_CPU=16000000 -Os -Wall -Wstrict-prototypes -std=gnu99 -I. -I.. -IC:/PROGRA~1/MATLAB/R2011a/rtw/c/ert -IC:/PROGRA~1/MATLAB/R2011a/extern/include -IC:/PROGRA~1/MATLAB/R2011a/simulink/include -IC:/PROGRA~1/MATLAB/R2011a/rtw/c/src -IC:/PROGRA~1/MATLAB/R2011a/rtw/c/src/ext_mode/common -Ic:/OU_SYSTEMS_ENG/GH/gh-dev/Simulink_Models/Drivers/GH_TopLevel_Test_arduino -Ic:/OU_SYSTEMS_ENG/GH/gh-dev/Simulink_Models/Drivers -Ic:/OU_SYSTEMS_ENG/GH/gh-dev/Simulink_Models -Ic:/OU_SYSTEMS_ENG/GH/gh-dev/Simulink_Models/Custom_Includes -Ic:/OU_SYSTEMS_ENG/GH/gh-dev/Simulink_Models/ArduinoML/blocks -IC:/arduino-1.0.3/hardware/arduino/variants/mega2560 -IC:/arduino-1.0.3/hardware/arduino/cores/arduino -IC:/arduino-1.0.3/libraries/Time -IC:/arduino-1.0.3/libraries/DS1307RTC -Ireferenced_model_includes -I../slprj/arduino/_sharedutils -IC:/ARDUIN~1.3/hardware/arduino/cores/arduino ../sfun_systime_get_wrapper.c -o sfun_systime_get_wrapper.o
In file included from ../sfun_systime_get_wrapper.c:39:
C:/arduino-1.0.3/libraries/DS1307RTC/DS1307RTC.h:12: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'DS1307RTC'
../sfun_systime_get_wrapper.c:40: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'sysTime'

Please let me know if you have any thoughts. I am wondering if this is still an issue with the newer Arduino support in later versions of ML/Simulink.

Joshua Hurst

Phil, i think the variable "lcd" needs to be defined as a global. Try to define it in the libraries pane, after all the includes, see page 16 of the guide.

phil

./io_wrappers.cpp: In function 'void Serial_read(int, int, uint8_t*, int*)':
./io_wrappers.cpp:40: warning: 'libFcnOutput' may be used uninitialized in this function
cc1plus.exe: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++
cc1plus.exe: warning: command line option "-std=gnu99" is valid for C/ObjC but not for C++
./DDvers1_wrapper.cpp: In function 'void DDvers1_Outputs_wrapper(const boolean_T*, const real_T*, const real_T*, int_T)':
./DDvers1_wrapper.cpp:73: error: 'lcd' was not declared in this scope
./DDvers1_wrapper.cpp:77: error: 'lcd' was not declared in this scope
In file included from ./ert_main.c:18:
C:/MATLAB/Targets/R2012b/arduino-1.0/hardware/arduino/cores/arduino/Arduino.h:24:1: warning: "true" redefined
In file included from ./DisplayDriverv1.h:23,
from ./ert_main.c:17:
./rtwtypes.h:158:1: warning: this is the location of the previous definition
In file included from ./ert_main.c:18:
C:/MATLAB/Targets/R2012b/arduino-1.0/hardware/arduino/cores/arduino/Arduino.h:25:1: warning: "false" redefined
In file included from ./DisplayDriverv1.h:23,
from ./ert_main.c:17:
./rtwtypes.h:154:1: warning: this is the location of the previous definition

Roni Peer

Great walk through for newbies!

phil

just what i was looking for!
it would be great if you guys could share your driver blocks!

i am currently writing one for an LCD display...quite a challenge.

NOTE: If you are working with external libraries and you get an “undefined reference” error that means that your code references objects defined elsewhere (in other files) and, at linking time, the linker cannot find where they are.

In this case you need to make sure that all the .c and .cpp files of the library you are using are in the current MATLAB folder and that they are all included in the "Includes" field of the "Libraries" pane of the S-Function Builder (include the .c and .cpp files directly not the .h files).

Also, make sure that you read the last section (i.e. the last 2 pages) of the driver guide, entitled: "Working with external libraries".

Arkadi

Great tutorial, Thank you.

This is exactly what I was searching for. A Step-by-Step guide to develop new and custom Simulink blocks for Arduino targets.

Thank you !

This is a good introduction to making all the device code I need inside blocks so that I can just drag and drop blocks and get all the processor-specific code. Say I need to add a new encoder. Copy and paste the block and change the pin numbers. Done. Thanks, Giampiero!

Updates

1.6.0.1

Updated license

1.6.0.0

Minor modification to documentation (e.g. updated copyrights).

1.6.0.0

Added System Object and Legacy Code Tool approach, examples, and documentation.

1.6.0.0

Documented masking S-Function Builder blocks and the MATLAB Function approach.

Also removed the motor shields -related files since updated versions can be found in the "motor shields" file exchange entry.

1.5.0.0

Included drivers for AF Motor Shield V2, and Embedded MATLAB-based examples.

1.4.0.0

Fixed small typos, updated copyright, and added troubleshooting section to the guide.

1.2.0.0

Fixed a few typos and added a troubleshoot page at the end of the guide.

1.1.0.0

The PDF document was slightly refined.

MATLAB Release Compatibility
Created with R2012b
Compatible with any release
Platform Compatibility
Windows macOS Linux

Discover Live Editor

Create scripts with code, output, and formatted text in a single executable document.


Learn About Live Editor