|
|
View previous topic :: View next topic |
Author |
Message |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
SPI generates only 1 interrupt |
Posted: Mon Jan 28, 2008 8:51 am |
|
|
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
|
|
Posted: Mon Jan 28, 2008 9:23 am |
|
|
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
|
|
Posted: Mon Jan 28, 2008 9:32 am |
|
|
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
|
|
Posted: Tue Jan 29, 2008 3:09 am |
|
|
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
|
|
Posted: Tue Jan 29, 2008 6:15 am |
|
|
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
|
|
Posted: Tue Jan 29, 2008 6:34 am |
|
|
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
|
|
Posted: Wed Jan 30, 2008 7:41 pm |
|
|
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. |
|
|
|
|
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
|