Skip to main content
Thomas Carrington
Associate III
May 30, 2017
Solved

DMA SPI read error(s)

  • May 30, 2017
  • 4 replies
  • 1443 views
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

    This topic has been closed for replies.
    Best answer by waclawek.jan
    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

    4 replies

    waclawek.jan
    Super User
    May 30, 2017
    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

    Thomas Carrington
    Associate III
    May 31, 2017
    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)

    waclawek.jan
    waclawek.janBest answer
    Super User
    May 31, 2017
    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