STM32, SPI With DMA  - Page 1
Forum section: electronics / general

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 08, 2014, 02:01:28 pm
content: Hi everyone,Again with STM32F, i have to interface an STM32F101 with an STM32L05 via SPI, the STM32L is configured as master , the STM32F1 as slave, using 8 bytes buffering with RX and TX DMA. The test code is simple, master send those 8 bytes and the slave must respond by sending back those 8 bytes...For master things are good i can receive and send data no problem at all. For the slave well, it receive right data , but it only send them back right at the third read mean :--First transmissionMOSI : 0xAA 0x01 0x07 0x01 0x01 0x01 0x01 0x01MISO: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00Normal, and as expected--2nd transmissionMOSI : 0xAA 0x01 0x07 0x01 0x01 0x01 0x01 0x01MISO: 0x00 0x01 0x07 0x01 0x01 0x01 0x01 0x010xAA is missing on the MISO--3rd transmissionMOSI : 0xAA 0x01 0x07 0x01 0x01 0x01 0x01 0x01MISO: 0xAA 0x01 0x07 0x01 0x01 0x01 0x01 0x01Correct data out of the slave !!i can't see what's seems to be the problemanyone had a similar problem before, please advice.

author: mrflibble
author_rank: Super Contributor
timestamp: September 09, 2014, 03:17:38 am
content: Can't say that I've had the same problem, but more of a suggestion. Can't you change the test pattern to something more unique? That may make it a bit easier to see what bits go where. Purely from the standpoint of debugging with your current data it's a toss up what could be going on. More unique patterns may help you reach that a-hah moment faster.A predefined random sequence for example would already make things easier.

author: Rasz
author_rank: Super Contributor
timestamp: September 09, 2014, 07:27:43 am
content: buy Salaleaeaea, or chinese clone, or any other logic analyser 0 your life will be so much easier, no more guessing what is happening on the pins

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 09, 2014, 08:18:18 am
content: Thanks for your replyI tried different test sequence, always the same missing byte, i checked data in slave Rx buffer once DMA interrupt occur, and it's correct the slave read correct data. I initialised the Slave Rx buffer with that sequence and read it and it's correct even on the first read. Am kind of new with STM32 and i did had a lot of a-hah moment for this application even unthinkable buzzard things for such easy protocol like SPI, for example master read wrong last byte and the problem was MISO input configured at low speed ( used MxCube for automatic configuration code ) , an other example is slave DMA rx interrupt occur only once, and was corrected with DMA mode circular ( i copied the first configuration from SPI DMA example given by ST libraryand it didn't work )here the init code for SPI, will be kind if you can help me with this stupid fault , i can't say i truly understand the working mechanism of SPI in STM32 because i don'tso SOSCode:#define SPI_SLAVE SPI2#define SPI_SLAVE_CLK RCC_APB1Periph_SPI2#define SPI_SLAVE_GPIO GPIOB#define SPI_SLAVE_GPIO_CLK RCC_APB2Periph_GPIOB#define SPI_SLAVE_PIN_NSS GPIO_Pin_12#define SPI_SLAVE_PIN_SCK GPIO_Pin_13#define SPI_SLAVE_PIN_MISO GPIO_Pin_14#define SPI_SLAVE_PIN_MOSI GPIO_Pin_15#define SPI_SLAVE_DMA DMA1#define SPI_SLAVE_DMA_CLK RCC_AHBPeriph_DMA1#define SPI_SLAVE_Rx_DMA_Channel DMA1_Channel4#define SPI_SLAVE_Rx_DMA_FLAG DMA1_FLAG_TC4#define SPI_SLAVE_Tx_DMA_Channel DMA1_Channel5#define SPI_SLAVE_Tx_DMA_FLAG DMA1_FLAG_TC5#define SPI_SLAVE_DR_Base 0x4000380C#define RXTXBufferSize 8uint8_t SPIRx;uint8_t SPITx={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};void SPI_LCD_Init(){SPI_InitTypeDef SPI_InitStructure;DMA_InitTypeDef DMA_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_AHBPeriphClockCmd(SPI_SLAVE_DMA_CLK, ENABLE);RCC_APB1PeriphClockCmd(SPI_SLAVE_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin = SPI_SLAVE_PIN_MISO ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(SPI_SLAVE_GPIO, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SPI_SLAVE_PIN_SCK | SPI_SLAVE_PIN_NSS| SPI_SLAVE_PIN_MOSI;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(SPI_SLAVE_GPIO, &GPIO_InitStructure);///DMA RXDMA_DeInit(SPI_SLAVE_Rx_DMA_Channel);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SPIRx;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize =RXTXBufferSize;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(SPI_SLAVE_Rx_DMA_Channel, &DMA_InitStructure);DMA_Cmd(SPI_SLAVE_Rx_DMA_Channel, ENABLE);DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);//DMA TXDMA_DeInit(SPI_SLAVE_Tx_DMA_Channel);DMA_StructInit(&DMA_InitStructure);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DR;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&SPITx;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = RXTXBufferSize;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(SPI_SLAVE_Tx_DMA_Channel, &DMA_InitStructure);DMA_Cmd(SPI_SLAVE_Tx_DMA_Channel, ENABLE);///SPISPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);SPI_Cmd(SPI_SLAVE, ENABLE);SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx , ENABLE);}void DMA1_Channel4_IRQHandler(){uint8_t i=0;if (DMA_GetITStatus(DMA1_IT_TC4)){for (i=0;i<=7;i++) {SPITx=SPIRx;}DMA_ClearITPendingBit(DMA1_IT_TC4);}}

author: Psi
author_rank: Super Contributor
timestamp: September 09, 2014, 08:21:28 am
content: I seem to remember a catch with the SPI FIFO buffer and DMA.Check the datasheet for any special cases where data can be lost. I have a vague memory of something like that.Also, in your example, is the slave output supposed to represent the previous master output?So the missing 0xAA is the first ever byte that the slave receives when started? If so then its probably to do with a bad init somewhere. eg, something isn't setup correctly and so misses the first byte.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 09, 2014, 08:24:18 am
content: Quote from: Rasz on September 09, 2014, 07:27:43 ami do have an oscilloscope and the byte is truly missing on MISO, the rest of the sequence is OKbut yes am thinking about getting a logic analyser, oscilloscope is not that practical in sequence data analysis

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 09, 2014, 08:36:55 am
content: Quote from: Psi on September 09, 2014, 08:21:28 amyes 0xAA is the first ever byte that the slave receives.and yes that's what i think too, i just can't figure out what am doing wrong, been 2 days on this and am stating to have dream about missing 0xAAThe application use 11 ADC channel with DMA, I2C connexion , uart connexion for diagnostic purpose and an other uart with dma for RS485 connectivity , SPI for an interface (LCD and some Push Bt) and a couple of generic input / output .. stopped all that , now i just have that SPI init everything else is not used. so if anything is wrong it must be in those lines.

author: Psi
author_rank: Super Contributor
timestamp: September 09, 2014, 08:56:12 am
content: Could be a incorrect initial clock polarity/idle state.If DMA tries to pull clock low but clock is already low then the receiver would miss it (and the same if it tries to pull high but its already high).

author: mikerj
author_rank: Super Contributor
timestamp: September 09, 2014, 05:49:14 pm
content: You need to enclose code in code blocks, so the forum doesn't interpret your code as formatting code.e.g. your array indexes aren't visible in your original post since 'i' in square brackets is a formatting code of italics. With code blocks, why you type is what you get:Code:void DMA1_Channel4_IRQHandler(){uint8_t i=0;if (DMA_GetITStatus(DMA1_IT_TC4)){for (i=0;i<=7;i++) {SPITx=SPIRx;}DMA_ClearITPendingBit(DMA1_IT_TC4);}}Are you performing the write and read as a single operation, i.e. without de-asserting and re-asserting the chip select? If so you have a race condition here as you have less than a single SPI clock cycle to enter the interrupt handler and copy the contents of one buffer to another. Chances are the DMA has already loaded the first byte from SPITx[] into the SPI hardware buffer before the copy operation has started.If you slow the SPI clock rate down and it starts working, then this is likely the problem.

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 09, 2014, 11:13:29 pm
content: Quote from: mikerj on September 09, 2014, 05:49:14 pmThe master send 8 bytes as a command then pull up the CS, wait a bit of time then pull it down and clock out slave response by sending 8 dummy bytes.Man that's the only sentence i neededcoz that's what actually happen , i think since the DMA in circular mode, it will load SPITx in hardware as soon as it send the last byte before starting the copy operation, i will add a DMA half transfer interrupt to copy the first byte and test itan other thing i didn't understand, the slave sending was a bit unstable and work randomly mean it can stop working by adding any random command in main loop ANYTHING, on scope i can see some little pulses on MISO that correspond what it should send, they are just not high enough to be considered as logic 1. again putting output in high speed mode ( 50Mhz ) solved the problem and i don't understand how this is workinganyway thanks for the tip i give a test and let you know

author: hamdi.tn
author_rank: Frequent Contributor
timestamp: September 10, 2014, 04:23:20 pm
content: well, update,By activating a DMA half transfer interrupt and loading only the first received byte in Tx buffer, and copy the rest of Rx buffer in Tx buffer once DMA transfer complete occur.Code:void DMA1_Channel4_IRQHandler(){uint8_t i=0;if(DMA_GetITStatus(DMA1_IT_HT4)) {SPITx=SPIRx;DMA_ClearITPendingBit(DMA1_IT_HT4);}if(DMA_GetITStatus(DMA1_IT_TC4)) {for (i=0;i<=7;i++) {SPITx=SPIRx;}DMA_ClearITPendingBit(DMA1_IT_TC4);}}Thanks everyoneProblem solved