2014-02-13 05:07 AM
I've set up my DMA to transfer 106 half-words via the SPI to a memory buffer. I am quite confident that my buffer size is correct. However, when the transfer actually occurs, it is twice the size I expect (and is consequently stepping on some global variables). Because the transfer is all 0xFFs, I can't tell if I'm getting 212 half-words, 106 full-words, or two 106 half-word ''packets'' back-to-back and somehow the destination pointer is getting scrambled. If I look at the NDTR register for that stream in my IDE just before it transfers, it says I have 106 data items, leading me to believe the case is 106 full-words, but then again it also says the memory and peripheral data sizes are set to half-words so I don't know which to believe.
Any thoughts are appreciated. Sample DMA/SPI setup:void SPI_Configuration()
{ StopSPI(); //Stop DMA, SPI/***************************
// SPI1 // ***************************/ SPI1_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI1_InitStructure.SPI_Mode = SPI_Mode_Master; SPI1_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI1_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI1_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI1_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI1_InitStructure.SPI_BaudRatePrescaler = SPI1SCALER; SPI1_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI1_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI1_InitStructure); // Rx Channel DMA_DeInit(DMA2_Stream2); DMA_StructInit(&SPI1RX_DMA_InitStructure); SPI1RX_DMA_InitStructure.DMA_Channel = DMA_Channel_3; SPI1RX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); SPI1RX_DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&g_spi1_adc_data; SPI1RX_DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; SPI1RX_DMA_InitStructure.DMA_BufferSize = g_chain1_buffer_size; SPI1RX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; SPI1RX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; SPI1RX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; SPI1RX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; SPI1RX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; SPI1RX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_Init(DMA2_Stream2, &SPI1RX_DMA_InitStructure); // Enable DMA Stream Transfer Complete interrupt DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE); // Tx Channel DMA_DeInit(DMA2_Stream3); DMA_StructInit(&SPI1TX_DMA_InitStructure); SPI1TX_DMA_InitStructure.DMA_Channel = DMA_Channel_3; SPI1TX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); SPI1TX_DMA_InitStructure.DMA_Memory0BaseAddr = g_spi1_config_buf_base_ptr; SPI1TX_DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; SPI1TX_DMA_InitStructure.DMA_BufferSize = g_chain1_buffer_size; SPI1TX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; SPI1TX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; SPI1TX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; SPI1TX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; SPI1TX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; SPI1TX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_Init(DMA2_Stream3, &SPI1TX_DMA_InitStructure);// Enable SPI1
SPI_Cmd(SPI1, ENABLE); // Enable DMA request SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE); } #dma #stm32 #spi2014-02-13 05:20 AM
g_chain1_buffer_size = number of 16-bit words to transfer
The DMA shouldn't overflow it's described buffer. You could make yourself a large buffer, put a fill character in it, and then observe how much gets over written. Avoid DMA to auto/local variables.2014-02-13 05:24 AM
Clive,
Thanks for the reply. I have confirmed that g_chain1_buffer_size is the number that I want (106). And without creating a larger buffer, I can tell pretty easily what size it's actually writing by viewing the memory starting at the destination pointer in my IDE. It's actually sending exactly twice what I expect (212 16-bit integers, instead of 106).2014-02-13 05:59 AM
Please try enable only DMA TX request - last line. Configured as full-duplex should also trigger a DMA RX, I hope.
2014-02-13 06:24 AM
Thank you for the reply. So I changed the last line to:
// Enable DMA request SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE); However, now I get NO data transferred at all. I think you may be on to something here: I just noticed that before I made this change, when I see this ''too large'' DMA transfer, both the RX stream and TX stream (which each have the same size buffer) have their NDTR registers cleared. Can you elaborate on why you say ''Configured as full-duplex should also trigger a DMA RX, I hope.''? I would not expect to receive anything when only the TX DMA transfer is enabled, but I may be missing something important. Thanks!2014-02-13 07:01 AM
DMA TX transfer is enabled ?
DMA_Cmd (DMA2_stream3, ENABLE); You can post also the DMA handler procedure called when transfer is complete2014-02-13 07:29 AM
Yes, it's when I actually enable the DMA that I see this overrun transfer:
DMA2_Stream3->CR |= (u32)DMA_SxCR_EN; I also notice that I get a FIFO error for this TX stream; in searching it appears that getting one of these error flags is normal since I enable the SPI before enabling the DMA. Can anyone confirm?2014-02-13 07:59 AM
I am thoroughly cinfused now: I changed the buffer size on the TX side of the config, trying to verify if it was indeed the TX stream contributing to the ovverun. Changed like this:
// Tx Channel DMA_DeInit(DMA2_Stream3); DMA_StructInit(&SPI1TX_DMA_InitStructure); SPI1TX_DMA_InitStructure.DMA_Channel = DMA_Channel_3; SPI1TX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR); SPI1TX_DMA_InitStructure.DMA_Memory0BaseAddr = g_spi1_config_buf_base_ptr; SPI1TX_DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; SPI1TX_DMA_InitStructure.DMA_BufferSize = (g_chain1_buffer_size - 20);SPI1TX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; SPI1TX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; SPI1TX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; SPI1TX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; SPI1TX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; SPI1TX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_Init(DMA2_Stream3, &SPI1TX_DMA_InitStructure); I expected I might see the total transfer to decrease by 20. Instead, it decreased by 40. It's as if the TX stream ONLY is writing to memory, instead of sending from memory to my peripheral. Does this make sense to anyone?
2014-02-13 09:42 AM
Does this make sense to anyone?
I'm confused too, present a complete test case that illustrates the problem. There are other things going on here, and I lack context.2014-02-13 11:09 AM