Sonsivri
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
December 09, 2016, 06:32:02 18:32


Login with username, password and session length


Pages: [1]
Print
Author Topic: [HELP] XC peripheral libraries spi implementation  (Read 320 times)
0 Members and 1 Guest are viewing this topic.
biomed12
Junior Member
**
Offline Offline

Posts: 52

Thank You
-Given: 37
-Receive: 3


« on: October 15, 2016, 12:08:40 00:08 »

I couldn't understand the aim of writing/reading address information for spi protocol. I have learned the spi protocol from pic18f4620 datasheet but there is nothing about it. I want to use the protocol with dac and adc device. In these examples, programs just read the char array from other device. When I used the RS-232 serial communication with assembly or CCS C, I was reading first low byte of data and high byte of data. Is the SPI implementation needs the address information like I2C? 

codes for master side
Code:
/*********************************************************************
* NOTES:
* Code uses the Peripheral library support available with MCC18 Compiler
* Code Tested on:
* PicDem2+ demo board with PIC18F4685 controller
*
* SDO,SDI & SCK must be connected to the corresponding in slave
* MASTER SLAVE
*
* SDO <------------> SDI
* SDI <------------> SDO
* SCk <------------> SCK
* NOTE: Refer Slave source code also
**********************************************************************/
#define USE_OR_MASKS
#include <p18cxxx.h>
#include "spi.h"
unsigned char SPI_Send[21] = "MICROCHIP_SPI_MASTER";
unsigned char SPI_Recv[21];
//****************** SPI MASTER *******************************
void main(void)
{
unsigned char sync_mode=0;
unsigned char bus_mode=0;
unsigned char smp_phase=0;
unsigned char w=0;
CloseSPI(); // Turn off SPI modules if was previosly on
//***Configure SPI MASTER module to transmit in master mode ***
sync_mode = SPI_FOSC_64 ;
bus_mode = MODE_01;
smp_phase = SMPMID;
OpenSPI(sync_mode,bus_mode,smp_phase );
//*** WRITE INITIAL CHARECTER ***
while(WriteSPI(0xF5)); //send initial charecter to use the same as flag      //HERE I AM CONFUSED
at slave side and send it till successful transmision
//*** WRITE THE STRING TO SPI ****
putsSPI(SPI_Send); //send the string of data to be sent to slave
//*** Read the initial flag id ****
if( 0xF5 == ReadSPI() )
{
getsSPI(SPI_Recv,20); // read the string sent from slave
SPI_Recv[20] = '\0' ; //terminate the string with a null charecter
}
/* Turn off SPI module and clear IF bit */
CloseSPI();
while(1); //End of program
}



Codes for slave side

Code:

Example Source Code demonstrating peripheral library usage
/*********************************************************************
* NOTES:
* Code uses the Peripheral library support available with MCC18 Compiler
* Code Tested on:
* PicDem2+ demo board with PIC18F4685 controller
*
* SDO,SDI & SCK must be connected to the corresponding in slave
* MASTER SLAVE
*
* SDO <------------> SDI
* SDI <------------> SDO
* SCk <------------> SCK
* NOTE: Refer Master source code also
**********************************************************************/
#define USE_OR_MASKS
#include <p18cxxx.h>
#include "spi.h"
8.15 Serial Peripheral Interface (SPI) PIC18F Peripheral Library Help Document SPI Examples
unsigned char SPI_Send[25] = "MICROCHIP_SPI_SLAVE";
unsigned char SPI_Recv[25];
//**************** SPI SLAVE *******************************************
void main(void)
{
unsigned char sync_mode=0;
unsigned char bus_mode=0;
unsigned char smp_phase=0;
unsigned char w=0,temp;
for(w=0;w<25;w++)
SPI_Recv[w]=0;
CloseSPI(); // Turn off SPI modules if was previosly on
//***Configure SPI SLAVE module *****
sync_mode = SLV_SSOFF;
bus_mode = MODE_01;
smp_phase = SMPMID;
OpenSPI(sync_mode,bus_mode,smp_phase );
//****Read the initial flag byte sent by master ***
temp = ReadSPI(); //This is for address implementation in software     //HERE I AM CONFUSED
if(temp == 0xF5)
{
getsSPI(SPI_Recv,21); //recieve the string of data from master
SPI_Recv[21] = '\0' ; //put null charecter at the end of string recieved
while( PIR1bits.SSPIF!=1 ); //wait till completion of transmission
WriteSPI(0xF5); //send the software flag bit to master
while( PIR1bits.SSPIF!=1 ); //wait till completion of transmission
//***** WRITE THE STRING TO SPI ****
putsSPI(SPI_Send);
}
/* Turn off SPI module and clear IF bit */
CloseSPI();
while(1); //End of program
}

Logged
Gallymimu
Hero Member
*****
Offline Offline

Posts: 579

Thank You
-Given: 101
-Receive: 151


« Reply #1 on: October 15, 2016, 04:00:28 04:00 »

SPI doesn't use addressing at the hardware or protocol layer.  SPI uses chip select pins to select or "address" different devices.  

The application layer may require addressing (i.e. send a command, indicate an address to read write dummy bytes to get all the data read out).

Sorry I don't understand your question in further detail and your code isn't very useful without understanding the implementation of putsSPI and getsSPI.

It is definitely not like I2C where there is an explicit address at the protocol layer.

to talk to an ADC in polling mode something like this is usually done:

send SPI byte
wait for transmission complete flag to set
read SPI byte (so that the read buffer doesn't overflow but you can throw the byte away)


For a multichannel ADC you often do the above 2 or 3 times then:

send SPI dummy byte
wait for transmission to finish
read SPI byte (store it as it's the real ADC value now)

repeat above for Huh bytes
« Last Edit: October 15, 2016, 04:03:02 04:03 by Gallymimu » Logged
mars01
Junior Member
**
Offline Offline

Posts: 51

Thank You
-Given: 106
-Receive: 82


« Reply #2 on: October 15, 2016, 02:28:37 14:28 »

@biomed12
In the code snippets that you've posted, from what I can see, there is a protocol implemented over the SPI. This is not just an SPI driver usage but more: one chip is designated as master, and one (or many more others) as slaves.
Maybe, the ones that writed this code wanted to use the same lines for all the slave chips, including the CS.
No slave will answer the data request from the master unless it receives "the password". Also, the master knows which slave is answering from the received "password".

« Last Edit: October 15, 2016, 02:31:56 14:31 by mars01 » Logged
biomed12
Junior Member
**
Offline Offline

Posts: 52

Thank You
-Given: 37
-Receive: 3


« Reply #3 on: October 15, 2016, 08:38:29 20:38 »

SPI doesn't use addressing at the hardware or protocol layer.  SPI uses chip select pins to select or "address" different devices. 

The application layer may require addressing (i.e. send a command, indicate an address to read write dummy bytes to get all the data read out).

Sorry I don't understand your question in further detail and your code isn't very useful without understanding the implementation of putsSPI and getsSPI.

It is definitely not like I2C where there is an explicit address at the protocol layer.

to talk to an ADC in polling mode something like this is usually done:

send SPI byte
wait for transmission complete flag to set
read SPI byte (so that the read buffer doesn't overflow but you can throw the byte away)


For a multichannel ADC you often do the above 2 or 3 times then:

send SPI dummy byte
wait for transmission to finish
read SPI byte (store it as it's the real ADC value now)

repeat above for Huh bytes

Dear Gallymimu,

Thanks for your advices. I am trying to read adc values from 10-bit adc(MCP3008, Microchip). But, I am always getting bad bytes which are not expected bytes. For example, I put the analog input pin of MCP3008 to the 5v line, I expect 1024(decimal) but always I get wrong bytes. The MCP3008 adc device sending 10-bit adc data and SPI protocol is making 8 bir communication. Is there any issue at reading these datas? Briefly, this program reads adc values from device and sends it via usart to my pc.

 My code:
Code:
void main(void) {
    unsigned char adcDataLow,adcDataHigh;

    //setup usart and peripherals
    setupUsartOnlyTransmit();     //MY CUSTOM FUNCTION IN myLib.h was given below
    setupSPIforMCP3008();         //MY CUSTOM FUNCTION IN myLib.h was given below

    //wait for 0.1ms
    _delay(4000);
   
    while(1)
    {
      adcDataLow = readSPI();
      adcDataHigh = readSPI() & 0b00000011;
      sendToSerial(adcDataHigh);
      sendToSerial(adcDataLow);
    }
   
   
    return;
}

My custom functions:
Code:

void setupUsartOnlyTransmit()
{
//Reset usart register
    TXSTA = 0;
    RCSTA = 0;
   
    //async op
    TXSTAbits.SYNC = 0;
   
    //8 bit transfer enable
    TXSTAbits.TX9 = 0;
   
    //high baud rate select
    TXSTAbits.BRGH = 1;
   
    //clear interrupt flag
    PIR1bits.TXIF = 0;
   
    //disable interrupt on receipt
    PIR1bits.RCIF = 0;
   
    //disable interrupt on transmission
    PIE1bits.TXIE = 0;
   
    //16bit baud generator disable
    BAUDCONbits.BRG16 = 0;
   
    //set SPBRG
    //for 10MHZ fosc, 51 for 9600 baud
    //for 40MHZ fosc, 21 for 115200 baud, 255 for 9600 baud
// the term "fosc" in datasheet refers the cpu clock speed
SPBRG = 255;


//auto baud rate disable
BAUDCONbits.ABDEN = 0;
   
    //transmitter enable
    TXSTAbits.TXEN = 1;
   
    //USART module is set as active! this config should be done definetely!
    RCSTAbits.SPEN = 1;
   
    //configure pinouts
    TRISCbits.RC6 = 0;
}

void setupSPIasMaster()
{   
    //for 18f4620,
    //RC5 sdo
    //RC4 sdi
    //RC3 sck
    //RA5 SS
   
    SSPCON1 = 0x00;
   
    //ssp power on state
    SSPSTAT = 0x3f;
   
    //bus mode is 00, data transmit on falling edge
    //spi clock select
    //transmit occurs on transition from active to idle state
    SSPSTATbits.CKE = 1;
    SSPCON1bits.CKP = 0 ;
   
    //bus-phase
    SSPSTATbits.SMP = 0;
   
    //0100 = SPI Slave mode, clock = SCK pin, SS pin control enabled
    //0000 = SPI Master mode, clock = Fosc/2
    //SSPM3:SSPM0: Master Synchronous Serial Port Mode Select bits(3)
    SSPCON1bits.SSPM0 = 0;
    SSPCON1bits.SSPM1 = 0;
    SSPCON1bits.SSPM2 = 0;
    SSPCON1bits.SSPM3 = 0;
   
    //define clock bit as output
    TRISCbits.RC3 = 0;
   
    //set input output pins
    TRISCbits.RC4 = 1;
    TRISCbits.RC5 = 0;
   
    //enable syncronous serial communication
    SSPCON1bits.SSPEN = 1;
   
    //use RD0 pin as cs
    TRISDbits.RD0 = 0;
    LATDbits.LATD0 = 1;
    _delay(100);
    LATDbits.LATD0 = 0;
   
}

void setupSPIforMCP3008()
{
//settings for mcp3008
    //0b10000000 for single ended ch0
    //msb transmitted first
setupSPIasMaster();
    unsigned char settings = 0b10000000;
    _delay(4000);//0.1ms bekle
    //write leading zeros
    while(writeSPI(0x01));
//write settings to ADC
    while(writeSPI(settings));
}



Logged
Gallymimu
Hero Member
*****
Offline Offline

Posts: 579

Thank You
-Given: 101
-Receive: 151


« Reply #4 on: October 17, 2016, 12:10:43 00:10 »

Have you read the data sheet for the ADC?

It's pretty clear how it works in the data sheet.  If you read data out of it you will see a bunch of invalid data:

data coming back is in a 3 byte format:
XXXXXXXX XXXXXXY98 76543210

you need to do what I said before:

set CS
write 0x01 (start bit)
wait for transmit to complete
read SPIBUFF (throw data away)
write 0xNM (where N is the mode and channel and M is don't care)
wait for transmit to complete
read SPIBUFF (2 lowest bits are part of your data)
write 0xMM (M is don't cares)
wait for transmit to complete.
read SPIBUFF (lowest 8 bytes of data)
unset CS

Where X is garbage data Y is a null bit that is always zero and 9-0 are the 10 bits of your ADC measurement.

unfortunately your code doesn't make sense.

You need to realize you always have to WRITE  to SPI (send clocks) in order to READ from SPI.  Both actions occur simultaneously.  The only asynchronous part is you WRITE to SPIBUFF to start the transmission and you READ from SPIBUFF after the transmission is over to get the data that was clocked in.
Logged
biomed12
Junior Member
**
Offline Offline

Posts: 52

Thank You
-Given: 37
-Receive: 3


« Reply #5 on: October 17, 2016, 03:08:11 03:08 »

Dear Gallymimu,

Thanks to you, I realized that I had not understood the concept of spi though I read the datasheet of MCP3008 many times. I have completely understood SPI now.

Thanks.
Logged
Gallymimu
Hero Member
*****
Offline Offline

Posts: 579

Thank You
-Given: 101
-Receive: 151


« Reply #6 on: October 17, 2016, 05:46:50 05:46 »

Dear Gallymimu,

Thanks to you, I realized that I had not understood the concept of spi though I read the datasheet of MCP3008 many times. I have completely understood SPI now.

Thanks.

Awesome, glad it helped!
Logged
Pages: [1]
Print
Jump to:  


DISCLAIMER
WE DONT HOST ANY ILLEGAL FILES ON THE SERVER
USE CONTACT US TO REPORT ILLEGAL FILES
ADMINISTRATORS CANNOT BE HELD RESPONSIBLE FOR USERS POSTS AND LINKS

... Copyright 2003-2999 Sonsivri.to ...
Powered by SMF 1.1.18 | SMF © 2006-2009, Simple Machines LLC | HarzeM Dilber MC