|
|
View previous topic :: View next topic |
Author |
Message |
benoitstjean
Joined: 30 Oct 2007 Posts: 566 Location: Ottawa, Ontario, Canada
|
Ho do you specify an SPI address with spi_xfer - SOLVED |
Posted: Mon Sep 17, 2012 1:38 pm |
|
|
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: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Sep 17, 2012 2:15 pm |
|
|
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
|
|
Posted: Mon Sep 17, 2012 2:16 pm |
|
|
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: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Sep 17, 2012 2:24 pm |
|
|
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
|
|
Posted: Mon Sep 17, 2012 5:09 pm |
|
|
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: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Tue Sep 18, 2012 6:23 am |
|
|
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: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Tue Sep 18, 2012 8:02 am |
|
|
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
|
|
Posted: Tue Sep 18, 2012 8:05 am |
|
|
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: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Tue Sep 18, 2012 8:24 am |
|
|
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: 1615 Location: Central Illinois, USA
|
|
Posted: Tue Sep 18, 2012 11:19 am |
|
|
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
|
|
Posted: Thu Sep 20, 2012 2:38 am |
|
|
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: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Thu Sep 20, 2012 6:22 am |
|
|
Deleted
Last edited by benoitstjean on Thu Sep 20, 2012 8:14 am; edited 1 time in total |
|
|
benoitstjean
Joined: 30 Oct 2007 Posts: 566 Location: Ottawa, Ontario, Canada
|
|
Posted: Thu Sep 20, 2012 8:07 am |
|
|
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. |
|
|
|
|
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
|