CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Not enough RAM for a 368byte PIC, but ok for a 192byte PIC ?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
John_Lintern



Joined: 30 Sep 2004
Posts: 14

View user's profile Send private message Send e-mail

Not enough RAM for a 368byte PIC, but ok for a 192byte PIC ?
PostPosted: Fri May 13, 2005 7:01 am     Reply with quote

I am using,

- a PIC16F874A which has 192 bytes of RAM
- a PIC16F877A which has 368 bytes of RAM

The PIC16F877A is the same as the PIC16F874A but has twice the amount of ROM and EEPROM and almost twice as much RAM.

I am using MPLAB ICE2000 to emulate these PICS, with the PCM16XV0 processor module.

When I try to compile my program for the 192 byte PIC16F874A, it compiles fine.

But when I try to compile my program for a the 368 byte PIC16F877A, it comes up with an error saying "Not enough RAM" ! ??

This doesn't make any sense because the PIC16F877A has almost twice the RAM of the PIC16F874A.

I need to use the PIC16F877A because I'm starting to run out of ROM on the PIC16F874A and Ive got more code to add yet.

The PIC16F877A has twice as much program memory so is ideal, but even though it has nearly twice as much RAM it wont compile because of the "Not enough RAM" error.

How can this be ????????

It makes no sense what so ever ??????

Code:

//************************** Inculde Files ***********************************//
#include <16F874A.h>
#device adc=8
#use delay(clock=20000000)
#fuses NOWDT,HS, PUT, NOPROTECT, NODEBUG, NOLVP, NOCPD, NOWRT, BROWNOUT
#use rs232(baud=38400,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)


#include <stdlib.h>
const long CCP1_Interrupt = 65216;  // this value gives a 104.35ms with a clock speed of 20MHz and a prescale of 8.
                                    // it is used to capture the TMR0 value used to count the pulses for RPM speed measurement.

//*************************** Definitions ************************************//
#define PID_Min_Limit 0         // Minimum value of PID output
#define PID_Max_Limit 255      // Maximum value of PID output

#define a_err_Min_Limit -255    // Minimum error limit for accumlative error (a_error)
#define a_err_Max_Limit 255    // Maximum error limit for accumlative error (a_error)

#define PWM_WRT PIN_E0         // PWM Controller WR pin low
#define PWM_SEL PIN_E1        // PWM Controller SEL pin high
#define PWM_RST PIN_E2         // PWM Controller RST pin low

#define RPM_Scaler 25         // Value RPM counter is multiplied by
#define RPM_SEL PIN_C2         // RPM source select

#define TESTPOINT_0   PIN_B0   // Used for debugging - test point 0 on evaluation board
#define TESTPOINT_1   PIN_B1   // Used for debugging - test point 1 on evaluation board
#define TESTPOINT_2   PIN_B2   // Used for debugging - test point 2 on evaluation board
#define OD_SWITCH      PIN_B5   // Used for debugging - use switch to toggle overdrive output

#define LOCKUP       PIN_C0   // Lockup output
#define OVERDRIVE    PIN_C1   // Overdrive output
#define WARNLAMP       PIN_C3   // Warning Lamp output
#define SPEEDDIAG      PIN_C4   // Speed Sensor Diagnosis (for CS1124)

//******************************* TRS Sensor *********************************//
// The values for the TRS Sensor are shown in the table below.                  //
//                                                                              //
//   A tolerance of +/-10 will be used on the ADC value to allow for errors.      //
//                                                                              //
// Position      Resistance   Voltage   ADC Value   ADC Range                     //
// Park          522.2         4.20      214         204 - 224                     //
// Reverse       206.2         3.37      171         161 - 181                     //
// Neutral       108.6         2.60      132         122 - 142                     //
// Drive       59.9         1.87      95            85 - 105                        //
// 2nd          31.9         1.21      61            51 - 71                        //
// 1st          13.7         0.60      30            20 - 40                        //
//                                                                              //
//****************************************************************************//
#define ParkMin       204
#define ParkMax       224
#define ReverseMin    161
#define ReverseMax    181
#define NeutralMin    122
#define NeutralMax    142
#define DriveMin       85
#define DriveMax       105
#define SecondMin    51
#define SecondMax    71
#define FirstMin       20
#define FirstMax       40
#define Park          0
#define Reverse       1
#define Neutral       2
#define Drive          3
#define Second       4
#define First          5

#define FIRSTGEAR      0
#define SECONDGEAR   1
#define THIRDGEAR      2
#define FOURTHGEAR   3

#define CalibIdle         0
#define CalibSetDuty      1
#define CalibReadOffset   2

#define MAXRPM 6000
#define MAXPRESSURE 100

//***************************** Debugging ************************************//
//#define DEBUG_RPM               // use to measure sample time duration - test point 0
//#define DEBUG_RPM_RS232         // send RPM to RS232 port
//#define DEBUG_PID               // use to measure duration and frequency of PID routine - test point 1
//#define DEBUG_PID_RS232         // send PID results to RS232 port
//#define DEBUG_a_error            // use to measure duration and frequency of a_error - test point 2
//#define DEBUG_d_error            // use to measure duration and frequency of d_error - test point 3
//#define DEBUG_ADC_RS232         // send ADC values to RS232 port
//#define DEBUG_TRS_RS232         // send Transmission Range Sensor position to RS232 port
//#define DEBUG_RPMSHIFT_RS232   // send Shift RPM to RS232 port
//#define DEBUG_PWM_CONTROL      // manually control the IDX610 PWM Device
//#define DEBUG_PIDPOT           // use the pot to control the PID setpoint
//#define DEBUG_PWM_POT_CONTROL   // use the pot to control the PWM duty cycle
//#define DEBUG_OD               // use switch to toggle overdrive output
#define DEBUG_SEND_PRESSURE_PORTB// sends 8-bit value of actual pressure to PORT B
#define PID_Neg_Feedback         // uses negative feedback for the PID control loop (undefine for positive feedback)
//#define DEBUG_PRESSURECALC_RS232   // sends the cacucated pressure to RS232 port
//************************** Global Variables ********************************//
unsigned int RPM_Output=0;         //
unsigned int RPM_Input=0;         //
unsigned int RPM_Capture=0;      //
int1 RPM_Select=0;               //
int1 RPMREADY=0;                  // set RPM_Select to flag output speed

signed int16 error=0;            // difference between the setpoint and measured output; error can range from -32,768 to +32,767
signed int16 a_error=0;          // accumulative error which is the sum of all past errors; a_error can range from -32,768 to +32,767
signed int16 p_error=0;          // previous error which is the value of the last error; p_error can range from -32,768 to +32,767
signed int16 d_error=0;          // derivative error which is the difference between error and p_error; d_error can range from -32,768 to +32,767

signed int16 prop_term=0;          // calculation of proportional term;  prop_term can range from -32,768 to +32,767
signed int16 integ_term=0;       // calculation of integral term; integ_term can range from -32,768 to +32,767
signed int16 deriv_term=0;       // calculation of derivative term; deriv_term can range from -32,768 to +32,767

// Kp,Ki & Kd are 8-bit vlaues that cannot exceed 255. Enter the PID gains scaled by a factor of 16 (i.e. default is 10x16)
unsigned int kp=0x60;             // proportional gain, default of 160, max=15 (16 levels)
unsigned int ki=0x20;             // integral gain, default of 160, max=15 (16 levels)
unsigned int kd=0x20;             // derivative gain, default of 160, max=15 (16 levels)

unsigned int PIDSetpoint;
unsigned int PIDFeedback;


unsigned int DerivValue=10;       // value for derivative term (derivative action = CCP2 interrupt * DerivValue)
unsigned int DerivCounter;       // counter for derivative term (derivative action = CCP2 interrupt * DerivValue)
unsigned int SCALE_FACTOR=0x10;    // Scaling factor of PID Output

unsigned int16 CCP2_Interrupt = 37500; // this value gives a 60ms interrupt with a clock speed of 20MHz and a prescale of 8.
                                       // it is used to calculate the a_error and d_error for the PID routine.

unsigned int Pressure_Sensor;       // ADC measurement of Pressure Sensor
unsigned int Pressure_PSI;
unsigned int Pressure_Required;
unsigned int Pressure_Offset=16;   // ADC measurement of Pressure sensor Zero Offset (must be between 0.315V [ADC 16] to 0.585V [ADC 30]; default to 0.315V)

unsigned int TPS;                  // ADC measurement of Throttle Position Sensor
unsigned int OILTEMP;              // ADC measurement of Oil Temperature Sensor
unsigned int TRS;                  // ADC measurement of Transmission Range Sensor

signed int16 PID_Result=0;          // calculation of PID output;  PID_Result can range from -32,768 to +32,767

unsigned int TRS_Mode;             // mode of Transmission Range Sensor (P,R,N,D,2,1)
int GEAR=FIRSTGEAR;
int UpShift_RPM=0;
int DownShift_RPM=0;
int ShiftPressure[3] = {20,40,60};   // setpoint pressures for first, second and third gear (in PSI)

unsigned int16 Timer2Counter=0;
int Calib_Mode=0;
int1 Timer2Running=0;
int1 PressureCalib=0;

int TPSPercent;

//************************ VMC Control Variables *****************************//
int r=0;
char RxBuffer[10];
int1 VMC_RECEIVED=FALSE;

int VMC_PWM;
int1 VMC_PWM_Flag=FALSE;
int1 VMC_PID_Flag=FALSE;

int1 VMC_ODFlag=FALSE;
int VMC_Overdrive;

int1 VMC_LUFlag=FALSE;
int VMC_Lockup;

//*************************** Shift Schedule *********************************//
int ShiftSched_1to2[2][4] = {{20,20,52,52},            // Co-ordinates work out as, (x)   500rpm   500rpm   1300rpm   1300rpm
                               {0,25,127,255}};         //                             (y)   0%         10%      50%      100%

int ShiftSched_2to3[2][4] = {{50,50,92,92},            // Co-ordinates work out as, (x)   1250rpm   1250rpm   2300rpm   2300rpm
                               {0,38,138,255}};         //                             (y)   0%         15%      54%      100%

int ShiftSched_3to4[2][4] = {{92,92,188,188},         // Co-ordinates work out as, (x)   2300rpm   2300rpm   4700rpm   4700rpm
                             {0,71,84,255}};            //                             (y)   0%         28%      33%      100%

int ShiftSched_4to3[2][4] = {{68,92,180,180},         // Co-ordinates work out as, (x)   1700rpm   2300rpm   4500rpm   4500rpm
                               {0,66,120,255}};         //                             (y)   0%         26%      47%      100%

int ShiftSched_3to2[2][4] = {{16,16,60,60},            // Co-ordinates work out as, (x)   400rpm   400rpm   1500rpm   1500rpm
                               {0,51,133,255}};         //                             (y)   0%         20%      52%      100%

int ShiftSched_2to1[2][4] = {{12,12,28,28},            // Co-ordinates work out as, (x)   300rpm   300rpm   700rpm   700rpm
                                {0,132,132,255}};         //                             (y)   0%         52%      52%      100%

//*************************** Shift Pressures ********************************//
// Co-ordinates work out as   (x)   0%      10%    20%     30%      40%    50%     60%      70%    80%     90%      100%
//                              (y)   5psi  10psi  15psi  25psi  30psi  40psi  45psi  45psi  65psi  80psi  80 psi
//                              (y)   5psi  10psi  15psi  25psi  30psi  40psi  45psi  45psi  65psi  80psi  80 psi
//                              (y)   5psi  10psi  15psi  25psi  30psi  40psi  45psi  45psi  65psi  80psi  80 psi
BYTE CONST GearPressures[4][11] =   {{0,26,51,77,102,128,153,179,204,230,255},
                                      {0,0,0,5,5,10,5,5,30,40,35},         // first gear
                                    {5,5,10,10,15,15,20,15,40,45,45},   // second gear
                                    {5,10,15,25,30,40,45,45,65,80,80}};   // third gear

//***************************** Functions ************************************//
void Get_TRS(void); // function to read Transmission Range Sensor
int ShiftSchedule(int ShiftSched[2][4]); // function to determine the upshift and downshift RPM
void SendPWMControl(int CONTROL); // function to write control data to PWM Controller
void SendPWMDuty(int DUTY); // function to write PWM Duty Cycle to PWM Controller
void SendPIDConfig(void);
void CalPressureSensor(void);
void CalcPIDSetpoint(void);
int CalcPressure(void); // function to calculate the require pressure
int ProcArray(*int, int);
//************************* RS232 Receive Interrupt **************************//
#int_RDA
RDA_isr()
{
   if ((RxBuffer[r++]=getchar())== '\r')
   {
      RxBuffer[--r]=0;
      r=0;
      VMC_RECEIVED=TRUE;
   }
output_low(PIN_E0);
}

//************************** CCP1 Interrupt **********************************//
#int_CCP1
CCP1_isr()
{
   RPM_Capture=get_timer0();                              // store Timer0 in variable Timer0_Capture
   CCP_1 += CCP1_Interrupt;                                 // add sample time (CCP1_Interrupt) to compare register (CCPR1) for next compare interrupt
   if (RPM_Select==0)                                    // check status of which speed source is selected, input speed (1) or output speed (0)?
   {                                                      // ---> Output speed is selected
                                                         #ifdef DEBUG_RPM
                                                            output_high (TESTPOINT_0);  // use to measure sample time duration
                                                         #endif
   output_high (RPM_SEL);                                 // set speed source to input speed
   RPM_Output = RPM_Capture;                               // store RPM value
   RPM_Select=1;                                          // set RPM_Select to flag input speed
   }
   else
   {                                                      // ---> Input speed is selected
                                                         #ifdef DEBUG_RPM
                                                            output_low (TESTPOINT_0);    // use to measure sample time duration
                                                         #endif
   output_low (RPM_SEL);                                 // set speed source to output speed
   RPM_Input = RPM_Capture;                               // store RPM value
   RPM_Select=0;                                          // set RPM_Select to flag output speed
   }
   set_timer0(0);                                          // reset the Timer0
   RPMREADY=1;
}



//********************* Update a_error and d_error ***************************//
#int_CCP2
CCP2_isr()
{
   CCP_2 += CCP2_Interrupt;                     // add sample time (CCP2_Interrupt) to compare register (CCPR2) for next compare interrupt
                                                         #ifdef DEBUG_a_error
                                                            if(bit_test(*6,2))
                                                            {
                                                              output_low (TESTPOINT_2);
                                                            }
                                                            else
                                                            {
                                                              output_high (TESTPOINT_2);
                                                            }
                                                            //   output_high (TESTPOINT_2); // use to measure duration and frequency of a_error
                                                         #endif
   if(error!=0)
   {                                         // if error is not zero....
     a_error=error+a_error;                  // calculate the accumulated error
        if (a_error < a_err_Min_Limit)         // is a_error less than the minimum limit ?
      {
       a_error=a_err_Min_Limit;                // YES ----> set a_error to the minimum limit
      }
      if (a_error > a_err_Max_Limit)         // is a_error greater than maximum limit ?
      {
       a_error=a_err_Max_Limit;                // YES ----> set a_error to the maximum limit
      }
     DerivCounter--;                         // decrement DerivCounter
     if(DerivCounter==0)                      // has DerivCounter reached zero ?
     {
                                                         #ifdef DEBUG_d_error
                                                            if(bit_test(*6,3))
                                                            {
                                                              output_low (TESTPOINT_3);
                                                            }
                                                            else
                                                            {
                                                              output_high (TESTPOINT_3);
                                                            }
                                                            //output_high (TESTPOINT_3); // use to measure duration and frequency of d_error
                                                         #endif
      d_error = (error - p_error);             // subtract the previous error from the current error
      p_error = error;                       // store the current error in previous error for next time round
        DerivCounter=DerivValue;               // restore DerivCounter for next delta error
                                                         #ifdef DEBUG_d_error
                                                            //output_high (TESTPOINT_3); // use to measure duration and frequency of d_error
                                                         #endif
     }
   }
                                                         #ifdef DEBUG_a_error
                                                            //output_low (TESTPOINT_2); // use to measure duration and frequency of a_error
                                                         #endif
}

#int_TIMER2
TIMER2_isr()
{
   Timer2Counter--;                           // decrement timer counter
   if (!Timer2Counter)                        // has timer counter reached zero ?
   {
      Timer2Running=FALSE;                     // YES -> clear flag Timer2Running to indicate the timer has finished
      disable_interrupts(INT_TIMER2);         // disable timer2 interrupts
   }
}

#rom 0x2100={1,2,3,4}
#define TempArray 0x2104
#rom TempArray={1,2,3,4,5,6,7,8}

//**************************** Main Program **********************************//
void main()
{
#ifndef 16C74B
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
#endif
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
     setup_counters(RTCC_EXT_H_TO_L,RTCC_DIV_1);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   setup_timer_2(T2_DIV_BY_16,241,13);
   CCP_1 = CCP1_Interrupt;         // Load compare (CCPR1) with default sample time CCP1_Interrupt
   CCP_2 = CCP2_Interrupt;         // Load compare (CCPR2) with default sample time CCP2_Interrupt
   DerivCounter=DerivValue;
   set_tris_A(0b11111111);         // set PORTA as inputs
   port_b_pullups(FALSE);
   set_tris_B(0b00000000);         // set PORTB bits as outputs
   set_tris_C(0b10000000);         // set PORTC bits 0 to 6 as outputs and bit 7 as an input
   set_tris_D(0b00000000);         // set PORTD as outputs for the databus on the PWM IC
   set_tris_E(0b00000000);         // set PORTE bits 0, 1 and 2 as outputs to control PWM IC
   output_D(0b00000000);           // set PWM Controller databus to zero
   output_high(PWM_WRT);         // set PWM Controller WRT pin high
   output_high(PWM_SEL);           // set PWM Controller SEL pin high
   output_high(PWM_RST);         // set PWM Controller RST pin high
   setup_adc_ports(A_ANALOG);    // set PORTA bits 0,1,2 and 3 as analogue inputs for the ADC
   setup_adc(ADC_CLOCK_INTERNAL);// set the ADC to run off the internal clock
   set_adc_channel(0);            // ADC set to look at channel 0

   output_high(PWM_RST);         // reset PWM Controller
   output_low(PWM_RST);            // reset PWM Controller
   output_high(PWM_RST);         // reset PWM Controller

   output_high (RPM_SEL);         // set speed source to output speed
   output_low (LOCKUP);            // set Lockup Solenoid off
   output_low (OVERDRIVE);         // set Overdrive Solenoid off
   output_high (WARNLAMP);         // set Warning Lamp off
   output_low (SPEEDDIAG);         // set Speed Sensor Diagnosis to off

   SendPWMControl(0b11000000);   // deadtime 0, control not locked, divide by 1, 8-bit resolution, output disabled
   SendPWMDuty(0x00);             // start with a 0% duty cycle

   set_timer0(0);                // Reset timer0 - used to count pulses for input and output speed
   set_timer1(0);                // Reset timer1 - used for two compare interrupts: CCP1 for speed measurement sample time: CCP2 for PID a_error and d_error
   set_timer2(0);                // Reset timer2 - used as 10ms interrupt for time delays
   disable_interrupts(INT_TIMER2);
   enable_interrupts(INT_RDA);   // enable RS232 receive data interrupt
   setup_ccp1(CCP_COMPARE_INT);   // interrupt used to capture the TMR0 vaule which counts pulses to calculate the output speed.
   setup_ccp2(CCP_COMPARE_INT);   // interrupt used to calculate the a_error and d_error for the PID routine.
   enable_interrupts(INT_CCP1);   // enable interrupt to capture the TMR0 value used to count the pulses for RPM speed measurement.
   enable_interrupts(INT_CCP2);   // enable interrupt to calculate the a_error and d_error for the PID routine.
   enable_interrupts(GLOBAL);      // enable all global interrupts

                                                         #ifdef DEBUG_PWM_CONTROL   // define this to manually control the IDX610 PWM Device
                                                            do
                                                            {
                                                            output_low(PWM_SEL);    // set SEL pin low to write data to pulse width register
                                                            output_low(PWM_WRT);     // set WRT pin low to prepare to write data (set 'breakpoint' on this line & manually change Port D value)
                                                            output_high(PWM_WRT);    // set WRT pin high to write data on the low-to-high transition
                                                            }
                                                            while(TRUE);
                                                         #endif

   Pressure_Required = ShiftPressure[0];         // set pressure setpoint to first gear
   do
   {
//************************** Read ADC Inputs *********************************//
                                                         #ifdef DEBUG_OD
                                                            output_bit(OVERDRIVE,!input(OD_SWITCH));
                                                         #endif
   set_adc_channel(0);                           // ADC set to look at channel 0
   delay_us(100);                                 // wait a short time after changing the channel to get a valid read
   Pressure_Sensor=read_adc();                  // read ADC input from pressure sensor
   if (Pressure_Sensor<Pressure_Offset)         // ensure the pressure sensor does not fall below the zero pressure offset voltage (should never happen)
   {
      Pressure_Sensor=Pressure_Offset;         // if it does make the pressure sensor equal to the zero pressure offset voltage
   }
   Pressure_PSI=(Pressure_Sensor-Pressure_Offset)/2.04;     // calculate pressure in psi using transfer function of sensor
                                                            //  i.e. PSI=(Sensor[ADC value] - Offset[ADC value]) ÷ 2.04
                                                         #ifdef DEBUG_SEND_PRESSURE_PORTB
                                                            output_B(Pressure_Sensor);
                                                         #endif
   set_adc_channel(1);                           // ADC set to look at channel 1
   delay_us(100);                               // wait a short time after changing the channel to get a valid read
    TPS=read_adc();                              // read value of Throttle Position Sensor

   set_adc_channel(2);                           // ADC set to look at channel 2
   delay_us(100);                               // wait a short time after changing the channel to get a valid read
   OILTEMP=read_adc();                           // read value of Transmission Oil Temperature
                                                // 0°C  = 1.6V (ADC value of 82) to 1.7V (ADC value of 87)
                                                // 10°C = 1.7V (ADC value of 87) to 1.8V (ADC value of 92)

                                                         #ifdef DEBUG_PWM_POT_CONTROL   // define this to manually control the IDX610 PWM Device
                                                            output_D(TPS);               // place data on databus
                                                            output_low(PWM_SEL);         // set SEL pin low to write data to pulse width register
                                                            output_low(PWM_WRT);         // set WRT pin low to prepare to write data
                                                            output_high(PWM_WRT);      // set WRT pin high to write data on the low-to-high transition
                                                         #endif
                                                         #ifndef DEBUG_PWM_POT_CONTROL
   CalPressureSensor();                     // calibrate the pressure sensor (if calibration conditions exist)
                                                         #endif
   Get_TRS();                              // determine the position of the Transmission Range Sensor
//************************ Act on TRS Position *******************************//
if(!VMC_PID_Flag)                                             // is VMC PID control is in use ?
{
   switch (TRS_Mode)                                          // NO ---> find required governor pressures
   {
   case Park:
      Pressure_Required=0;
      break;
   case Reverse:
      Pressure_Required=0;
      break;
   case Neutral:
      Pressure_Required=0;
      break;
   case Second:
      Pressure_Required=0;
      break;
   case First:
      Pressure_Required=0;
      break;

   case Drive:
      Pressure_Required=CalcPressure();
                                                         #ifdef DEBUG_PRESSURECALC_RS232
                                                            TPSPercent=(((float)TPS/255)*100);
                                                            printf("Pressure = %03U\t Throttle (ADC) = %03U\t",Pressure_Required,TPS);
                                                            printf("Throttle (%%) = %03U\t Current Gear = %03U\r",TPSPercent,GEAR+1);
                                                         #endif
   //**************** Determine Up Shift and Down Shift RPM ******************//
      switch (GEAR)
      {
      case FIRSTGEAR:
         UpShift_RPM=ShiftSchedule(ShiftSched_1to2);      // determine the upshift rpm when in 1st gear
         break;
      case SECONDGEAR:
         UpShift_RPM=ShiftSchedule(ShiftSched_2to3);      // determine the upshift rpm when in 2nd gear
         DownShift_RPM=ShiftSchedule(ShiftSched_2to1);   // determine the downshift rpm when in 2nd gear
         break;
      case THIRDGEAR:
         UpShift_RPM=ShiftSchedule(ShiftSched_3to4);      // determine the upshift rpm when in 3rd gear
         DownShift_RPM=ShiftSchedule(ShiftSched_3to2);   // determine the downshift rpm when in 3rd gear
         break;
      case FOURTHGEAR:
         DownShift_RPM=ShiftSchedule(ShiftSched_4to3);   // determine the downshift rpm when in 4th gear
         break;
      default:
         break;
      }                                                   // end parenthesis switch (GEAR)
   //****** If RPM rises above Up Shift threshold then change up a gear ******//
      if (GEAR!=FOURTHGEAR)
      {
         if (RPM_Output > UpShift_RPM)
         {
            GEAR++;
            if (GEAR==FOURTHGEAR)                  // is current gear in fourth (i.e. overdrive) ?
            {
               if (!VMC_ODFlag)                     // is VMC overdrive control not in use ?
               {
                  output_high (OVERDRIVE);         // set Overdrive Solenoid off
               }
            }
            else
            {
               Pressure_Required=ShiftPressure[GEAR];   // required pressure used as the PID setpoint
            }
         }
      }
   //**** If RPM falls below Down Shift threshold then change down a gear ****//
      if (GEAR!=FIRSTGEAR)
      {
         if (RPM_Output < DownShift_RPM)
         {
            if (GEAR==FOURTHGEAR)                  // is current gear in fourth (i.e. overdrive)
            {
               if (!VMC_ODFlag)                     // is VMC overdrive control not in use ?
               {
                  output_low (OVERDRIVE);            // set Overdrive Solenoid on
               }
            }
            GEAR--;
            Pressure_Required=ShiftPressure[GEAR];   // required pressure used as the PID setpoint
         }
      }
   break;
   default:
   break;
   }                                                // end parenthesis switch (TRS_Mode)
}                                                   // end parenthesis of if(!VMC_PID_Flag)
                                                           #ifdef DEBUG_RPMSHIFT_RS232
                                                            printf ("Gear=%U\tRPM=%03U\tUpShift=%03U\tDownShift=%03U\tTPS=%03U\r",GEAR+1,RPM_output,UpShift_RPM,DownShift_RPM,TPS);
                                                         #endif

                                                         #ifdef DEBUG_ADC_RS232
                                                            PRINTF("Pressure=%4.1f psi\t Offset=%03U\t TPS=%03U\t Oiltemp=%03U\t TRS=%03U\t \r",Pressure_PSI,Pressure_Offset,TPS,OILTEMP,TRS); // send ADC values to RS232 port
                                                         #endif

//**************************** PID Routine ***********************************//

   CalcPIDSetpoint();

   #ifdef PID_Neg_Feedback                        // define type of feedback used for the PID control
      error=(int16)PIDSetpoint-Pressure_Sensor;   // negative feedback
   #else
      error=(int16)Pressure_Sensor-PIDSetpoint;   // positive feedback
   #endif

   if(!VMC_PWM_Flag)                        // if VMC PWM control is not active then allow PID control
   {
      if ((error)&&(!PressureCalib))      // if error is not zero and pressure calibration is not active
      {                                    // then allow PID control
                                                         #ifdef DEBUG_PID
                                                            output_high (TESTPOINT_1); // use to measure duration and frequency of PID routine
                                                         #endif
      disable_interrupts(GLOBAL);         // disable all interrupts whilst calculating the PID term
      prop_term=error*kp;                 // calculate the proportional term
      integ_term=a_error*ki;              // calculate the integral term
      deriv_term=d_error*kd;              // calculate the derivative term
        PID_Result=((prop_term + integ_term + deriv_term)/SCALE_FACTOR);  // calculate the PID calculation
         if (PID_Result < PID_Min_Limit)  // is the result less than the minimum limit ?
         {
           PID_Result=PID_Min_Limit;      // YES ----> return the minimum limit
         }
         if (PID_Result > PID_Max_Limit)  // is the result greater than maximum limit ?
         {
           PID_Result=PID_Max_Limit;      // YES ----> return the maximum limit
         }
      SendPWMDuty(PID_Result);             // send PID result as the duty cycle for the PWM device
      enable_interrupts(GLOBAL);            // enable all global interrupts
                                                         #ifdef DEBUG_PID
                                                            output_low (TESTPOINT_1); // use to measure duration and frequency of PID routine
                                                         #endif
      }
   }
   else
   {
      PID_Result=VMC_PWM;                  // use VMC PWM value as PID Result
      SendPWMDuty(PID_Result);             // send PID result as the duty cycle for the PWM device
   }

                                                         #ifdef DEBUG_PID
                                                            output_low (TESTPOINT_1); // use to measure duration and frequency of PID routine
                                                         #endif

                                                         #ifdef DEBUG_PID_RS232
                                                            printf ("%03ld\t %03ld\t %03ld\t %03ld\t %03U\n\r",error,a_error,d_error,PID_Result,Pressure_PSI);      // send PID results to RS232 port (takes 5-6ms at 38400 baud)
                                                         #endif
//****************************************************************************//
                                                         #ifdef DEBUG_RPM_RS232
                                                            if (RPMREADY)
                                                            {
                                                            PRINTF("Output=%04lu\t Input=%04lu\r",(int16)RPM_Output * RPM_Scaler,(int16)RPM_Input * RPM_Scaler); // send RPM to RS232 port
                                                            RPMREADY=0;
                                                            }
                                                         #endif
   }
   while(TRUE);
}


//***********************************************************************//
// Function: Get_TRS                                                       //
// Overview: This routine will read the ADC value for the Transmission   //
//             Range Sensor and set the necessary mode, P,R,N,D,2 or 1       //
// Input:    -                                                           //
// Output:    -                                                             //
//***********************************************************************//
void Get_TRS(void)
{
   set_adc_channel(3);                     // ADC set to look at channel 3
   delay_us(100);                         // wait a short time after changing the channel to get a valid read
   TRS=read_adc();                        // read value of Transmission Range Sensor
   if ((TRS>=ParkMin)&&(TRS<=ParkMax))
   {
   TRS_Mode=Park;
   }
   if ((TRS>=ReverseMin)&&(TRS<=ReverseMax))
   {
   TRS_Mode=Reverse;
   }
   if ((TRS>=NeutralMin)&&(TRS<=NeutralMax))
   {
   TRS_Mode=Neutral;
   }
   if ((TRS>=DriveMin)&&(TRS<=DriveMax))
   {
   TRS_Mode=Drive;
   }
   if ((TRS>=SecondMin)&&(TRS<=SecondMax))
   {
   TRS_Mode=Second;
   }
   if ((TRS>=FirstMin)&&(TRS<=FirstMax))
   {
   TRS_Mode=First;
   }
                                                         #ifdef DEBUG_TRS_RS232
                                                            printf ("%02U\r",TRS_Mode);      // send TRS to RS232 port
                                                         #endif
}

//****************************************************************************//
// Function: CalPressureSensor                                                   //
// Input:    -                                                                 //
// Output:    -                                                                   //
// Description:                                                                //
// The governor pressure sensor will be affected by environmental changes as    //
// well as manufacturing tolerances.                                          //
//                                                                            //
// Although the transfer function will remain constant, there could be an       //
// offset variation due to barometric pressure and temperature change.  This    //
// requires a calibration procedure to measure the offset.                     //
//                                                                            //
// The sensor will be calibrated by measuring the offset when the governor    //
// pressure is at zero psi.                                                   //
//                                                                            //
// The calibration will only be performed when the following conditions exist://
//                                                                            //
//    • the transmission oil temperature is above 10°C (50°F)                  //
//    • the output speed falls below 200 rpm                                    //
//                                                                            //
// The calibration procedure works by providing the governor pressure          //
// solenoid with a 95% duty cycle for 500ms, the governor pressure sensor is    //
// then measured and this value is used as the offset value. The calibration   //
// procedure is repeated every 3 seconds under the above conditions.            //
//                                                                            //
// The pressure sensor has the following transfer function...                  //
//    Voltage = (0.04 * Pressure) + Offset                                    //
//      where Offset will be from 0.315V to 0.585V (with a supply voltage of 5V)//
//                                                                            //
// Therefore...                                                               //
//      Pressure = (Voltage - Offset) ÷ 0.04                                    //
//      where Offset will be from 0.315V to 0.585V (with a supply voltage of 5V)//
//                                                                            //
// The values in this equation are with a 5V supply, so as the ADC value will   //
// be 255 at 5V, the values in the equation must be scaled by 51 (i.e.255÷5)   //
// The equation becomes...                                                      //
//                                                                            //
//      Pressure = (Pressure_Sensor - Pressure_Offset) ÷ 2.04                        //
//      where Offset will be from 16 to 30 (with a supply voltage of 5V)         //
//****************************************************************************//
void CalPressureSensor(void)
{
   if (!VMC_PWM_Flag)                           // is VMC PWM Control not in use ?
   {
      if ((RPM_Output<8)&&(OILTEMP>87))         // is the output speed less than 200 rpm and the oil temp greater than 10°C ?
      {
      if (!Timer2Running)                        // YES---> is Timer2 running ?
      {
         PressureCalib=TRUE;                     // NO---> set flag PressureCalib as an indication not to use the PID control
         switch (Calib_Mode)
         {
            case CalibIdle:
               SendPWMDuty(0);                   // set duty cycle to 0%
               Timer2Counter=300;               // load counter with 300 (counter increments every 10ms, so 300 counts = 3sec)
               Timer2Running=TRUE;               // set flag Timer2Running to indicate the timer is running
               set_timer2(0);                   // Reset timer2 - used as 10ms interrupt to increment counter (Timer2Counter)
               enable_interrupts(INT_TIMER2);   // enable timer2 interrupt
               Calib_Mode=CalibSetDuty;         // set Calib_Mode to indicate the duty cycle must be set next
               break;

            case CalibSetDuty:
               SendPWMDuty(243);                // set duty cycle to 95% (243/256 = 95%)
               Timer2Counter=50;                  // load counter with 50 (counter increments every 10ms, so 50 counts = 500ms)
               Timer2Running=TRUE;               // set flag Timer2Running to indicate the timer is running
               set_timer2(0);                   // Reset timer2 - used as 10ms interrupt for time delays
               enable_interrupts(INT_TIMER2);   // enable timer2 interrupt
               Calib_Mode=CalibReadOffset;      // set Calib_Mode to indicate the offset must be read next
               break;

            case CalibReadOffset:
               set_adc_channel(0);               // ADC set to look at channel 0
               delay_us(100);                   // wait a short time after changing the channel to get a valid read
               Pressure_Offset=read_adc();      // read value of Pressure sensor
               SendPWMDuty(0);                   // set duty cycle to 0%
               if ((Pressure_Offset>=16)&&(Pressure_Offset<=30))   // is zero pressure offset voltage between 0.313V [ADC 16] and 0.585V [ADC 30] ?
               {
                     output_high (WARNLAMP);      // turn off warning lamp to indicate zero pressure calibration was within range
               }
               else
               {
                  if (Pressure_Offset<16)         // is zero pressure offset voltage less than 0.313V [ADC 16]
                  {
                     Pressure_Offset=16;         // limit the zero pressure offset to 0.315V [ADC 16]
                     output_low (WARNLAMP);      // turn on warning lamp to indicate there was a fault with the zero pressure calibration (offset voltage too low)
                  }
                  if (Pressure_Offset>30)         // is zero pressure offset voltage greater than 0.585V [ADC 30]
                  {
                     Pressure_Offset=30;         // limit the zero pressure offset to 0.585V [ADC 30]
                     output_low (WARNLAMP);      // turn on warning lamp to indicate there was a fault with the zero pressure calibration (offset voltage too high)
                  }
               }
               Calib_Mode=CalibIdle;            // set Calib_Mode to indicate that calibration has finished and not in progress
               break;
               default:
               break;
         }                                       // end parenthesis of switch statement
      }                                          // end parenthesis of if (Timer2Running)
      }                                          // end parenthesis of if ((RPM_Output<8)&&(OILTEMP>87)) statement
      else
      {
         PressureCalib=FALSE;                     // set flag PressureCalib as an indication to use the PID control
         Calib_Mode=CalibIdle;                  // set Calib_Mode to indicate that calibration is no longer in progress
      }
   }                                             // end parenthesis of if (VMC_PWM_Flag!=TRUE) statement
}                                                // end parenthesis of function CalPressureSensor


//***********************************************************************//
// Function: ShiftSchedule                                                 //
// Overview: This routine will determine which shift schedule should be  //
//             used from the sensors TRS, TPS and OILTEMP.                    //
// Input:    -                                                           //
// Output:    -                                                             //
//***********************************************************************//
int ShiftSchedule(int ShiftSched[2][4])
{
int x,temp;
float grad;

       for(x=0 ; x<3 ; x++)
        {
            if ((TPS>=ShiftSched[1][x])&&(TPS<=ShiftSched[1][x+1]))
            {
               if ((ShiftSched[0][x])==(ShiftSched[0][x+1]))
               {
                  return (ShiftSched[0][x]);
                  break;
               }
               else
               {
                  grad= ((float)TPS-(float)(ShiftSched[1][x])) / ((float)(ShiftSched[1][x+1])-(float)(ShiftSched[1][x]));
                  temp=((((ShiftSched[0][x+1])-(ShiftSched[0][x])) * grad) + ShiftSched[0][x]);
                  return ((((ShiftSched[0][x+1])-(ShiftSched[0][x])) * grad) + ShiftSched[0][x]);
                  break;
               }
            }
       }
                                                         #ifdef DEBUG_RPMSHIFT_RS232
                                                            printf ("ShiftRPM=%02U\t TPS=%03U\r",UpShift_RPM,TPS);      // send UpShift_RPM to RS232 port
                                                         #endif
}


//***********************************************************************//
// Function: SendPWMDuty                                                   //
// Overview: This routine will send a duty cycle to the PWM controller.  //
// Input:    DUTY                                                        //
// Output:    -                                                             //
//***********************************************************************//
void SendPWMDuty(int DUTY)
{
   output_low(PWM_SEL);     // set SEL pin low to write data to pulse width register
   output_low(PWM_WRT);     // set WRT pin low to prepare to write data
   output_D(DUTY);          // place data on databus
   output_high(PWM_WRT);    // set WRT pin high to write data on the low-to-high transition
}


//***********************************************************************//
// Function: SendPWMControl                                                //
// Overview: This routine will send the control word to the PWM          //
//           controller (IXDP610).                                       //
// Input:    CONTROL                                                     //
// Output:    -                                                             //
//Bit    Name  Description                                               //
//bit 0  DT0   for setting the dead-time period                          //
//bit 1  DT1   0 is no dead-time delay and 7 is maximum dead-time.       //
//bit 2  DT2                                                             //
//bit 3        not used, reserved; always write a zero to this bit       //
//bit 4  Lock  setting this bit prevents further access to all bits in   //
//             the Control latch, except the Stop bit.                   //
//bit 5  DIV   determines frequency of the internal PWM clock.           //
//bit 6  7/8   chooses between 7-bit and 8-bit resolution.               //
//bit 7  Stop  disables (turns off) the complementary outputs.           //
//***********************************************************************//
void SendPWMControl(int CONTROL)
{
   output_high(PWM_SEL);    // set SEL pin high to write data to control register
   output_low(PWM_WRT);     // set WRT pin low to prepare to write data
   output_D(CONTROL);       // place data on databus
   output_high(PWM_WRT);    // set WRT pin high to write data on the low-to-high transition
}


//***********************************************************************//
// Function: SendPIDConfig                                                 //
// Overview:
// Input:    -                                                           //
// Output:    -                                                             //
//***********************************************************************//
void SendPIDConfig(void)
{
      printf ("%02X%02X%02X%04LX%02X%02X%02X%02X%02X\r",kp,ki,kd,CCP2_Interrupt,DerivValue,Pressure_Required,VMC_PID_Flag,Pressure_Offset,PIDSetpoint);
}



//***********************************************************************//
// Function: CalcPressure                                                  //
// Overview: This routine will determine the governor pressure which     //
//             changes depending on Throttle Position.                        //
// Input:    -                                                           //
// Output:    -                                                             //
//***********************************************************************//
int CalcPressure()
{
int x;
float grad;

       for(x=0 ; x<10 ; x++)
        {
            if ((TPS>=GearPressures[0][x])&&(TPS<=GearPressures[0][x+1]))
            {
               if ((GearPressures[1+GEAR][x])==(GearPressures[1+GEAR][x+1]))
               {
                  return (GearPressures[1+GEAR][x]);
                  break;
               }
               else
               {
                  grad= ((float)TPS-(float)(GearPressures[0][x])) / ((float)(GearPressures[0][x+1])-(float)(GearPressures[0][x]));
                  if((GearPressures[1+GEAR][x+1])>=(GearPressures[1+GEAR][x]))
                  {
                     return ((((GearPressures[1+GEAR][x+1])-(GearPressures[1+GEAR][x])) * grad) + GearPressures[1+GEAR][x]);
                  }
                  else
                  {
                     return (GearPressures[1+GEAR][x]-(((GearPressures[1+GEAR][x])-(GearPressures[1+GEAR][x+1])) * grad));
                  }
                  break;
               }
            }
       }
                                                         #ifdef DEBUG_RPMSHIFT_RS232
                                                            printf ("ShiftRPM=%02U\t TPS=%03U\r",UpShift_RPM,TPS);      // send UpShift_RPM to RS232 port
                                                         #endif
}

//***********************************************************************//
// Function: SendPIDConfig                                                 //
// Overview:
// Input:    -                                                           //
// Output:    -                                                             //
//***********************************************************************//
void CalcPIDSetpoint(void)
{
   PIDSetpoint=(Pressure_Required*2.04)+Pressure_Offset;     // make PID setpoint equal to the required pressure (given in psi) which is then converted to an ADC value, including the offset pressure
}


rwyoung



Joined: 12 Nov 2003
Posts: 563
Location: Lawrence, KS USA

View user's profile Send private message Send e-mail

PostPosted: Fri May 13, 2005 7:16 am     Reply with quote

Code:
#device *=16 adc=8
instead of
Code:
#device adc=8
"fixes" the issue. That is to say, the program compiles.

This is a bit odd though...

Email CCS support and let them chew on the problem too.

FYI, I tested with PCWH 3.224. Always give your compiler revision when posting.
_________________
Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month!
Ttelmah
Guest







PostPosted: Fri May 13, 2005 7:47 am     Reply with quote

There is nothing 'odd' about this behaviour at all.
Without the *=16, you are only using the low two RAM banks on the chips, not the full area. On the 874, the banks are 'normal', but on the 876, the top 16bytes of the second bank, are duplicates of the top 16bytes on the first bank.
So the 874, has 96*2 bytes available in the bottom two banks, but the 877, only has 96+80 bytes available in the same area.
Without *=16, this is the total RAM available to the program, with the bigger chip having 16bytes less memory accessible in this mode.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group