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

dsPIC33 SPI Interrupt

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



Joined: 06 May 2013
Posts: 33
Location: Toronto

View user's profile Send private message

dsPIC33 SPI Interrupt
PostPosted: Fri Jun 08, 2018 12:20 pm     Reply with quote

Hi All,

I am working on a project where LabVIEW RIO is communicating with dsPIC33 over SPI. It works fine, but sometimes dsPIC33 stops responding. I checked with RealICE, its going into the SPI interrupt but not executing properly. Below is the code. Any suggestions


Code:
#include <33FJ256GP710A.h>
#fuses XT,NOWDT,NOPROTECT
#device ADC = 12
#use delay(clock = 100MHz, crystal = 40MHz)
#use spi(SLAVE, SPI2, BITS = 8, MODE = 1, ENABLE = PIN_G9, stream = SPI_2)


/******************************************************************************/
// ADC Parameters
// Alpha = 0.1611328125 = 660/4096 ; 660 is maximum temperature value; 5mV/ 1C change
float Alpha = 0.1611328125;
/******************************************************************************/
// PID Parameters//
float C_out = 0, M_Variable = 0, Error = 0,  Previous_Error;
float FC_out = 0, FM_Variable = 0, FError = 0,  FPrevious_Error;
float dt = 0.01,  DTM, Kp = 10, Ki = 0.5, Kd = 2, Integral = 11, Derivative = 0;
float FKp = 10, FKi = 0.5, FKd = 2, FIntegral = 11, FDerivative = 0;
/******************************************************************************/

int8 SPI_Flag = 0, Byte_Count = 0, Rx, Tx, Cmand, ProbeID = 1,count = 0;
unsigned int8 Version = 2,SP = 0, SP_H = 0, FSP = 0, FSP_H = 0;
unsigned int Value, Duty = 0, FDuty = 0, Err_cnt = 0, ViewFMV, ViewMV, Set_Point, FSet_Point, Old_SP;
unsigned char MV = 0, MVH = 0,  FMVH = 0, FMV = 10;

float Flange;
/******************************************************************************/
// 8 bits SPI
#INT_SPI2 level = 7

void spi2_slave_isr(void)
{
  Rx = spi_xfer_in(SPI_2, 8);
  Byte_Count++;
 
  switch(Byte_Count)
            {
            case 1:
                spi_prewrite(Version);
                if(Cmand == 1)
                    spi_prewrite(0);
                else if(Cmand == 2)
                    spi_prewrite(0);
                break;
     
            case 2:
                Cmand = Rx;
                if(Cmand == 1)
                    spi_prewrite(MV);
                else if(Cmand == 3)
                        spi_prewrite(ProbeID);
                else if(Cmand == 5)
                    spi_prewrite(FMV);               
                break;
           
            case 3:
                 
                if(Cmand == 1)
                {SP_H = Rx;
                    spi_prewrite(MVH);}
                else if(Cmand == 3)
                   spi_prewrite(0);
                else if(Cmand == 5)
                    {FSP_H = Rx;
                    spi_prewrite(FMVH);}
                break;     
           
           
            case 4:
                Byte_Count = 0;           
                if(Cmand == 1)
                    SP = Rx;
                else if(Cmand == 3)
                    spi_prewrite(50);
                else if(Cmand == 5)
                    FSP = Rx;
                break;
               
            default:
                Byte_Count = 0;
                break;
            }

}

#INT_TIMER1
void  timer1_isr(void)
{
    M_Variable= ((float)read_adc() * Alpha) - 4;  // 4 is the offset
    FM_Variable = ((float)read_adc2() * Alpha);
    Error = Set_Point - M_Variable;
    if(Old_SP != Set_Point || Integral < 0)
            Integral = 0;

    Old_SP = Set_Point;
    if(Error < 10)
    Integral = Integral + (Error * dt);
}

void main()
{   
   output_float(PIN_G9); // SS as an input
   setup_adc_ports(sAN0, VSS_VDD);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);
   
   setup_adc_ports2(sAN2, VSS_VDD);
   setup_adc2(ADC_CLOCK_INTERNAL);
   set_adc_channel2(2);
   
   // Timer 1 for 10 ms INT when clock is 100MHz
   setup_timer1(TMR_INTERNAL | TMR_DIV_BY_64, 7812);

   
   setup_timer2(TMR_INTERNAL | TMR_DIV_BY_64, 500);
   setup_compare(2, COMPARE_PWM | COMPARE_TIMER2);
   set_pwm_duty(2,0);
   
   setup_compare(3, COMPARE_PWM | COMPARE_TIMER2);
   set_pwm_duty(3,0);
   
   
   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_SPI2);
   enable_interrupts(INTR_GLOBAL);
   
   DTM = 1/dt;
 
   while(1)
    {
       
      if(SP_H)
         Set_Point =  (float)SP + 256;
      else
         Set_Point = (float)SP;
     
        if(FSP_H)
            FSet_Point =  (float)FSP + 256;
        else
            FSet_Point = (float)FSP;
     
      Value = (unsigned int16)M_Variable;
      ViewMV = Value;
      MV  = (unsigned char)Value;
      MVH = Value >> 8;
     

     Value = (unsigned int16)FM_Variable;
     ViewFMV = Value;
     FMV = (unsigned char)Value;
     FMVH = Value >> 8;

     FError = FSet_Point - FM_Variable;

      C_out = (Kp * Error) + (Ki * Integral);
      FC_out = (FKp * FError);
     
      if(C_out > 500)
          C_out = 500;
      else if(C_out < 0)
          C_out = 0;
     
      if(FC_out > 500)
          FC_out = 500;
      else if(FC_out < 0)
          FC_out = 0;
       
        Duty = (int)C_out;
        set_pwm_duty(2,Duty);
       
        FDuty = (int)FC_out;
        set_pwm_duty(3,FDuty);

    }
}   
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Fri Jun 08, 2018 12:31 pm     Reply with quote

There are a lot of cases where it won't do a spi_prewrite.
Also some where it'll try to do two prewrites. Since a second byte has not been clocked in, another can't be loaded. I'd suspect these are the ones causing problems.
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jun 08, 2018 12:32 pm     Reply with quote

couple of comments though I don't use that PIC...

1) Using floats inside any ISR is ALWAYS 'bad news'...
2) I don't know how long an spi_prewrite(xx) takes but I'd dump the listing to see. Again ISRs are meant to be small and fast.

Other who use that PIC wll see other things....
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Fri Jun 08, 2018 2:33 pm     Reply with quote

spi_prewrite is an efficient operation. It just loads the buffer register, ready for the next master read.
jeremiah



Joined: 20 Jul 2010
Posts: 1345

View user's profile Send private message

PostPosted: Sat Jun 09, 2018 7:05 am     Reply with quote

Just a question for the OP:

I see in case 1 you read the value of Cmand, but where is it initialized to a value prior to the usage in the interrupt? Are there any situations where you can get into case 1 and Cmand could be random data?

I see your declaration up top, but I honestly don't remember if chained declarations like that infer the same default value?
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Jun 11, 2018 5:25 am     Reply with quote

also.... Rx is never initalised and Cmand can be Rx, so another possible random act.

Actually aside from 'case 2' where cmand=rx, I didn't see where cmand is set to anything.
Maybe it's the blurry green on my screen, early here !

Also, is the adc_clock_internal legal for the 33 series PICs ? something to confirm....

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Mon Jun 11, 2018 8:56 am     Reply with quote

Yes ADC_CLOCK_INTERNAL s OK for the DsPIC's.
There are so many 'random' things in the code that I'm surprised it works at all..... :(
Post what the master actually sends, and what it expects to receive.
tripper269



Joined: 06 May 2013
Posts: 33
Location: Toronto

View user's profile Send private message

PostPosted: Tue Jun 12, 2018 10:30 am     Reply with quote

Master sends 4 bytes, to set temperature and read back temperature.To send more than 255, it makes one byte as 1, which means its 255 +. Master code is written in LabVIEW, and its very big program. There are two dsPIC33, one with only SPI interrupt and this one which has ADC and SPI interrupt. Other one is working fine.
tripper269



Joined: 06 May 2013
Posts: 33
Location: Toronto

View user's profile Send private message

PostPosted: Tue Jun 12, 2018 10:38 am     Reply with quote

And, when SPI stops responding, Byte_Count also stops at one value. Which is usually between 1 - 3.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Tue Jun 12, 2018 11:21 am     Reply with quote

Thing that worries me particularly is the double prewrite.
Think about it. This routine is called every time a byte is transferred. You load two bytes on the arrival of some bytes, so now there is more in the transmit buffer than the bytes being received. Next time the routine is called, this could get worse. I'd be checking the SPI port status bits and see if OERR gets set.
It'd really be much safer to only ever load one byte when a byte is received. Set a flag to say 'more to send', load the first byte, and then on the next call send the second byte.
tripper269



Joined: 06 May 2013
Posts: 33
Location: Toronto

View user's profile Send private message

PostPosted: Tue Jun 12, 2018 1:57 pm     Reply with quote

If i disable Timer1 interrupt, it works fine. I checked all run time SFRs using Real ICE, for ex - IFS2, SPI2BUF, SPI2CON1, SPI2CON2, SPI2STAT, INTCON1, INTCON2 and IEC0 - 2. When error state generated, no SFR change it value.
Ttelmah



Joined: 11 Mar 2010
Posts: 19499

View user's profile Send private message

PostPosted: Wed Jun 13, 2018 11:40 am     Reply with quote

Problem is that the timer1 interrupt is taking a very long time. Floats in an interrupt. Ugh. because it is in this interrupt, it then misses a SPI interrupt.

Ideally get rid of the use of floats in the timer interrupt. However raise the priority of the SPI interrupt so it can occur even when the timer interrupt is triggered.
You have it set to level7, which should work.
I'd suggest increasing the stack size. Remember if you have an interrupt call inside another interrupt it requires a _lot_ of stack. I'd suspect you have a stack overflow, when you get an SPI interrupt inside a timer interrupt.
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