2011-01-10 01:55 PM
Receiving SPI data through DMA - STM32 internal hardware error ?
#spi-dma2011-05-17 05:21 AM
Hi ANN;
I solved the problems with the receiving. I tried to receive data through DMA which memory size was set to 8-bit while SPI data word size was set to 16-bit. This is why it didn't work. Now it seems it works correctly.Can you please mention the steps you have taken in order to get the receiving part of SPI work without DMA. I am also trying to do that. But it is not working properly.
I need to receive in slave mode.
I've never used slave mode without DMA but i will present the code that works well without DMA for master mode. I think it should also work in slave mode with slight modification. Sending a byte in master mode: void Send_SPI_Byte(u8 b) { while (SPI1->SR & SPI_SR_BSY); while (!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = b; while (SPI1->SR & SPI_SR_BSY); while (!(SPI1->SR & SPI_SR_RXNE)); tmp8 = SPI1->DR; } The above function may look strange especially because of the flags SPI_SR_BSY that are checked twice. However, the functions NEVER worked when i writte them in other way. The ''tmp8'' variable must be declared as global (otherwise the compiler will remove the code for '' tmp8 = SPI1->DR'' from you program) As for slave mode i think the receiving function may look like this: u8 ReadSlave_SPI_Byte(void) { while (SPI1->SR & SPI_SR_BSY); while (!(SPI1->SR & SPI_SR_TXE)); return (u8) SPI1->DR; }
2011-05-17 05:21 AM
Thanks Robert.
Will look into it.2011-05-17 05:21 AM
You should use return SPIx->DR, not tmp8 return to global variable. Its not efficient and the global variable consumes memory for whole program run. Local variable are better because they are pushed on stack only for the needed time and then poped.
2011-05-17 05:21 AM
You should use return SPIx->DR, not tmp8 return to global variable.
The tmp8 global variable consumes only one byte so this is not a problem for 20KB memory. Besides if tmp8 is declared as a local variable the compiler removes the code for the instruction: tmp8 = SPIx->DR because it detects the tmp8 is never used again in the function. This is due to optimization compiler does when compiling a program.
2011-05-17 05:21 AM
I am also having trouble with DMA and SPI, on STM32F100. First time I receive a data block after reset, I get only 0x00. The second time I get the correct data except one byte missing from beginning.
Here is my code: // Transmit 0xFF and receive to buf. static void dma_rx(BYTE *buf, UINT count) { char txvalue = 0xff; // Transmit channel DMA1_Channel3->CPAR = (int) &(SPI1->DR); DMA1_Channel3->CMAR = (int) &txvalue; DMA1_Channel3->CNDTR = count; DMA1_Channel3->CCR = (1 << 8) | DMA_CCR1_DIR; // Low priority // Receive channel DMA1->IFCR = DMA_IFCR_CGIF2; DMA1->IFCR = 0; DMA1_Channel2->CPAR = (int) &(SPI1->DR); DMA1_Channel2->CMAR = (int) buf; DMA1_Channel2->CNDTR = count; DMA1_Channel2->CCR = (1 << 12) | (1 << 8) | DMA_CCR1_MINC | DMA_CCR1_TCIE; // Medium priority NVIC_EnableIRQ(DMA1_Channel2_IRQn); NVIC_SetPriority(DMA1_Channel2_IRQn, 14); always_read(SPI1->DR); always_read(SPI1->SR); DMA1_Channel2->CCR |= DMA_CCR1_EN; DMA1_Channel3->CCR |= DMA_CCR1_EN; SPI1->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN; vTaskDelay(1); xSemaphoreTake(mmc_dma_semaphore, 10000); SPI1->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN); DMA1_Channel3->CCR &= ~DMA_CCR1_EN; DMA1_Channel2->CCR &= ~DMA_CCR1_EN; }2011-05-17 05:21 AM
Not really enough information to work with here.
What are you connecting it too, and how are you initializing the system? Have you attached a scope/analyzer to the bus to confirm it's not sending zeros? If it is then the DMA is not the problem, but rather the peripheral.2011-05-17 05:21 AM
Never mind, got it fixed after all. It was a bunch of overlapping problems. Most importantly, I wasn't reading back the data after transmission-only requests, leaving one byte in DR.
For anyone else who might need it: To clear the SPI RXNE and overflow flags before starting the DMA transfer, I use this: #define always_read(x) asm(''''::''r''(x)) while (!(SPI1->SR & SPI_SR_TXE)); // Wait for bus free while (SPI1->SR & SPI_SR_BSY); always_read(SPI1->DR); // Clear RX flags always_read(SPI1->SR);