Is EOQF unreliable on PK60N512

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

Is EOQF unreliable on PK60N512

889 Views
CiaranMacA_hkc
Contributor III

Hi,

I am trying to use a  simple polled Tx driver for SPI on the PK60N512 (2N30D). For my app I need to manually control a CS for specific time. My micro is master - so in order to control the CS after the last xfer I need to wait on EOQF. Sometimes it works, sometimes not. Code below. See comment where it gets stuck near the bottom of spi_write waiting for EOQF.

Thank you,

Ciarán

void spi_init(spi_id_t spi_id)

{

    spi_regs[spi_id]->MCR = SPI_MCR_HALT_MASK;        // Ensure halt (Only safe to write other MCR bits when Halted)

    spi_regs[spi_id]->MCR &= ~SPI_MCR_MDIS_MASK;    // Must be zero in order for TFFF to work properly

    // Master mode, flush fifos, disable fifos (i.e sz = 1), non contiuous clk mode,

    spi_regs[spi_id]->MCR |= SPI_MCR_MSTR_MASK | SPI_MCR_CLR_TXF_MASK | SPI_MCR_CLR_RXF_MASK| SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK ;        

    // CTAR determines frame size=FMSZ=1 (set here for 16), clock divider, and CPHA=1,

    spi_regs[spi_id]->CTAR[0] = SPI_CTAR_FMSZ(15) | SPI_CTAR_BR(0xE) |SPI_CTAR_CPHA_MASK;

    // Start Peripheral

    spi_regs[spi_id]->MCR &= ~SPI_MCR_HALT_MASK; // CMA_DBG - maybe need on off per usage

}

void spi_write(spi_id_t spi_id, uint8_t* data, uint16_t len)

{

    uint32_t tx_word;

    // Loop over data and pad data so that it's 16 bit aligned

    while (len)

    {

        // Wait TFFF (Tx FIFO Fill Flag)

        // See important note on TFFF section 49.4.7.2 of the datasheet

        while (!(spi_regs[spi_id]->SR & SPI_SR_TFFF_MASK));

        // Use long winded way to enfore 16 bit tx. (ie. two bytes and mark pad bytes as recognisable for debug

         if (len > 1)

        {

            tx_word = (*data << 8) + *(data+1);

            data += 2;

            len -= 2;

        }

        else

        {

            tx_word = (*data << 8) + 0xAA; // padding

            len = 0;

        }

        // PUSHR - write data : CONTinuous CS, using CTAR0, and mark last transfer so we get an EOQ Flag below

        if (!len)

        {

            tx_word |= (SPI_PUSHR_EOQ_MASK | SPI_PUSHR_PCS(1));

        }

        else

        {

            tx_word |=  (SPI_PUSHR_PCS(1));

        }

        spi_regs[spi_id]->PUSHR = tx_word;

               

        // Clear TFFF

        spi_regs[spi_id]->SR |= SPI_SR_TFFF_MASK;

    }   

    // Wait on last transfer to complete (we are implementing a synchronous write function)

    while (!(spi_regs[spi_id]->SR & SPI_SR_EOQF_MASK));  <----- sometimes gets stuck here, why? /////////////////

    spi_regs[spi_id]->SR |= SPI_SR_EOQF_MASK;

}

0 Kudos
6 Replies

605 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi CiaranMacA_hkc


I am checking with this issue, I will be back when I could get any updated info.

Thank you for the patience.

B.R.

Ma Hui

0 Kudos

605 Views
CiaranMacA_hkc
Contributor III

Thank you Ma Hui. I appreciate your help - I have spent a lot of time on this and did read the manual - though perhaps I missed something. It is now a significant block for my progress.

For your information I'm using Header file "MK60D10.h" v 1.8 with silicon 2N30D. (I notice a late update in the header file for v 1.8 mentions SPI and PCSIS. Can you confirm that everything is ok. My erata sheet doesn't mention anything significant for SPI.

All the best,

Ciarán

0 Kudos

605 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

For the Kinetis DSPI TX FIFO is 4 entires depth, so the maximum refresh SPIx_PUSHR register is four times.

You can refer below code to write data to SPI TX FIFO, otherwise it will cause TX FIFO overflow.

  for(i=0;i<120;i += 4)

    {

        SPI0_PUSHR = 0x80010000;

        SPI0_PUSHR = 0x80010000;

        SPI0_PUSHR = 0x80010000;

        SPI0_PUSHR = 0x88010000;     //set [EOQ] bit

     

        SPI0_MCR &= 0xFFFFFFFE;   // Start transfer , halt = 0 

        printf("EDMA_HRSL = 0x%08x\n\r",EDMA_HRSL);

        while( SPI_SR_EOQF != (SPI0_SR & SPI_SR_EOQF));

        SPI0_SR = SPI0_SR | SPI_SR_EOQF | SPI_SR_TCF ;

        SPI0_MCR |= 0x1; // halt = 1

    }    

Wish it helps. 

0 Kudos

605 Views
CiaranMacA_hkc
Contributor III

Thanks for the reply.

You can see from my init code that I am using a FIFO depth of 1. (Though even if I use 4 I have the same problem). The difference with your code is that you halt and restart the SPI engine every time you transfer one "queue full" of data. That is, you start and stop every four transfers. Surely this is not necessary? Surely the peripheral allows one to keep pumping data into its queue any time the q has space (ie. when TFFF is set).

As I indicated - the code was stalling waiting for the EOQF. As if EOQF was never being set - but an experiment showed that in fact EOQF _was_ being set - every time. I turned on the EOQF interrupt in RSER. And the interrupt fired every time - even though sometimes my code was no seeing it set.  I thought perhaps it was an optimization problem but that would be predictable and would either work or fail every time.

So my question remains: how can I continuously pump data into the SPI without halting AND at the same time, make sure my function returns only after the last transfer in the queue is transmitted.

I presume the peripheral has no measure of Queue size. It just implements a 'last' trasfer mechanism. The actual queue is  not in any way related to the size of the FIFO (please confirm). At least this interpretation is implied..

Thanks again for your help.

Ciarán

0 Kudos

605 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

I checked your spi_write function, for in your code with disabled TX FIFO, then I would suggest to use TCF bit to check if data had been transfered.

Please comment the code below in spi_write function:

        while (!(spi_regs[spi_id]->SR & SPI_SR_TFFF_MASK));

And add below code before clear TFFF bit code:

    while((SPI0_SR & SPI_SR_TCF_MASK)==0);

    SPI0_SR |= SPI_SR_TCF_MASK;

Please also comment below code in spi_write function:

        // Clear TFFF

        spi_regs[spi_id]->SR |= SPI_SR_TFFF_MASK;

I don't think you need to add EOQF bit checking in your spi_write routine.

For there disabled TX FIFO, it will send each 16-bit data after each write to SPIx_PUSHR register.

Below code is just for an example, which will send a byte data:

u8 hal_spi_transfer_one_byte(u8 v, bool end)

{

    if(end)

        SPI0_PUSHR = SPI_PUSHR_EOQ_MASK  |

                     SPI_PUSHR_PCS(1<<0) |

                     (v);

    else

        SPI0_PUSHR = SPI_PUSHR_CONT_MASK |

                     SPI_PUSHR_PCS(1<<0) |

                     (v);

    while((SPI0_SR & SPI_SR_TCF_MASK)==0)

        ;

    SPI0_SR |= SPI_SR_TCF_MASK;

    return SPI0_POPR&0xff;

}

Wish it helps.  

0 Kudos

605 Views
egoodii
Senior Contributor III

I have also found the EOQF to be 'unreliable' (causing hangs), and went instead for the 'FIFO empty' status.

And what I finally ended up doing now is 'waiting' for the expected number of bytes to 'show up' in the RX FIFO, as that insures full TX delivery has been made:

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

0 Kudos