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

16F877A spi uses 8-bit, I need 16

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

16F877A spi uses 8-bit, I need 16
PostPosted: Fri Nov 20, 2009 6:37 pm     Reply with quote

I have a 16F877A and am trying to use spi to set up a MCP6S22 PGA which requires an uninterrupted 16-bit SCLK. Everything I have tried inserts a SCLK delay between the high and low bytes. The documentation suggests that 16-bit words are possible using the FORCE_HW mode. Has anyone done 16-bit spi mode without a SCLK delay after 8 bits? I just need to do a few bytes of setup so clock rate is not a concern.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 6:47 pm     Reply with quote

Don't use the #use spi() library. Use the setup_spi() function to setup
the SPI mode and speed. Then use spi_write() two consecutive times
to send two bytes. Make sure you connect your device to the hardware
spi pins on the PIC.

Look at the w5100_write_reg() routine in this code:
http://www.ccsinfo.com/forum/viewtopic.php?t=40693&start=10
Notice how several consecutive bytes are written to the slave device
with spi_write() statements.

You need to write your own routine(s) in a similar way, to make a
driver for the mcp6s22. Study the SPI bit diagrams in the mcp6s22
data sheet and make your routines conform to those diagrams.
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 7:01 pm     Reply with quote

That is basically what I did however looking at the SCLK on a scope, there is a delay between the 8 cycles of the first byte and the second. The MCP6S22 timing diagrams (and the text) say that the SCK must be continuous for 16 cycles.
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 7:04 pm     Reply with quote

I did try using the setup_spi() call instead of the #USE SPI with no improvement.
One note: I am using a slow (1MHz) clock. Could that be the issue? Interrupt latency?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 8:03 pm     Reply with quote

In the general case, the 16 bits of the transmitted SPI word do not have
to be transmitted at the exactly the same interval. You're allowed to
have a gap between the two bytes.
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 8:45 pm     Reply with quote

That's good to know. Perhaps the MCP6S22 spec is overly restrictive and my problem is elsewhere.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 20, 2009 9:10 pm     Reply with quote

Post your driver code and a small, complete, compilable test program
that calls the driver. Explain how it fails.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Nov 21, 2009 8:06 am     Reply with quote

Quote:
MCP6S22 PGA which requires an uninterrupted 16-bit SCLK

Quote:
The MCP6S22 timing diagrams (and the text) say that the SCK must be continuous for 16 cycles.

Quote:
Perhaps the MCP6S22 spec is overly restrictive

You apparently didn't read the datasheet thoroughly. Apart from showing 16 "continuous" clock cycles in the diagram,
nothing is said in this regard. The SPI clock specification in constrast is fully static, allowing to insert infinite
delays at any point.

If the device doesn't work, you obviously have a different problem, e.g. wrong SPI mode or wrong circuit.
John P



Joined: 17 Sep 2003
Posts: 331

View user's profile Send private message

PostPosted: Sat Nov 21, 2009 9:14 am     Reply with quote

I agree with what others have said--I'm very skeptical that the component requires an absolutely regular clock for a 16-bit SPI input. Especially as there's apparently no spec for what the frequency needs to be!

But anyway, if you want an absolutely regular clock and you're prepared to accept a slow sending rate, you can always forget the built-in SPI routines and just simulate the whole thing with a timer interrupt and bit-banging, and nothing prevents you from using the "normal" SPI pins to communicate with. I don't think it's likely to change anything. But you can do it.
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

PostPosted: Sat Nov 21, 2009 6:00 pm     Reply with quote

From Section 5.1 of the MCP spec:

"There must be multiples of 16 clocks (SCK) while CS is low or commands will abort (see Section 5.3, “Registers”)."

And from my code:

Code:
int16 SetAmplifierRange(char range)
{
   int16      Value;
   char      gain1;
   char      gain2;
   char      chan;
   char      datah;

   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
      
   AMP1_CS   = HIGH;
   AMP2_CS   = HIGH;
   switch (range)
   {   
      case RANGE_50R:
               gain1 = PGA_GAIN_1;
               gain2 = PGA_GAIN_1;
               chan = 1;
               break;
               
      case RANGE_5R:
               gain1 = PGA_GAIN_10;
               gain2 = PGA_GAIN_1;
               chan = 1;
               break;
               
      case RANGE_500MR:
               gain1 = PGA_GAIN_1;
               gain2 = PGA_GAIN_1;
               chan = 0;
               break;
               
      case RANGE_50MR:
               gain1 = PGA_GAIN_10;
               gain2 = PGA_GAIN_1;
               chan = 0;
               break;
               
      case RANGE_5MR:
               gain1 = PGA_GAIN_10;
               gain2 = PGA_GAIN_10;
               chan = 0;
               break;
   }
   
   AMP1_CS   = LOW;
   AMP1_CS   = LOW;
   spi_write(PGA_INST+PGA_CHAN_REG);      // Address Channel Register
   spi_write(chan);
   AMP1_CS   = HIGH;
   AMP1_CS   = HIGH;
   
   AMP1_CS   = LOW;
   AMP1_CS   = LOW;
   spi_write(PGA_INST+PGA_GAIN_REG);      // Address Gain Register
   spi_write(gain1);
   AMP1_CS   = HIGH;
   AMP1_CS   = HIGH;
   
   AMP2_CS   = LOW;
   AMP2_CS   = LOW;
   spi_write(PGA_INST+PGA_GAIN_REG);      // Address Gain Register
   spi_write(gain2);
   AMP2_CS   = HIGH;
   AMP2_CS   = HIGH;
   
   
   return 0;
}

Admittedly, I haven't much experience with SPI devices so I'm probably not doing something else correctly. I do however have another SPI device (a motor controller) on the same board that is working fine.
Ttelmah
Guest







PostPosted: Sun Nov 22, 2009 3:11 am     Reply with quote

The 8bit SPI, is fine for what they say.
The 'point' is that the chip must _always_ receive 16 clocks, between the CS going low, and the CS rising. This is common. However the clocks do _not_ need to be the same length.
Some comments:
1) Why do you drop and raise the CS twice. Not necessary.
2) Check the data sheet. Is there a specification for how much time is needed between CS dropping and the first clock. It is common for a small delay to be needed. You may have added the second operation on the line becaue of this?.
3) Your main problem, is that you are not waiting for the SPI to send the data before raising CS. This would violate the data sheet requirement.
The SPI hardware, will still be sending the last byte.
For the transmssion, use a _read_:
Code:

   AMP1_CS   = LOW;
   delay_cycles(1);
   dummy = spi_read(PGA_INST+PGA_CHAN_REG);      // Address    Channel Register
   dummy = spi_read(chan);
   AMP1_CS=HIGH;


The first is not actually needed, but the second is vital.
The difference, is a 'write', simply transfers the data to the output register, and returns _immediately_ so your code can get on with other jobs. The read, with a value, clocks out a byte, and _waits_ for the byte to be sent, then returns the value clocked back during the transmission.

So your problem is that when you send your second byte, the code returns immediately at present, and then raises the CS line. The chip at this point, has not sent all 16 clocks, so invalidates what your target requires. By using a read, to wait for the data to be sent, you will avoid the problem.

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sun Nov 22, 2009 4:13 am     Reply with quote

After you finally revealed your code, there is at least one trivial problem (I guess, there aren't more):
MCP6S22 is specifying SPI mode 0 or 3 while you are using mode 1. Correct this and try again.
Code:
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_XMIT_L_TO_H | SPI_CLK_DIV_16);


P.S.: I'm not familiar to PIC16 hardware SPI, but Ttelmah is most likely right, that spi_write() doesn't wait for the transmission to finish.

P.P.S.: No, spi_write() is waiting for end of transmission as well as spi_read(). But it's different e.g. with PIC24.
dbaltz



Joined: 20 Nov 2009
Posts: 13

View user's profile Send private message

PostPosted: Mon Nov 23, 2009 11:12 am     Reply with quote

Setting the SPI mode to 1,1 was the fix. All is working now. Thanks.

The PIC16 does indeed finish the spi_write(). There was no need to add delays or an spi_read().
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