Problem with continuous SPI when using DMA

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

Problem with continuous SPI when using DMA

802 Views
migry
Contributor I

I am using a Teensy3.5 (MK64FX512VMD12 based).

Having made some progress experimenting with DMA, I am trying to generate a single bit datastream using SPI and DMA. My requirement is I want this stream to be totally continuous at a 1MHz rate with no gaps.

I have written code to use DMA to stream from a 8-bit array, by using DMA to re-fill the PUSHR SPI register.


The code is working to an extent, except for the problem that at the end of every 8 bits written to PUSHR is a single '1' bit, sort of like a stop bit. So for each byte transferred via DMA I see 9 bits and 9 corresponding clocks.

I am aware of the CONT bit in the PUSHR register and I am setting this to '1' (I think - perhaps not!).

The DMA transfer however is 8-bit. I am hoping that the earlier 32 bit write to PUSHR is held and the DMA write only overwrites the lower 8-bits, but I am not sure that this is happening. With CONT zero you see the behaviour I observe on the scope.

In the reference manual I see the cryptic text "Specifies data to be transferred to the TX FIFO. An 8- or 16-bit write access transfers all 32 bits to the TX FIFO". I do not know how to interpret this.

I tried reading back the register having written to all 32 bits, but I get a strange value.

      SPI1_PUSHR = 0x80005555;
      SPI1_PUSHR = 0x80005555;
      SPI1_PUSHR = 0x80005555;
      SPI1_PUSHR = 0x80005555;
      SPI1_PUSHR = 0x80005555;
      uint32_t cxn = SPI1_PUSHR;
      sprintf(sbuf," SPI1_PUSHR = %08lx",cxn); Serial.println(sbuf);

This is my attempt to initialise the CONT bit to '1', hoping it will remain set to '1' during the later DMA 8-bit transfer of the 8-bit value to be transmitted.

The value printed out is "000000aa". Obviously not the result I expected.

I do not know whether to use CONT in DMA mode you are forced to do 32-bit transfers?

I operate in Master mode.

#define SPI1_PUSHR (KINETISK_SPI1.PUSHR) // DSPI PUSH TX FIFO Register In Master Mode

#define KINETISK_SPI1 (*(KINETISK_SPI_t *)0x4002D000)

typedef struct {
volatile uint32_t MCR; // 0
volatile uint32_t unused1;// 4
volatile uint32_t TCR; // 8
volatile uint32_t CTAR0; // c
volatile uint32_t CTAR1; // 10
volatile uint32_t CTAR2; // 14
volatile uint32_t CTAR3; // 18
volatile uint32_t CTAR4; // 1c
volatile uint32_t CTAR5; // 20
volatile uint32_t CTAR6; // 24
volatile uint32_t CTAR7; // 28
volatile uint32_t SR; // 2c
volatile uint32_t RSER; // 30
volatile uint32_t PUSHR; // 34
volatile uint32_t POPR; // 38
volatile uint32_t TXFR[16]; // 3c
volatile uint32_t RXFR[16]; // 7c
} KINETISK_SPI_t;

TBH is seems a strange choice to mix this mode bit with the transmit buffer register.

0 Kudos
Reply
4 Replies

634 Views
migry
Contributor I

I have no use for and do not care about the PCS signal!

I want the SPI packets (8 or 16 bit) to be sent back to back with no gap or extra clock. This can ONLY be achieved by setting the CONT bit.

HOWEVER if using DMA mode, because the CONT bit is part of the PUSHR register, you are FORCED to transfer 32 bit values. This is very wasteful Each 32 bit value can hold either a 8-bit or 16-bit SPI value (depends on another register setting). I selected 16-bit SPI length, so to send each 16 bits of serial SPI data, costs one entry in a 32-bit array, i.e. to send the 16-bit SPI value of 0x55, the 32-bit array MUST have the value 0x8055, where the top (31st) bit is the CONT bit.

This is not ideal, but this restriction is NOT documented. If you are not using DMA mode, it would be easy to take an 8-bit value from your array, put it into a 32-bit variable and then set the top (CONT) bit, before writing to the PUSHR register. Clearly this manipulation can't be done in DMA mode.

0 Kudos
Reply

731 Views
migry
Contributor I

OK, I was aware that I needed to set the CONT bit, however I have no interest in the PCS signal, I need a continuous serial data stream on MOSI, with no gaps or extra added bits. My serial data stream needs to have one SPI MOSI bit per clock, where the clock is continuous, allowing me to create any arbitrary digital waveform. I am NOT using the SPI MOSI or SCK to connect to any other SPI chip. Use of the SPI hardware module fits well with my requirements because I need each bit to be output every 1us.

The issue is that the only way I could achieve this continuous single bit data stream on MOSI, i.e. by setting the CONT bit in the register field you show above, was to DMA 32 bit values in which the top bit (corresponding to CONT) was set.

This is very wasteful of memory, although TBH this SoC has plenty of RAM, enough for the length of the data stream I need to generate.

Nevertheless my question is - can I set the CONT bit in some way, such that I can DMA transfer only 8-bit values to the bottom 8-bits of the PUSHR register?

My guess is that the answer is no, in which case I would ask, why on earth did NXP decide to put the CONT bit as part of the PUSHR register???

0 Kudos
Reply

791 Views
migry
Contributor I

After some experimentation, I have got continuous mode working, but it's far from ideal.

I changed the 8-bit DMA into 32-bit DMA, and in the test data set the CONT bit (bit 31) in each word of the array. The bottom 8-bits were the wanted serial data SPI packet. This worked and I got 8 bits and 8 clocks per array word. 

This is horribly wasteful of memory as I have to change the 8-bit array to 32-bit. 

I was able to change the SPI packet format from 8-bits to 16-bits, so now only half as wasteful.

Hopefully I am missing something, and it is possible to get continuous SPI mode (CONT=1) to operate in 8-bit DMA mode, but only an expert can say for sure. 

0 Kudos
Reply

739 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

I am glad to hear that you have solved your issue.

The CONT bit can determine which transfer will assert the PCS signal.

 

xiangjun_rong_0-1703576413014.png

Hope it can help you

BR

XiangJun Rong

0 Kudos
Reply