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

Ho do you specify an SPI address with spi_xfer - SOLVED

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



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

Ho do you specify an SPI address with spi_xfer - SOLVED
PostPosted: Mon Sep 17, 2012 1:38 pm     Reply with quote

PIC: 24HJ128GP306
PCWHD: 4.132

First, I know I should use the #USE SPI directive in order to configure my SPI port. Then, I need to use the spi_xfer function to transmit...

Second, like any protocol, you should somehow somewhere specify the address where you want to write followed by the data you want to write to that address.... In the spi_xfer function, I don't see such parameter to specify the address where to write. I looked at the CCS docs and whatever's in there isn't clearly indicating how to write to a specific address.

I am using a 23LC1024 (1MB SRAM). If I want to write the value 0xAA at address 0x0F4321 on that chip over SPI, how would I implement that using the spi_xfer function?

The CCS docs say <data is the variable or constant to transfer via SPI.>... so, that's fine... but do they mean that 'data' can be either the data AND the address and I must write using multiple calls to spi_xfer?

Should I be doing this:
Code:

/* Write to address 0x0F4321 */
spi_xfer( 0x0f ); // high byte
spi_xfer( 0x43 ); // middle byte
spi_xfer( 0x21 ); // low byte
spi_xfer( 0xAA ); // data


Otherwise, what is it?


Last edited by benoitstjean on Thu Sep 20, 2012 8:24 am; edited 1 time in total
bkamen



Joined: 07 Jan 2004
Posts: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Mon Sep 17, 2012 2:15 pm     Reply with quote

Mmm...

No.

SPI can output to a stream depending on how the function is written...

but typically SPI's addressing is in controlling of the CHIPSELECT line that the SPI device has in some form. (some are call SEL or CS or NCS or CSB -- but it's all a line to say "Hey - I'm talking to you!")

If you only have one SPI device on an SPI bus, the chipselect can in some cases even be tied to "true" all the time. (usually Low) -- although in some cases, it's not wise since release of CS resets the protocol state machine inside the SPI device -- a desirable thing.

So... with SPI, typically a statement code setting the devices CS line is separate from the function that stuffs a byte into the transmit buffer so addressing can be utilized as the coder/device needs.

Make sense?

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Sep 17, 2012 2:16 pm     Reply with quote

The documentation means 'data' in a generic sense. It means simply
that 8 bits of digital information are shifted out. The interpretation of
the 'data' is decided by you, or by the protocol required by the SPI slave
device.
bkamen



Joined: 07 Jan 2004
Posts: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Mon Sep 17, 2012 2:24 pm     Reply with quote

PCM programmer wrote:
The documentation means 'data' in a generic sense. It means simply
that 8 bits of digital information are shifted out. The interpretation of
the 'data' is decided by you, or by the protocol required by the SPI slave
device.



Right -- some SPI devices have so much stuff inside them, that a structure for setting/configuring all that stuff requires the concept of addressing.

But that's outside of what SPI defines. SPI is just to transfer bits around. What you DO with those bits is entirely different.

Think about RS232 and modems and now layer PPP or MPP on top of it.

Where in RS232 is there any mention of host address or data payload sizes and checksums. None.
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
ckielstra



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

View user's profile Send private message

PostPosted: Mon Sep 17, 2012 5:09 pm     Reply with quote

Just want to elaborate a bit more on the Chip Select (CS) line:
Each device you want to address is to be activated by a CS line, meaning that if you have 8 devices you need 8 CS lines as well. This is one of the major drawbacks of SPI when compared to the competing I2C bus.
SPI is great when high speed data (over 400kbit/sec) and/or a few devices are to be addressed.
When more than 3 or 4 devices are to be addressed the I2C bus often results in cheaper hardware configurations (but has a speed limit at 400 kbit/sec).
benoitstjean



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 18, 2012 6:23 am     Reply with quote

Sorry guys but the chip select thing is totally off topic. I created this post asking how to write data to a specific address on an SRAM chip using the spi_xfer function. The chip select line is at the electrical level and is simply to select the chip, or not, but has nothing to do with writing a certain value at a specific address.

So again, if I want to write value 0xAA at address 0xF4321 on a 23LC1024 (1MB SRAM), would I do the following:

* Write to address 0x0F4321 */
spi_xfer( 0x0f ); // high byte
spi_xfer( 0x43 ); // middle byte
spi_xfer( 0x21 ); // low byte
spi_xfer( 0xAA ); // data

If this is not the case, then how do I do it? From what PCM Programmer said, "The documentation means 'data' in a generic sense. It means simply
that 8 bits of digital information are shifted out" so it seems, to me, that above is what I would do.

But then will I get an SPI TX interrupt after every call to spi_xfer once the data has been shifted-out?

I don't see how else this function can be used other than feeding it the information byte by byte keeping in mind that I must also follow the protocol for my chip...

I will try it but in the meantime, if someone has comments regarding this topic, please post.

Thank you.


************** UPDATE **************

It's a 1Mbit SRAM, not 1MBYTE so I changed my data below and also, after every call to spi_xfer, I *do* get an interrupt. So, I think that I simply need to break-down the commands, address and data into their individual 8-bit values and send them out following the specs for the chip. I'll post some code shortly once it's fully working for a read/write.

************************************
benoitstjean



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 18, 2012 8:02 am     Reply with quote

Ok, so there's something weird going-on with the functions...

First off, what's the difference in the #USE SPI when using SPI1 or SPI2 versus using FORCE_HW? In either case, the CCS documentation says for SPI1/SPI2 "Use the hardware pins for SPI Port x" but for FORCE_HW, it says "Use the pic hardware SPI". What should I use? To me, it's the same thing... the hardware SPI... isn't it?

Second, I tied a logic analyzer to the 4 signal pins on my 23LC1024 SRAM so I could see what is going-on. I tried both spi_write2 and spi_xfer (I am using hardware SPI 2).

The result is that I see data being transferred but as much as I'm sending 5 bytes, each byte has only 4-5 clock cycles when it should be eight and if I base myself on the CCS docs for spi_write2, it says "Sends a byte out the SPI interface. This will cause 8 clocks to be generated."... so I should at least see 8 clock ticks per byte, which I'm not.

I've setup the SPI like this:

#use spi ( MASTER, BITS=8, SPI2 )

Any comment?
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Sep 18, 2012 8:05 am     Reply with quote

No, its all on topic and relevant.

"So, I think that I simply need to break-down the commands, address and data into their individual 8-bit values and send them out following the specs for the chip."

Yes, that is precisely what you have to do. Its always what you have to do: read the datasheet for the relevant devices and implement accordingly. While in concept a bi-directional interrupted bit stream of arbitary but finite length, in practise SPI *generally* transfers 8 bits of data *in both directions* at a time. Other bit lengths are possible but uncommon and rare in hardware based implementations, software can do almost whatever length you like. That means pretty much all SPI transactions have to be broken down into a sequence of bytes with enough or more bits as required.

From the datasheet for the 23LC1024, to write 0xAA to address 0x0F4321 you would need the following:
* Write to address 0x0F4321 */
Select memory chip somehow
Code:

spi_xfer( 0x02 ); // Write command
spi_xfer( 0x0f ); // high byte of address
spi_xfer( 0x43 ); // middle byte
spi_xfer( 0x21 ); // low byte of address
spi_xfer( 0xAA ); // data for byte

Deselect memory chip
If you want to do this in the background using interrupts *and* you are using the hardware SPI (not a soft emulation) then yes, you will get a SPI TX interrupt after each byte has been sent/received. To make use of this, buffe the data to be transmitted, selecting the chip and then sending the first from your main code, buffering the rest - by a send routine that makes buffering transparent is best practise - the rest of the data is then sent via the interrupt until the buffer is empty when it deselects the chip, probably setting or clearing some flag to indicate the SPI is no longer in use. All of that, the buffering and interrupts are totally separate from the data itself.

All this, buffered, interrupt driven IO, was sorted out a long time ago, as in the late 50's/early 60's, and is absolutely standard systems programming which should be taught by all systems/embedded coding courses worth the name. Trouble is that hobbyists and most students have never heard of it, and can't work it out for themselves. Many otherwise decent engineers are expected to somehow know all this stuff without taking any training in embedded programming whatsoever, as if knowing about Ohm's law and how to wire an LED somehow makes them embedded experts.

Rant over.

RF Developer
benoitstjean



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Sep 18, 2012 8:24 am     Reply with quote

Thanks. I am selecting the chip myself through the CS pin but the main idea behind my post was how to write data X at address Y, not how to access the chip. I know that there is a certain protocol to follow to write the data (such as the first byte being sent must contain a certain bit pattern depending on if it is a "read" or a "write" command).

As mentioned in my last post, I have a logic analyzer tied to the 4 signal pins on the SRAM and the functions are called in a sequence but the clock pin isn't even toggled 8 times per byte sent. I tried both the spi_write2 and spi_xfer and the result is the same.

Now, about the #USE SPI directive, what's what? As stated, what's the difference between the flag SPI1/SPI2 versus using FORCE_HW? In either case, the CCS documentation says for SPI1/SPI2 "Use the hardware pins for SPI Port x" but then, for FORCE_HW, it says "Use the pic hardware SPI". So, what's the difference?

And I do get an interrupt everytime the spi_write2 or spi_xfer command is issued since I write a '*' on a display on every #INT_SPI2 interrupt. The problem I'm seeing through the logic analyzer is that either command doesn't seem to issue the proper number of clock cycles for each byte. And I am, in deed, sending 0x02 as the first "command" (write):
Code:
   
output_low( SPI_CS );
spi_xfer( SPI_WRITE ); //0x02
spi_xfer( 0x01 );
spi_xfer( 0xFF );
spi_xfer( 0xFF );
spi_xfer( 0xAA ); // data
output_high( SPI_CS );
bkamen



Joined: 07 Jan 2004
Posts: 1611
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Tue Sep 18, 2012 11:19 am     Reply with quote

benoitstjean wrote:

As mentioned in my last post, I have a logic analyzer tied to the 4 signal pins on the SRAM and the functions are called in a sequence but the clock pin isn't even toggled 8 times per byte sent. I tried both the spi_write2 and spi_xfer and the result is the same.


That's because you're releasing the nCS line while the data is still clocking out of the SPI Buffer. (The PIC always runs faster than the SCK line. Just look at the divisors that come into the MSSP module.)

Any time you send via SPI, you should either wait some time (yuk) or spin while monitoring the transmit buffer empty bit. Once it's true, you can raise the nCS line to that device.

Of course, if this is based on IRQ's, when the IRQ fires and the service routine runs, the buffer *IS* empty (that's why the IRQ fired) -- so there's no waiting or checking needed there.

But you get the idea.

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
NEW_GUY



Joined: 31 Aug 2012
Posts: 10
Location: India

View user's profile Send private message

PostPosted: Thu Sep 20, 2012 2:38 am     Reply with quote

Probably the following command you might have gone through,

spi_xfer(stream, data, bits);

The sequence of transmission of Data on perticular address would be:
- make sure, your SRAM operating mode is BYTE MODE, other wise, no need to send an address.
- make sure that your CS pin is enable thorught the command and data transfer.
- according to above api,
stream: any_name
data: write command
bits: 8

this command can transfer any no. of bits on spi by generating those many no. of clocks.....

- you shud follow following sequence:
ENABLE CS = 0;
1. send write command : 8 bits
2. send address: 24 bits
3. send data: 8 bits
DISABLE CS = 1;

to read:
Enable CS =0;
1. send read command : 8 bits
2. send address : 24 bits
3. receive data:8 bits
Disable CS =1;


Try it out...
benoitstjean



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Sep 20, 2012 6:22 am     Reply with quote

Deleted

Last edited by benoitstjean on Thu Sep 20, 2012 8:14 am; edited 1 time in total
benoitstjean



Joined: 30 Oct 2007
Posts: 553
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Thu Sep 20, 2012 8:07 am     Reply with quote

UPDATE:

IT WORKS. I can now WRITE and READ properly to the address I want.

CODE (for my PIC24HJ128GP306 tied to a 23LC1024 SRAM):

Add to .h file:
Code:

#use spi( MASTER, BITS=8, SPI2 )
#define SPI_CS       PIN_G13

Add to .c file:

WRITE CODE:
Code:

uiHiByte = 0x01;
uiMidByte = 0xFF;
uiLowByte = 0xFF;

output_low( SPI_CS );

spi_write2( SPI_WRITE ); //0x02
spi_write2( uiHiByte );
spi_write2( uiMidByte );
spi_write2( uiLowByte );
spi_write2( 0x11 ); // data

output_high( SPI_CS );

READ CODE:
Code:
         
output_low( SPI_CS );         

spi_write2( SPI_READ ); //0x03
spi_write2( uiHiByte );
spi_write2( uiMidByte );
spi_write2( uiLowByte );
uiValue = spi_read2(0);

output_high( SPI_CS );

So, it takes now 89.3125us to make the above WRITE and READ commands together.
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