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

how to transmit data in spi slave mode?
Goto page Previous  1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 12987

View user's profile Send private message

PostPosted: Wed Mar 16, 2011 3:13 am     Reply with quote

hayee wrote:
PCM Programmer
Its pin #7 of 18f252. /SS
I have change the hardware from A0 to A5 on slave side, but I am not using that pin in the slave software, so will it work without declaring that pin? Is it necessary to change the pin of master from A0 to A5?

Slave select, is _enabled by default_ on slave devices.
It is possible to run SPI without slave select, _but_ very likely to go wrong, and makes code hard to ensure a resynchronise takes place, if a bit is missed. Your code is currently using SS, and won't work without it....

Best Wishes
hayee



Joined: 05 Sep 2007
Posts: 252

View user's profile Send private message

PostPosted: Wed Mar 16, 2011 4:53 am     Reply with quote

This code is not working
Master
Code:

#include <18f252.h>
#fuses HS,NOWDT,NOLVP,PUT,NOBROWNOUT,protect                               
#use delay(clock=20000000)                               
#use rs232(xmit=PIN_C6, rcv=PIN_C7, baud=9600)

#define SPI_SS PIN_A5

#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)

char c;
int result;

void main()
{
 output_high(SPI_SS);
 
 setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4);
 setup_adc_ports(NO_ANALOGS);

 while(1)
 {
  c=getc();
  c=toupper(c);
 
  switch(c)
  {
   case 'A':
   output_low(SPI_SS);
   spi_write(1);
   output_high(SPI_SS);
   delay_us(100);
   output_low(SPI_SS);
   result=spi_read(0);
   output_high(SPI_SS);
   printf("value =%u\r\n",result);
   break;
   
   case 'B':
   output_low(SPI_SS);
   spi_write(2);
   output_high(SPI_SS);
   delay_us(100);
   output_low(SPI_SS);
   result=spi_read(0);
   output_high(SPI_SS);
   printf("value =%u\r\n",result);
   break;
   
   case 'C':
   output_low(SPI_SS);
   spi_write(3);
   output_high(SPI_SS);
   delay_us(100);
   output_low(SPI_SS);
   result=spi_read(0);
   output_high(SPI_SS);
   printf("value =%u\r\n",result);
   break;
  }
 }
}


Slave

Code:

#include <18f252.h>
#fuses HS,NOWDT,NOLVP,PUT,NOBROWNOUT,protect
#use delay(clock=20000000)             
#use rs232(xmit=PIN_C6, rcv=PIN_C7, baud=9600)

#byte SSPBUF = 0xFC9//register value for 18f252

#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)

int counter;
int buffer;
#int_ssp
void ssp_isr(void)
{
 
 int command;
 
 command=SSPBUF;
 
 switch(command)
 {
  case 1:
  SSPBUF=5;
  break;
 
  case 2:
  SSPBUF=46;
  break;
 
  case 3:
  SSPBUF=12;
  break;
 }
 output_toggle(PIN_C0);
 
}

void main()
{
 setup_spi(SPI_SLAVE | SPI_MODE_0);
 clear_interrupt(INT_SSP);
 enable_interrupts(INT_SSP);
 enable_interrupts(GLOBAL);
 
 while(1)
 {
 
 }
}


But this code is working

Master
Code:

#include <18f252.h>
#fuses HS,NOWDT,NOLVP,PUT,NOBROWNOUT,protect                               
#use delay(clock=20000000)                               
#use rs232(xmit=PIN_C6, rcv=PIN_C7, baud=9600)

#define SPI_SS PIN_A5

#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)

int counter;

void main()
{
 output_high(SPI_SS);
 
 setup_spi(SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_4);
 setup_adc_ports(NO_ANALOGS);

 while(1)
 {
  counter++;
  output_low(SPI_SS);
  spi_write(counter);
  output_high(SPI_SS);
  delay_ms(2000);
 
 }
}


Slave
Code:

#include <18f252.h>
#fuses HS,NOWDT,NOLVP,PUT,NOBROWNOUT,protect
#use delay(clock=20000000)             
#use rs232(xmit=PIN_C6, rcv=PIN_C7, baud=9600)

//#byte SSPBUF = 0xFC9//register value for 18f252

#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)

int counter;
int buffer;
#int_ssp
void ssp_isr(void)
{
 
 buffer=spi_read();
 output_toggle(PIN_C0);
 
}

void main()
{
 setup_spi(SPI_SLAVE | SPI_MODE_0);
 clear_interrupt(INT_SSP);
 enable_interrupts(INT_SSP);
 enable_interrupts(GLOBAL);
 
 while(1)
 {
  if(counter==1)
  {
  printf("buffer=%u",buffer);
  counter=0;
  }
 }
}


Dont know what is happening, where i am wrong?
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Wed Apr 13, 2011 6:25 pm     Reply with quote

whats the advantage to use directly the register SSPBUF like the program of PCM (for select comands) instead use read spi and write spi
tks Very Happy
PCM programmer



Joined: 06 Sep 2003
Posts: 20270

View user's profile Send private message

PostPosted: Thu Apr 14, 2011 2:12 pm     Reply with quote

You are right. The .LST file shown below shows that calling spi_read()
and reading SSPBUF directly, both produce the same code:
Code:

.................... #int_ssp 
.................... void ssp_isr(void) 
.................... { 
....................   
....................  int command; 
....................   
....................  command=SSPBUF; 
00AE:  MOVFF  SSPBUF,command
.................... 
....................  command=spi_read();
00B2:  MOVFF  SSPBUF,command
....................   
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Thu Apr 14, 2011 3:33 pm     Reply with quote

jejeje good to know Very Happy
tks pcm
Ttelmah



Joined: 11 Mar 2010
Posts: 12987

View user's profile Send private message

PostPosted: Fri Apr 15, 2011 1:58 am     Reply with quote

If you go 'back in time', the functions differed, with the compiler SPI_READ always checking the data available bit before reading. Sensible if using the code in a main program, but pointless in an ISR, where the ISR triggering implies that a byte has been clocked in. Hence people wanting to avoid the extra test talked directly to the registers. It appears that at some point the compiler behaviour has been improved in this regard.

Best Wishes
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Fri Apr 15, 2011 9:05 am     Reply with quote

so if I'm going to use ISR the best thing to do is work with the register directly...

I GET THIS .LST!!!

ISR SPI READ
Code:

.................... #int_ssp
.................... void ssp_isr(void)
....................  {
........................char a;
.....................   a=spi_read();
*
0035:  MOVF   13,W
0036:  BSF    03.5
0037:  MOVWF  2C


ISR USING SSPBUF
Code:

.................... #int_ssp
.................... void ssp_isr(void)
....................  {
....................   char a;
....................   a=SSPBUF;   
*
0035:  MOVF   13,W
0036:  BSF    03.5
0037:  MOVWF  2C


SSPBUF IN MAIN without ISR
Code:

....................  while(true)
....................    {
..........................char a;
.......................   a=SSPBUF;
035F:  MOVF   13,W
0360:  MOVWF  72


SPI_READ IN MAIIN without ISR
Code:

....................   while(true)
....................    {char a;
....................    a=spi_read();
035F:  MOVF   13,W
0360:  MOVWF  72


to me looks like the same... I'm wrong?
...where is sspbuf? ... Question
Ttelmah



Joined: 11 Mar 2010
Posts: 12987

View user's profile Send private message

PostPosted: Fri Apr 15, 2011 9:13 am     Reply with quote

No, as I said 'if you go back in time'. The early spi_read function tested the BF bit. CCS have dropped this, probably when they added the 'spi_data_is_in' function, so that you have the _option_ to test the bit if you want. As now coded, the spi_read is identical to the direct read.
It was an annoyance in the early days when trying to code a SPI ISR, hence a lot of people took the safe route, and went to direct register I/O.

Best Wishes
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Fri Apr 15, 2011 9:17 am     Reply with quote

ok tks Very Happy
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

mmm
PostPosted: Wed May 11, 2011 7:55 pm     Reply with quote

Hi I had to rebuild my circuit because I was using 2 PIC'S comunicating with software SPI, after a few bumps I get the answer. There is no way to get a software slave spi!!! using #use_SPI.

So I rebuild my slave for use hardware SPI. I connect to my software master SPI and now I realize that I have to waste one byte to get an answer from slave HW SPI!!! I just don't get it... Sad

I got 2 questions for you:

1.- There is any way to set the speed of my master SPI with #use_spi besides the baud rate?

2.- There is a way to send a byte from master get in slave and return to the answer to the master in one instruction? Or always I have to sent a dummy byte?

master
Code:

#include <18f4550.h>
#fuses HS,NOPUT,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOUSBDIV,PLL1,CPUDIV1,NOVREGEN
#use delay(clock=8000000)

#use spi(DO=PIN_D6,DI=PIN_D5,CLK=PIN_D4,MODE=0,BITS=8,MSB_FIRST)

#define SPI_SS PIN_C0

void inicializar()
 { 
  set_tris_d(0b00100000);
  set_tris_c(0b00000000);
  delay_us(100);
  output_high(SPI_SS);
  output_low(PIN_D4);
  output_low(PIN_D6);
  output_float(PIN_D5);
 }
 
 void main()
 {   
  int a=0;
  int ret;
  inicializar();
 
  while(true)
   {               
    output_LOW(SPI_SS);
    SPI_XFER(0);                         //dumy waste of time!!!
    output_HIGH(SPI_SS);
    delay_us(200);
    output_LOW(SPI_SS);
    ret=SPI_XFER(a);                  //usefull data in and out!!!
    output_HIGH(SPI_SS);
   }
 }

slave
Code:

#include <16f876A.h>
#device ADC=8
#fuses HS,NOWDT,NOPROTECT,NOLVP,NODEBUG
#use delay(clock=20000000)

#byte SSPBUF=0x13
#define SPI_MODE_0_0 0x4000       

#int_ssp
void ssp_isr(void)
 {
  int comando;
  static int count; 
  comando=SSPBUF;   //also i use comando=spi_read(count)
  count++;                                                //geting wrong data!!!
  SSPBUF=count; 
 } 

inicializacion()
 {   
  // habilita iterrupcion por spi
  clear_interrupt(INT_SSP);
  enable_interrupts(INT_SSP);
  enable_interrupts(GLOBAL);
 
  // Initialize the hardware SSP for SPI Slave mode.
  setup_spi(SPI_SLAVE |SPI_L_TO_H|SPI_XMIT_L_TO_H);
 }
 void main()
 {   
  inicializacion();
 
  while(true)
  {}
 }

result

any help wold be great!!!
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Wed May 11, 2011 8:36 pm     Reply with quote

i need to return the same data i'm sending

i also try with spi_read();

with no results... Sad
PCM programmer



Joined: 06 Sep 2003
Posts: 20270

View user's profile Send private message

PostPosted: Wed May 11, 2011 9:32 pm     Reply with quote

Quote:

1.- There is any way to set the speed of my master SPI with #use_spi
besides the baud rate?

I don't see any method of setting the baud rate listed in the manual
for #use spi, except for the BAUD=n method.

I don't use the #use spi() method for hardware SPI. I use setup_spi().

Quote:

2.- There is a way to send a byte from master get in slave and return to
the answer to the master in one instruction? Or always I have to sent a
dummy byte?

I need to return the same data i'm sending
i also try with spi_read();
with no results


spi_read(); won't clock in any data to the Master. You need to give it a
parameter to make the Master generate the clock (SCLK).

For example, the line below will transmit a 0x00 byte to the slave, and it
will force the slave to transmit the byte in it's buffer to the master.
Code:
result = spi_read(0);


SPI is just two shift registers. The master has one, and the slave has
one. There is no way get back the transmitted data with just 8 clocks
from the master. It would take 16 clocks, total. Look at this diagram
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Data_transmission
Here is another diagram of the two SPI shift registers:
http://elm-chan.org/docs/spi_e.html
Here is an SPI tutorial from Microchip:
http://ww1.microchip.com/downloads/en/devicedoc/spi.pdf
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Thu May 12, 2011 10:52 am     Reply with quote

tks for the answer and the info
and yes i understoot everything you say but:
the master send 0xff

a=spi_xfer(0xff);

and the slave get the 0xff and save into resp and return 0x05 to the master:

resp=spi_read(0x05);

what is the result for a? i guess it should be 0x05?
I'm not getting 0x05!!! my code is wrong?
slave
Code:

#include <16f876A.h>
#device ADC=8
#fuses HS,NOWDT,NOPROTECT,NOLVP,NODEBUG
#use delay(clock=20000000)

#byte SSPBUF=0x13
#define SPI_MODE_0_0 0x4000

int resp;

#int_ssp
void ssp_isr(void)
 {   
  resp=spi_read(0x05);   
 } 

inicializacion()
 {   
  // habilita iterrupcion por spi
  clear_interrupt(INT_SSP);
  enable_interrupts(INT_SSP);
  enable_interrupts(GLOBAL);
 
  // Initialize the hardware SSP for SPI Slave mode.
  setup_spi(SPI_SLAVE |SPI_MODE_0_0);
 }
 void main()
 {   
  inicializacion(); 
  while(true)
  {}
 }

master
Code:

#include <18f4550.h>
#fuses HS,NOPUT,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOUSBDIV,PLL1,CPUDIV1,NOVREGEN
#use delay(clock=8000000)

#use spi(DO=PIN_D6,DI=PIN_D5,CLK=PIN_D4,MODE=0,BITS=8,MSB_FIRST)

#define SPI_SS PIN_C6

#byte porta=0xf80
#byte portb=0xf81
#byte portc=0xf82
#byte portd=0xf83

void inicializar()
 { 
  set_tris_d(0b00100000);
  set_tris_c(0b00000000);
  delay_us(100);
  output_high(SPI_SS);
  output_low(PIN_D4);
  output_low(PIN_D6);
  output_float(PIN_D5);
 }
 
 void main()
 {   
  int a;
  inicializar();
     
  while(true)
   {       
      output_LOW(SPI_SS);
      a=SPI_XFER(0xff);         
      output_HIGH(SPI_SS);
      delay_ms(2000);
   }
 }


wrong result??? Question[/code]

thanks
PCM programmer



Joined: 06 Sep 2003
Posts: 20270

View user's profile Send private message

PostPosted: Thu May 12, 2011 6:15 pm     Reply with quote

I note the problems. I'm still working on it.
nahumof



Joined: 09 Apr 2011
Posts: 15

View user's profile Send private message

PostPosted: Fri May 13, 2011 9:56 am     Reply with quote

ok PCM tks

well after a few test i discover that my program send a byte (0x0f)to the slave and save a returning byte in B:
B=SPI_XFER(0x0f);

i receive the byte in the slave and return the same to master
a=SSPBUF;

when this happen i receive the half of whatever i send...

if i send 0x0f i get 0x07
if i send 0x08 i get 0x04
if i send 0x02 i get 0x01

only if i send 0xfx i get f something wrong
if i send 0xf0 i get 0xf8

i don't know what is causing this? maybe a configuration? speed?compiler?
some help would be great
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4  Next
Page 3 of 4

 
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