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 Communication between 2 MCU's

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



Joined: 02 Jun 2010
Posts: 74

View user's profile Send private message

SPI Communication between 2 MCU's
PostPosted: Thu Nov 01, 2012 8:00 pm     Reply with quote

Hi, I am trying to have 2 MCU's communicate with each other using SPI.

I have 18F47J53 USB PIC running at 12MHz * 4 = 48MHz as master, and 18F25K22 as slave.

I am using DMA module for simple SPI transfer of data, and interrupt driven SPI slave for 18F25K22.

I use EXT interrupt on 18F25K22(same as /SS2 pin) to synchronize the buffer index's. SPI lines are directly connected with less than an inch apart on board, with only 10k pull-up resistors on each lines.

I programmed both devices and looking at one of the device's variables at a time using debugger. It works sometimes, but most of the time, it doesn't work, yielding wierd data or skipping data's.

I looked at the wave form for the SPI lines using oscilloscope, and it looks clean.

Below is master code
Code:


#include "18F47J53.h"
#DEVICE HIGH_INTS = TRUE
#include "def_18F47J53.h"
#include "stdint.h"
#use delay(clock = 48000000)

#fuses NOWDT, NOXINST, NODEBUG, HSPLL, PLL3,PLLEN, NOCPUDIV, STVREN

#define SS_PORT PORTD0
#define SS_TRIS TRISD0

#define SCK_TRIS TRISC0
#define SDO_TRIS TRISC1
#define SDI_TRIS TRISC2

#define SPI_BUFFER_SIZE 236

uint8_t spi_in_buffer[SPI_BUFFER_SIZE];
uint8_t spi_out_buffer[SPI_BUFFER_SIZE];

uint8_t * spi_in_ptr;
uint8_t * spi_out_ptr;

void init_main(void){   
   uint8_t i;   
   #pin_select SCK2OUT = PIN_C0
   #pin_select SCK2IN = PIN_C0
   #pin_select SDO2 = PIN_C1
   #pin_select SDI2 = PIN_C2
   
   SS_TRIS = 0;
   SS_PORT = 1;
   SCK_TRIS = 0;
   SDO_TRIS = 0;
   SDI_TRIS = 1;
   setup_ADC_PORTS(NO_ANALOGS);
   //FOSC = 48MHz
   //FOSC/4 = 12MHz,  8 instruction cycles per char
   //FOSC/8 = 12MHZ, 16 instruction cycles per char
   //FOSC/64 = 128 instruction cycles per char
   
   //If I add the SPI_SS_DISABLE, the DMAEN doesn't automatically reset after finishing transmission
   setup_spi2(SPI_MASTER|SPI_SCK_IDLE_HIGH|SPI_XMIT_H_TO_L|SPI_SAMPLE_AT_MIDDLE|SPI_CLK_DIV_64);
   for(i=0;i<SPI_BUFFER_SIZE;i++){
      spi_out_buffer[i] = i;
      spi_in_buffer[i] = 0;
   }   
   spi_in_ptr = &spi_in_buffer[0];
   spi_out_ptr = &spi_out_buffer[0];
   //Setup full-duplex DMA
   //No Toggling of SS pin. We control SS pin manually
   DMACON1 = 0b00111000;
   //Delay between bytes = 1 cycle. Interrupt ASAP
   DMACON2 = 0x00;
   //enable_interrupts(INT_SSP2);
}   

void main(void){
   init_main();
   while(1){
      SS_PORT = 1;
      if(!DMACON1_DMAEN){
         //Process and save SPI In buffer
         SS_PORT = 0;
         delay_ms(2);//delay for the slave to process the received data
      
         DMACON2 = 0XF0;//Give maximum delay between bytes for the slave to respond
         DMABCH = 0;
         DMABCL = SPI_BUFFER_SIZE - 1;
         TXADDRH = (int8)(spi_out_ptr >>8);
         TXADDRL = (int8)(spi_out_ptr & 0xFF);
         RXADDRH = (int8)((int16)spi_in_ptr >>8);
         RXADDRL = (int8)((int16)spi_in_ptr & 0xFF);
         DMACON1_DMAEN = 1;
      }   
   }
}




below is slave code
Code:

//main.c
#include <18F25K22.h>

#include <def_18f25k22.h>
#device HIGH_INTS = TRUE
#fuses HSH, PLLEN, NOXINST, NOEBTR, NOEBTRB, NOCPB, debug
#use delay(clock = 58982400)
#include <stdint.h>

#define SS_TRIS PORTB0
#define SCK_TRIS PORTB1
#define SDI_TRIS PORTB2
#define SDO_TRIS PORTB3

#define DEBUG_TRIS TRISC5
#define DEBUG_PORT PORTC5


#define SPI_BUFFER_SIZE 236


uint8_t spi_buffer[SPI_BUFFER_SIZE];

uint8_t input_buffer[SPI_BUFFER_SIZE];

uint8_t spi_idx = 0;
uint8_t spi_status;
uint8_t highest_idx = 0;

#define SPI_WAITING 0
#define SPI_XMITING 1
#define SPI_COMPLETE 2

#opt 0
void initialize(void){
   uint8_t i;
   SCK_TRIS = 1;
   SDI_TRIS = 1;
   SDO_TRIS = 0;
   SS_TRIS = 1;
   
   for(i=0;i<SPI_BUFFER_SIZE;i++){
      spi_buffer[i] = 0;
   }   
   DEBUG_TRIS = 0;
   
   setup_spi2(SPI_SLAVE | SPI_SCK_IDLE_HIGH | SPI_XMIT_H_TO_L | SPI_SAMPLE_AT_MIDDLE|SPI_SS_DISABLED);
   enable_interrupts(INT_SSP2);
   TRISB0 = 1;
   ext_int_edge(H_TO_L);
   enable_interrupts(INT_EXT_H2L);//SPI index 동기화용 Interrupt
   enable_interrupts(GLOBAL);
   
}
#INT_SSP2
ssp2_isr(){
   
   if(spi_idx<=SPI_BUFFER_SIZE){
      spi_buffer[spi_idx] = SSP2BUF;
      spi_idx++;
      SSP2BUF = spi_buffer[spi_idx];
      if(spi_idx==SPI_BUFFER_SIZE){
         spi_status = SPI_COMPLETE;
      }   
   }
   
   if(spi_idx>highest_idx) highest_idx = spi_idx;

}


#INT_EXT
ext_isr(){
   
   uint8_t buffer8;
   buffer8 = SSP2BUF;//Read it anyways just to clear buffer
   SSP2BUF = spi_buffer[0];//Load the buffer
   
   spi_idx = 0;
   
   spi_status = SPI_XMITING;
   DEBUG_PORT = !DEBUG_PORT;
}   




void main(void){   
   uint8_t i;
   initialize();
   while(1){
      switch(spi_status){
         case SPI_WAITING:                //Prepare spi buffer for output
            for(i=0;i<SPI_BUFFER_SIZE;i++) spi_buffer[i] = i+10;
            
            
            break;
         case SPI_XMITING:
            break;
         case SPI_COMPLETE://Process spi buffer input
            //do processi
            for(i=0;i<SPI_BUFFER_SIZE;i++) input_buffer[i] = spi_buffer[i];
            spi_status = SPI_WAITING;
            break;
      }//end switch      
   }//end while(1);
}   
   


anyone experienced with SPI have any idea?? I am using PCH 4.127 for both devices.

Thank you
Ttelmah



Joined: 11 Mar 2010
Posts: 19347

View user's profile Send private message

PostPosted: Fri Nov 02, 2012 3:32 am     Reply with quote

First comment, the slave should always read the SSPBUF in INT_SSP. This will result in SSPOV getting set if another byte is then received. You should have handling for this error anyway.

You may well get a spurious INT_EXT at start-up. Basic sequence (to avoid this), is:
Code:

   ext_int_edge(H_TO_L); //set the edge to use
   clear_interrupt(INT_EXT); /clear interrupt
   enable_interrupts(INT_EXT);//Now enable interrupt without setting edge

PIC's all have the behaviour that in some circumstances setting the interrupt edge can trigger an interrupt, so it is 'better' to set the edge, clear, then enable like this.

Generally far better to use SS. This handles the SPI synchronisation for you. Without this getting byte synchronisation is _very_ hard. What happens if (for instance) your PIC's don't wake up exactly together?. Depending on how the bus clock is biased, and the timing of wake up, the slave can effectively receive an unexpected clock edge. Now you read SSPBUF in your INT_EXT in an attempt to re-sync, but this only affects a byte received. The shift register will still be left with a bit in it. The only way to clear the shift register is to disable and re-enable the MSSP. Turn SSPEN, off, and then on again. You should do this in your slave at boot up, turning it off, waiting for the clock line to go to the idle state, and then turning this on again, and also in your INT_EXT routine.

Why #opt 0?. You want as much speed as possible.

Your return data reads beyond the end of the array. You increment the idx, then write the data from the array, and then test if the idx==buffer size. At this point you will have read a byte beyond the end of the array.

Best Wishes
hello188



Joined: 02 Jun 2010
Posts: 74

View user's profile Send private message

PostPosted: Fri Nov 02, 2012 4:37 am     Reply with quote

Always reading from the INT_SSP and using SS for synchronization cleared up the problem.


Thank you so much!!
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