cancel
Showing results for 
Search instead for 
Did you mean: 

DMA SPI read error(s)

Thomas Carrington
Associate III
Posted on May 30, 2017 at 18:56

Hi All,

I've got a 

Nucleo-F103RB, and have been able to successfully implement an SPI interface to an FPGA, using the software to control the flow of the SPI.

I want to now move this across to the DMA, such that the DMA transmits and reads the data from the SPI. I've gotten the transmission part of it working correctly; data goes across correctly and the FPGA recognises it.

The issue that I have is the STM DMA reading the data, it doesn't come in the correct format:

The data from the FPGA is in 8 packets

(1 byte each), with the 3 MSB bits indicating its position within the sequence ('000' is first, '001', second, etc.), when I read the data that the DMA has received it doesn't follow this sequence it's all over the place (I know that the FPGA is transmitting the data correctly, as I've gotten this working in software). So I wonder if there are some conflicts with using the DMA, as to read data via SPI, you need to transmit data.

Below is a copy of initializing the DMA for both the transmission and receiving of data with the SPI. I've configured the SPI such that it uses the hardware Slave Select.

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock

// DMA1 Channel 3 for SPI transmission

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DMA_StructInit(&FPGA_DMA);

FPGA_DMA.DMA_BufferSize = FPGA_ArraySize*FPGA_bytesperPack; // Define the size of data to be DMA'd

FPGA_DMA.DMA_DIR = DMA_DIR_PeripheralDST;  // Read from memory

FPGA_DMA.DMA_M2M = DMA_M2M_Disable; // Disable the Memory to Memory transfer

FPGA_DMA.DMA_MemoryBaseAddr = (uint32_t) &FPGATransmitArray[0]; // Point to Transmit array

FPGA_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // State data is 8bits

FPGA_DMA.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment the memory pointer

FPGA_DMA.DMA_Mode = DMA_Mode_Normal; // Normal DMA mode (not circular)

FPGA_DMA.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI_Port[SPIx]->DR));

// 0x4001300c

FPGA_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // State data is 8bits wide

FPGA_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Disable peripheral pointer increment

FPGA_DMA.DMA_Priority = DMA_Priority_High; // High priority

DMA_Init(DMA1_Channel3, &FPGA_DMA); // Initialise the DMA1 channel 3 (SPI_TX)

DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); // Enable the Complete Transfer Interrupt

DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE); // Enable the error interrupt

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn; // DMA1 Channel 3 interrupt

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0xFF; // Lowest priority

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0xFF; // Lowest priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // Enable DMA1 Channel 3 interrupt

NVIC_Init(&NVIC_InitStructure);

SPI_SSOutputCmd(SPI_Port[SPIx], ENABLE);

SPI_I2S_DMACmd(SPI_Port[SPIx], SPI_I2S_DMAReq_Tx, ENABLE); // Enable SPI DMA interface (Txd)

//DMA_Cmd(DMA1_Channel3, ENABLE);

// DMA1 Channel 2 for SPI reading

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DMA_StructInit(&FPGA_DMA);

FPGA_DMA.DMA_BufferSize = FPGA_ArraySize*FPGA_bytesperPack; // Define the size of data to be DMA'd

FPGA_DMA.DMA_DIR = DMA_DIR_PeripheralSRC; // Read from peripheral

FPGA_DMA.DMA_M2M = DMA_M2M_Disable; // Disable the Memory to Memory transfer

FPGA_DMA.DMA_MemoryBaseAddr = (uint32_t) &FPGAReadArray[0]; // Point to Transmit array

FPGA_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // State data is 8bits

FPGA_DMA.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment the memory pointer

FPGA_DMA.DMA_Mode = DMA_Mode_Normal; // Normal DMA mode (not circular)

FPGA_DMA.DMA_PeripheralBaseAddr = (uint32_t) (&(SPI_Port[SPIx]->DR));

// 0x4001300c

FPGA_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // State data is 8bits wide

FPGA_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Disable peripheral pointer increment

FPGA_DMA.DMA_Priority = DMA_Priority_High; // High priority

DMA_Init(DMA1_Channel2, &FPGA_DMA); // Initialise the DMA1 channel 2 (SPI_RX)

DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE); // Enable the Complete Transfer Interrupt

DMA_ITConfig(DMA1_Channel2, DMA_IT_TE, ENABLE); // Enable the error interrupt

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn; // DMA1 Channel 2 interrupt

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0xFF; // Lowest priority (but higher than transmission)

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0xFF; // Lowest priority

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // Enable DMA1 Channel 2 interrupt

NVIC_Init(&NVIC_InitStructure);

//SPI_SSOutputCmd(SPI_Port[SPIx], ENABLE);

SPI_I2S_DMACmd(SPI_Port[SPIx], SPI_I2S_DMAReq_Rx, ENABLE); // Enable SPI DMA interface (Rxd)

The interrupts are configured such that they switch off the DMA that triggered the interrupt.

Is there anything which I am missing which will make the SPI DMA read correctly?

Regards,

  Thomas

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on May 31, 2017 at 10:19

Also requesting the same seqeunce twice I get different results

Sounds like sampling on the incorrect edge (i.e. incorrect CPOL/CPHA setting).

JW

View solution in original post

4 REPLIES 4
Posted on May 30, 2017 at 22:46

when I read the data that the DMA has received it doesn't follow this sequence it's all over the place

Specifically?

Shifted by a bit, shifted by a byte, one bit of each byte appears in the neighbouring byte, anything else?

Transfer any well-recognizable sequence? Perhaps plainly looping back?

Do both DMA finish at the same time?

I'd enable Rx first to avoid risk of losing a byte or a couple of them.

JW

Posted on May 31, 2017 at 09:13

Hi JW,

So it appears that extra bits are introduced next to the highest MSB, or removed. Also requesting the same seqeunce twice I get different results (they should be the same)

Below is a sequence:

Expected           Read

0x1F                  0x1F

0x20                  0xA0      <extra bit added near to highest MSB

0x40                  0x40

0x60                  0x20      <highest MSB removed

0x80                  0xC0      <extra bit added

0xA0                  0xD0      <extra bit added

0xC0                  0xE0      <extra bit added

0xE0                  0xF0      <extra bit added

0x1F                  0x1F

0x30                  0x30

0x40                  0x40

0x60                  0x60

0x80                  0x80 (second try got 0x40)

0xA0                  0x60 (second try got 0xD0)

0xC0                  0x60 (second try got 0xE0)

0xF0                  0xF0 (second try got 0xF8)

Posted on May 31, 2017 at 10:19

Also requesting the same seqeunce twice I get different results

Sounds like sampling on the incorrect edge (i.e. incorrect CPOL/CPHA setting).

JW

Posted on May 31, 2017 at 10:45

Ah....Right, so looks like I was messing with the SCLK clock speed, and hadn't quite brought it back to a working speed.

Once set this up correctly, the DMA read things correctly. Thanks Jan.