AnsweredAssumed Answered

Kinetis DSPI...undocumented behaviour?

Question asked by Thomas Dowad on Jun 12, 2013
Latest reply on Jun 19, 2013 by Monica Arvizu

I am doing some experimenting, trying to get the DSPI on the K20 to behave like the documentation says it should. It doesn't seem to work as documented. I am monitoring the registers in debug, in CW 10.4.

 

The DSPI is being run in master mode. There is are two FIFOs, transmit and receive, each 4 words deep. The transmit FIFO has both command and data fields. I am setting the command field to select CTAR0, which is specifying 8 bits etc. The chip select field is being set to a known-good value. The MSB of the command field has been alternately set to 1 and 0, with no change in behaviour.

 

The two FIFOs are empty. I write 4 values into the tx FIFO. Now I presume this will generate the clocks required for 4 values to be received, and so the receive FIFO should therefore be full, some time after the 4 are written to the tx FIFO. As well, the FIFO counters in the status register should change to reflect the same. So at the end of this (with a little waiting perhaps, depending on the clock frequency setting), the rx counter should have the value 4.

 

That doesn't happen. The first word is written to the tx FIFO, and the rx counter shows 1. Then it shows 0, and stays there. It's almost as if the DMA is sneaking in and grabbing data out of the register, but the DMA should not be enabled. There a known-good PE interrupt handler that would steal the rx data, so I am disabling that first thing.

 

Here's the code. It uses macros from PE, which are also used in known-good PE code.

 

void sd_read4(uint8_t *buffer)

{

    byte i;

    uint16_t d;

   

    SPI_PDD_DisableDmasInterrupts(SPI0_BASE_PTR, SPI_PDD_RX_FIFO_DRAIN_INT_DMA); // don't let the interrupt handler steal the rx data

    SPI0_SR |= SPI_SR_RFDF_MASK;          // clear drain flag (for laughs)

    // fill the tx FIFO

  SPI_PDD_WriteMasterPushTxFIFOReg(SPI0_BASE_PTR, (uint32_t)0x040100ffU); // first one clears the tx counter, for laughs

  SPI_PDD_WriteMasterPushTxFIFOReg(SPI0_BASE_PTR, (uint32_t)0x000100ffU);

  SPI_PDD_WriteMasterPushTxFIFOReg(SPI0_BASE_PTR, (uint32_t)0x000100ffU);

  SPI_PDD_WriteMasterPushTxFIFOReg(SPI0_BASE_PTR, (uint32_t)0x000100ffU);

  // I presume the same number of bytes should come back?

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

    {

        while(!(SPI0_SR & SPI_SR_RXCTR_MASK))  // wait til something in rx FIFO (NOTE: THIS HANGS)

            ;

     d = (uint16_t)SPI_PDD_ReadPopRxFIFOReg(SPI0_BASE_PTR); // read the rx FIFO

     *buffer = (uint8_t)d; // save the data (this casting matches the PE code that works)

     buffer++;

    }

    SPI_PDD_ClearInterruptFlags(SPI0_BASE_PTR,SPI_PDD_RX_FIFO_DRAIN_INT_DMA);          // makes sure no interrupt is generated

    SPI_PDD_EnableDmasInterrupts(SPI0_BASE_PTR, SPI_PDD_RX_FIFO_DRAIN_INT_DMA);   // restore interrupts so the other SPI code still works

}

 

Truth is though --- nowhere in the DPSI docs for this processor does it say that you need to write the tx FIFO in order to cause a byte to be received. You've got to wonder. Astounding, really, and omission of that magnitude. Yet the working code in all cases writes a byte then reads a byte.

 

 

Outcomes