Multi processor project

nsaspook

Joined Aug 27, 2009
12,998
quick question

I am soldering a perfboard to do SPI and when I tried my programs (that wored well before on a breadboard) they fail. The slave transmits garbage, 0x00 or other meaningless chars.
I ve checked the connections, they seemed to be fine. The only thing I can thing of is that when I did it on the breadboard I used jumper wires (and it went well)
Now I am using the following (pardon the ugliness, I am not good at doing this)
View attachment 90581
are these thin wires not good for SPI communication? Should I use jumper wires instead? width 20 perhaps?

Any advice very much appreciated
The wire size is not a problem. (I use 28 or 30 awg wire on perfboards) Recheck your wiring, layout and look for solder bridges.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
I checked it like 10 times... the wiring is ok.
I changed the cables...
The layout is the same as the one working in the breadboard

Still garbage:(

Quick question. If I send data to a slave and the slave is not there (meaning there is no receiving slave attached) what should the master receive back??
 

John P

Joined Oct 14, 2008
2,025
The byte received by the master is whatever was on the master's input pin when the clock transitions occurred. You could try connecting the SDI pin to Gnd or Vdd and see if the chip receives 0x00 or 0xFF; if it doesn't, something is seriously wrong. (It's best to make these connections via a resistor, so that if the SDI pin is somehow set as an output, you aren't overloading it.) Or you can try connecting SDI and SDO together, to verify that what gets sent out is what gets received.

I said a few days ago that I always set up projects with an oscilloscope available. If I get some mysterious situation where I need to know what a processor is doing, I can just program it to blip an output pin when events occur--something transmitted, something received, a particular value received, whatever makes a good diagnostic item. If you haven't got a scope, you could set up LEDs to flash when events occur. You can also run wires from your breadboard to the perfboard setup, and try to use the working system to debug the non-working one.

Edited to say, if you truly are seeing "trash" on the master's SDI line, that might be useful information right there. It might indicate an open pin that's picking up electrical noise--a resistor to Vdd or Gnd would tell you that. But if a slave is driving it, the question has to be the slave's software--it's driving the line but putting the wrong thing there. Why?

And your picture only shows the back of the board, but I really hope you've got the chips in sockets.
 
Last edited:

nsaspook

Joined Aug 27, 2009
12,998
+1 sockets so you can easily swap chips if one is suspect and to avoid heating the uC pins too much while adding wires to them.
Make sure you have all the vdd and vss connections made and have used proper bypass caps on the correct pins on all devices. This is always important but double so on perboards with high speed logic.
I've got some true rat's nest wired boards that still operate perfectly. I also run wires to a set of diagnostic pins for important signals to make scoping out problems easier.

 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
So far i was using development boards instead of chip so suspecting bad connections, I put a chip but even worse results.

Now the slave only sends 0xFF.

I can see that by debugging the master program. The slave program can not be debugged (I supposed because the master program never stops so when I tried to debug the slave the debug cursor just dissapears)

(sigh).... why it works so well on breadboards yet so bad on perfboards...

cap2.jpg
 

nsaspook

Joined Aug 27, 2009
12,998
So far i was using development boards instead of chip so suspecting bad connections, I put a chip but even worse results.

Now the slave only sends 0xFF.

I can see that by debugging the master program. The slave program can not be debugged (I supposed because the master program never stops so when I tried to debug the slave the debug cursor just dissapears)

(sigh).... why it works so well on breadboards yet so bad on perfboards...

View attachment 90651
Maybe it's time to restart. A simple logic probe or o-scope would be invaluable here.
Write a very simple debug master program the sends a constant pattern with at a slow clock to the slave at a very slow rate with a flashing led to verify it's running. Write a simple slave program that enables the SPI module and flashes a led when the same byte is received and another led that flashes when the program is running. Make sure this works on the some other board first then try it on the perfboard. Look for silly things like reversed power or a hidden broken interconnect wire on the backside.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Ok I will try your suggestions

Question, when connecting SDI SDO SCK etc do I need to pull up or down anything?? RIght now I am just connecting directly from one pin to another with cables
 

nsaspook

Joined Aug 27, 2009
12,998
Ok I will try your suggestions

Question, when connecting SDI SDO SCK etc do I need to pull up or down anything?? RIght now I am just connecting directly from one pin to another with cables
It depends, you can config SPI outputs to be open drain on some chips. I think most of the K series has the ODCON register for open drain on several modules so you can use a pullup to interface a 3.3 chip to 5 volt logic. The default should be open drain disabled.
 

John P

Joined Oct 14, 2008
2,025
The only line you should be pulling up is SDO from the slaves, which of course is SDI for the master. That's because the slaves only drive it when one of them is enabled, and otherwise it floats. It probably wouldn't do any harm floating, but I'd still pull it up. Actually I might not--maybe I'd pull it to 4V or something with 2 resistors, so I could tell the difference between an open line and a driven line on the scope. Do a few of these projects and your mind automatically moves to diagnostics you can install! NSASpook had a good idea about running the SPI so slowly that you can see the bits as flashing lights. But get a scope--you'll wonder how you lived without it.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
Well, I have been asked to put this on hold and do another project (which I am going to post in another thread). I will come back in a couple of weeks and hope to see the light. Thank you guys...
and any help in the other project welcomed (brushless motors)
 

vluban

Joined Aug 31, 2015
4
slave would bump back "%HELLO WORL" (with % being garbage the first time,
When the first byte is transmitted from Master over SPI, slave has nothing as nothing received from the master yet, so it transmits whatever garbage is there. The last byte should be transmitted AFTER master finished it's transmission, but as it's master that controls the clock, if there's no clock there's no last byte transmission.

So, to have successful "echo", master needs to ignore first received byte and send one dummy byte out (to clock the slave for it's last byte) after transmission is done.
 

Thread Starter

KansaiRobot

Joined Jan 15, 2010
324
FOUND the problem sorry!! (it was a bad cable)

-------------------------------------------------------------------------------------------------
Well I never solved the problem on that one. :(

Anyway, I have a new problem dealing with SPI and I would appreciate some help

I tried to write a very simple SPI program to communicate two 18F45K20. It doesnt work (Similar to the one I wrote for 18F2550 some months ago and it used to work)
At first I thought the master was wrong but viewing it with a oscilloscope I can see the master is working. (Although I have no idea how come the clock is running at 125KHz)
lm13000.jpg
There you can see that the CLK (green) is working, the SDO (yellow) gives the correct data, the CS(blue) is being driven to 0 (although at first I wanted to do it every three transmissions) but the SDI (red) is not working at all.
I have read and reread the code and I cant find what is wrong. I would appreciate very much if someone can take a look please

Master
Code:
#include <stdio.h>
#include <stdlib.h>
#include "configuration.h"

#define  _XTAL_FREQ 64000000      // 64MHz for the delay function

void CPU_Init()
{
  // first we select the appropriate preescaler
    OSCCON |= 0x70; //Select 16MHz as Internal Oscillator IRCF<2:0>=111
// Then use the PLL to multiply this by 4 (16x4= 64MHz)
    OSCTUNEbits.PLLEN=1; //PLL (x4) enabled

    TRISB=0x00;  // to enable the LEDs
}

void delay_ms(unsigned int ms)
{
   unsigned long int index=0;


   for(index=0;index<ms;index++)
       __delay_ms(1);


}
//------------Some LEDs for output
#define GREEN_LED LATBbits.LATB0
#define RED_LED   LATBbits.LATB1



//--------------SPI FUNCTIONS --------------------------
// These are the functions in charge of initializing and using the spi functions


#define CS_PIN     LATAbits.LATA5    //Chip Select

void spi_master_init ( void );
unsigned char spi_data ( unsigned char tx_data );
unsigned char spi_read_data;

#define DATA_A  0x90  //1001 0000
#define DATA_B  0xD0  // 1101 0000
#define DATA_C  0x00

int main(int argc, char** argv)
{
    CPU_Init();
    spi_master_init();

    RED_LED=0;
    GREEN_LED=0;

    while(1)
    {
       // CS_PIN=0;
        delay_ms(1);
        spi_read_data=spi_data(DATA_A);

        if(spi_read_data!=DATA_C)
              { RED_LED=1;
              GREEN_LED=0;
              }
        else  { RED_LED=0;
              GREEN_LED=1;
              }
        delay_ms(1);
        spi_read_data=spi_data(DATA_B);

        if(spi_read_data!=DATA_A)
              { RED_LED=1;
              GREEN_LED=0;
              }
        else  { RED_LED=0;
              GREEN_LED=1;
              }

        delay_ms(1);
        spi_read_data=spi_data(DATA_C);

        if(spi_read_data!=DATA_B)
              { RED_LED=1;
              GREEN_LED=0;
              }
        else  { RED_LED=0;
              GREEN_LED=1;
              }


//        CS_PIN=1;

        delay_ms(10);
    }//while 1

    return (EXIT_SUCCESS);
}


void spi_master_init ( void )
{
     SSPSTAT = 0x00;
     SSPCON1 = 0x22;

    TRISC &= 0xD7;   // 1101 0111  MO cleared CLK cleared
    TRISA &= 0xDF;      //  1101 1111  CS cleared
    //TRISB |= 0x01;        // 0000 0001   IRQ_PIN set

    //Disabling the chip
    CS_PIN=1;

    ADCON0 = 0x38;
     ADCON1= 0x00;


}
//WARNING: This function DOES NOT select the chip. This has to do from OUTSIDE<--- Not anymore
//actually it does now!!!
unsigned char spi_data ( unsigned char tx_data )
{
    char data_read;

    CS_PIN=0;

   //do{  SSPCON1bits.WCOL=0;
    SSPBUF=tx_data;  // put the data in the SSPBUF register which going to be send
    //}while(SSPCON1bits.WCOL);  //to check if the buffer is empty (not collisions)

   while( !SSPSTATbits.BF );  // wait until the all bits received

   CS_PIN=1;

   data_read=SSPBUF;
   return data_read;

}
slave
Code:
#include <stdio.h>
#include <stdlib.h>
#include "configuration.h"



void CPU_Init()
{
  // first we select the appropriate preescaler
    OSCCON |= 0x70; //Select 16MHz as Internal Oscillator IRCF<2:0>=111
// Then use the PLL to multiply this by 4 (16x4= 64MHz)
    OSCTUNEbits.PLLEN=1; //PLL (x4) enabled

   // TRISB=0x00;  // to enable the LEDs
}

//--------------SPI FUNCTIONS --------------------------
// These are the functions in charge of initializing and using the spi functions
void spi_slave_init ( void );
unsigned char spi_data ( unsigned char tx_data );

unsigned char spi_read_data;

int main(int argc, char** argv) {

    CPU_Init();
    spi_slave_init (); // initialize the slave

    while(1)
      {
       while ( !SSPSTATbits.BF );           // wait until the all bits received
       spi_read_data = SSPBUF; // read the received data from the buffer
       SSPBUF = spi_read_data;   // put the data in the SSPBUF register which will get transmitted on master's clock
      }





    return (EXIT_SUCCESS);
}


void spi_slave_init ( void )
{
SSPSTAT = 0x00; // SMP=0(slave mode),CKE=0(transmission on Idle to active clock state),all other bits 0
SSPCON1 = 0x24; // SSPEN=1(Enable SPI),SSPM[3-0]=0100(SPI Slave mode,clock=SCKpin,SSpin control enabled)

TRISC &= 0xDF;   // 1101 1111  MO cleared
TRISC |= 0x08;   //  0000 1000  CLK set
TRISA |= 0x20;   //  0010 0000  CS set

ADCON0 = 0x38;
ADCON1= 0x00;
ANSEL= 0x00; //enable digital use of A
}
// this function is not used
unsigned char spi_data ( unsigned char tx_data )
{
char data_read;

while ( !SSPSTATbits.BF );        // wait until the all bits received
data_read = SSPBUF; // read the received data from the buffer
SSPBUF = tx_data;  // put the data in the SSPBUF register which will get transmitted on master's clock

return data_read;
}
configuration.h
Code:
#ifndef CONFIGURATION_H
#define    CONFIGURATION_H

#ifdef    __cplusplus
extern "C" {
#endif

#include <xc.h>
// PIC18F45K20 Configuration Bit Settings
// 'C' source line config statements

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1H
#pragma config FOSC = INTIO67   // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 18        // Brown Out Reset Voltage bits (VBOR set to 1.8 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF             // Single-Supply ICSP Enable bit (Single-Supply ICSP Disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection Block 0 (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection Block 1 (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection Block 2 (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection Block 3 (Block 3 (006000-007FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection Block 0 (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection Block 1 (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection Block 2 (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection Block 3 (Block 3 (006000-007FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection Block 0 (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection Block 1 (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection Block 2 (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection Block 3 (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)




#ifdef    __cplusplus
}
#endif

#endif    /* CONFIGURATION_H */
Thanks a lot in advance
 
Last edited:
Top