generating c code from a simulink model - miami … · web viewgenerating c code from a simulink...

57
Generating C Code from a Simulink Model Generating C Code from a Simulink Model...................1 Introduction.............................................1 Setting up a Model for C Code Generation..................3 Signal Properties........................................4 Configuration Parameters.................................9 TLC Selection...........................................11 Hardware Implementation Pane............................13 Generating Code.........................................15 The Code Generation Process.............................18 File and Directory Naming Conventions...................21 Integrating Generated C Code with Existing C Code........21 About the Shipping Hands-free Kit Code...................23 Preparing the Legacy Code for Integration with Generated Code..................................................... 24 Creating an MPLAB Project................................26 Preventing User Source Code from Being Deleted...........30 Changes to MAIN.C........................................32 Necessary Project Modifications..........................36 It Built! Are We Done?...................................42 Is There An Automated Way To Locate Source File Dependencies?............................................43 Everything About A Simulink Model You Never Wanted To Know ......................................................... 44 Code Customizations......................................46 Using Structures........................................47 Using #defines..........................................51 Next Steps............................................... 53 Introduction In this chapter we are going to start with the Simulink model we left off with from the previous chapter and generate C code for the Echo Canceller subsystem. We will

Upload: vuthien

Post on 08-Jun-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Generating C Code from a Simulink Model

Generating C Code from a Simulink Model........................................................................1Introduction......................................................................................................................1

Setting up a Model for C Code Generation.........................................................................3Signal Properties..............................................................................................................4Configuration Parameters................................................................................................9TLC Selection................................................................................................................11Hardware Implementation Pane....................................................................................13Generating Code............................................................................................................15The Code Generation Process........................................................................................18File and Directory Naming Conventions.......................................................................21

Integrating Generated C Code with Existing C Code........................................................21About the Shipping Hands-free Kit Code..........................................................................23Preparing the Legacy Code for Integration with Generated Code....................................24Creating an MPLAB Project..............................................................................................26Preventing User Source Code from Being Deleted...........................................................30Changes to MAIN.C..........................................................................................................32Necessary Project Modifications.......................................................................................36It Built! Are We Done?......................................................................................................42Is There An Automated Way To Locate Source File Dependencies?...............................43Everything About A Simulink Model You Never Wanted To Know...............................44Code Customizations.........................................................................................................46

Using Structures.............................................................................................................47Using #defines...............................................................................................................51

Next Steps..........................................................................................................................53

Introduction

In this chapter we are going to start with the Simulink model we left off with from the previous chapter and generate C code for the Echo Canceller subsystem. We will take this code and integrate it into an existing Microchip project targeting a dsPIC30F6014A processor. The assumption here is that the Simulink model has performed reasonably well in terms of its Metrics during simulation. Now we want to see if that performance translates to the real DSP.

All of the files referred to in this workflow are accessed from an HTML example selector. You can open this example selector by running the included M-file run_exsel.m.

Page 2: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This model we are going to be generating code for in this chapter is accessed via the “Macro” link from the example selector.

Page 3: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is our starting point model for C code generation. We need to first set it up for C code generation.

Setting up a Model for C Code Generation

There is always some set up work to be done before generating C code.We will be generating code for one part of the overall Simulink model. Naturally the test bench is not in the picture when it comes to code generation. There are cases where you would include part of the test bench in the code generation step but those are not typical cases and as such are not covered in this document.

Page 4: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is the subsystem for which we are generating C code. Notice there are names below the signal lines a couple of antenna-looking symbols on the input and output ports.

Signal Properties

Page 5: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Here is a larger view of the same subsystem. We covered how to set up each signal’s characteristics using the menu item Signal Properties in a previous chapter on Modeling an Echo Canceller.

The names rin_linear, sin_linear, and sout_linear will appear in the generated C code as arrays of 80 16 bit signed integers. How do we know that? Because we specified such parameters in our data dictionary, ec_fixed_setup.m. This was described in the previous chapter on test-benches.

pic_frame_size = 80;mpt_dimensions = [pic_frame_size 1];sin_linear = mpt.Signal;sin_linear.SamplingMode ='Frame based';sin_linear.Dimensions = mpt_dimensions;sin_linear.Description = 'Near end voice plus echo';sin_linear.DataType = 'fixdt(1,16,14)';sin_linear.RTWInfo.StorageClass = 'ImportedExtern'; This is a snippet from ec_fixed_setup.m. You can see that sin_linear is a fixed point object, signed, 16 bits wide, with 14 precision bits. It’s storage class is ‘ImportedExtern’. It’s frame-based with dimensions of 80 by 1. This would correspond to a declaration as follows in the generated C code, in ec_private.h.

extern int16_T sin_linear[80]; /* '<Root>/Sin' */

Page 6: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Why did we set up sin_linear to be an extern int instead of just int? The reason is that sin_linear was already declared in the existing or legacy C code in main.c so we just refer to the existing declaration in the generated code.

this is how sin_linear was originally declared in the legacy projectint sin_linear[80]; //

One declaration says int while the other uses int16_T. int16_T is typedef’d to int in rtwtypes.h so they are actually the same thing.

Optionally, you could have set the storage class for sin_linear in the Simulink model itself rather than using an m-file data dictionary approach.

You can set the storage class for any Simulink signal from its Signal Properties dialog. The checkbox “Signal name must resolve to Simulink signal object” must be unchecked to set storage class in this dialog.

Page 7: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

In the MATLAB workspace browser you can find rin_linear along with all of the other variables used by our model. You must run the model before you see these variables since ec_fixed_setup.m is called from the Model Properties InitFcn callback. Double-click on rin_linear to see all of its properties.

Page 8: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

By double-clicking on rin_linear you see the same properties we set explicitly in our data dictionary M-file, ec_fixed_setup.m. You can over-ride the M-file here via this GUI. If you do however, remember the changes won’t back-propagate into ec_fixed_setup.m so consider them temporary changes.

pic_frame_size = 80;mpt_dimensions = [pic_frame_size 1];sin_linear = mpt.Signal;sin_linear.SamplingMode ='Frame based';sin_linear.Dimensions = mpt_dimensions;sin_linear.Description = 'Near end voice plus echo';sin_linear.DataType = 'fixdt(1,16,14)';sin_linear.RTWInfo.StorageClass = 'ImportedExtern';It’s convenient to be able to control your data types programmatically in a text file that is external to your Simulink model. For instance, you could have 3 different M-files with 3 different sets of data types. Just run the M-file with the data types you want to test with and instantly your Simulink model is updated and ready to be tested. This is much

Page 9: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

quicker and reproducible than manually going into the separate dialogs and changing the data types.

Configuration Parameters

There is more to code generation setup than just describing the inputs and outputs. For that we go to the Simulation/Configuration Parameters.

To generate C code for an embedded target like a DSP chip you must use a fixed-step solver.

Page 10: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

At this point your optimization settings are not critical but these settings are a good place to start and they do impact the generated C code. Use the Help button at the bottom to get an in-depth description of what each selection does. Most of the defaults are the best choices for C code generation.

Page 11: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is the where you start setting up your C code generation options. But it doesn’t end here. A common misconception when generating C code is that only the settings under the Real-Time Workshop tab impact code generation. That is not true. The settings under Solver, Optimization, and Hardware Implementation impact the generated C code as well.

TLC Selection

Select ERT.TLC for the system target file if you purchased the Real-Time Workshop Embedded Coder. Otherwise you’re only choice will be GRT.TLC. You will have more flexibility in terms of the look and feel of the generated code with ERT.TLC.

Page 12: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Set up the main Real-Time Workshop pane as follows.

Target SelectionSystem Target file = ERT.TLCLanguage = C

Documentation and traceabilityCheck Generate HTML ReportCheck Launch report automaticallyCheck Code-to-block highlightingCheck Block-to-code highlighting (not available with GRT.TLC)

Makefile configurationBuild Process and Makefile configuration are not relevant to this example. We will be using the dsPIC compiler which is a separate step from the Simulink environment here. As a note, Microchip is currently working on an integrated link from MPLAB to

Simulink to automate the build process from Simulink for dsPIC targets. This new link is not covered in this document. Please contact Microchip for complete details.Custom storage class

Uncheck Ignore custom storage classes (default)Check Generate code only.

We are only using Simulink here for the C code generation aspect of the work, not for compiling and linking. The Microchip MPLAB IDE will be used to initate compiling and linking.

Page 13: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is the Real-Time Workshop setup pane located under Simulation/Configuration Parameters. We checked both code-to-block highlighting and block-to-code highlighting. This is forwards and backwards code traceability. It allows you to match up a section in the code with a block in the model or a block in the model with a section in the code.

Hardware Implementation Pane

Because we are targeting a dsPIC DSP, we have to tell the code generation engine something about the data types supported by that processor. To do that go to the Hardware Implementation pane.

Page 14: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

In the Hardware Implementation pane we specify the size information for integers, bytes, shorts, characters, and the native word size. All of this information impacts how the C code gets generated. You will have to look up the data types for the processor you are using and tell Simulink here how big they are.

Page 15: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

The reference documentation on our dsPIC tells us sizes for each data type.

Generating Code

This is the moment we’ve been waiting for. Let’s generate C code for the echo canceller subsystem.

Page 16: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Here is the subsystem we’ll generate C code for. Right click on this block and select Real-Time Workshop/Build Subsystem. Make sure MATLAB’s present working directory (pwd) contains your Simulink model. Otherwise you will get an error. It is an all too common error so be aware of it.

Page 17: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is the error you’ll see when attempting to generate code from a directory that does not contain the Simulink model file. It’s very easy to do this and generally will happen when you cd to the code generation directory, ec_ert_rtw, to inspect the results of the previous build. Just cd back to the Simulink’s model directory and code generation should proceed normally.

Page 18: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Push Build when you see this dialog appear.

The Code Generation Process

In the MATLAB command window you will see the code generation process begin. Make sure the command window is visible before you press Build or else you won’t be to bring the command window to the foreground until the build process is complete. The Build process is a blocking process within the MATLAB and Simulink environment.

### Starting Real-Time Workshop build procedure for model: ec### Generating code into build directory: C:\work\experiments\dspic\echo_cancel\myec\ec_ert_rtw### Invoking Target Language Compiler on ec.rtw

Bunch of messages later….

### Writing header file ec_types.h### Writing header file ec.h.### Writing source file ec.c### Writing header file ec_private.h### Writing source file ec_data.c.### Writing source file ert_main.c### TLC code generation complete.### Creating HTML report file ec_codegen_rpt.html.

Page 19: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

### Processing Template Makefile: C:\R2007b\rtw\c\ert\ert_lcc.tmf### Creating ec.mk from C:\R2007b\rtw\c\ert\ert_lcc.tmf### Successful completion of Real-Time Workshop build procedure for model: ec

The most important line is the last line, successful completion. You’re not done yet however. Now you have to marry the two worlds, the legacy C code with the C code generated from Simulink. That requires some work.

The code was generated in a sub-directory under your model’ directory in a directory named, ec_ert_rtw. The directory is created the first time you generate code for the ec subsystem. Note the first part of the directory name is the subsystem name, ec.

Here are the files that were generated in the ec_ert_rtw subdirectory. We will be concentrating on the generated C and H files only. For a complete description of the other files generated, refer to the Real-Time Workshop documentation.

Page 20: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Since we selected “Generate HTML Report” under Simulation/Configuration Parameters we also see a Real-Time Workshop Report. This is a hyper-linked document containing an HTML version of the code with links back to the Simulink model. Also included are other reports on the generated code. The generated HTML is located in a subdirectory under ec_ert_rtw called html.

Page 21: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

File and Directory Naming Conventions

If the subsystem name you are generating C code for is the same as your present working directory, the name of the generated code and the generated subdirectory will have a “0” appended to the subsystem name. For example, the subsystem we are generating C code for is named “ec”. If our present working directory for this model is also named “ec”, then the name of the generated sub-directory under “ec” will be “ec0_ert_rtw” instead of “ec_ert_rtw” as you might want or expect. The generated C files in the ec0_ert_rtw directory will also have the “0” appended to the file names. If this is undesirable you will need to either rename your present working directory or rename the subsystem such that they don’t match.

Integrating Generated C Code with Existing C Code

After generating code from the ec subsystem, you have to integrate it with the legacy code base or project. In the case of this hands-free kit, there was an existing code base provided by Microchip. Part of the integration work took place already when we specified the storage class and data type of the input and output ports as 16 bit integers with an ImportedExtern storage class.

There is more than one way to go about integrating C code from a Simulink model with a legacy project. In this document we’ll just be illustrating one way relevant to this particular effort. It’s the most straight-forward method but not necessarily the best way for your particular project or company to go about doing so.

Page 22: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Here is a top-level view at the existing project provided by Microchip for their hand-free kit development package. It included a number of C and H source files plus library files (.a files) and a linker command file (gld file).

Page 23: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

We are using Version 7.60 of the MPLAB IDE.

About the Shipping Hands-free Kit Code

The existing project had about 8 C source files, 2 header files, 2 library files, and one linker command file. The existing project was a complete project with its own implementation of an echo canceller. As it shipped however the dsPIC assembly-language based implementation of the echo canceller was determined to be numerically non-functional. Some very controlled experiments were performed to verify this. These tests were not dependent on amplifier gain, acoustics, speaker/microphone placement etc. The tests were purely digital in the software domain. These sames tests were also applied to the generated C code as we will see later.

Page 24: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

The challenge was to integrate the generated C code into this existing project, preserving as much of the legacy code as possible while stripping away the parts we no longer needed.

We are keeping every C file in the legacy project. However most of the files were modified in at least some small way. We kept the peripheral control files necessary for communicating with the data communications interface (DCI). The interrupt service routines (ISRs) is preserved. The timer code is preserved. The trap code is preserved in case something goes wrong like a bad address being generated at run-time. We also preserved the linker command file, the .gld file for our particular dsPIC.

The dsPIC assembler based library files were removed, libaec.a and libns.a. These files were for echo cancellation and noise suppression respectively. It is in one or both of these files that were found to have problems. We also removed the serial peripheral interface code and any code making a reference to it, e.g. InitSPI1. We could do this since our echo canceller implementation is running in so-called Analog Mode on the evaluation board (see the dsPIC Hands-Free Kit documentation for a complete description of Analog Mode vs Digital Mode).

The existing project was very handy as it contains all the functioning boilerplate code to get started testing our own version of the echo canceller. Getting all the DSP’s registers initialized properly, writing ISRs, and architecting the code is a time-consuming process. Now we can just concentrate on our echo canceller design and not all of the other tedious embedded systems stuff. That is a relief.

Preparing the Legacy Code for Integration with Generated Code

In this section we are going to list the steps required to take the legacy code and massage it such that it can be used with the generated C code. The most important thing about these modifications is that they are only done once! This is critical. If the process you are following requires you to modify the either the legacy code or the generated code manually every time you generate code, then there is a problem with your process. There are two downsides to requiring a human be involved in the code generation process. One, it takes more time and two, it increases the risk for error. Make sure the code generation process is as automated as possible. With that point emphasized here are the steps.

Page 25: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Build code for the echo canceller subsystem as illustrated in the previous section. We call this a right-click build since you right-click on the subsystem of interest and select Real-Time Workshop/Build Subsystem. That creates the ec_ert_rtw subdirectory with the C and H file implementation of the echo canceller contained within.

Press Build here.

Copy the legacy code into the Simulink build directory, namely, ec_ert_rtw. This is a controversial step and many folks will disagree with this. The philosophy taken here in this learning document was one of keeping it simple, not necessarily being the most elegant. By keeping all of our source files in one directory, it’s easy to share the project with anyone. It’s easy to know all of your project’s dependencies. Nothing is hidden. Just zip up the directory and send it. If you wish to keep the generated files in a separate directory from the legacy project, then that is a completely valid approach and probably the right thing to do on large projects. Whatever you do, do not refer to the include files in the Mathworks shipping directories in your C project. By placing a Mathworks directory on your MPLAB include path you loose knowledge of what header files are required to build the project and which aren’t. You also loose project portability, i.e. it’s going to be hard to move the project to another machine in the lab where Matlab is likely not installed. There are over 100 include files in many of the Matlab directories. Your project likely only requires a

Page 26: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

handful of them. Make sure you know which ones are required. We’ll cover the process of finding the required files in the following steps.

Creating an MPLAB Project

In MPLAB, create a new project using the Project Wizard or Project/New.This sequence illustrates how to use the Project Wizard.

Select the particular processor.

Page 27: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Point to the compiler, assembler, and linker.

Select a name and location for the project. We are placing it in the ec_ert_rtw directory along with the rest of our other files.

Page 28: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Select the files to be included as part of the project. You don’t have to get every file right here. You can add and remove files later as well. Don’t worry if you don’t know every file at this time.

Page 29: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Click Finish and your MPLAB project is created.

After creating your new project, there will be two new files in the ec_ert_rtw directory. One is the project file, ec.mcp. The second is the workspace file, ec.mcw.

Page 30: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Add the special string “target specific file” to the first line of every legacy C and H file. Don’t add this to the generated C/H code. The presence of this string prevents the legacy C/H file from being deleted during the code generation process. This is explained in Chapter 14 of the Real-Time Workshop User’s Guide.

Preventing User Source Code from Being Deleted

Prior to Release 13 (Version 5.0), Real-Time Workshop did not delete any .cor .h files that the user had placed in the build directory when rebuildingtargets. From Release 13 onward, all foreign source files are by default deletedduring builds, but can be preserved by following the guidelines given below.If you put a .c/.cpp or .h source file in a build directory, and you want toprevent Real-Time Workshop from deleting it during the TLC code generationprocess, insert the string target specific file in the first line of the.c/.cpp or .h file. For example,/* COMPANY-NAME target specific file** This file is created for use with the* COMPANY-NAME target.* It is used for ...*/...

Page 31: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

The MPLAB project should now look something like this. We’ve narrowed the window to focus on the included files. DCI.C, INT_PINS.C, LIN2ULAW.C, MAIN.C, TIMER.C, TRAPS.C and ULAW2LIN.C were legacy C files. The generated C files are EC.C and EC_DATA.C. The only legacy header file is PARAMS.H. The rest of the H files were generated. As

Page 32: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

we’ll see later more header files are required to build the output HEX file for flash.

Changes to MAIN.C

Some modifications to main.c in the legacy project were required to integrate the generated C code. The legacy real-time code was essentially structured as while forever loop that polled a flag to see if new data was available or not. If new data is ready, grab it and process it. If it’s not ready, just sit and wait for it to become ready. In other words, it’s a very simple single-tasking polling architecture.

while(1) { // Wait for all input data to be: // (a) transmitted for previous frame // (b) received for current frame while ( (DCI_SPI_Done == 0) || (DCI_Done == 0) ); DCI_SPI_Done = 0; DCI_Done = 0; // Suspend interrupts up to level 6 until data is copied SRbits.IPL = 6; // Copy input signal samples from buffers for processing for(i = 0; i < FRAME; i++) { sin_ulaw[i] = DCI_SPI_Rx[i]; rin_ulaw[i] = DCI_Rx[i]; DCI_SPI_Tx[i] = rin_ulaw[i]; DCI_Tx[i] = sout_ulaw[i]; } // Allow interrupts after data copy is complete SRbits.IPL = 0; for(i = 0; i < FRAME; i++) { sin_linear[i] = Ulaw2Lin((int)sin_ulaw[i]); rin_linear[i] = Ulaw2Lin((int)rin_ulaw[i]);

} if (nsflag == 1) { NoiseSuppression(noise_supp_mem, sin_linear, y_scratch); Nop(); } if (aecflag == 1) { AcousticEchoCanceller(echo_mem, vad_memory, rin_linear, sin_linear, sout_linear, inhibit_flag, y_scratch); Nop(); } for(i = 0; i < FRAME; i++) sout_ulaw[i] = lin2ulaw(sout_linear[i]); }

Page 33: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is the while forever loop. DCI_SPI_Done and DCI_Done are variables controlled by an interrupt service routine. The legacy code is frame-based. 80 samples are processed by the routine AcousticEchoCanceller each time it is called. 80 samples corresponds to 10 milli-seconds of data at an 8000 Hz sampling rate.

void __attribute__((__interrupt__)) _DCIInterrupt(void){ /* reset DCI interrupt flag */ IFS2bits.DCIIF = 0;

toggle_bit = !toggle_bit;LATFbits.LATF1 = toggle_bit; /* In analog mode, for both phone and mic/speaker data bytes */ DCI_Rx[DCI_Index++] = RXBUF0 >> 8; DCI_SPI_Rx[DCI_SPI_Index++] = RXBUF0; DCI_Rx[DCI_Index++] = RXBUF1 >> 8; DCI_SPI_Rx[DCI_SPI_Index++] = RXBUF1; DCI_Rx[DCI_Index++] = RXBUF2 >> 8; DCI_SPI_Rx[DCI_SPI_Index++] = RXBUF2; DCI_Rx[DCI_Index++] = RXBUF3 >> 8; DCI_SPI_Rx[DCI_SPI_Index++] = RXBUF3; DCI_Index -= 4; DCI_SPI_Index -= 4; TXBUF0 = (DCI_Tx[DCI_Index++] << 8) + DCI_SPI_Tx[DCI_SPI_Index++]; TXBUF1 = (DCI_Tx[DCI_Index++] << 8) + DCI_SPI_Tx[DCI_SPI_Index++]; TXBUF2 = (DCI_Tx[DCI_Index++] << 8) + DCI_SPI_Tx[DCI_SPI_Index++]; TXBUF3 = (DCI_Tx[DCI_Index++] << 8) + DCI_SPI_Tx[DCI_SPI_Index++]; /* Reset Index pointer and set Done flag */ if (DCI_Index == FRAME) { DCI_SPI_Index = 0; DCI_Index = 0; DCI_SPI_Done = 1; DCI_Done = 1; } } This ISR sets the DCI_Done flag telling the main while loop that 80 new data samples are available in RXBUF[0 to 3] for processing. This ISR gets triggered every time 4 new samples from the codec are available for reading. Writing also takes place in this ISR to TXBUF[0 to 3]. Note that it takes 20 calls to this ISR to set the Done flags, 20 calls times 4 reads/call. Also note that there is a 2 frame (or 20 msec) delay between receiving a sample and transmitting the corresponding echo cancelled sample. The reason it’s 2 frames and not just 1 frame is that there is a 1 frame of delay on the read side plus another frame of delay on the write side.

Page 34: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

How do we modify this code? We need to do two things.

1. Remove the code we don’t need anymore, namely, the shipping echo canceller from Microchip.

2. Insert our RTW-based echo canceller code in its place

We preserve the ISR code. The only thing we will modify is the main.c file and it turns out to be really easy.

while(1) { // Wait for all input data to be: // (a) transmitted for previous frame // (b) received for current frame while ( (DCI_SPI_Done == 0) || (DCI_Done == 0) ); DCI_SPI_Done = 0; DCI_Done = 0; // Suspend interrupts up to level 6 until data is copied SRbits.IPL = 6; // Copy input signal samples from buffers for processing for(i = 0; i < FRAME; i++) { sin_ulaw[i] = DCI_SPI_Rx[i]; rin_ulaw[i] = DCI_Rx[i]; DCI_SPI_Tx[i] = rin_ulaw[i]; DCI_Tx[i] = sout_ulaw[i]; } // Allow interrupts after data copy is complete SRbits.IPL = 0; for(i = 0; i < FRAME; i++) { sin_linear[i] = Ulaw2Lin((int)sin_ulaw[i]); rin_linear[i] = Ulaw2Lin((int)rin_ulaw[i]);

}

#ifDEF USE_LEGACY_CODE if (nsflag == 1) { NoiseSuppression(noise_supp_mem, sin_linear, y_scratch); Nop(); } if (aecflag == 1) { AcousticEchoCanceller(echo_mem, vad_memory, rin_linear, sin_linear, sout_linear, inhibit_flag, y_scratch); Nop(); } #else // USE_RTW_GENERATED_CODE ec_step(); // that’s it, how simple.#endif

Page 35: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

for(i = 0; i < FRAME; i++) sout_ulaw[i] = lin2ulaw(sout_linear[i]); }We just disable the legacy code with a conditional #ifdef and insert a call to the generated echo canceller function. Note that no input arguments are required since they were defined out of the scope of the main function as globals. Later we will elaborate this simple calling structure for numerical and timing verification purposes. But at its heart, the modification boils down to a one line function call in C. Simple is good…if it works.

Before compiling this code we need to setup the MPLAB IDE properly.

This is the USB-based In-Circuit Debugger for use with Microchip processors.

Necessary Project Modifications

Select Debugger/Select Tool/MPLAB ICD 2 (In-Circuit Debugger).Select Project/Build Configuration/Debug. This prevents the linker from placing data in illegal areas of memory which are needed by the debugger.

Page 36: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Select Project/Build Options/Project. Select the MPLAB C30 tab. Select Optimization on the Category pulldown menu. Select the highest speed optimization level of 3. The default selection is 0. This setting can have a substantial impact on the performance of the object code.

Select Debugger/Connect. If you are using your ICD (In-Circuit Debugger) for the first time it may be necessary to download the ICD 2 Operating System. Refer to your Microchip documentation for details concerning ICD 2 setup.

Page 37: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

If it fails to connect, it will say something like this.

Page 38: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

If a connection is established it will report MPLAB ICD 2 Ready.

Now we are ready to compile the code in our newly created project.Select Project/Build All or click on the Build All shortcut icon.

With the project as-is, you will get some build errors.In file included from ec.c:14:ec_private.h:16:107: dsp_rt.h: No such file or directoryec_private.h:37:97: dspeph_rt.h: No such file or directory

Page 39: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

The generated file ec.c refers to a few include files dsp_rt.h and dspeph_rt.h. These standard include files were not copied into your local build subdirectory, ec_ert_rtw at code generation time. Instead you must either refer to them where they are located under your Matlab installation or you can copy them over to your ec_ert_rtw directory manually. I chose the latter. I want everything local for now. Finding these files is a manual process using the Windows File Explorer or equivalent tool. It turns out that most of the dependencies are located in just a few standard directories.

Search for dsp_rt.h under C:\R2007B\toolbox using Windows File Explorer. There were two instances on my machine but they are both the same. I’m going to grab the file in C:\R2007b\toolbox\dspblks\include and copy it to my local ec_ert_rtw directory. As it turns out dspeph_rt.h is in the same directory.

Page 40: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Most file dependencies related to signal processing can be found under these subdirectories.

Make sure to add the “target specific file” string to the first line of these files, else they will be deleted upon the next right-click build in Simulink.

Add these include files to the MPLAB project and then build again.

In file included from ec_private.h:16, from ec.c:14:dsp_rt.h:42:29: dsp_iso_math_rt.h: No such file or directory

Now it complains that another header file is missing, dsp_iso_math_rt.h. We will use the same process to find this file using Windows File Explorer. This file is also in C:\R2007b\toolbox\dspblks\include. Copy it over to your local directory. Make the necessary modification to the first line. Include this file in your MPLAB project. Build again.

C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\main.o(.text+0x0): In function `main':C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\main.c:89: multiple definition of `main'C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\ert_main.o(.text+0x0):C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\ert_main.c:60: first defined hereC:\Microchip_7p5\MPLAB C30\bin\pic30-coff-ld.exe: Link terminated due to previous error(s).

Page 41: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Link step failed.BUILD FAILED: Tue Nov 27 10:29:54 2007

The build failed because we have two different functions with the name “main”. Fixing this problem is simple. Just remove ert_main.c from the project. It is not required. The legacy code has its own main function, the only one we’ll need.

With that change we build again, this time successfully. The code download process can take about a minute with the slower ICD devices. Faster devices for programming the flash are now available.

Executing: "C:\Microchip_7p5\MPLAB C30\bin\pic30-bin2hex.exe" "C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\ec.cof"Loaded C:\Work\experiments\dspic\echo_cancel\myec\ec_ert_rtw\ec.cof.BUILD SUCCEEDED: Tue Nov 27 12:35:14 2007

It Built! Are We Done?

Are we done just because we got the code to build and download successfully? No, not even close but it’s a big step in the right direction.

What have we accomplished? We now have a process in place allowing us to follow this very manageable sequence:

1. Simulate, tune model parameters, and collect data during simulation. This is all Simulink.

2. Regenerate C code via a right-click build subsystem in Simulink.3. Rebuild and download in MPLAB. This is two mouse clicks in

MPLAB, one for building and the second for burning flash.4. Test code while running on dsPIC. The specifics of how to verify

the code while running on the dsPIC will be covered in a follow-on section.

The main point is that no manual modifications to the code required. If you add new blocks to the model then new C or H file dependencies may be incurred. In this case you would have to follow the same process illustrated earlier of finding these files under your Matlab installation, moving them over to your MPLAB project, and then rebuilding.

Page 42: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Is There An Automated Way To Locate Source File Dependencies?

You are probably asking by now if there is a more automated way of finding all of the source file dependencies rather than go through this trial and error process. As currently illustrated up to this point, the process of finding all of the required files relies upon using the dsPIC compiler to fail and in doing so tell us what files are missing. Unfortunately the compiler doesn’t give us a list of ALL the files on the first failed attempt. Generally speaking it stops after the first error. We go find that file dependency, include it in our project, and then repeat the build process all over again until the compiler and linker are both satisfied. Isn’t there a better, more streamlined way?

The answer is yes but. And the author doesn’t like answers that end with but so for the time being he is still recommending the slower yet deterministic approach to determining file dependencies. There are three utilities available for locating a model’s file dependencies, each with their caveats or “buts” as I called them. The details on how to go about using these utilities is not included in this document.

1. The first utility is called packNGo which is part of the Real-Time Workshop.>> doc packngoThe current limitation with packNGo is that it includes too many

files as dependencies beyond what is truly required. For a fixed point implementation of the LMS block it included 1411 C and H files in the dependency zip file when approximately only 10 files are actually required.

Page 43: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

This is an example of using the PackNGo utility.

The annotation callback in this model amounts to 2 lines of MATLAB code.

set_param(gcs,'PostCodeGenCommand','packNGo(buildInfo)')slbuild(gcs);

Everything About A Simulink Model You Never Wanted To Know

You cannot set the PostCodeGenCommand from the Configuration Parameters GUI. It must be done via a MATLAB command as shown. In case you are curious about other model parameters that aren’t visibile

Page 44: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

via in the Configuration Paramters GUI, you can use a few other approaches to get and set these parameters.

There are 2 ways in which you can list a model’s parameters at once without knowing the explicit syntax for each one.

1) h = get_param(gcs,'handle') inspect(h)

This opens up an inspector GUI for the block diagram and each parameter can be changed.

2) h = get_param(gcs,'ObjectParameters')

This stores all the parameters in the handle 'h' which is a structure and is similar to the 'get(h)' functionality in handle graphics. However please note that in both these methods, some parameters are still hidden.

2. The second utility for locating a model’s source file dependencies is called the Minimal Source Tool. This tool does not package up any unnecessary files, thus the name minimal source tool. You only get the bare minimum number of files required to rebuild the .out file on a separate non-Mathworks machine. This tool requires Microsoft Visual C++ and does not work with LCC. LCC ("Local C Compiler" or "Little C Compiler") is a small free retargetable compiler program for the ANSI C programming language that ships with MATLAB. The Minimal Source Tool is not part of the standard Mathworks release but is available on a per request basis. Contact your Mathworks account manager for more information.

3. The third utility is called ccsmake_portableproj. It is specific to the TI compiler and CodeComposer Studio (CCS). It is a demo feature in the Link for CCS product. In the Help under the Demos tab, select Links and Targets, then Workflow Demos, then Code Generation Workflow. See Task 6, Package Code for Portable Reuse.

Page 45: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Code CustomizationsThere are times when you’ll want to customize more about how the generated C code looks and feels as if you had written it yourself. In this section we will illustrate how you can use custom storage classes (CSC) to organize signals into C data structures or use a #define in place of a hard-coded constant.

The documentation is a great way to get the inside scoop on Custom Storage Classes (CSC). Here we’ll take a few particular examples of CSC’s and put them to work for us.

There were three key input and output signals associated with our echo canceller, rin_linear, sin_linear, and sout_linear. They were each 80 element integer arrays. What if instead of 3 independent integer array declarations we wanted a single data structure holding all three signals. This is how you would do this.

Page 46: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Open up the modified model called ec_fixed_slm_structures.mdl. As always you should run the model first to make sure it works. But in this section we are going to concentrate on customizing the code generation to use structures and #defines.

Using Structures

Click on the link, edit ec_fixed_setup_structures.m to see how we modified our data dictionary to use structures.

Page 47: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

Here is how rin_linear and sout_linear were defined in the model we generated code for.

Page 48: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

But here is how we modified rin_linear to include it in a data structure.The signal rin_linear is still an MPT Data Object but the storage class has changed to Custom. Two new fields in the data object were also set, namely CustomStorageClass and StructName.

%% Input Signal: rin_linearrin_linear = mpt.Signal;rin_linear.SamplingMode ='Frame based';rin_linear.Dimensions = mpt_dimensions;rin_linear.Description = 'Far End Voice';rin_linear.DataType = 'fixdt(1,16,14)';rin_linear.RTWInfo.StorageClass = 'Custom';rin_linear.RTWInfo.CustomStorageClass = 'Struct';rin_linear.RTWInfo.CustomAttributes.StructName = 'ec_struct'; %% Input Signal: sin_linearsin_linear = mpt.Signal;

Page 49: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

sin_linear.SamplingMode ='Frame based';sin_linear.Dimensions = mpt_dimensions;sin_linear.Description = 'Near end voice plus echo';sin_linear.DataType = 'fixdt(1,16,14)';sin_linear.RTWInfo.StorageClass = 'Custom';sin_linear.RTWInfo.CustomStorageClass = 'Struct';sin_linear.RTWInfo.CustomAttributes.StructName = 'ec_struct'; %% Input Signal: sout_linearsout_linear = mpt.Signal;sout_linear.SamplingMode ='Frame based';sout_linear.Dimensions = mpt_dimensions;sout_linear.Description = 'Echo Cancelled Output (near end)';sout_linear.DataType = 'fixdt(1,16,14)';sout_linear.RTWInfo.StorageClass = 'Custom';sout_linear.RTWInfo.CustomStorageClass = 'Struct';sout_linear.RTWInfo.CustomAttributes.StructName = 'ec_struct';Here is the same code in a text listing for data structures. The three signals rin_linear, sin_linear, and sout_linear will all go into a single structure called ec_struct.

If you double-click on rin_linear in the workspace browser you’ll see all of the same attributes we just set programmatically in M-code.

Page 50: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

typedef struct ec_struct_tag { int16_T sout_linear[80]; int16_T rin_linear[80]; int16_T sin_linear[80];} ec_struct_type;The generated structure definition looks like this in the _types.h file.

ec_struct.sout_linear[i] = ec_struct.sout_linear[i] - rtb_LMS_Fixed_o1[i];Here a reference to the structure in the generated C code appears.

Using #defines

The step_size for the LMS block is a constant in our application. We are not changing its values depending on conditions although some applications will do just that. If it is a constant you can define it as a #define to avoid allocating data memory for the step_size yet refer to it symbolically in the C code as STEP_SIZE instead of just hard-coding the constant value 300 into the code.

Let’s create a Simulink Parameter object that corresponds to a #define in the generated C code.

%% Input Signal: step_sizestep_size = Simulink.Parameter;step_size.Description = 'Echo Canceller Step Size';step_size.DataType = 'auto'; % must use auto, fixpt doesn't work herestep_size.RTWInfo.StorageClass = 'Custom'; % originally 'Auto'step_size.RTWInfo.CustomStorageClass = 'Define';step_size.RTWInfo.Alias = 'STEP_SIZE';step_size.Value = 300/32768;Here is the M-code from ec_fixed_setup_structures.m that creates a Simulink Parameter object using a custom storage class called ‘Define’. We changed the data type to ‘auto’ as well.

Page 51: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

You can access this variable in the MATLAB workspace by double-clicking on it or just typing it and hitting enter in the command window.

>> step_size step_size = Simulink.Parameter (handle) RTWInfo: [1x1 Simulink.ParamRTWInfo] Description: 'Echo Canceller Step Size' DataType: 'auto' Min: -Inf Max: Inf DocUnits: '' Value: 0.009155273437500 Complexity: 'real' Dimensions: [1 1]This is how step_size appears when accessed from the command window.

Then when you generate code you will see this./* Definition for custom storage class: Define */#define STEP_SIZE 300This definition occurs in “subsystem name”.h In our case it was Echo_Canceller.h.

Page 52: Generating C Code from a Simulink Model - Miami … · Web viewGenerating C Code from a Simulink Model 1 Introduction 1 Setting up a Model for C Code Generation 3 Signal Properties

/* Calculate mu*err outside the adaptation loop */ { int32_T rtb_s32_tmp; rtb_s32_tmp = (int32_T)STEP_SIZE * (int32_T)This usage of STEP_SIZE occurs in “subsystem name.c” in the _step function.

Next Steps

In the next chapter we are going to verify that the project we just built successfully is doing the right thing. Verification can be a lengthy and involved process so we will spend a substantial amount of time on it.