Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SPI Slave Bitbangin

Status
Not open for further replies.

AtomSoft

Well-Known Member
Hey all i know you all are probably tired of me making threads by now. :D

Im trying to figure out how to bitbang a SPI Slave and i have a theory only so please be nice when criticizing me :)

In theory i would think i need to wait for the SS or CS pin to go low so i would do:

Code:
while(cs == 1);

meaning to wait until CS pin is low. Once its low continue.

Then i need to get the command which is 8 bits (1 byte)

Code:
char CMD,x=0;           //ComManD

for(x=0;x<8;x++){       //loop 8 times
    while(SCL == 0);    //wait until CLOCK is HIGH to get bit (Serial CLock)

    if(SDI)             //if SDI pin is high (Serial Data In)
        CMD|=1;         //add a 1 if its high if not just shift (automatically a 0)


    CMD=CMD<<1;         //shift over 1

    while(SCL == 1);    //wait until CLOCK is LOW to get continue loop
}

I would also use the above to collect 1 byte of data at a time determined by command and other variables.

Do you think it would work?
 
Last edited:
Ok here is a better example on how to get a command then get 1024 Bytes of data:
Code:
void main(void){
    char CMD,x=0;           //ComManD
    int y = 0;

while(1){
    while(CS == 1);     ////Wait until user selects the pic to continue

    CMD = GetByte();

    switch(CMD){
        case 0x30:                        
            for(y=0;y<1024;y++){
                *buff++ = GetByte();
            }
            loadimg(&buff, 1024);
        break;
    }

    while(CS == 0);     //Wait until user deselects the pic to continue
}
}

char GetByte(void){
char x, tmp = 0;

    for(x=0;x<8;x++){       //loop 8 times to get COMMAND
        while(SCL == 0);    //wait until CLOCK is HIGH to get bit (Serial CLock)

        if(SDI)             //if SDI pin is high (Serial Data In)
            tmp|=1;         //add a 1 if its high if not just shift (automatically a 0)

        tmp=tmp<<1;         //shift over 1

        while(SCL == 1);    //wait until CLOCK is LOW to get continue loop
    }
}

Since i havent tested it i wanted to know does it seem as if it would work?
 
Last edited:
The only thing I can see wrong is the shift needs to be before the or, actually it is better if it is before the edge detect,
Code:
        tmp=tmp<<1;         //shift over 1
        while(SCL == 0);    //wait until CLOCK is HIGH to get bit (Serial CLock)
        if(SDI)             //if SDI pin is high (Serial Data In)
            tmp|=1;         //add a 1 if its high if not just shift (automatically a 0)
You may also want to do a wait SCL high before low assuming that the data line is valid on the falling edge of the clock.

And your CS appears to be active low which may be correct anyway.

Mike.
 
So you are saying wait for a toggle of the Clock line before taking in data? I had it the way i did because i was going to set data when the clock is low and then send it out when the clock is high.

So i thought i should receive data when the clock is high and then wait until clock is low then repeat. so would the below be better?:

Code:
char GetByte(void){
char x, tmp = 0;

    for(x=0;x<8;x++){       //loop 8 times to get COMMAND

        tmp=tmp<<1;         //shift over 1

        while(SCL == 0);    //wait until CLOCK is HIGH to get bit (Serial CLock)
        while(SCL == 1);    //wait until CLOCK is LOW to get continue loop

        if(SDI)             //if SDI pin is high (Serial Data In)
            tmp|=1;         //add a 1 if its high if not just shift (automatically a 0)

    }
}

Or should i keep the clocking in as it was?
 
That code should work fine as long as you have the master clocking data out on a falling edge. Is this going to be bidirectional?

Mike.
 
No just 1 way. Also i forgot to the "return" lol

Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
char GetByte(void);
/***********************************
            Defines
***********************************/
#define CS   PORTAbits.RA0
#define SCL  PORTAbits.RA1
#define SDI  PORTAbits.RA2
/***********************************
            Main
***********************************/
void main(void){
    char CMD,x=0;           //ComManD
    int y = 0;

    ADCON1 = 0x0F;
    TRISB  = 0x00;
    TRISA  = 0xFF;
    LATB = 0;

while(1){

    while(CS == 1);      //Wait until user selects the pic to continue
    LATBbits.LATB1 = 1;    

    CMD = GetByte();

    switch(CMD){
        case 0x30:                        
            LATBbits.LATB0 = 1;
            break;
        case 0xFF:
            LATB = 0xFF;  //ERROR
            break;
    }

    while(CS == 0);     //Wait until user deselects the pic to continue
    LATBbits.LATB1 = 1;
}
}
/***********************************
            GetByte
***********************************/
char GetByte(void){
char x, tmp = 0;

    for(x=0;x<8;x++){                   //loop 8 times to get COMMAND

        tmp=tmp<<1;                     //shift over 1

        while(SCL == 0)                 //wait until CLOCK is HIGH to get bit (Serial CLock)
            if(CS == 1) return 0xFF;    //If user sets high CS pin aka error break!
        while(SCL == 1)                 //wait until CLOCK is LOW to get continue loop
            if(CS == 1) return 0xFF;    //If user sets high CS pin aka error break!

        if(SDI)                         //if SDI pin is high (Serial Data In)
            tmp|=1;                     //add a 1 if its high if not just shift (automatically a 0)
    }
    return tmp;                         //return our data
}

Thats the sample/test i will try.

And to send the data i made this:
Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
char SendByte(char byte);
/***********************************
            Defines
***********************************/
#define CS   LATEbits.LATE0
#define SCL  LATEbits.LATE1
#define SDO  LATEbits.LATE2
/***********************************
            Main
***********************************/
void main(void){
    char CMD = 0x30;

    ADCON1 = 0x0F;
    TRISE  = 0x00;
    TRISB  = 0x00; 
    LATB   = 0x00;
    
    CS = 0;
    SendByte(CMD);
    CS = 1;

    LATBbits.LATB0 = 1;
    while(1);
}
/***********************************
            SendByte
***********************************/
char SendByte(char byte){
char x = 0;

    for(x=0;x<8;x++){
    
        SCL = 0;

        if((byte & 0x80) != 0)
            SDO = 1;
        else
            SDO = 0;

        byte = byte << 1;

        SCL = 1;
    }
}
 
Last edited:
AHH! i cant get it. Its doesnt sync i guess. Can someone point me to some info on PIC -> PIC communication please. My hope is to send data from a 18F4620 to a 18F248.

I was testing on a 18F448 & 18F248 but no go :(
 
AHH! i cant get it. Its doesnt sync i guess. Can someone point me to some info on PIC -> PIC communication please. My hope is to send data from a 18F4620 to a 18F248.

Why not just use asyncronous data (like RS232)?, dead simple to do, and no concerns over trying to detect clock pulses without missing one. For simple communication between two PIC's why complicate it for no reason?.
 
i guess i need a break. I cant even get that to work (using software VIA C18):
This is the SLAVE
Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <sw_uart.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
void DelayTXBitUART(void);
void DelayRXBitUART(void);
void DelayRXHalfBitUART(void);
/***********************************
            Defines
***********************************/
#define SWTXD       PORTA
#define SWTXDpin    1
#define TRIS_SWTXD  TRISA

#define SWRXD       PORTA
#define SWRXDpin    2
#define TRIS_SWRXD  TRISA
/***********************************
            Main
***********************************/
void main(void){
    char CMD,x=0;           //ComManD
    int y = 0;

    ADCON1 = 0x0F;
    TRISB  = 0x00;
    TRISA  = 0xFF;
    TRISAbits.TRISA5 = 0;
    LATB = 0;
    OpenUART();

while(1){
   
    LATBbits.LATB1 = 1;    

    while(!CMD){
        CMD = ReadUART();
    }
    
    
    switch(CMD){
        case 0x30:                        
            LATBbits.LATB0 = 1;
            LATBbits.LATB1 = 0;
            break;
        default:
            LATB = 0xFF;  //ERROR
            break;
    }

    CMD = 0;
    LATBbits.LATB1 = 1;
}
}
/*************************************
            UsART
**************************************/
void DelayRXHalfBitUART(void){
    char x;
    x = (((((2*20000000) / (8*9600)) + 1) / 2) - 9) / 10;
    Delay10TCYx(x);
}

void DelayTXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 12) / 10;
    Delay10TCYx(x);
}

void DelayRXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 14) / 10;
    Delay10TCYx(x);
}

MASTER:
Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <sw_uart.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
void DelayTXBitUART(void);
void DelayRXBitUART(void);
void DelayRXHalfBitUART(void);
/***********************************
            Defines
***********************************/
#define SWTXD       PORTE
#define SWTXDpin    1
#define TRIS_SWTXD  TRISE

#define SWRXD       PORTE
#define SWRXDpin    2
#define TRIS_SWRXD  TRISE
/***********************************
            Main
***********************************/
void main(void){

    ADCON1 = 0x0F;
    TRISE  = 0x00;
    TRISEbits.TRISE0 = 1;

    TRISB  = 0x00; 
    OpenUART();    
    while(1){

        LATB = 0x00;
        while(PORTEbits.RE0);

        WriteUART(0x30);
        LATBbits.LATB0 = 1;    
    }
}
/*************************************
            UsART
**************************************/
void DelayRXHalfBitUART(void){
    char x;
    x = (((((2*20000000) / (8*9600)) + 1) / 2) - 9) / 10;
    Delay10TCYx(x);
}

void DelayTXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 12) / 10;
    Delay10TCYx(x);
}

void DelayRXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 14) / 10;
    Delay10TCYx(x);
}


Doesnt work. I need a beer. Ill be back.
 
YAY! it did work but the code to set the pins didnt so i had to rewrite the ASM but i was smart and left the original data as a comment. The issue is its in a bunch of file of the "C:\MCC18\src\pmc_common\SW_UART" Directory.

Code:
SWTXD           equ     PORTB           ; Transmit pin port and pin
SWTXDpin        equ     4
TRIS_SWTXD      equ     TRISB           ; Transmit pin tris and pin
SWRXD           equ     PORTB           ; Receive pin port and pin
SWRXDpin        equ     5
TRIS_SWRXD      equ     TRISB           ; Receive pin tris and pin

I had to change that. I assumed doing:

Code:
#define SWTXD       PORTA
#define SWTXDpin    1
#define TRIS_SWTXD  TRISA

#define SWRXD       PORTA
#define SWRXDpin    2
#define TRIS_SWRXD  TRISA

I thought i could simply do that and it would work. But thats not the case :(

So the fix was to copy that entire sw_usart folder to my project directory ad add them all in the project then edit them and compile it all
 
Last edited:
ok NOTE that code works fine for 1 byte but for a string its no good. Im trying to send and receive 1025 bytes.

I need to send 1 command and 1024 data bytes to another pic im using this code but it seems to be wrong. Only the first byte is received correct. The rest isnt. This test is trying just 6 bytes.

RECEIVE CODE:
Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <sw_uart.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
void DelayTXBitUART(void);
void DelayRXBitUART(void);
void DelayRXHalfBitUART(void);
/***********************************
            Main
***********************************/
unsigned char buff[6];
void main(void){
    unsigned char CMD,x=0;           //ComManD
    int y = 0;

    ADCON1 = 0x0F;
    TRISB  = 0x00;
    TRISA  = 0xFF;
    TRISAbits.TRISA5 = 0;
    LATB = 0;
    OpenUART();

while(1){
    LATB = 0x00;
    LATBbits.LATB1 = 1;    

    getsUART( buff, 5 );
    CMD = buff[0];

    switch(CMD){
        case 0x7E:                     
            LATBbits.LATB0 = 1;
            LATBbits.LATB1 = 0;
            break;
        default:
            LATB = 0xFF;  //ERROR
            break;
    }

    CMD = 0;
    LATBbits.LATB1 = 1;
}
}
/*************************************
            UsART
**************************************/
void DelayRXHalfBitUART(void){
    char x;
    x = (((((2*20000000) / (8*9600)) + 1) / 2) - 9) / 10;
    Delay10TCYx(x);
}

void DelayTXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 12) / 10;
    Delay10TCYx(x);
}

void DelayRXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 14) / 10;
    Delay10TCYx(x);
}

SEND CODE:
Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <sw_uart.h>

#pragma config WDT = OFF, LVP = OFF, OSC = HS
/***********************************
            Prototypes
***********************************/
void DelayTXBitUART(void);
void DelayRXBitUART(void);
void DelayRXHalfBitUART(void);
/***********************************
            Main
***********************************/
void main(void){
    char x;
    unsigned char mybuff [] = "~Jason";
    ADCON1 = 0x0F;
    TRISE = LATE = 0x00;
    TRISEbits.TRISE0 = 1;

    TRISB  = 0x00; 
    OpenUART();    
    while(1){

        LATB = 0x00;
        while(PORTEbits.RE0);

        putsUART( mybuff );

        LATBbits.LATB0 = 1;    
    }
}
/*************************************
            UsART
**************************************/
void DelayRXHalfBitUART(void){
    char x;
    x = (((((2*20000000) / (8*9600)) + 1) / 2) - 9) / 10;
    Delay10TCYx(x);
}

void DelayTXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 12) / 10;
    Delay10TCYx(x);
}

void DelayRXBitUART(void){
    char x;
    x = (((((2*20000000) / (4*9600)) + 1) / 2) - 14) / 10;
    Delay10TCYx(x);
}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top