DMA SPI read error(s)
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 priorityDMA_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 interruptNVIC_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 interruptNVIC_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 priorityDMA_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 interruptNVIC_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 interruptNVIC_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
