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 Problems

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







SPI Communication Problems
PostPosted: Wed Jun 07, 2006 9:49 am     Reply with quote

I'm having trouble with SPI communications between two uC's. The basic setup is like this:

[PC]<--(RS232)---->[Max232]<-->[PIC18F8390]<---(SPI)--->[PIC16F88]

I have verified that I can send the data over RS232, and it will be output over SPI (as seen with a scope) at the PIC18F8390. The 18F doesn't seem to see any data but junk.

The data received by the 16F is converted into two 12-bit numbers to send to a pair of DAC's. The DAC's never update. The data is then sent back to the 16F and back to the PC for verification. I cannot get the data to transfer back either, but this may make sense if the 16F can't read in the data in the 1st place.

18F Code.h
Code:

#include <18F8390.h>
#device adc=10

#FUSES WDT                       //Watch Dog Timer uses 1:32 Postscale
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT               //No brownout reset
#FUSES BORV28                   //Brownout reset at 2.8V
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOMCLR                   //Master Clear pin enabled
#FUSES LPT1OSC                  //Timer1 configured for low-power operation
#FUSES NOXINST                  //Extended set extension and Indexed Addressing mode disabled (Legacy mode)

#use delay(clock=4000000, RESTART_WDT)
#use rs232(baud=9600,xmit=PIN_C7,rcv=PIN_C6, RESTART_WDT)

#byte TMR0 = 0x01

#define PORTA_TRIS 0b11111111 // All Inputs - Not Used
#define PORTB_TRIS 0b11111110 // All Inputs except RB0, used for SS
#define PORTC_TRIS 0b11010111 // SDO RC5, SDI RC4, SCK RC3

#byte SSPBUF = 0x0FC9
#bit  SSP_BF = 0x0FC7.0

//*************************************************************************************************************************

//-----------------------------------------------------------------------------------
//      Variables for the RS232-Connection           //
int      RS232_Rx[12];                              //   Inputbyte
int      RS232_Tx[12];                              //   Outputbytes
int      RS232_TxCount;                              //   Counter for Outputbytes
int       RS232_POINTER;
short     RS232_Receive_Complete;
short     RS232_Receive_Successful;

#define  RS232_IN_START      0xA7               //    RS232 Receive Start Signal
#define  RS232_IN_STOP       0x7A               //   RS232 Receive Stop Signal
#define  RS232_OUT_START    0xA9               //   RS232 Transmit Start Signal
#define  RS232_OUT_STOP    0x9A               //   RS232 Transmit Stop Signal
//-----------------------------------------------------------------------------------
//      Variables for SPI                        //
int SPI_IN_CHO;
int   SPI_IN_CH1;
int   SPI_OUT_CH0;
int   SPI_OUT_CH1;

#define   SPI_OUT_STOP
#define   SPI_IN_STOP
#define   SPI_OUT_START
#define   SPI_IN_START

//-----------------------------------------------------------------------------------
void ConfigureIO();
void PreLaunch();
void Launch();
void Clear_RS232_INPUT();
void Timer();
void Send_RS232(int Tx_Byte);
void SPI_TxRx();

//------------------------------------------------------------------------------------
// Communications Protocol
//
// PC Send / uC Receive
// Bytes:  Start  CH0_H  CH0_M  CH0_L  CH1_H  CH1_M  CH1_L  STOP
//         0xAF   0x1#   0x2#   0x3#   0x4#   0x5#   0x6#   0xFA
//
// PC Receive / uC Send
// Bytes:  Start  CH0_H  CH0_M  CH0_L  CH1_H  CH1_M  CH1_L  STOP
//         0xAA   0x1#   0x2#   0x3#   0x4#   0x5#   0x6#   0xFF
//
// Each D/A is 12 bits.  MSB _ _ _ _ | _ _ _ _ | _ _ _ _ LSB
//                               H         M         L
// The 12 bits are divided into nibbles (shown as a # above)
//-----------------------------------------------------------------------------------

18F Code.c
Code:

#include "18F Code.h"

void PreLaunch(){
   setup_oscillator(OSC_4MHZ|OSC_NORMAL); // External XTAL 4MHz
   //setup_wdt(WDT_ON);
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);//T1_INTERNAL
   setup_timer_2(T2_DIV_BY_16,125,1); //4e6/4/2/16/125 = 250Hz
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_counters(RTCC_INTERNAL,RTCC_DIV_2);         //   Timer0 for RTCC

   setup_ccp1(CCP_OFF);
   setup_ccp2(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);

   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_T2 | SPI_XMIT_L_TO_H);

   setup_low_volt_detect(FALSE);
   setup_lcd(LCD_DISABLED);

   SSPBUF = 0;
   ConfigureIO();

   RS232_Receive_Successful = False;
   Clear_RS232_INPUT();
   RS232_POINTER=0;
}

void ConfigureIO() {
      Set_TRIS_A(PORTA_TRIS);
      Set_TRIS_B(PORTB_TRIS);
      Port_B_Pullups(True);
      Set_TRIS_C(PORTC_TRIS);
   output_high(PIN_B0);
}

void Clear_RS232_INPUT() {
   int i;
   
   for (i = 0; i < 8; i++) {   
      RS232_Rx[i]=0;
   }
   RS232_POINTER=0;
}

void SPI_TxRx() {                                 //  Send/Receive SPI
   int i;

   output_low(PIN_B0);                     // CS to other uC
   delay_ms(20);

   for (i=0; i < 8; i++) {                  //   Transmit SPI Data
      spi_write(RS232_Rx[i]);
      delay_us(200);
   }

   delay_ms(40);

   for (i=0; i < 8; i++) {                  //   Receive SPI Data
      RS232_Tx[i] = spi_read(0);
      delay_us(200);
   }

   delay_ms(20);
   output_high(PIN_B0);                   // CS to other uC
   delay_ms(20);

   for (i=0; i < 8; i++) {                  //   Transmit RS232 Data
      putc(RS232_Tx[i]);
      delay_us(20);
   }
}

void main() {
   PreLaunch();

   while(1) {
       restart_WDT();                                 //   Reset Watchdog

      // Wait for RS232 Data Input
      // RS232_Receive_Successful ... Flag set when all data is in, stop confirmed

   RS232_Receive_Successful=False;

      RS232_Rx[RS232_POINTER]   =   getc();            //  Read-Out received byte
   if (RS232_Rx[RS232_POINTER] != ' ') {         // Determine if data is received??? Better way?
      if (RS232_Rx[RS232_POINTER] == RS232_IN_START) {//  Reset RS232 Pointer at
         RS232_Rx[0] = RS232_Rx[RS232_POINTER];
         RS232_POINTER = 1;
         RS232_Receive_Successful = False;
      } else if (RS232_Rx[RS232_POINTER] == RS232_IN_STOP) {
         if (RS232_POINTER == 7) {
            RS232_Receive_Successful = True;      //  Stop bit confirmed, data complete
         } else {
            RS232_Receive_Successful = False;      //  Stop bit received, data missing
            Clear_RS232_INPUT();
         }
      } else {
         if ((RS232_POINTER == 7) && (RS232_Rx[RS232_POINTER] != RS232_IN_STOP)) {                  // 
            Clear_RS232_INPUT();
            RS232_POINTER=0;
         } else {
            RS232_POINTER++;
         }
      }
   }

   delay_ms(100);

      if (RS232_Receive_Successful==True) {
      
         // Output SPI Data, Input SPI Data (to verify) and Output RS232_OUT
         SPI_TxRx();
         Clear_RS232_INPUT();
         RS232_Receive_Successful = False;
      }

   }
}


16F Code.h
Code:

#include <16F88.H>
#device adc=10
#include <STDLIB.h>

#fuses INTRC, NOWDT, PUT, NOPROTECT, BROWNOUT, NOLVP, MCLR, NOCPD, NOWRT, NODEBUG, FCMEN, NOIESO
#use delay(clock=2000000)
#use fast_io(A)
#use fast_io(B)

#define DAC_COMMAND     0x70    // 0111 (DAC_A | BUFFERED | GAIN_1 | OUTPUT_ENABLED)
#define PORTA_TRIS      0xFF    // All inputs (for ADC).
#define PORTB_TRIS      0xF2    // 11100010 was 00011101 1D
#define PORTB_DEFAULT   0x09    // 00000000

// PIN_B1 is unused in this model
// PIN_B2 is used for serial data input
// PIN_B2 is used for serial data output
// PIN_B5 is uC serial transmit
// PIN_B6 is ICSP Clock and //Switch A Input
// PIN_B7 is ICSP Data and //Switch B Input

#define DAC_SELECT_0    PIN_B0
#define DAC_SELECT_1    PIN_B3
#define DAC_DATA_IN     PIN_B2
#define DAC_CLK         PIN_B4

// These are the exclusive modes of operation.
#define MODE_STARTUP        0x01 // 0000 0001  Set in PreLaunch
#define MODE_NORMAL         0x02 // 0000 0010  Set in Launch

// State variables.
int ModeG;                       // Tracks current progam state (MODE_*).
unsigned int uiConfig;

#define Offset 16
#define Slope 16

#ifndef NO_AVG
#define AVG0    0.8
#define AVG1    0.2
#else
#define AVG0    0
#define AVG1    1
#endif

/* Function Prototypes */
void PreLaunch();
void ConfigureIO();
void Launch();
void SetOutputs();
void WriteDAC(long int value, int1 chan);

Code:

[b]16F Code.c[/b]

void main() {
   int abc;
   int i;
   unsigned long int abcd;
   int data[8];
   short DataCompleteFlag;
   PreLaunch(); // Configures interal regs., sets DAC output to 0x0000
   Launch();
   delay_ms(50);
   for (abc = 0; abc < 8; abc++) {
      data[abc] = 0;
      DataCompleteFlag = True;
   }

   while (1) {

      DataCompleteFlag = False;

      if ( !input(pin_B5) ); // Wait for CS low
      // Receive Data
         while ( !spi_data_is_in() ) { // Wait for Data
         }
         for (abc = 0; abc < 8; abc++) {
            data[abc] = spi_read();
            DataCompleteFlag = True;
         }

            data[0] = 0xA9;         // Change start/end bytes
            data[7] = 0x9A;

            for (abc=0; abc < 8; abc++) {
               spi_write(data[abc]);
            }

            setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_T2 | SPI_XMIT_L_TO_H);      // Set SPI to write to DAC's
            delay_ms(250);

            abcd = (data[1] & 0x0F) * 256 + (data[2] & 0x0F) * 16 + (data[3] & 0x0F);
            WriteDAC(abcd, 0);
            delay_ms(200);
            abcd = (data[4] & 0x0F) * 256 + (data[5] & 0x0F) * 16 + (data[6] & 0x0F);
            WriteDAC(2000, 1);
            delay_ms(20);

            // Set SPI back to read from RS232
            setup_spi(SPI_slave | SPI_SS_DISABLED | SPI_L_TO_H | SPI_XMIT_L_TO_H);
            delay_ms(250);
      }

}

void PreLaunch() {
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DIV_BY_16,125,1); //2e6/4/2/16/125 = 125Hz
   ModeG = MODE_STARTUP;
   ConfigureIO();
   setup_wdt(WDT_576MS);
}

void Launch() {
   restart_wdt();
   delay_us(ADC_DELAY);
}

void ConfigureIO() {
   set_tris_a(PORTA_TRIS);
   setup_adc_ports(sAN0|sAN1|sAN2|sAN3|sAN4|VSS_VREF);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   port_b_pullups(TRUE);
   set_tris_b(PORTB_TRIS);
   output_b(PORTB_DEFAULT);
   setup_spi(SPI_SLAVE | SPI_SS_DISABLED | SPI_L_TO_H | SPI_XMIT_L_TO_H);
}

void WriteDAC(unsigned long int value, int1 chan) { // This function works properly
   unsigned int CmdHigh, CmdLow;

   CmdHigh   = (DAC_COMMAND & 0xF0) | ((value & 0x0F00) >> 8);
   CmdLow   = value & 0xFF;

   if (chan == 0) {
      output_low(DAC_SELECT_0);
      spi_write(CmdHigh);
      spi_write(CmdLow);
      output_high(DAC_SELECT_0);
   } else if ((uiConfig & CONFIG_TEMP_LOOP) && (chan == 1)) {
      output_low(DAC_SELECT_1);
      spi_write(CmdHigh);
      spi_write(CmdLow);
      output_high(DAC_SELECT_1);
   }
}


Ttelmah
Guest







PostPosted: Wed Jun 07, 2006 10:17 am     Reply with quote

Obvious thing is that both chips cannot be 'master'...
The 'master' chip, is the one that generates clock pulses for the transaction. You have both chips set to do this.

Best Wishes
GregPIC
Guest







PostPosted: Wed Jun 07, 2006 12:53 pm     Reply with quote

Maybe this will not work how I wanted it to, but I wanted the 18F to be the master for comm. to the 16F.

The 16F device must be the master to communicate to the DAC's, so after it receives and responds with data, it switches to Master to talk to the DAC's. After that is complete, it switches back to be the slave.
Ttelmah
Guest







PostPosted: Wed Jun 07, 2006 2:25 pm     Reply with quote

SPI, sends data in both directions at once, clocked by one 'master' chip. Just have the chip that is sending/asking for the data as master, and the other as slave. If you want to turn the bus 'round', you are going to have to reprogram the SPI at both ends, adjust the TRIS register to match, and (if major current spikes are to be avoided), ensure that the changeover is done so that the lines switch to receive, ahead of the lines from the other end switching to transmit. This is complex, and full of danger. Take advantage of the bi-directional ability of the existing bus, and just have one master. If you want to 'trigger' the transfer from the other end, then use another line as a control signal.
If you want a 'multi-master' interface, save a wire, and use I2C. This is relatively much easier to reprogram.

Best Wishes
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