AnsweredAssumed Answered

DMA SPI read error(s)

Question asked by Thomas Carrington on May 30, 2017
Latest reply on May 31, 2017 by Thomas Carrington

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

Outcomes