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 CCS Technical Support

SPI help
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Dec 03, 2006 2:57 pm     Reply with quote

Quote:
I use the setup_spi(MASTER | H_TO_L | DIV_4)
With respect to what Ttelmah wrote about operating the ADC in continuous mode and reading the status bit I recommend you study chapter 5.5 of the MCP3551 datasheet. It is recommended to operate the SPI-bus either in mode 0,0 or mode 1,1. You are operating the SPI-bus in mode 1,0.
In mode 0,0: read 4 bytes
In mode 1,1: read 3 bytes

Configuring the SPI-modes is always very confusing to me because Motorola (the inventor of SPI), Microchip and CCS do things in different ways. That's why I use the table below as reference
Code:
//     MOTOROLA              MICROCHIP                 CCS
//---------------------------------------------------------------------------------
//   SPI Mode 0,0   ==    CKP = 0, CKE = 1   ==   SPI_L_TO_H | SPI_XMIT_L_TO_H
//   SPI Mode 0,1   ==    CKP = 0, CKE = 0   ==   SPI_L_TO_H
//   SPI Mode 1,0   ==    CKP = 1, CKE = 1   ==   SPI_H_TO_L
//   SPI Mode 1,1   ==    CKP = 1, CKE = 0   ==   SPI_H_TO_L | SPI_XMIT_L_TO_H


Use this in your program as
Code:

#define SPI_MODE_0_0  (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1  (SPI_L_TO_H)
#define SPI_MODE_1_0  (SPI_H_TO_L)
#define SPI_MODE_1_1  (SPI_H_TO_L | SPI_XMIT_L_TO_H)

setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_4 );


Edit: Fixed error in number of bytes to read in mode 0,0 and 1,1.


Last edited by ckielstra on Sun Dec 03, 2006 4:01 pm; edited 1 time in total
das
Guest







SPI Help
PostPosted: Sun Dec 03, 2006 3:05 pm     Reply with quote

I will try that. Right now, here is the current code:

#int_RDA
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)

int byte1, byte2, byte3, byte4;
int byte_1, byte_2, byte_3, byte_4;
int32 value;
int i;
int completed, loop;



RDA_isr()
{
puts("RDA was tripped");
}



void main()
{
int loop = 1;
OUTPUT_HIGH(PIN_D0); //Start with CS high

setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_4 );

delay_ms(5000); //Delay 5 seconds
puts("Magnum Torque Meter Initialized");
while(TRUE)
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
loop = 1;
OUTPUT_LOW(PIN_D0); //Start the conversion
delay_ms(10); //Delay 10 ms for the conversion to complete
do //Do...while loop
{
if(input(PIN_C4) == 0) //Check to see if the conversion is completed
{
byte_4 = spi_read(byte4);
byte_3 = spi_read(byte3);
byte_2 = spi_read(byte2);
byte_1 = spi_read(byte1);

value = make32(byte_4, byte_3, byte_2, byte_1);
for(i = 0; i < 32; i++)
{
putc(bit_test(value, 31 - i));
}
OUTPUT_HIGH(PIN_D0);
completed = 1;
}

if(input(PIN_C4) == 1)
{
delay_us(1);
} //Closing if PIN_
}while(loop = 1);
delay_ms(10000);
}
}
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Dec 03, 2006 3:41 pm     Reply with quote

Some general remarks:
- When posting code on this forum please use the 'code' buttons. It will help to preserve the layout of your program and makes it easier for us to read the code.
- When debugging a problem like this, get rid of all other program code that might interfere. Especially enabled interrupts might cause unexpected side effects.
- Never use a printf or put instruction in an interrupt handler unless you know and accept the side effects. Receiving a character on the UART will take the same amount of time as sending a single character. You are receiving one character and transmitting 10-fold, this will block receiving and cause buffer overflow. The UART will stop responding at receive buffer overflow (the third character). Resetting the UART requires specific actions or adding the ERRORS directive to the #use RS232 directive.


Then about your program:
- Move the enable_interrupt() functions out of the while loop. You never disable these functions, so why add the overhead?
- I made a mistake in an earlier post. For the spi_read() to generate a clock signal you have to pass the spi_read() function a value, however this doesn't have to be a variable. Just any constant value will do for generating the clock signal, for example spi_read(0).
- while(loop = 1); Change this to '=='
- In SPI-mode 0,0 you are supposed to read 3 bytes, not 4.
- You said you want to operate in single conversion mode. If so, then your handling of the ChipSelect line seems incorrect (read Ttelmah's note on this).


Last edited by ckielstra on Sun Dec 03, 2006 3:46 pm; edited 1 time in total
das
Guest







SPI Help
PostPosted: Sun Dec 03, 2006 3:43 pm     Reply with quote

I refined some of the code shown above - and made changes to keep it in constant conversion mode. I am still seeing all outputs as zeros. Any other ideas? Current code is:

#int_RDA
#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)

int byte1, byte2, byte3, byte4;
int byte_1, byte_2, byte_3, byte_4;
int32 value;
int i;
int completed, loop;



RDA_isr()
{
puts("RDA was tripped");
}



void main()
{
int loop = 1;
OUTPUT_LOW(PIN_D0); //Start with CS high

setup_spi(SPI_MASTER | SPI_MODE_0_0 | SPI_CLK_DIV_4 );

delay_ms(5000); //Delay 5 seconds
puts("Initialized"); //Output string for debug
while(TRUE)
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
loop = 1;
delay_ms(10); //Delay 10 ms for the conversion to complete
do //Do...while loop
{
if(input(PIN_C4) == 0) //Check to see if the conversion is completed
{
byte_4 = spi_read(byte4);
byte_3 = spi_read(byte3);
byte_2 = spi_read(byte2);
byte_1 = spi_read(byte1);

value = make32(byte_4, byte_3, byte_2, byte_1);
for(i = 0; i < 32; i++)
{
putc(bit_test(value, 31 - i) + 48);
}
putc(10);
putc(13);
loop = 0;
}

if(input(PIN_C4) == 1)
{
delay_us(1);
}
delay_ms(10000);
}while(loop = 1);
}
}

I know that you said in a previous response something about the
if(input(PIN_C4) == 0)

Can you elaborate?
Ttelmah
Guest







PostPosted: Sun Dec 03, 2006 3:44 pm     Reply with quote

Your code, now generates 32 clocks. This won't work.
You need to either generate 25 clocks, and not operate the CS, or generate 24 and operate the CS.
Generating 32 clocks, will result in the bytes being shifted, and a garbage result.
The way to generate the extra clock, is to simply toggle it in software.
Code:

#bit SSPEN=0x14.5
#bit SCL=0x7.3
//Add this after your three reads.


//Ensure the line is the same polarity as the SPI leaves it
SCL=1;
//Turn off the SPI
SSPEN=0;
//Clock the line low
SCL=0;
delay_cycles(1);
//clock the line high
SCL=1;
//turn the SSP back on
SSPEN=1;

//Now you can read the input bit, and see the conversion status in
//continuous mode.

I am directly accessing the bit, rather than using the 'output' instruction, so that TRIS doesn't get changed (it is already set as output for the SPI).

As an aside, Ckielstra is dead right that the SPI mode is wrong, but it shouldn't matter. The reason is that the value of the second bit in the SPI settings (CKE), only affects how data is sent. The chip you are using, only receives data, so shouldn't 'care' if this is right. In fact the description in the data sheet is 'misleading' here really, since it should accept modes 0,x, or 1,x, according to how the data is being read. It is still 'better' to get it right, but I don't think that affects your problem....

Best Wishes
das
Guest







SPI Help
PostPosted: Sun Dec 03, 2006 3:51 pm     Reply with quote

Sorry - I didn't realize about the code posting. I disabled what you recommended. Looking at the Mode 0 0 it generates 4 bytes - not three based on the Figure 5-7. That would seem to work better for the continuos conversion anyway as it will send out the 25th clock cycle.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

Re: SPI Help
PostPosted: Sun Dec 03, 2006 3:59 pm     Reply with quote

das wrote:
Looking at the Mode 0 0 it generates 4 bytes - not three based on the Figure 5-7.
You are right, I reversed 0,0 and 1,1.
das
Guest







SPI Help
PostPosted: Sun Dec 03, 2006 4:11 pm     Reply with quote

Thank you for the help. I am having some issues compiling the low level changes in. I am getting errors on your recommendation. Do these need another specification?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Dec 03, 2006 4:22 pm     Reply with quote

What is the version number of your compiler?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sun Dec 03, 2006 5:05 pm     Reply with quote

A problem in your program is that you are trying to read the _RDY signal from PIN_C4. This will return undefined values as the pin is used by the SPI module.
Not tested, but could you give the following program a try?

Code:
#include <16F877.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define SPI_MODE_0_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_0_1 (SPI_L_TO_H)
#define SPI_MODE_1_0 (SPI_H_TO_L)
#define SPI_MODE_1_1 (SPI_H_TO_L | SPI_XMIT_L_TO_H)

#define LF  10
#define CR  13

#bit SSPEN=0x14.5


void main()
{
  int8 byte_1, byte_2, byte_3;
  int8 i;
  int32 value;

  output_high(PIN_D0); //Start with CS high
  setup_spi(SPI_MASTER | SPI_MODE_1_1 | SPI_CLK_DIV_4 );

  puts("Initialized"); //Output string for debug
  while(TRUE)
  {
    // Toggle CS in order to start AD conversion
    output_low(PIN_D0);
    output_high(PIN_D0);
   
    // Wait for AD conversion to finish
    SSPEN = 0;  // disable SPI so we can access the data line.
    do
    {
      // The Ready state is latched on each falling edge of CS and will not
      // dynamically update if CS is held low. CS must be toggled high
      // through low.
      output_low(PIN_D0);
      if (input(PIN_C4) == 0) // Check to see if the conversion is completed
        break;                // Break out of the loop, leaving _CS active.
      output_high(PIN_D0);
    } while (TRUE);
    SSPEN = 1;  // Enable SPI again

    // Read value from ADC   
    byte_3 = spi_read(0);
    byte_2 = spi_read(0);
    byte_1 = spi_read(0);

    output_high(PIN_D0);  // De-select ADC

    value = make32(0, byte_3, byte_2, byte_1);
    for (i = 32; i>0; i--)
    {
      putc(bit_test(value, i-1) + '0');
    }
    putc(CR);
    putc(LF);

    delay_ms(10000);
  }
}
Ttelmah
Guest







PostPosted: Mon Dec 04, 2006 3:43 am     Reply with quote

PIN C4, should read OK.
If you look at the 'logic' for the I/O pin, there is a pickoff for read, and a picoff for the SPI, and both should be working. When SPI is enabled, it overrides the logic feeding the 'output' connections, but doesn't affect the input connections in this case.
I have driven the ADC involved here OK, but have only used it in single conversion mode, not continuous conversion mode.
I used a pull up on the SD line, and read PIN C4 fine.

Best Wishes
Ttelmah
Guest







PostPosted: Mon Dec 04, 2006 3:48 am     Reply with quote

I think there is a critical misnderstanding about the useable 'modes' going on here.
If you use the four byte transfer, you cannot read C4, to get the RDY status. When four byte transfer is used, the RDY bit is transferred as the first _bit_ of the fourth byte, and from then he line sits high. To have the bit available to read on pin C4, you need to use the 25bit transfer mode.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Dec 04, 2006 8:01 am     Reply with quote

Ttelmah wrote:
PIN C4, should read OK.
If you look at the 'logic' for the I/O pin, there is a pickoff for read, and a picoff for the SPI, and both should be working. When SPI is enabled, it overrides the logic feeding the 'output' connections, but doesn't affect the input connections in this case.
You are right. Because the digital output is disabled when using SPI I assumed the same to be true for the input. Instead of only reading the table of PortC functions I should have looked at the diagrams as well.

Quote:
I think there is a critical misnderstanding about the useable 'modes' going on here.
If you use the four byte transfer, you cannot read C4, to get the RDY status. When four byte transfer is used, the RDY bit is transferred as the first _bit_ of the fourth byte, and from then he line sits high. To have the bit available to read on pin C4, you need to use the 25bit transfer mode.
Sorry, I don't agree with you here. As I read Figure 5-7 the RDY bit is in the first bit of the _first_ byte. At first I thought we had a misunderstanding in numbering the bytes, which one is first and which one fourth? But then you wrote 'from then the line sits high', this is only true for the byte most right in the picture which I also see as fourth. The fourth byte contains the LSB data bit, not the RDY status bit !

Besides the 3 or 4 byte transfer 'mode' there is also the choice of 'single conversion' and 'continuous conversion' mode. The behaviour of the RDY pin is different in both modes:
1) In the continuous mode the CS pin is always low and the RDY pin dynamically changes depending on the state of the internal conversion process.
2) In 'single conversion' mode the RDY pin shows the Ready state at the time of falling _CS edge. There are no dynamic updates of the RDY pin, in order to get a status update CS must be toggled high through low.

So, in 'single conversion' mode you can always read the RDY status by toggling the CS line, this is independent of reading the data with 3 or 4 byte transfers.

Although my posted code can be simplified by removing all lines referring to SSPEN, I guess it should work as it is. I don't have access to a MCP3551 chip to confirm this, so shoot and tell me if I'm wrong. Smile
das
Guest







SPI Help
PostPosted: Mon Dec 04, 2006 8:13 am     Reply with quote

I can change it to single conversion mode... I just need it to work ASAP. Can I see your code that you used to drive it in single conversion mode?
Ttelmah
Guest







PostPosted: Mon Dec 04, 2006 8:16 am     Reply with quote

The more I read this part of the sheet, the more I am inclined to go back to my original statement, that you cannot (sensibly) use the 4 byte mode, for continuous conversions!.
The diagram that shows the status in the first bit, is from a mode with CS enabled, where the bit becomes available when CS is lowered, and is then clocked in as the first bit of the first byte. The description text for the two wire transfer (without CS), says that the RDY line activates one clock after 24 bits are transferred, and a transfer cannot be interrupted. As such then, four byte mode cannot be used this way. Look at paragraph 5.4.1. It is the only one that refers to the mode being used, and makes no mention of using a four byte transfer.

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
Goto page 1, 2, 3  Next
Page 1 of 3

 
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