STM32F103C8T6 SPI communication with ADS1220 stops - Page 1
Forum section: electronics / general

author: aleks_sitno
author_rank: Newbie
timestamp: March 01, 2017, 09:43:12 am
content: Hello,I'am using and STM32F103C8T6 development board to communicate via SPI with ADS1220(Analog to Digital Converter). My code needs to read the buffer of the ADS1220 at certain times. When i run the code the SPI works only for a few minutes(max 14 min) before it stops. The SPI code i am using is :void SPIx_Init(){// Initialization structSPI_InitTypeDef SPI_InitStruct;GPIO_InitTypeDef GPIO_InitStruct;// Step 1: Initialize SPIRCC_APB2PeriphClockCmd(SPIx_RCC, ENABLE);SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStruct.SPI_Mode = SPI_Mode_Master;//SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;SPI_Init(SPIx, &SPI_InitStruct);SPI_Cmd(SPIx, ENABLE); // Enables SPIx peripheral.// Step 2: Initialize GPIORCC_APB2PeriphClockCmd(SPI_GPIO_RCC, ENABLE);// GPIO pins for MOSI and SCKGPIO_InitStruct.GPIO_Pin = SPI_PIN_MOSI | SPI_PIN_SCK;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(SPI_GPIO, &GPIO_InitStruct);// GPIO pins for MOSI, MISOGPIO_InitStruct.GPIO_Pin = SPI_PIN_MISO;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(SPI_GPIO, &GPIO_InitStruct);}uint8_t SPIx_Receive(uint8_t data){// Write data to be transmitted to the SPI data registerSPIx->DR = data;// Wait until transmit completewhile (!(SPIx->SR & (SPI_I2S_FLAG_TXE)));// Wait until receive completewhile (!(SPIx->SR & (SPI_I2S_FLAG_RXNE)));// Wait until SPI is not busy anymorewhile (SPIx->SR & (SPI_I2S_FLAG_BSY));//Return received data from SPI data registerreturn SPIx->DR;}The program always stops at this line of code :while (!(SPIx->SR & (SPI_I2S_FLAG_TXE)));Before the code stops, it has done at least 1000 reads(usually more than a 1000,maybe even 50000) of the buffer successfully. Why does my code stop after successfully running for so long time. Is there a problem with the SPI buffer, some data not being send. The data I am transmitting is a dummy byte 0x00.Any help would be greatly appreciated.

author: Kjelt
author_rank: Super Contributor
timestamp: March 01, 2017, 09:56:23 am
content: not sure if this is the answer for you but did you read this topic:https://www.eevblog.com/forum/beginners/problems-with-stm32-spi-and-chip-select/msg940848/#msg940848

author: capt bullshot
author_rank: Super Contributor
timestamp: March 01, 2017, 10:45:48 am
content: Edit:I believe your code stops at some point because you're reading the TX empty too soon. Place a few cycles of delay in between, or try my approach (below)/EditFrom my experience, a better approach would be to wait for the TX to be empty and then send:// Wait until transmit completewhile (!(SPIx->SR & (SPI_I2S_FLAG_TXE)));// Write data to be transmitted to the SPI data registerSPIx->DR = data;then wait for the receiver register// Wait until receive completewhile (!(SPIx->SR & (SPI_I2S_FLAG_RXNE)));then read the data and return//Return received data from SPI data registerreturn SPIx->DR;IMO the wait for SPI not busy isn't necessary, but I'd have to check that (nice if you'd do that for me :-)

author: fsedano
author_rank: Contributor
timestamp: March 01, 2017, 11:45:26 pm
content: Quote from: capt bullshot on March 01, 2017, 10:45:48 amI've found if you only wait for tx reg to be empty you will exit too early, causing problems if you raise CS just after that.

author: capt bullshot
author_rank: Super Contributor
timestamp: March 02, 2017, 07:23:55 am
content: Quote from: fsedano on March 01, 2017, 11:45:26 pmYou're right, I've found that piece of code I wrote two years ago (skipped some meaningless lines):59 unsigned short xfer_srio(void)60 {61 unsigned short out,in;77 out=srio1_out | srio2_out;78 SPI1->DR = out;79 while (!(SPI1->SR & SPI_I2S_FLAG_TXE));80 while ((SPI1->SR & SPI_I2S_FLAG_BSY));81 in = SPI1->DR;82 SRIO_LATCH_LOW;83 asm("nop; ");84 asm("nop; ");85 asm("nop; ");86 asm("nop; ");87 asm("nop; ");88 SRIO_LATCH_HIGH;89 SRIO_OE_LOW;90 srioz_out=out;97 return in;98 }The nops are for creating a slightly longer latch pulse after having shifted the data in and out (some HC595 / HC 597 shift registers are involved here). I haven't touched this code since then and the device is still running. (used a STM32F303 afair). Never had problems using the SPI this way on various STM32F1 and F3 devices.Using the SPI on a STM32F7 nucleo board (with STM HAL and Cube generated drivers) didn't work out well, these drivers appear to be quite buggy. Better roll your own.This is the associated SPI init (GPIO init is done elsewhere):void init_srio()39 {40 SPI_InitTypeDef SPI_InitStructure;4142 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);434445 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;46 SPI_InitStructure.SPI_Mode = SPI_Mode_Master;47 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;48 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;49 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;50 SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;51 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;52 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;53 SPI_InitStructure.SPI_CRCPolynomial = 7;54 SPI_Init(SPI1, &SPI_InitStructure);55 SPI_SSOutputCmd(SPI1, ENABLE);56 SPI_Cmd(SPI1, ENABLE);57 }58

author: aleks_sitno
author_rank: Newbie
timestamp: March 02, 2017, 08:34:43 am
content: Thx a lot, it works. I did try the delay thing before and it didn't work, but your approach works and i removed wait for SPI not busy as you suggested. I left the program to run over night, and the SPI didn't stop.

author: Kjelt
author_rank: Super Contributor
timestamp: March 02, 2017, 09:07:45 am
content: Hi just a side question:Quote from: capt bullshot on March 02, 2017, 07:23:55 amWhat kind of contingencies did you take if any of the two flags for any reason will not work, eg the peripheral gets stuck ?Do you have an RTOS with a timeout arbiter resetting the peripheral or a watchdog resetting the entire uC, or.... ?

author: capt bullshot
author_rank: Super Contributor
timestamp: March 02, 2017, 10:08:05 am
content: > What kind of contingencies did you take if any of the two flags for any reason will not work, eg the peripheral gets stuck ?> Do you have an RTOS with a timeout arbiter resetting the peripheral or a watchdog resetting the entire uC, or.... ?I've used ChibiOS (RTOS), this function is located in a low priority thread - so this thread may get stuck here. In case that happens, the whole uC is reset by either a supervising higher priority thread or lack of triggering the watchdog. I've no means to reset the peripheral alone, in case of anything getting stuck the whole thing simply reboots (and the incident ist logged for later inspection).Except for some priority / semaphore / mutex issues at the beginning, this thing runs quite stable over more than a year now without a reset.

author: Kjelt
author_rank: Super Contributor
timestamp: March 02, 2017, 01:30:56 pm
content: Quote from: capt bullshot on March 02, 2017, 10:08:05 amImpressive.

author: capt bullshot
author_rank: Super Contributor
timestamp: March 02, 2017, 02:45:55 pm
content: Quote from: Kjelt on March 02, 2017, 01:30:56 pmThanks!No, not impressive at all. Simply just as expected from an embedded micro in an always on application supplying power to most of my home network boxes (http://wunderkis.de/pvbat/). But quite an amount of effort to get it all up and running.

author: Jeroen3
author_rank: Super Contributor
timestamp: March 04, 2017, 02:16:00 pm
content: The busy flag does not indicate receive has been completed. It fell for that one too.The only way to know for sure receive is complete as master is by DMA or IRQ.So, why not use the DMA RX IRQ?Then when it's not finished, and you do this:Code: (c)// Write data to be transmitted to the SPI data registerSPIx->DR = data;// Wait until transmit completewhile (!(SPIx->SR & (SPI_I2S_FLAG_TXE)));You get an lockup because you're supposed to check if the spi is ready for transmitBEFOREtransmitting.Quote from: RM0008