|
|
View previous topic :: View next topic |
Author |
Message |
tripper269
Joined: 06 May 2013 Posts: 33 Location: Toronto
|
dsPIC33 SPI Interrupt |
Posted: Fri Jun 08, 2018 12:20 pm |
|
|
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: 19552
|
|
Posted: Fri Jun 08, 2018 12:31 pm |
|
|
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: 9246 Location: Greensville,Ontario
|
|
Posted: Fri Jun 08, 2018 12:32 pm |
|
|
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: 19552
|
|
Posted: Fri Jun 08, 2018 2:33 pm |
|
|
spi_prewrite is an efficient operation. It just loads the buffer register, ready for the next master read. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Sat Jun 09, 2018 7:05 am |
|
|
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: 9246 Location: Greensville,Ontario
|
|
Posted: Mon Jun 11, 2018 5:25 am |
|
|
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: 19552
|
|
Posted: Mon Jun 11, 2018 8:56 am |
|
|
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
|
|
Posted: Tue Jun 12, 2018 10:30 am |
|
|
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
|
|
Posted: Tue Jun 12, 2018 10:38 am |
|
|
And, when SPI stops responding, Byte_Count also stops at one value. Which is usually between 1 - 3. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Jun 12, 2018 11:21 am |
|
|
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
|
|
Posted: Tue Jun 12, 2018 1:57 pm |
|
|
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: 19552
|
|
Posted: Wed Jun 13, 2018 11:40 am |
|
|
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. |
|
|
|
|
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
|