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 support@ccsinfo.com

SPI generates only 1 interrupt

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



Joined: 28 Aug 2007
Posts: 106

View user's profile Send private message

SPI generates only 1 interrupt
PostPosted: Mon Jan 28, 2008 8:51 am     Reply with quote

Hello,

following problem: with activated SPI interrupt there is only 1 intrerrupt after the complete datainput ( byte 1 + byte 2). Datasheet and a college with an other compiler says there has to be 2 interrupt: 1 after first byte(command) and 1 after second byte(data).
Whats my error? herer is the code:
I want to give only the first byte to the RS232 interface


Code:

#include <18F87J60.h>

#fuses HS,NOWDT,NOPROTECT,DEBUG,NOETHLED

#use delay(clock=25000000)
#use rs232 (UART1, stream=UART1, BAUD=115200, ERRORS)

#USE STANDARD_IO (A)
#USE STANDARD_IO (B)
#USE STANDARD_IO (C)

#define NOP   #asm NOP #endasm;


#define        CS                       PIN_B0
#define        CLK                      PIN_C3
#define        DATA_IN                   PIN_C4
#define        DATA_OUT               PIN_C5
#define        DATA_LED               PIN_C2                     

short   GELESEN;

//int      DAT_EINGANG;
int      AUSGANG_1;
int      AUSGANG_2;

long    i;
long    x;

int      array[1024];


#INT_SSP
void SPI_int()
   {
   ++i;
   array[i] = spi_read2 ();

   output_high(DATA_LED);
   output_low(DATA_LED);
   }   



void main()
   {
   SETUP_SPI(SPI_SLAVE);


//   EXT_INT_EDGE(L_TO_H);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);
   //enable_interrupts(INT_EXT);
   GELESEN = 0;
   i = 0;
   x = 0;

   for(;;)
      {
      if (i > 1023)
            {
            disable_interrupts(GLOBAL);
            AUSGANG_1 = array[x] & 0x0F;
            AUSGANG_2 = array[x] & 0xF0;
            ++x;
            AUSGANG_2 = AUSGANG_2 >> 4;
            if (AUSGANG_2 > 9)
               AUSGANG_2 = AUSGANG_2 + 7;
            if (AUSGANG_1 > 9)
               AUSGANG_1 = AUSGANG_1 + 7;
            fputc( (AUSGANG_1 + 0x30), UART1);
            fputc( (AUSGANG_2 + 0x30), UART1);
            fputc( 0x0D, UART1);
            fputc( 0x0A, UART1);
            while (x == 1023)
               {
               NOP;
               }
            }



      }//   for(;;)

   }//main
Ttelmah
Guest







PostPosted: Mon Jan 28, 2008 9:23 am     Reply with quote

Er.
You are setting up the INT_SSP (primary SPI), but reading the byte from the secondary (spi_read2), which your chip doesn't have (the 87J50, has two SPI ports for example.
Use SPI_read, not spi_read2. I'd not be suprised if reading from the wrong port, was stopping the handler from working properly.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Jan 28, 2008 9:32 am     Reply with quote

Code:
#INT_SSP
void SPI_int()
   {
   ++i;
   array[i] = spi_read2 ();
There seems to be a conflict between the SPI interrupt you handle and the SPI port you are reading: #INT_SSP is for port 1 but you are reading the data with spi_read2() which if for port2. Your setup_spi() call is also for port 1, or did you mean to use setup_spi2() for port 2?

Another problem is you are increasing i before assigning the value to array, this way you start at array[1] and array[0] is never used.


Code:
#use rs232 (UART1, stream=UART1, BAUD=115200, ERRORS)
To avoid confusion it is best to add the Rx and Tx pin numbers as well (I didn't know it would compile without these numbers).


Code:
   SETUP_SPI(SPI_SLAVE);
This definition is incomplete, you also have to specify which of the four possible SPI modes you want to use. Now it defaults to:
Code:
   SETUP_SPI(SPI_SLAVE | SPI_L_TO_H);
but in a new compiler version this could be changed and it would take you forever to find the error.
A translation table for the four SPI modes to CCS notation can be found at http://www.ccsinfo.com/forum/viewtopic.php?t=32040&start=5
richi-d



Joined: 28 Aug 2007
Posts: 106

View user's profile Send private message

PostPosted: Tue Jan 29, 2008 3:09 am     Reply with quote

Oh, this was my last test with:
array[i] = spi_read2 ();


All tests before has been with the right:

array[i] = spi_read ();


The RS232 work fine - no problems. The Data I receive over SPI is also right, but I don´t get 2 interrupts...


Also: | SPI_H_TO_L) this add changes the SPI SLAVE to a master- it seem that there is a error in the CCS. Have a look to the SSP1CON1 register...
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Jan 29, 2008 6:15 am     Reply with quote

Quote:
Also: | SPI_H_TO_L) this add changes the SPI SLAVE to a master- it seem that there is a error in the CCS. Have a look to the SSP1CON1 register...
I said your code is the same as SPI_L_TO_H not SPI_H_TO_L. Both master and slave should have the same spi_mode parameters (except for master/slave ofcourse).
What is your compiler version number?

How do you know you get only 1 interrupt?

Did you fix the error of array[0] never being used? In reading the array you use x starting at 0 but when filling the array ++i is performed one line too early, effectively starting at 1.
richi-d



Joined: 28 Aug 2007
Posts: 106

View user's profile Send private message

PostPosted: Tue Jan 29, 2008 6:34 am     Reply with quote

It doesn´t matter if the array[0] is not written- I simple put it out via RS232 in a list. But I changed it.
I see that only 1 interrupt is generated because I can measure it with the oscilloskope at Pin DATA_LED
But i figured out the problem: the interrupt handler is to slow. The first interrupt is generated when the second byte already came in. So the second interrupt can´t occur because the controller is still in the first interrupt routine.
If I delete the lines:
array[i] = spi_read ();
++i;

I can see 2 interrupts but with a very long delay. The result is: I only get the first byte to read, I can´t read the second byte!

I have a very fast SPI device, and it seems that CCS is too slow with his standard modules.
We wrote the test programm with another compiler and it works...

So my question: how can I make the CCS routine faster? The controller is running with 25MHz!

Code:
#include <18F87J60.h>

#fuses HS,NOWDT,NOPROTECT,DEBUG,NOETHLED

#use delay(clock=25000000)
#use rs232 (UART1, stream=UART1, BAUD=57600, XMIT=PIN_C6, RCV=PIN_C7, ERRORS)

#USE STANDARD_IO (A)
#USE STANDARD_IO (B)
#USE STANDARD_IO (C)
#USE STANDARD_IO (D)
#USE STANDARD_IO (E)
#USE STANDARD_IO (F)
#USE STANDARD_IO (G)
#USE STANDARD_IO (H)
#USE STANDARD_IO (J)

#define NOP   #asm NOP #endasm;


#define        CS                       PIN_B0
#define        DATA_LED               PIN_C2                     

short   GELESEN;

int      AUSGANG_1;
int      AUSGANG_2;

long    i;
long    x;

int      array[1024];


#INT_SSP
void SPI_int()
   {
   array[i] = spi_read ();
   ++i;

   output_high(DATA_LED);
   output_low(DATA_LED);

   }   



void main()
   {
   SETUP_ADC_PORTS(NO_ANALOGS);
   SETUP_comparator(NC_NC_NC_NC);
   SETUP_SPI(SPI_SLAVE);

   enable_interrupts(GLOBAL);
   enable_interrupts(INT_SSP);

   i = 0;
   x = 0;

   for(;;)
      {
      if (i >= 1023)
            {
            disable_interrupts(GLOBAL);
            AUSGANG_1 = array[x] & 0x0F;
            AUSGANG_2 = array[x] & 0xF0;
            ++x;
            AUSGANG_2 = AUSGANG_2 >> 4;
            if (AUSGANG_2 > 9)
               AUSGANG_2 = AUSGANG_2 + 7;
            if (AUSGANG_1 > 9)
               AUSGANG_1 = AUSGANG_1 + 7;
            fputc( (AUSGANG_2 + 0x30), UART1);
            fputc( (AUSGANG_1 + 0x30), UART1);
            fputc( 0x0D, UART1);
            fputc( 0x0A, UART1);
            while (x == 1023)
               {
               NOP;
               }
            }

      }//   for(;;)

   }//main
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Jan 30, 2008 7:41 pm     Reply with quote

You didn't mention your compiler version so I can't verify your remark of the spi_setup() function being wrong.

The CCS compiler makes it very easy to create an interrupt routine but this universal approach comes at the cost of a larger overhead. The compiler saves every possible register you could change in the interrupt and restores the registers on interrupt exit. Depending on the number of registers in your processor the overhead can be in the range 40 to 80 instructions.

My guess is that your interrupt routine including the interrupt overhead takes about 80 instructions. You can measure this yourself in the MPLAB simulator. At 25 MHz this means a maximum of 78,125 bytes per second, or 625,000 bits per second on the SPI bus.

The only way to minimize the CCS interrupt handling overhead is by writing your own interrupt handler. For this the CCS compiler provides two methods:
1) #int_global: This gives you a bare entry point for the interrupt routine. You are in full control but have also the responsibility of saving and restoring all registers you touch. Easy to implement when you have only one short interrupt routine but becomes more complex when you have multiple interrupts.
2) A high priority interrupt, only available on PIC18 processors and higher. Confusingly there are two keywords for the high priority interrupt: HIGH for a high priority where the compiler is saving/restoring the registers, and FAST where this is your responsibility. The FAST keyword is the one you want to use. Requires the definition of HIGH_INTS=TRUE. Not very well supported by the compiler, only one FAST interrupt is allowed in a program. Like in option 1) you are responsible for saving and restoring all registers you touch. Advantages of the FAST interrupt are that you can mix it with other normal interrupts (where the compiler does the register saving/restoring) and it has higher priority so it can interrupt an already active 'normal' interrupt.


I don't have time now, but if you want to I can post example code for the FAST interrupt, this is the most difficult but also fastest interrupt handler. My guess is it will take about 10 instructions to handle your 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