Transmit 32 Bit via SPI

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Transmit 32 Bit via SPI

Jump to solution
3,196 Views
pascalschröer
Contributor V

Hi at all,

I have got a little question to the SPI configuration. I'm using a MK10DX128VLH7 cpu and would like to communicate

from the cpu to an external AD converter. So there is no problem, I have initialised the spi and there is a function to

transmit  and to receive bytes from the ADC. Now my question:

I have to send 32bit to the adc. So I have to transmit 16Bytes two times. Thats works, but between the last clock

of the first 16bits and the first clock of the second 16bits there is only a very small gap (low time of the clock).

(pls. see the logic diagramm). Does anyone know, how to fix this problem? I don't want to work with external

delay functions... that must be possible, I think..

Thanks a lot!

Pascal

void SPI_init(uint8_t module, uint8_t mode)

{

    SPI0_MCR = 0x00

                      | SPI_MCR_MSTR_MASK

                      | SPI_MCR_DCONF(0x00)

                      | SPI_MCR_PCSIS(0x01)

                      | SPI_MCR_DIS_TXF_MASK

                      | SPI_MCR_DIS_RXF_MASK;

    SPI0_CTAR0 = 0x00

                         | SPI_CTAR_FMSZ(0x0F)

                         | SPI_CTAR_BR(0x08);

}

void SPI_transmit_byte(uint8_t address,uint16_t data)

{

    SPI0_PUSHR = data

                         | SPI_PUSHR_PCS(0x01)

                         | SPI_PUSHR_CONT_MASK;     //keep the cs low

            

    while(!(SPI0_SR & SPI_SR_TCF_MASK));

    SPI0_PUSHR = data

                         | SPI_PUSHR_PCS(0x01);

    while(!(SPI0_SR & SPI_SR_TCF_MASK));

}

pastedImage_1.png

                                                                                                                           ^

                                                                                                      |

                                                                                                      |

                                                                                                      |

                                                                                                      |

                                                                                       Here is the fault!

0 Kudos
1 Solution
2,260 Views
egoodii
Senior Contributor III

The other parameter to look at is ASC or DT in the SPIx_CTARn register.  Even though PCS is NOT to be negated between the two 'transfer parts' (SPIx_PUSHR CONT set), I believe one of these parameters still defines the 'time between transactions'.

View solution in original post

0 Kudos
10 Replies
2,259 Views
adriancano
NXP Employee
NXP Employee

Hi,

You can try to enable the Continuous SCK bit. This is in the SPIx_MCR register.

cont scke.png

Check the section Continuous Serial Communications Clock in the reference manual to see the proper configurations when this bit is used

I hope this information can help you.

Regards,

-----------------------------------------------------------------------------------------------------------------------

Note: If this post answers your question, please click the Correct Answer button. It would be nice!

-----------------------------------------------------------------------------------------------------------------------

2,261 Views
egoodii
Senior Contributor III

The other parameter to look at is ASC or DT in the SPIx_CTARn register.  Even though PCS is NOT to be negated between the two 'transfer parts' (SPIx_PUSHR CONT set), I believe one of these parameters still defines the 'time between transactions'.

0 Kudos
2,260 Views
pascalschröer
Contributor V

Thanks!

I have to set the CSSCK time! Now it works!

So there is another question, do I have to do a dummy read before read out the POPR register?

because there aren't stored the whole data in this register:smileyconfused:!? I have heard something like this

for the spi... but I'm note sure...



Thanks!

0 Kudos
2,260 Views
adriancano
NXP Employee
NXP Employee

Hi,

What are you receiving, which part of the 32 bits you transmitted?

Regards

0 Kudos
2,260 Views
pascalschröer
Contributor V

Hi,

At the moment I only get the first byte... in my example 0x1b (see above). But I don't know where the other 3 bytes are. Do I have to wait for an

specific flag before read the register?

Thanks!

0 Kudos
2,260 Views
egoodii
Senior Contributor III

After I have 'sent some stuff' and await the answer (that shifts in at the same time) I simply wait for the receive FIFO to get 'in' as many transactions as I 'sent', and at that point I know the 'whole operation' is complete.  Works, of course, only for 'transaction sets' that fit all in the receive FIFO!  So I have this macro:

#define WAIT_SPI0_TRANSMISSON_END(count) {while ((SPI0_SR & SPI_SR_RXCTR_MASK) < (count<<SPI_SR_RXCTR_SHIFT)) {};

I am working in a 'high performance' analog-processing system, and have SPI-connected AtoDs, much like your setup.  But I can't 'waste much time' at 4K samples per second, so I have to 'intelligently' interleave SPI operations with 'other work.  I do this with some other macros that make it 'look simple' to send each transaction (Bytes in my case).  Each macro contains the SPI module #, the CS #, and the CTAR reg to use:

#define WRITE_2SPI0_CMD0(byte) SPI0_PUSHR = (byte | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(4) | SPI_PUSHR_CTAS(0))
#define WRITE_2SPI0_CMD0_LAST(byte) SPI0_PUSHR = (byte /*| SPI_PUSHR_EOQ_MASK */| SPI_PUSHR_PCS(4) | SPI_PUSHR_CTAS(0))
#define WRITE_2SPI0_CMD1(byte) SPI0_PUSHR = (byte | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(4) | SPI_PUSHR_CTAS(1))  //Same for 2nd CTAR
#define WRITE_2SPI0_CMD1_LAST(byte) SPI0_PUSHR = (byte /*| SPI_PUSHR_EOQ_MASK */| SPI_PUSHR_PCS(4) | SPI_PUSHR_CTAS(1))

So to use these, my AtoD 'dummy input' bytes during a 'result read' are just 'zero', so I will get those 'going out' in one 24bit transfer like this:

///While we start working with the first AtoD sample, start the second channel coming in
WRITE_2SPI0_CMD1(0);
WRITE_2SPI0_CMD1(0);
WRITE_2SPI0_CMD1_LAST(0);//Prompt the three data bytes to come along!

Then I will 'do a bunch of work' for about the number of microseconds these take to shift-out, then:

//Now to finish-off the second channel!!

            WAIT_SPI0_TRANSMISSON_END(2);  //Spin for the first couple of the second channel to be in, should more time be needed

            AtoD[1].sample.s8.hm = READ_SPI0_DATA();       // Read MSByte

            if( (AtoD[1].sample.s8.hm & 0x80) == 0 )

                AtoD[1].sample.s8.hh = 0;

            else

                AtoD[1].sample.s8.hh = -1;               //Sign-extend to Q8.23

            AtoD[1].sample.s8.lm = READ_SPI0_DATA();       // Read middle

            WAIT_SPI0_TRANSMISSON_END(1);

            AtoD[1].sample.s8.ll = READ_SPI0_DATA();       // Read LSByte

2,260 Views
pascalschröer
Contributor V

Hi,

Now it works!!! :smileyhappy: Thanks for your answer! Now I have got only a question to

understand the spi behavior.

I have read in the data sheet, that this bit SPI_SR_RXCTR is incremented every

time when I write the PUSHR register and is decremented, when I read the POPR

register.

So, am I right if I read out the POPR register for two times??

Because in my case (pls. see my code above) I would like to send out two bytes.


If that's right I have to do the following steps:

while ((SPI0_SR & SPI_SR_RXCTR_MASK) < 2) {};


tmp_32 = SPI0_POPR;

tmp_32 <<= 16;

tmp_32 = tmp_32 | SPI0_POPR;

tmp_16 = tmp_32 >>10;              //only for the ADC protocol


return tmp_16;



So I'm a bit confused because there is a 32bit receive register and I have to read it out

for two times a 16bits?? At first view, that doesn't make sense for me... Could you explain

it to me?

Thanks a lot!



Pascal


0 Kudos
2,260 Views
egoodii
Senior Contributor III

While your PUSHR/POPR description is 'logically sufficient', what actually happens of course is that PUSHR increments TXCTR, and then thru the process of serialization and simultaneous input/output bits a 'result' is accumulated and thence inserted into the receive FIFO, and THAT increments RXCTR.  That is why when RXCTR makes it to 'two' (in your case) we know the full 32 bit operation is complete.  And since you have set 16 bit operations, your two read/assembly operations certainly look correct!  I can't vouch for the >>10 to a 16 bit(?) value, or what may be 'signed' or 'unsigned', but I assume you have that worked out for your situation!

However, there is one 'major' shortcoming in the code you presented, compared to my 'macro' -- you left out the 2<<SPI_SR_RXCTR_SHIFT part -- the RXCTR field is NOT in the 'least significant bits' of _SR!  So your 'compare' will 'continue' as soon as RXCTR is nonzero.  This probably leaves 'stale' data in the FIFO.  When I start a 'batch' of operations, I will always hit CLR_TXF and CLR_RXF in SPIx_MCR (one |= write).

0 Kudos
2,260 Views
pascalschröer
Contributor V

Hi,

Thank you very much! That was the explanation I searched for! :smileyhappy:

You are completely right, I have forgotten the shift order in my code!

But I haven't mentioned this fault because now I'm using the "End of Queue"

interrupt request. So I don't have to wait till the transaction is completed.

Have a nice day!

Pascal

0 Kudos
2,260 Views
egoodii
Senior Contributor III

I will just state that my initial implementation was to rely on EOQ as well (notice the 'commented out' EOQ bit in the 'last' macros above), however I found it NOT to be reliable to 'spin' on -- at times it would FAIL to get set.  Instead of figuring out why, I went to this RXCTR approach.  If it never fails for you, then good deal!

0 Kudos