|
|
View previous topic :: View next topic |
Author |
Message |
FoxtrotMike
Joined: 31 May 2007 Posts: 11
|
Trouble with SPI!!! |
Posted: Tue Jul 29, 2008 2:04 pm |
|
|
Hi:
·I'm having a weird problem with SPI communication. I've got a PIC as a transmitter in slave mode; it sends a fixed string thru SPI. The master receives the SPI data and sends it to a PC via USART, in this case just to check if the SPI is being received alright. Problem is, when using SPI_L_TO_H, it works just fine. But when i changed it to SPI_H_TO_L, the output is wrong. Actually, the data looks misaligned to the clock (i'm looking it with an oscilloscope). For example:
*If i send periodically 86 (01010110), what i get in my terminal is
172 (10101100).
*If i send periodically 240 (11110000), what i get in my terminal is
225 (01111000).
·It's as if the bytes are shifted in one bit, that's what it looks like when looking at the scope.
·The code for the slave:
Code: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=2400, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
//////////////////
// DEFINICIONES //
//////////////////
#define nop delay_cycles(1)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
////////////////////
// INTERRUPCIONES //
////////////////////
#int_timer2
void timer2_isr(void)
{
int16 ctr;
ctr++;
if(ctr==620)
{
output_toggle(PIN_C2);
ctr = 0;
nop;
}
}
#int_rda
void UART_isr(void)
{
putc(getc());
}
//////////////////////
// RUTINA PRINCIPAL //
//////////////////////
void main(void)
{
int i;
char string[32] = "Simulador TX Serial Sincrónica";
setup_timer_2(T2_DIV_BY_16, 130, 1);
setup_spi(SPI_SLAVE|SPI_MODE_2|SPI_SS_DISABLED);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1)
{
//String que se repite periódicamente
i = 0;
while(string[i]!=0)
{
spi_write(string[i]);
i++;
}
//spi_write(0xF0);
//CR LF
spi_write(0x0D);
spi_write(0x0A);
}
}
|
·The code for the master:
Code: |
#include <18F252.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=20000000)
#use rs232(baud=2400, parity=N, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
//////////////////
// DEFINICIONES //
//////////////////
#define nop delay_cycles(1)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#byte PORTB = 0x0F81
////////////////////////
// VARIABLES GLOBALES //
////////////////////////
int data;
int changes = 0, last_b = 0b10000000;
short RTS = 0;
short SPI = 0;
////////////////////
// INTERRUPCIONES //
////////////////////
#INT_RB
void portb_isr(void)
{
changes = last_b ^ PORTB;
last_b = PORTB;
//Canto de bajada en PIN_B7 (baja a 0 V)
if (bit_test(changes,7)&& !bit_test(last_b,7))
RTS = 1;
//Canto de subida en PIN_B7 (sube a 5 V)
if (bit_test(changes,7)&& bit_test(last_b,7))
RTS = 0;
//Debouncer
delay_us(100);
}
#INT_TIMER2
void timer2_isr(void)
{
int16 ctr;
ctr++;
if(ctr == 1250)
{
output_toggle(PIN_C2);
ctr = 0;
}
}
#INT_SSP
void SPI_isr(void)
{
if(spi_data_is_in())
SPI = 1;
}
////////////////
// PROTOTIPOS //
////////////////
int fix(int data);
//////////////////////
// RUTINA PRINCIPAL //
//////////////////////
void main(void)
{
data = 225;
data = fix(data); //should be 240
data = 172;
data = fix(data); //should be 86
setup_timer_2(T2_DIV_BY_16, 130, 1);
setup_spi(SPI_MASTER|SPI_MODE_2|SPI_CLK_T2);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER2);
enable_interrupts(INT_SSP);
while(1)
{
while(RTS)
{
spi_write(0x40);
if(SPI)
{
data = spi_read();
putc(fix(data));
SPI = 0;
}
}
}
}
int fix(int data)
{
int aux;
if(bit_test(data,0))
aux = 0x80;
else
aux = 0;
data >>= 1;
data |= aux;
return(data);
}
|
·The master generates a 1200 Hz clock (i need to interface with a 1200 bps synchronous device). If it receives a high to low signal on pin B7, it generates a clock signal, then sends to the usart the data read thru SPI.
·BTW, the "fix" function is a cheap attempt to undo the shift that the byte suffered. When using SPI_L_TO_H i didn't use it, as it worked alright.
·In both cases i'm using the pin C2 as an "i'm alive!" indicator, specially in the slave.
·Any help will be appreciated, as i'm really confused about what's happening here.
Thanks in advance!! |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Jul 30, 2008 8:06 am |
|
|
It sounds like you have the wrong SPI_MODE, i.e. you are sampling on the wrong clock edge. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jul 30, 2008 5:15 pm |
|
|
I agree with SherpaDoug that it sounds like a problem with the SPI mode.
Why are you using the SSP interrupt in the master? In this simple test program the test in main can be replaced by: Code: | if(spi_data_is_in()) | and then the SSP interrupt can be removed.
Hint: add the NOLVP fuse to your program for improved stability. 99% of the people are using a 'high voltage programmer' and with the NOLVP fuse missing the PIC will stall when the LVP pin goes high (static voltage, etc.).
What is your compiler version? |
|
|
FoxtrotMike
Joined: 31 May 2007 Posts: 11
|
|
Posted: Mon Aug 11, 2008 9:35 am |
|
|
Thanks for your help, guys.
*ckielstra: I removed the interrupt, as it really served no purpose. Also, i added a little delay between every spiread() call, and of course, i removed the "fix". It seems to be working now. However, I noticed that between every byte there's a longer clock pulse. It's like there's a small delay between every two bytes received. Something like this (sorry for the crude ASCII "art"):
Code: |
CLK
b1 b2 b8
┌-┐ ┌-┐ ┌--┐ ┌-┐ ┌-┐
-┘ └-┘ └···┘ └-┘ └-┘ └···
^
/_\
Longer ---┘
clock
pulse
|
·Any idea why is this happening? I believe it's disrupting the communication with the slave device, as it's very sensitive to clock drift. |
|
|
Ttelmah Guest
|
|
Posted: Mon Aug 11, 2008 9:48 am |
|
|
The master can't load new data, till the last byte has been sent. This takes time.
SPI, shouldn't have any issues with 'clock drift'. The master generates the clock as it sends the data.
Use
data=spi_read(0x40);
This will remove the need to wait for the byte to be sent, and then check again that the buffer is full to receive the byte.
Best Wishes |
|
|
|
|
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
|