| Real-Time Workshop User's Guide | ![]() |
インライン化されたADCドライバのソースコード
下記のファイルは、「例題:インライン化されたADCドライバ」で説明しています。
adc.c
/*
* File : adc.c
* Abstract:
* Example S-function device driver (analog to digital convertor) for use
* with Simulink and Real-Time Workshop.
* This S-function contains simulation code only (except mdlRTW, used
* only during code generation.) An error will be generated if
* this code is compiled without MATLAB_MEX_FILE defined. That
* is,it must be compiled via the MATLAB mex utility.
*
* DEPENDENCIES:
* (1) This S-function is intended for use in conjunction with adc.tlc,
* a Target Language Compiler program that generates inlined, real-time code that
* implements the real-time I/O functions required by mdlOutputs, etc.
*
* (2) device.h defines hardware-specific macros, etc. that implement
* actual I/O to the board
*
* (3) This file contains a mdlRTW function that writes parameters to
* the model.rtw file during code generation.
*
* Copyright (c) 1994-2000 by The MathWorks, Inc. All Rights Reserved.
*
*/
/*********************
* Required defines *
*********************/
#define S_FUNCTION_NAME adc
#define S_FUNCTION_LEVEL 2
/*********************
* Required includes *
*********************/
#include "simstruc.h" /* The Simstruct API, definitions and macros */
/*
* Generate a fatal error if this file is (by mistake) used by Real-Time
* Workshop. There is a target file corresponding to this S-function: adc.tlc,
* which should be used to generate inlined code for this S-funciton.
*/
#ifndef MATLAB_MEX_FILE
# error "Fatal Error: adc.c can only be used to create C-MEX S-Function"
#endif
/*
* Define the number of S-function parameters and set up convenient macros to
* access the parameter values.
*/
#define NUM_S_FUNCTION_PARAMS (4)
#define N_CHANNELS (2) /* For this example, num. of channels is fixed */
/* 1. Base Address */
#define BASE_ADDRESS_PARAM (ssGetSFcnParam(S,0))
/* 2. Analog Signal Range */
#define SIGNAL_RANGE_PARAM (ssGetSFcnParam(S,1))
#define MIN_SIGNAL_VALUE ((real_T) (mxGetPr(SIGNAL_RANGE_PARAM)[0]))
#define MAX_SIGNAL_VALUE ((real_T) (mxGetPr(SIGNAL_RANGE_PARAM)[1]))
/* 3. Hardware Gain */
#define HARDWARE_GAIN_PARAM (ssGetSFcnParam(S,2))
#define HARDWARE_GAIN ((real_T) (mxGetPr(HARDWARE_GAIN_PARAM)[0]))
/* 4. Sample Time */
#define SAMPLE_TIME_PARAM (ssGetSFcnParam(S,3))
#define SAMPLE_TIME ((real_T) (mxGetPr(SAMPLE_TIME_PARAM)[0]))
/*
* Hardware specific information pertaining to the A/D board. This information
* should be provided with the documentation that comes with the board.
*/
#include "device.h"
/*====================*
* S-function methods *
*====================*/
/* Function: mdlCheckParameters ================================================
* Abstract:
* Check that the parameters passed to this S-function are valid.
*/
#define MDL_CHECK_PARAMETERS
static void mdlCheckParameters(SimStruct *S)
{
static char_T errMsg[256];
boolean_T allParamsOK = 1;
/*
* Base I/O Address
*/
if (!mxIsChar(BASE_ADDRESS_PARAM)) {
sprintf(errMsg, "Base address parameter must be a string.\n");
allParamsOK = 0;
goto EXIT_POINT;
}
/*
* Signal Range
*/
if (mxGetNumberOfElements(SIGNAL_RANGE_PARAM) != 2) {
sprintf(errMsg,
"Signal Range must be a two element vector [minInp maxInp]\n");
allParamsOK = 0;
goto EXIT_POINT;
}
if ( !adcIsSignalRangeParamOK(MIN_SIGNAL_VALUE, MAX_SIGNAL_VALUE) ) {
sprintf(errMsg,
"The specified Signal Range is not supported by I/O board.\n");
allParamsOK = 0;
goto EXIT_POINT;
}
/*
* Hardware Gain
*/
if (mxGetNumberOfElements(HARDWARE_GAIN_PARAM) != 1) {
sprintf(errMsg, "Hardware Gain must be a scalar valued real number\n");
allParamsOK = 0;
goto EXIT_POINT;
}
if (!adcIsHardwareGainParamOK(HARDWARE_GAIN)) {
sprintf(errMsg, "The specified hardware gain is not supported.\n");
allParamsOK = 0;
goto EXIT_POINT;
}
/*
* Sample Time
*/
if (mxGetNumberOfElements(SAMPLE_TIME_PARAM) != 1) {
sprintf(errMsg, "Sample Time must be a positive scalar.\n");
allParamsOK = 0;
goto EXIT_POINT;
}
EXIT_POINT:
if ( !allParamsOK ) {
ssSetErrorStatus(S, errMsg);
}
} /* end: mdlCheckParameters */
/* Function: mdlInitializeSizes ================================================
* Abstract:
* Validate parameters,set number and width of ports.
*/
static void mdlInitializeSizes(SimStruct *S)
{
/* Set the number of parameters expected. */
ssSetNumSFcnParams(S, NUM_S_FUNCTION_PARAMS);
if ( ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S) ) {
/*
* If the number of parameter passed in is equal to the number of
* parameters expected, then check that the specified parameters
* are valid.
*/
mdlCheckParameters(S);
if ( ssGetErrorStatus(S) != NULL ) {
return; /* Error was reported in mdlCheckParameters. */
}
} else {
return; /* Parameter mismatch. Error will be reported by Simulink. */
}
/*
* This S-functions's parameters cannot be changed in the middle of a
* simulation, hence set them to be nontunable.
*/
{
int_T i;
for (i=0; i < NUM_S_FUNCTION_PARAMS; i++) {
ssSetSFcnParamNotTunable(S, i);
}
}
/* Has no input ports */
if ( !ssSetNumInputPorts(S, 0) ) return;
/* Number of output ports = number of channels specified */
if ( !ssSetNumOutputPorts(S, N_CHANNELS) ) return;
/* Set the width of each output ports to be one. */
{
int_T oPort;
for (oPort = 0; oPort < ssGetNumOutputPorts(S); oPort++) {
ssSetOutputPortWidth(S, oPort, 1);
}
}
ssSetNumSampleTimes( S, 1);
} /* end: mdlInitializeSizes */
/* Function: mdlInitializeSampleTimes ==========================================
* Abstract:
* Set the sample time of this block as specified via the sample time
* parameter.
*/
static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
} /* end: mdlInitializeSampleTimes */
/* Function: mdlStart ==========================================================
* Abstract:
* At the start of simulation in Simulink, print a message to the MATLAB
* command window indicating that output of this block will be zero during
* simulation.
*/
#define MDL_START
static void mdlStart(SimStruct *S)
{
if (ssGetSimMode(S) == SS_SIMMODE_NORMAL) {
mexPrintf("\n adc.c: The output of the A/D block '%s' will be set "
"to zero during simulation in Simulink.\n", ssGetPath(S));
}
} /* end: mdlStart */
/* Function: mdlOutputs ========================================================
* Abstract:
* Set the output to zero.
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
int oPort;
for (oPort = 0; oPort < ssGetNumOutputPorts(S); oPort++) {
real_T *y = ssGetOutputPortRealSignal(S, oPort);
y[0] = 0.0;
}
} /* end: mdlOutputs */
/* Function: mdlTerminate ======================================================
* Abstract:
* Required S-function method that gets called at the end of simulation
* and code generation. Nothing to do in simulation.
*/
static void mdlTerminate(SimStruct *S)
{
} /* end: mdlTerminate */
/* Function: mdlRTW ============================================================
* Abstract:
* Evaluate parameter data and write it to the model.rtw file.
*/
#define MDL_RTW
static void mdlRTW(SimStruct *S)
{
boolean_T polarity = adcIsUnipolar(MIN_SIGNAL_VALUE, MAX_SIGNAL_VALUE);
real_T offset = polarity ? 0.0 : MIN_SIGNAL_VALUE/HARDWARE_GAIN;
real_T resolution = (((MAX_SIGNAL_VALUE-MIN_SIGNAL_VALUE)/HARDWARE_GAIN)/
ADC_NUM_LEVELS);
char_T baseAddrStr[128];
if ( mxGetString(BASE_ADDRESS_PARAM, baseAddrStr, 128) ) {
ssSetErrorStatus(S, "Error reading Base Address parameter, "
"need to increase string buffer size.");
return;
}
if ( !ssWriteRTWParamSettings(S, 4,
SSWRITE_VALUE_QSTR, "BaseAddress", baseAddrStr,
SSWRITE_VALUE_NUM, "HardwareGain", HARDWARE_GAIN,
SSWRITE_VALUE_NUM, "Resolution", resolution,
SSWRITE_VALUE_NUM, "Offset", offset) ) {
return; /* An error occured, which will be reported by Simulink. */
}
} /* end: mdlRTW */
/*
* Required include for Simulink-MEX interface mechanism
*/
#include "simulink.c"
/* EOF: adc.c */
adc.tlc
%% File : adc.tlc
%% Abstract:
%% Target file for the C-Mex S-function adc.c
%%
%% Copyright (c) 1994-2000 by The MathWorks, Inc. All Rights Reserved.
%%
%implements "adc" "C"
%% Function: BlockTypeSetup ===========================================
%% Abstract:
%% This function is called once for all instance of the S-function
%% "dac" in the model. Since this block requires hardware specific
%% information about the I/O board, we generate code to include
%% "device.h" in the generated model.h file.
%%
%function BlockTypeSetup(block, system) void
%%
%% Use the Target Language Ccompiler global variable INCLUDE_DEVICE_H to make sure that
%% the line "#include device.h" gets generated into the model.h
%%file only once.
%%
%if !EXISTS("INCLUDE_DEVICE_H")
%assign ::INCLUDE_DEVICE_H = 1
%openfile buffer
/* Include information about the I/O board */
#include "device.h"
%closefile buffer
%<LibCacheIncludes(buffer)>
%endif
%endfunction %% BlockTypeSetup
%% Function: Start ====================================================
%% Abstract:
%% Generate code to set the number of channels and the hardware gain
%% mask in the start function.
%%
%function Start(block, system) Output
/* %<Type> Block: %<Name> (%<ParamSettings.FunctionName>) */
%%
%assign numChannels = block.NumDataOutputPorts
%assign baseAddr = SFcnParamSettings.BaseAddress
%assign hwGain = SFcnParamSettings.HardwareGain
%%
%% Initialize the Mux Scan Register to scan from 0 to NumChannels-1.
%% Also set the Gain Select Register to the appropriate value.
%%
adcSetLastChannel(%<baseAddr>, %<numChannels-1>);
adcSetHardwareGain(%<baseAddr>, adcGetGainMask(%<hwGain>));
%endfunction %% Start
%% Function: Outputs =================================================
%% Abstract:
%% Generate inlined code to perform one A/D conversion on the enabled
%% channels.
%%
%function Outputs(block, system) Output
%%
%assign offset = SFcnParamSettings.Offset
%assign resolution = SFcnParamSettings.Resolution
%assign baseAddr = SFcnParamSettings.BaseAddress
%%
/* %<Type> Block: %<Name> (%<ParamSettings.FunctionName>) */
{
int_T chIdx;
uint_T adcValues[%<NumDataOutputPorts>];
for (chIdx = 0; chIdx < %<NumDataOutputPorts>; chIdx++) {
adcStartConversion(%<baseAddr>);
while (adcIsBusy(%<baseAddr>)) {
/* wait for conversion */
}
adcValues[chIdx] = adcGetValue(%<baseAddr>);
}
%foreach oPort = NumDataOutputPorts
%assign y = LibBlockOutputSignal(oPort, "", "", 0)
%<y> = %<offset> + %<resolution>*adcValues[%<oPort>];
%endforeach
}
%endfunction %% Outputs
%% EOF: adc.tlc
device.h
/*
* File : device.h
*
* Copyright (c) 1994-2000 by The MathWorks, Inc. All Rights
* Reserved.
*
*/
/*
* Operating system utilities to read and write to hardware
* registers.
*/
#define ReadByte(addr) inp(addr)
#define WriteByte(addr,val) outp(addr,val)
/*=============================================================*
* Specification of the Analog Input Section of the I/O board
* (used in the ADC device driver S-function, adc.c and *adc.tlc)
*=======================================================*/
/*
* Define macros for the attributes of the A/D board, such as the
* number of A/D channels and bits per channel.
*/
#define ADC_MAX_CHANNELS (16)
#define ADC_BITS_PER_CHANNEL (12)
#define ADC_NUM_LEVELS ((uint_T) (1 << ADC_BITS_PER_CHANNEL))
/*
* Macros to check if the specified parameters are valid.
* These macros are used by the C-Mex S-function, adc.c
*/
#define adcIsUnipolar(lo,hi) (lo == 0.0 && 0.0 < hi)
#define adcIsBipolar(lo,hi) (lo + hi == 0.0 && 0.0 < hi)
#define adcIsSignalRangeParamOK(l,h) (adcIsUnipolar(l,h) || adcIsBipolar(l,h))
#define adcGetGainMask(g) ( (g==1.0) ? 0x0 : \
( (g==10.0) ? 0x1 : \
( (g==100.0) ? 0x2 : \
( (g==500.0) ? 0x3 : 0x4 ) ) ) )
#define adcIsHardwareGainParamOK(g) (adcGetGainMask(g) != 0x4)
#define adcIsNumChannelsParamOK(n) (1 <= n && n <= ADC_MAX_CHANNELS)
/* Hardware registers used by the A/D section of the I/O board */
#define ADC_START_CONV_REG(bA) (bA)
#define ADC_LO_BYTE_REG(bA) (bA)
#define ADC_HI_BYTE_REG(bA) (bA + 0x1)
#define ADC_MUX_SCAN_REG(bA) (bA + 0x2)
#define ADC_STATUS_REG(bA) (bA + 0x8)
#define ADC_GAIN_SELECT_REG(bA) (bA + 0xB)
/*
* Macros for the A/D section of the I/O board
*/
#define adcSetLastChannel(bA,n) WriteByte(ADC_MUX_SCAN_REG(bA), n<<4)
#define adcSetHardwareGain(bA,gM) WriteByte(ADC_GAIN_SELECT_REG(bA), gM)
#define adcStartConversion(bA) WriteByte(ADC_START_CONV_REG(bA), 0x00)
#define adcIsBusy(bA) (ReadByte(ADC_STATUS_REG(bA)) & 0x80)
#define adcGetLoByte(bA) ReadByte(ADC_LO_BYTE_REG(bA))
#define adcGetHiByte(bA) ReadByte(ADC_HI_BYTE_REG(bA))
#define adcGetValue(bA) ((adcGetLoByte(bA)>>4) | (adcGetHiByte(bA)<<4))
/*============================================================*
* Specification of the Analog Output Section of the I/O board
* (used in the DAC device driver S-function, adc.c and adc.tlc)
*============================================================*/
#define DAC_BITS_PER_CHANNEL (12)
#define DAC_UNIPOLAR_ZERO ( 0)
#define DAC_BIPOLAR_ZERO (1 << (DAC_BITS_PER_CHANNEL-1))
#define DAC_MIN_OUTPUT (0.0)
#define DAC_MAX_OUTPUT ((real_T) ((1 << DAC_BITS_PER_CHANNEL)-1))
#define DAC_NUM_LEVELS ((uint_T) (1 << DAC_BITS_PER_CHANNEL))
/*
* Macros to check if the specified parameters are valid.
* These macros are used by the C-Mex S-function,dac.c.
*/
#define dacIsUnipolar(lo,hi) (lo == 0.0 && 0.0 < hi)
#define dacIsBipolar(lo,hi) (lo+hi == 0.0 && 0.0 < hi)
#define dacIsSignalRangeParamOK(l,h) (dacIsUnipolar(l,h) || dacIsBipolar(l,h))
/* Hardware registers */
#define DAC_LO_BYTE_REG(bA) (bA + 0x4)
#define DAC_HI_BYTE_REG(bA) (bA + 0x5)
#define dacSetLoByte(bA,c) WriteByte(DAC_LO_BYTE_REG(bA),(c & 0x00f)<<4)
#define dacSetHiByte(bA,c) WriteByte(DAC_HI_BYTE_REG(bA),(c & 0xff0)>>4)
#define dacSetValue(bA,c) dacSetLoByte(bA,c); dacSetHiByte(bA,c)
/* EOF: device.h */
| MEX-ファイルとドライバブロックのビルド | パラメータと信号のインタフェース | ![]() |