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

16 Bit SPI with 16F877A- Is it possible?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

16 Bit SPI with 16F877A- Is it possible?
PostPosted: Fri Feb 27, 2015 1:22 am     Reply with quote

Hello Experts,

I am quite new to SPI with PICs.
Please help me out with the basics of SPI communication.

PIC 16F877A datasheet mentions that SPI is for 8bits.

I want to communicate with L9942 Stepper Motor Driver IC whose SPI frame width is 16bit.
Also the datasheet of L9942 Stepper Motor driver IC specifically says the following condition for its Data Input Pin (DI)

Serial data in (DI)
"The input pin is used to transfer data serial into the device. The data applied to the DI will be
sampled at the rising edge of the CLK signal and latched into an internal 16 bit shift register.
The first 3 bit are interpreted as address of the data register. At the rising edge of the CSN
signal the contents of the shift register will be transferred to the selected data register. The
writing to the register is only enabled if exactly 16 bits are transmitted within one
communication frame (i.e. CSN low). If more or less clock pulses are counted within one
frame the complete frame will be ignored. This safety function is implemented to avoid an
activation of the output stages by a wrong communication frame"


Please find the link below for the datasheet:
http://www.st.com/web/en/resource/technical/document/datasheet/CD00072898.pdf

Please help me out if I can interface PIC16F877A with L9942 via SPI by holding the SS pin of SPI for two bytes?

Or else what are the other solutions?

Thanks in Advance Smile
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Fri Feb 27, 2015 2:10 am     Reply with quote

Of course you can. Smile

Key is to understand SPI. Devices using 16bit SPI (or 24bit - some Texas devices), can be driven with 8bit SPI fine. On SPI, the device is 'synchronous', so depends on the clock from the master device. An 8bit SPI master talking to a 16bit SPI slave, just sends two 8bit bytes one after the other.
The sequence is 'drop the CSN line'.
Send byte #1.
Send byte #2.
Raise the CSN.

Now there is a fractional 'pause' in the clock between byte #1, and byte #2, as the PIC SPI buffer is reloaded, but because of the synchronous nature this doesn't matter at all.

The key things are that you must wait for the second byte to send before raising CSN, and must (obviously) get the bytes in the right order (remember SPI is usually MSB first).

Now things to look at are the SPI clock rate (4MHz max), and the modes (sampling is on rising edge, and clock can idle high or low, so Mode1, or mode3 - I'll use 1).

The CCS #use spi, and spi_xfer driver can do this automatically for you.
Code:

//only an overview
#use SPI (MASTER, MODE=1, BAUD=4MHz, SPI1, BITS=16, STREAM=L9942)
//Using hardware SPI
#define CSN PIN_xx //whatever pin you want

//Then at the start of code
   int16 rval;
   int16 tval;
   //ensure CSN goes high
   output_high(CSN);

//Then to send:
   tval = what_you_want_to_send;
   output_low(CSN); //start the transfer
   rval=spi_xfer(L9942,tval,16);
   output_high(CSN); //and complete

Now key is loading the return value. This forces spi_xfer to _wait_ for the transaction to complete, so CSN can be raised after the transfer. If you don't wait for the return value, spi_xfer will exit after one byte has sent, and the other is 'in transit'.

So this sends the 16bit value 'what_you_want_to_send' to the device. Remember the top three bits will be the register address.
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

PostPosted: Fri Feb 27, 2015 3:28 am     Reply with quote

Thanks for the great response.

Quote:
Now there is a fractional 'pause' in the clock between byte #1, and byte #2, as the PIC SPI buffer is reloaded, but because of the synchronous nature this doesn't matter at all


From this I understand that, since master holds control over the clock, there won't be any pulse from the Master SCK to the Slave even when there is a fractional 'pause'. Since if this can be ensured by the Master SPI, there won't be any data and no. of pulse mismatch at the slave.

Is my understanding right?
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Fri Feb 27, 2015 8:07 am     Reply with quote

With SPI the clock duty cycle timing can be erratic with no harm.

What matters is that the timing of clock to data is correct.

ie: change data -then toggle clock. and repeat as needed.

SPI frames of ANY bit count can be transferred this way -
and even simple bit-banging works perfectly.
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

PostPosted: Fri Mar 27, 2015 4:59 am     Reply with quote

Experts,
Please find program below:
Code:

#include "E:\EMBEDDED\PICDEM 2 PLUS Projects\SPI_L9942\SPI_L9942.h"

#use spi(MASTER, MODE=1, DO = PIN_C5, DI = PIN_C4, CLK = PIN_C3, baud = 100000, BITS = 8, MSB_FIRST,  stream = L9942 )

#define CSN PIN_B5
#define DIR PIN_B4
#define EN PIN_B3

#define STALL PIN_B3

void L9942_init();


int8 tval;
int8 rval;


int8 t_register0H=0b00000000;//15-13_Address,12-8_Phase Counter
int8 r_register0H;
int8 t_register0L=0b10000110;//7_DM2.6_DM1.5_DM0(Decay Mode),4_SR1.3_SR0(Slew Rate),2_ST1.1_ST0(Step Mode),0_DIR
int8 r_register0L;

void L9942_init()
{

output_high(CSN);                         //REGISTER 0
tval=t_register0H;
output_low(CSN);
rval=spi_xfer(L9942,tval,8);
r_register0H=rval;
tval=t_register0L;
rval=spi_xfer(L9942,tval,8);
r_register0L=rval;

}

void main()
{

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_psp(PSP_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
 
   output_high(EN);   
   L9942_init();
   output_high(EN);
   
   while(1)
   {
   
   output_high(EN);
   
   if(input(DIR))
   {
   bit_set(t_register0L,0);
   }
   else
   {
   bit_clear(t_register0L,0);
   }
     
   }
     
}

Is the basic coding right or something major is missing? (for SPI communication)

Controller: PIC16F877A (Master)
L9942 Driver (Slave)
_________________
-humble request from a beginner
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 27, 2015 9:56 am     Reply with quote

Quote:
#use spi(MASTER, MODE=1, DO = PIN_C5, DI = PIN_C4, CLK = PIN_C3, baud = 100000, BITS = 8, MSB_FIRST, stream = L9942 )

Did you read the data sheet for the L9942 ?
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/datasheet/CD00072898.pdf

There is a section which tells you the SPI mode to use:
Quote:

4.3 Serial peripheral interface (SPI)

This device uses a standard 16 bit SPI to communicate with a
microcontroller. The SPI can be driven by a microcontroller with its SPI
peripheral running in following mode: CPOL = 0 and CPHA = 0.


If you Google for SPI modes, you will find websites that tell you
the SPI mode if CPOL=0 and CPHA=0:
http://www.byteparadigm.com/kb/admin/media_store/2/AA-00255/figure3.jpg
http://www.totalphase.com/support/articles/200349236-SPI-Background#modes
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

PostPosted: Tue Apr 07, 2015 2:37 am     Reply with quote

Thank You for your grateful response.
I have changed the mode to MODE0. Still there are issues with SPI communication.

Need to understand more on how this SPI communication works.
Here in my code I am using spi_xfer () function. I have initialized variables for both transferring and receiving.

For my driver IC, I have to send data to 8 registers and each register is of 16 bits.So I have initialized two variables for each registers and sending both one after the other having CSN High.

With spi_xfer (), it also receives the data from the slave (Driver IC in my case) during the falling edge of the clock. But the slave (Driver IC) does not send any data for the first three clock cycles as it is the address. It actually sends the data for the address selected in the data sent to slave (Driver IC).

So,do I have only 5 bits of data received or how it is?
If it is only 5bits of data, how it is stored in the receive buffer?

Also there is a fault bit sent by the slave when both the Clock (CLK) and CSN are low. Will this also be stored in the receive buffer?

I am displaying the received values in an LCD, but they are not the same which I have sent.

Is my SPI programming sequence right in the code?
Code:

#include "E:\EMBEDDED\PICDEM 2 PLUS Projects\SPI_L9942\SPI_L9942.h"

#use spi(MASTER, MODE=0, DO = PIN_C5, DI = PIN_C4, CLK = PIN_C3, baud = 10000, BITS = 8, MSB_FIRST,  stream = L9942 )

#include <flex_lcd_16x2.h>

#define LED PIN_B1
#define CSN PIN_B2
#define EN PIN_B3
#define STALL PIN_B4

#define RDIR PIN_A4
#define LDIR PIN_B0

#define input1 PIN_E0
#define input2 PIN_E1
#define input3 PIN_E2

int8 register_val,i,bit;

void L9942_init();
void default_display();


int8 tval;
int8 rval;


int8 t_register0H=0b00000000;//15-13_Address,12-8_Phase Counter
int8 r_register0H=0b00000000;
int8 t_register0L=0b10011000;//7_DM2.6_DM1.5_DM0(Decay Mode),4_SR1.3_SR0(Slew Rate),2_ST1.1_ST0(Step Mode),0_DIR10011001
int8 r_register0L=0b00000000;

int8 t_register1H=0b00110100;//15-13_Address,12-10_DAC Scale, 9-8_Control bits of DAC (read only)
int8 r_register1H=0b00100000;
int8 t_register1L=0b00000000;//7-0_Control bits of DAC (read only)
int8 r_register1L=0b00000000;

int8 t_register2H=0b01000110;//15-13_Address,12-8_Current Profile 1
int8 r_register2H=0b01000000;
int8 t_register2L=0b00000010;//7_OVW(Over Voltage),6-5_Test Pins(should be programmed to zero),4-0_Current Profile 0
int8 r_register2L=0b00000000;

int8 t_register3H=0b01110001;//15-13_Address,12-8_Current Profile 3
int8 r_register3H=0b01100000;
int8 t_register3L=0b00001100;//7_D1,6_D0,5_NPWM,4-0_Current Profile 2
int8 r_register3L=0b00000000;

int8 t_register4H=0b10011010;//15-13_Address,12-8_Current Profile 3
int8 r_register4H=0b10000000;
int8 t_register4L=0b10010110;//7_D4,6_D3,5_D2,4-0_Current Profile 4
int8 r_register4L=0b00000000;

int8 t_register5H=0b10111110;//15-13_Address,12-8_Current Profile 7
int8 r_register5H=0b10100000;
int8 t_register5L=0b10011101;//7_D7,6_D6,5_D5,4-0_Current Profile 6
int8 r_register5L=0b00000000;

int8 t_register6H=0b11000000;//15-13_Address,12_CLR6 (clears read only),11_SST,10_FT,9_PWM Freq,8_ST(read only)
int8 r_register6H=0b11000000;
int8 t_register6L=0b00011111;//7_RREF Error(read only),6_Phase B Open Status(read only),5_Phase A Open Status(read only),4-0_Current Profile 8
int8 r_register6L=0b00000000;

int8 t_register7H=0b11100000;//15-13_Address,12_CLR7,11_TSD(read only),10_TW(read only),9_OV(W)(read only),8_UV
int8 r_register7H=0b11100000;
int8 t_register7L=0b00000000;//7-0_Over Current Failure-I>2A (read only)
int8 r_register7L=0b00000000;


void L9942_init()
{

delay_ms(5);
output_high(CSN); 
 
tval=t_register0H;       //REGISTER 0
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register0H=rval;
tval=t_register0L;
rval=spi_xfer(L9942,tval,8);
r_register0L=rval;
output_high(CSN);
delay_ms(10);
                             
tval=t_register0H;      //REGISTER 0
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register0H=rval;
tval=t_register0L;
rval=spi_xfer(L9942,tval,8);
r_register0L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register1H;      //REGISTER 1
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register1H=rval;
tval=t_register1L;
rval=spi_xfer(L9942,tval,8);
r_register1L=rval;
output_high(CSN);
delay_ms(10);
           
tval=t_register1H;      //REGISTER 1   
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register1H=rval;
tval=t_register1L;
rval=spi_xfer(L9942,tval,8);
r_register1L=rval;
output_high(CSN);
delay_ms(10);
       
tval=t_register2H;      //REGISTER 2   
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register2H=rval;
tval=t_register2L;
rval=spi_xfer(L9942,tval,8);
r_register2L=rval;
output_high(CSN);
delay_ms(10);
           
tval=t_register2H;      //REGISTER 2     
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register2H=rval;
tval=t_register2L;
rval=spi_xfer(L9942,tval,8);
r_register2L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register3H;      //REGISTER 3
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register3H=rval;
tval=t_register3L;
rval=spi_xfer(L9942,tval,8);
r_register3L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register3H;      //REGISTER 3
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register3H=rval;
tval=t_register3L;
rval=spi_xfer(L9942,tval,8);
r_register3L=rval;
output_high(CSN);
delay_ms(10);
           
tval=t_register4H;      //REGISTER 4   
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register4H=rval;
tval=t_register4L;
rval=spi_xfer(L9942,tval,8);
r_register4L=rval;
output_high(CSN);
delay_ms(10);
             
tval=t_register4H;      //REGISTER 4
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register4H=rval;
tval=t_register4L;
rval=spi_xfer(L9942,tval,8);
r_register4L=rval;
output_high(CSN);
delay_ms(10);
             
tval=t_register5H;      //REGISTER 5 
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register5H=rval;
tval=t_register5L;
rval=spi_xfer(L9942,tval,8);
r_register5L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register5H;      //REGISTER 5
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register5H=rval;
tval=t_register5L;
rval=spi_xfer(L9942,tval,8);
r_register5L=rval;
output_high(CSN);
delay_ms(10);
             
tval=t_register6H;      //REGISTER 6
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register6H=rval;
tval=t_register6L;
rval=spi_xfer(L9942,tval,8);
r_register6L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register6H;      //REGISTER 6
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register6H=rval;
tval=t_register6L;
rval=spi_xfer(L9942,tval,8);
r_register6L=rval;
output_high(CSN);
delay_ms(10);
               
tval=t_register7H;      //REGISTER 7
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register7H=rval;
tval=t_register7L;
rval=spi_xfer(L9942,tval,8);
r_register7L=rval;
output_high(CSN);
delay_ms(10);
             
tval=t_register7H;      //REGISTER 7   
output_low(CSN);
delay_ms(10);
rval=spi_xfer(L9942,tval,8);
r_register7H=rval;
tval=t_register7L;
rval=spi_xfer(L9942,tval,8);
r_register7L=rval;
output_high(CSN);
delay_ms(10);

}

void default_display()
{
   lcd_putc('S');
   lcd_putc('H');
   lcd_putc('L');
   lcd_putc('_');
   lcd_putc('A');
   lcd_putc('F');
   lcd_putc('S');
 }

void main()
{

   //setup_adc_ports(NO_ANALOGS);
   //setup_adc(ADC_CLOCK_DIV_2);
   //setup_psp(PSP_DISABLED);
   //setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   //setup_timer_1(T1_DISABLED);
   //setup_timer_2(T2_DISABLED,0,1);
   //setup_comparator(NC_NC_NC_NC);
   //setup_vref(FALSE);
   
  // set_tris_a(0b11111111);
  // set_tris_b(0b00000000);
   
   lcd_init();
   default_display();
   output_high(EN);
   delay_ms(3000);
   L9942_init();
   output_low(CSN);
   output_high(EN);
   
    lcd_init();
       
 while(1)
   {
   
    output_high(EN);
    if(input(input1)==0&&input(input2)==0&&input(input3)==0) //register 0
    {
    register_val=0;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 0");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register0H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register0L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
   
    if(input(input1)==0&&input(input2)==0&&input(input3)==1) //register 1
    {
    register_val=1;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 1");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register1H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register1L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
   
    if(input(input1)==0&&input(input2)==1&&input(input3)==0) //register 2
    {
    register_val=2;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 2");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register2H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register2L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
   
    if(input(input1)==0&&input(input2)==1&&input(input3)==1) //register 3
    {
    register_val=3;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 3");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register3H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register3L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
   
 
    if(input(input1)==1&&input(input2)==0&&input(input3)==0) //register 4
    {
    register_val=4;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 4");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register4H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register4L,i);
    printf(lcd_putc,"%d",bit);
    }
    }

    if(input(input1)==1&&input(input2)==0&&input(input3)==1) //register 5
    {
    register_val=5;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 5");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register5H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register5L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
   
    if(input(input1)==1&&input(input2)==1&&input(input3)==0) //register 6
    {
    register_val=6;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 6");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register6H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register6L,i);
    printf(lcd_putc,"%d",bit);
    }
    } 
   
    if(input(input1)==1&&input(input2)==1&&input(input3)==1) //register 7
    {
    register_val=4;
   
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register 7");
    lcd_putc('\n');
    for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register7H,i);
    printf(lcd_putc,"%d",bit);
    }
   for(i=7;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register7L,i);
    printf(lcd_putc,"%d",bit);
    }
    }
    else
    {
    default_display();
    delay_ms(10);
    }
 

   }
   
   

}


++++++++++++++++
Added code block.

- Forum Moderator
++++++++++++++++

_________________
-humble request from a beginner
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Tue Apr 07, 2015 3:03 am     Reply with quote

1) Please learn to use the code buttons......
2) Approach is much more complex than it wants to be.
Just the initialisation, but:
Code:

#use spi(MASTER, MODE=0, DO = PIN_C5, DI = PIN_C4, CLK = PIN_C3, baud = 1000000, BITS = 32, MSB_FIRST, stream = L9942 )

int16 register_init[8] = { 0b000000000011000,
    0b0011010000000000,
    0b0100011000000010,
    0b0111000100001100,
    0b1001101010010110,
    0b1011111010011101,
    0b1100000000011111,
    0b1110000000000000 };
//Initial values to transmit for all eight register

int16 receive[8]= {0};
//receive buffer

int16 send16(int16 val);
{
    int16 rval;
    output_low(CSN);
    rval=spi_xfer(L9942,val,16); //send 16bits and get 16bit return
    output_high(CSN);
    return rval;
}

void L9942_init()
{
    int8 ctr;
    output_high(CSN)); //ensure select start high
    delay_ms(5);
    for (ctr=0;ctr<8;ctr++)
    {
       receive[ctr]=send16(register_init[ctr]);
       //send 16bit initialisation value and get reply
       delay_us(2)
    }
}


Anything repeated more than perhaps a couple of times, should just be done as a routine.

If you want to access the bytes, just use make8.

spi_xfer (unlike the older spi_read, and spi_write), will automatically handle outputting multiple bytes if asked to.
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

PostPosted: Thu Apr 09, 2015 12:31 am     Reply with quote

Thank You Experts...
I have changed approach as you suggested by you.
Also I am sending the register value twice which makes it happen.

But reading the register value back from the slave is a problem now for me, because the DI of controller shall receive only 13 bits in return. So how are the values stored in the variable?

Please refer to the attached image link below for the Transfer timing requirement with the slave (L9942 Driver)

[img] https://drive.google.com/file/d/0B-AU2eF393PpRWNnaW8wd3Rodm8/view?usp=sharing [/img]

Should I use any delay between spi_xfer() function and the return value assignment operation?

Code:

#include "E:\EMBEDDED\PICDEM 2 PLUS Projects\SPI_L9942\SPI_L9942.h"

#use spi(MASTER, MODE=0, DO = PIN_C5, DI = PIN_C4, CLK = PIN_C3, baud = 1000, BITS = 32, MSB_FIRST,  stream = L9942 )

#include <flex_lcd_16x2.h>
     
#define LED PIN_B1
#define CSN PIN_B2
#define EN PIN_B3
#define STALL PIN_B4

#define DIR PIN_B0

#define input1 PIN_E0
#define input2 PIN_E1
#define input3 PIN_E2


void default_display();
void L9942_init();
void r_registers_value(int register_val);


int8 register_val,i,bit;
int16 tval;
int16 rval;
int8 reg_ctr;

int16 t_register_init[8]={0b0000000010011110,   //15-13_Address,12-8_Phase Counter,7_DM2.6_DM1.5_DM0(Decay Mode),4_SR1.3_SR0(Slew Rate),2_ST1.1_ST0(Step Mode),0_DIR10011001
                          0b0011000000000000,   //15-13_Address,12-10_DAC Scale, 9-8_Control bits of DAC (read only),7-0_Control bits of DAC (read only))
                          0b0100011000000010,   //15-13_Address,12-8_Current Profile 1,7_OVW(Over Voltage),6-5_Test Pins(should be programmed to zero),4-0_Current Profile 0// 0100011000000010
                          0b0111000100001100,   //15-13_Address,12-8_Current Profile 3,7_D1,6_D0,5_NPWM,4-0_Current Profile 2 //0111000100001100
                          0b1001101000010110,   //15-13_Address,12-8_Current Profile 5,7_D4,6_D3,5_D2,4-0_Current Profile 4 //1001101000010110
                          0b1011111000011101,   //15-13_Address,12-8_Current Profile 7,7_D7,6_D6,5_D5,4-0_Current Profile 6 //1011111000011101 //1100000000011111
                          0b1100000000011111,   //15-13_Address,12_CLR6 (clears read only),11_SST,10_FT,9_PWM Freq,8_ST(read only),7_RREF Error(read only),6_Phase B Open Status(read only),5_Phase A Open Status(read only),4-0_Current Profile 8
                          0b1110000000000000};  //15-13_Address,12_CLR7,11_TSD(read only),10_TW(read only),9_OV(W)(read only),8_UV,7-0_Over Current Failure-I>2A (read only) //1110000000000000

int16 r_register[8]={0b0000000000000000,   //15-13_Address,12-8_Phase Counter,7_DM2.6_DM1.5_DM0(Decay Mode),4_SR1.3_SR0(Slew Rate),2_ST1.1_ST0(Step Mode),0_DIR10011001
                     0b0010000000000000,   //15-13_Address,12-10_DAC Scale, 9-8_Control bits of DAC (read only,7-0_Control bits of DAC (read only))
                     0b0100000000000000,   //15-13_Address,12-8_Current Profile 1,7_OVW(Over Voltage),6-5_Test Pins(should be programmed to zero),4-0_Current Profile 0
                     0b0110000000000000,   //15-13_Address,12-8_Current Profile 5,7_D1,6_D0,5_NPWM,4-0_Current Profile 2
                     0b1000000000000000,   //15-13_Address,12-8_Current Profile 3,7_D4,6_D3,5_D2,4-0_Current Profile 4
                     0b1010000000000000,   //15-13_Address,12-8_Current Profile 7,7_D7,6_D6,5_D5,4-0_Current Profile 6
                     0b1100000000000000,   //15-13_Address,12_CLR6 (clears read only),11_SST,10_FT,9_PWM Freq,8_ST(read only),7_RREF Error(read only),6_Phase B Open Status(read only),5_Phase A Open Status(read only),4-0_Current Profile 8
                     0b1110000000000000};  //15-13_Address,12_CLR7,11_TSD(read only),10_TW(read only),9_OV(W)(read only),8_UV,7-0_Over Current Failure-I>2A (read only)
void L9942_init()
{

delay_ms(6);
output_high(CSN); 

for(reg_ctr=0;reg_ctr<8;reg_ctr++)
{
for(j=0;j<2;j++)
{
tval=t_register_init[reg_ctr];
output_low(CSN);
delay_ms(100);
rval=spi_xfer(L9942,tval,16);
r_register[reg_ctr]=rval;
delay_ms(100);
output_high(CSN);
delay_ms(100);
}
}
}

void r_registers_value(int register_val)
{
    lcd_gotoxy(1,1);
    printf(lcd_putc,"Register ");
    printf(lcd_putc,"%d",register_val);
    lcd_putc('\n');
    for(i=15;i>=0;i--)
    {
    if(i==(-1))
    break;
    bit=bit_test(r_register[register_val],i);
    printf(lcd_putc,"%d",bit);
    }
}

void main()
{
   
   lcd_init();
   default_display();
   output_high(EN);
       
   delay_ms(3000);
   L9942_init();
   output_high(EN);
   output_low(CSN);
     
   lcd_init();
       
 while(1)
   {
     
    output_high(EN);
    /* Keypad code to select the register output to be displayed. The key is scanned and the appropriate value is stored in register_val variable*/
     r_registers_value(register_val);
   
    }
     

}

_________________
-humble request from a beginner
Ttelmah



Joined: 11 Mar 2010
Posts: 19236

View user's profile Send private message

PostPosted: Thu Apr 09, 2015 1:28 am     Reply with quote

First, printing. Why waste time and code printing all the bits one by one?.
string=itoa(value,2,string);

converts a value into a binary string. Part of stdlib. It's a standard C function.

Then spend some time actually reading the data sheet. Look at figure 10 'transfer timing diagram'. Note how the chip returns 3 bits shown as 'fault bit', then clocks out 13bits of the value being returned. Since SPI is MSb first, means the register value if the low 13 bits in the value returned.

The data sheet also answers the question about delays: Look at what Tcsn must be. Then think why I have a particular delay between the functions.

Then, CSN, wants to be high when you arrive in the code. This should be part of your chip initialisation at the start of the main. Why are you setting it high when you have finished?. Also why the enormous delays. The load times of registers etc., are in nSec. mSec delays may well cause chip problems leaving parts of it programmed to modes you don't want.

You seem also to be determined to do things as slowly as possible. This risks problems. When programming a chip involving power, you need to be sending the values ASAP, or if it momentarily goes into an invalid setting, you can damage hardware. The whole programming should be done in a few uSeconds, not at 1000bps, with mSec delays. Most such chips do have _minimum_ clock rates. The data sheet has it being programmed at 4MHz, to 5MHz.

Then you are not having to send the data twice. It is programmed the first time you send it, but you need to understand SPI.
When you clock a value 'to' an SPI register, you receive 'back', the value that _was_ in the register. The new value is in there. You are wasting time by sending it a second time. Unless you have no confidence at all in your hardware, you _know_ what you have sent.

The data sheet has the double transfer described, with the comment that if you want to be sure the chip has received the data, clock it to it twice, and then verify what is read back matches what is sent.

Why do you initialise the receive registers?. Since you fill them with a value returned, putting values into them is pointless.
indiansiva555@gmail.com



Joined: 23 Jun 2012
Posts: 22

View user's profile Send private message

PostPosted: Fri Apr 10, 2015 1:44 am     Reply with quote

Thank You..

    Return value works perfectly with the current program itself, I had not observed it properly. The last 13 bits are actually showing the status of the registers, but only if I write to the slave twice.

    I have now changed CSN and reduced timings as suggested which has improved the response time for my direction input.

    With change in baud rate, I observe a strange change in smoothness of the motor rotation. As baud rate increases, the motor is not smooth in operation but SPI communication is proper. Why does it happen so? Is it because of improper impedance in the driver IC circuitry?

_________________
-humble request from a beginner
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