You are on page 1of 11

Technion - Israel Institute of Technology

Faculty of Mechanical Engineering, Haifa 32000, ISRAEL

Dr. I. Bucher

18 October 2002, ‫י"ב חשון תשס"ג‬

Project in Mechatronics semester No. 2

The 1st meeting will take place on Wednesday, 23-Oct-2002 at 17:30.

Please come to the Mechatronics Laboratory

All groups must bring the manufactured (and assembled) projects

Next phase:

The groups must start reading about the Analog to digital conversion of the F240
and the PWM generating facility.

You will be asked to create programs on the MicroController that perform the
following:

1) Generate PWM signal using one of the Timers


2) Being able to change the Duty-Cycle from Matlab/or DMCD-pro as we did in the
Micro-course.
3) Write a program that reads a single ADC channel and records 100 values in an
array and a rate of 100 Samples/Sec. Read the Array into Matlab and plot
4) Using an external voltage source (potentiometer) you should change the PWM-
Duty-cycle according to the read voltage

>> These are all necessary in the way for a working control system <<

Enjoy: The Mechatronics Project Team

Technion City Phone: (972 4) 829 3153


Haifa 32000, Fax: (972 4) 832 4533
ISRAEL E-mail: bucher@technion.ac.il
- 2 -

Detailed assignments
1) Complete the mechanical construction of the prototypes
- Please be in contact with Yosi Rotheberg for this part. The assembled projects
(or partially assembled projects) must be brought to the meeting
- Check

2) Make progress with the Microprocessor control. For this purpose each group
must begin with the development of modules for the F240 (identical to the lab
system).
- develop a subroutine that uses the Analog to digital converting system on the
TMS320F240 to read an analog voltage. Please consult an application note:
spra461.pdf from TI
(http://mechatronics.technion.ac.il/microprocessors/doc/spra461.pdf )
this document is not directly related by has very useful subroutines that can be
used to:
a) Set-up the ADC (analog to digital converting system)
b) Set-up the PWM

- Both systems are triggered by the timers. The analog to digital converting
device beings a conversion cycle that is triggered by the timer (automatically
each period, say). It is possible to program the ADC to issue an Interrupt when
the Analog to digital conversion is complete and a digital value can be collected

void interrupt adc_int(void) // this routine is called from asm


{ // the asm is the int handler
adc_value =ADC1_read(); // as we did in class
do_computations_if needed();
return;
}

Reads out the FIFO of the ADC1 by checking the interrupt flag.
If ADC is not valid returns 0xffff.

int ADC1_read()
{
unsigned int temp =0xffff;
if(ADCTRL1 &0x0100)
{
ADCTRL1 |=0x0100;
temp =ADCFIFO1;
}
return(temp);
}
Æ some of the code is supplied below
- 3 -
- 4 -

/*
===> See spra461.pdf from TI
*/

/*---------------------------------------------------------------------------------------
filename:initfunc.c
project:oversampling on C24x
description:Functions for initializing the C24x peripherals and EVM and support
functions for reading ADC and programming simple compare PWM outputs.
---------------------------------------------------------------------------------------*/

#include "osample.h"
#include "c240.h"
#include "initfunc.h"

unsigned int pwm_step; /*pwm_step:


The step size for each incremental stage.
Calculated as (pwm_period /pwm_oversample)
*/
unsigned int pwm_half; /*pwm_half:
The maximum 'amplitude'of the PWM signal
Calculated as (pwm_step*pwm_oversample)-1
If pwm_period is a magnitude of pwm_oversample
this value is pwm_period-1
*/
unsigned int pwm_current; /*pwm_current:
Current 'value'of the pwm signal.Incremented
by pwm_step on each compare interrupt.
*/
unsigned char pwm_ramp; /*pwm_ramp:
Indicator if the pwm signal is 'counting'up-or
downwards.
Will be changed on pwm_current=0 or
pwm_current=pwm_half
*/
unsigned int pwm_oversample;/*pwm_oversample:
Oversample factor.
*/
unsigned int pwm_sampletime;/*pwm_sampletime:
PWM signal period in 100ns resolution.
Multiply it with 2 and you have the number of timer ticks
*/

/****************************************************************************
TIMER
*****************************************************************************/
/*---------------------------------------------------------------------------
void Timer_Init(int timer,unsigned int period,int timer_prescaler)
Initializes GP timer #timer with 'period'as the value written into
the period regster and 'timer_prescaler'indicating the prescaler
value.
Arguments:
timer:a value of 1,2,3 indicating which timer should be configured.
period: the value for the period register of GP timer 1
timer_prescaler: a value of TIMER_PRESCALER1-TIMER_PRESCALER128
describing the timer prescaler for GP timer 1
Note:Timer and Timer Compare are disabled.
----------------------------------------------------------------------------*/
- 5 -

void Timer_Init(int timer,unsigned int period,int timer_prescaler)


{
unsigned int timerreg;
timerreg =0x7404 +((timer-1)<<2);/*get address of TxCON */

/*disable counter,clear TENABLE in TxCON */


*(unsigned *)(timerreg)=TIMER_CONTINOUS_UP |timer_prescaler;
OCRA |=0x0200; /*enable PWM8/CMP8 of shared IO */
}
if (spwm ==3)
{
SACTR &=0xffcf;
SACTR |=(spwm_type <<4);
OCRA |=0x0400;/*enable PWM9/CMP9 of shared IO */
}
if (timer==1)
COMCON &=0xff7f;
else
COMCON |=0x0080;
COMCON |=0x0100;/*enable simple compare unit */
COMCON |=0x8000;/*enable COMPARE unit */
}

/*---------------------------------------------------------------------------
void SPWM_1_Send(unsigned int value)
Sends a value to Simple Compare Unit 1
Arguments:value:the value that should be written into the SCMPR1
register
Note:This function is for the sake of easy readability.
----------------------------------------------------------------------------*/
inline void SPWM_1_Send(unsigned int value)
{
SCMPR1 =value;
}
/*---------------------------------------------------------------------------

void SPWM_2_Send(unsigned int value)


Sends a value to Simple Compare Unit 2.dito as SPWM_1_Send()
----------------------------------------------------------------------------*/
inline void SPWM_2_Send(unsigned int value)
{
SCMPR2 =value;
}
/*---------------------------------------------------------------------------
void SPWM_3_Send(unsigned int value)
Sends a value to Simple Compare Unit 3.dito as SPWM_1_Send()
*(unsigned *)(timerreg-1)=period;/*write period to TxPR register */
}
- 6 -

/*---------------------------------------------------------------------------
void Timer_Enable(int timer,int enable)
Enables or disables the GP timer specified in the timer parameter.
Arguments:timer:a value of 1,2 or 3 indicating which GP timer
should enable or disabled
enable:boolsche variable indicating if the function
should start or stop the timer
Note:Function does not initialize the GP timer,nor does it modify
other parameters of the timer,but the TENABLE bit.
----------------------------------------------------------------------------*/

void Timer_Enable(int timer,int enable)


{
int timerreg;
timerreg =0x7404 +((timer-1)<<2);/*get address of TxCON */

/*disable that counter,TENABLE in TxCON */


if (enable)
*(unsigned *)(timerreg)=*(unsigned *)(timerreg)|TIMER_ENABLE;
else
*(unsigned *)(timerreg)=*(unsigned *)(timerreg)&0xffbf;
}

/****************************************************************************
SPWM
*****************************************************************************/

/*---------------------------------------------------------------------------
void SPWM_Init(int spwm,int spwm_type,int timer)
Initializes the simple compare unit specified in the 'spwm'parameter to
use the GP timer as specified in 'timer'parameter.
The simple compare output pin are configured as described in the
'spwm_type'parameter.
Arguments:spwm:a value of 1,2 or 3 indicating which simple
compare unit should be configured
spwm_type:a value of SPWM_TYPE_FORCED_LOW,
SPWM_TYPE_ACTIVE_LOW,SPWM_TYPE_ACTIVE_HIGH or
SPWM_TYPE_FORCED_HIGH describing the desired output
of the simple compare unit outputs
Note:Function does initialize the Simple Compare Unit #spwm.
It does not initialize or enable GP Timer1 #timer.
----------------------------------------------------------------------------*/
- 7 -

void SPWM_Init(int spwm,int spwm_type,int timer)


{
COMCON &=0x7fff;/*disable compare unit */
if (spwm ==1)/*construct SACTR word */
{/*and set the appropriate bits */
SACTR &=0xfffc;
SACTR |=spwm_type;
OCRA |=0x0100;/*enable PWM7/CMP7 of shared IO */
}
if (spwm ==2)
{
SACTR &=0xfff3;
SACTR |=(spwm_type <<2);
Appendix A:TMS320C24x Code for Oversampling
OCRA |=0x0200;/*enable PWM8/CMP8 of shared IO */
}
if (spwm ==3)
{
SACTR &=0xffcf;
SACTR |=(spwm_type <<4);
OCRA |=0x0400;/*enable PWM9/CMP9 of shared IO */
}
if (timer==1)
COMCON &=0xff7f;
else
COMCON |=0x0080;
COMCON |=0x0100;/*enable simple compare unit */
COMCON |=0x8000;/*enable COMPARE unit */
}
/*---------------------------------------------------------------------------
void SPWM_1_Send(unsigned int value)
Sends a value to Simple Compare Unit 1
Arguments:value:the value that should be written into the SCMPR1
register
Note:This function is for the sake of easy readability.
----------------------------------------------------------------------------*/
inline void SPWM_1_Send(unsigned int value)
{
SCMPR1 =value;
}
/*---------------------------------------------------------------------------
void SPWM_2_Send(unsigned int value)
Sends a value to Simple Compare Unit 2.dito as SPWM_1_Send()
----------------------------------------------------------------------------*/
inline void SPWM_2_Send(unsigned int value)
{
SCMPR2 =value;
}
/*---------------------------------------------------------------------------
void SPWM_3_Send(unsigned int value)
Sends a value to Simple Compare Unit 3.dito as SPWM_1_Send()
----------------------------------------------------------------------------*/
inline void SPWM_3_Send(unsigned int value)
{
SCMPR3 =value;
}
- 8 -

/****************************************************************************
ADC
*****************************************************************************/
/*---------------------------------------------------------------------------
void ADC_Init(int channel,int mode)
Initializes the ADC Module,by setting the required registers to sample
a certain channel and to use a GP timer to trigger the sample event.
If required (channel 0 or 1)the function activates the shared GPIOx/ADCINx
signal lines to use the ADCIN0 and ADCIN1 respectively.
The function expects SYSCLK to run at 10MHz.
The function will initialize the Event Module to generate the trigger impulse
for ADC1 by calling the InitADC_TriggerMode(int timer)function.
Arguments:channel:ADC is programmed to use this channel as input
channel valid range is 0..7 for ADC1 and
channel 8..15 for ADC2.
mode:describes the mode the ADC uses to trigger a new
conversion.
valid modes are:
ADC_TRIGGER_CONTINOUS
ADC_TRIGGER_GP_TIMER1
ADC_TRIGGER_GP_TIMER2
ADC_TRIGGER_GP_TIMER3
ADC_TRIGGER_EXTERNAL
----------------------------------------------------------------------------*/
void ADC_Init(int channel,int mode)
{
switch (channel)
{
case 0:OCRA |=0x0001;/*activate muxed ADCIN0 */
break;
case 1:OCRA |=0x0002;/*activate muxed ADCIN1 */
break;
case 9:OCRA |=0x0004;/*activate muxed ADCIN9 */
break;
case 8:OCRA |=0x0008;/*activate muxed ADCIN8 */
break;
}
if (mode ==ADC_TRIGGER_CONTINOUS)
{
ADCTRL1 =0x0400;/*continous mode */
ADCTRL2 =0x0003;/*Prescaler =10 */
return;
}
if (mode ==ADC_TRIGGER_EXTERNAL)
{
ADCTRL1 =0x0000;
ADCTRL2 =0x0203;/*Prescaler =10 */
OCRB |=0x0001;/*activate pin as ADCSOC */
return;
}
/*prepare ADC Control Registers for Event Manager triggered conversion */
ADCTRL1 =0x0000;/*non continous mode */
ADCTRL2 =0x0403;/*Prescaler=10,event manager triggers conversion */
/*configure timer to generate interrupt on compare */
ADC_InitTriggerMode(mode);
return;
}
/*---------------------------------------------------------------------------
void ADC_InitTriggerMode(int mode)
Initializes the Event Manager Module,by setting the required registers
to derive the ADC's trigger events from the GP timer compare interrupt.
Arguments:mode:a value of ADC_TRIGGER_GP_TIMER1/2/3 indicates
which GP timer should be used to trigger ADC
conversion
Following modes are already handled in ADC_1_Init:
- 9 -

ADC_TRIGGER_CONTINOUS
a value of ADC_TRIGGER_CONTINOUS indicates that
the ADC should run continously
ADC_TRIGGER_EXTERNAL
a value of ADC_TRIGGER_EXTERNAL indicates that
the ADC should be triggered on external events
Note:Function does not initialize the GP timer,this should be
performed in advance.However,the timer is stopped
temporarily,but restored to the previous value on exit.
----------------------------------------------------------------------------*/
void ADC_InitTriggerMode(int mode)
{
unsigned int txcon;
if (mode ==ADC_TRIGGER_GP_TIMER1)
{
txcon =T1CON;/*save T1CON */
T1CON &=0xffbf;/*clear TENABLE in T1CON =disable timer */
GPTCON &=0xfe7f;/*clear bit 7-8 in GPTCON */
GPTCON |=0x0100;/*set bit 8 =1 (=period i-flag)*/
T1CON =txcon;/*restore T1CON again */
return;
}
if (mode ==ADC_TRIGGER_GP_TIMER2)
{
txcon =T2CON;/*save T2CON */
T2CON &=0xffbf;/*clear TENABLE in T2CON =disable timer */
GPTCON &=0xf9ff;/*clear bit 9-10 in GPTCON */
GPTCON |=0x0400;/*set bit 10 =1 (=period i-flag)*/
T2CON =txcon;/*restore T2CON again */
return;
}
if (mode ==ADC_TRIGGER_GP_TIMER3)
{
txcon =T3CON;/*save T3CON */
T3CON &=0xffbf;/*clear TENABLE in T3CON =disable timer */
GPTCON &=0xe7ff;/*clear bit 11-12 in GPTCON */
GPTCON |=0x1000;/*set bit 12 =1 (=period i-flag)*/
T3CON =txcon;/*restore T3CON again */
return;
}
}
/*---------------------------------------------------------------------------
void ADC_Enable(int channel,int enable)
Enables or disables the ADC1 and ADC2 respectively,depending on the
channels passed in the 'channel'argument.
Arguments:channel:a value between 0 and 15 specifing the
channels 1-16
0-7 accesses ADC1
8-15 accesses ADC2
enable:TRUE or FALSE to enable or disable the
appropriate ADC
----------------------------------------------------------------------------*/
- 10 -

void ADC_Enable(int channel,int enable)


{
if (channel <8)/*ADC1 */
{
ADCTRL1 &=0xfff1;/*mask off bits */
ADCTRL1 |=(channel<<1);/*select ADC channel */
if (enable)
ADCTRL1 |=0x0800;/*enables ADC1 */
else
ADCTRL1 &=0xf7ff;/*disable ADC1 */
}
else
{
ADCTRL1 &=0xff8f;/*mask off bits */
ADCTRL1 |=((channel-8)<<4);/*select ADC channel */
if (enable)
ADCTRL1 |=0x1000;/*enables ADC2 */
else
ADCTRL1 &=0xefff;/*disable ADC2 */
}
}
/*---------------------------------------------------------------------------
int ADC1_read()
Reads out the FIFO of the ADC1 by checking the interrupt flag.
If ADC is not valid returns 0xffff.
----------------------------------------------------------------------------*/
int ADC1_read()
{
unsigned int temp =0xffff;
if(ADCTRL1 &0x0100)
{
ADCTRL1 |=0x0100;
temp =ADCFIFO1;
}
return(temp);
}
/*---------------------------------------------------------------------------
int ADC2_read()
Reads out the FIFO of the ADC2 by checking the interrupt flag.
If ADC is not valid returns 0xffff.
----------------------------------------------------------------------------*/
int ADC2_read()
{
volatile unsigned int temp=0xffff;
if(ADCTRL2 &0x0100 )
{
ADCTRL2 |=0x0100;
temp =ADCFIFO2;
}
return(temp);
}
- 11 -