Showing results for 
Search instead for 
Did you mean: 

Readout external ADC by SPI doesn't work correctly

Associate III

Hallo everyone,

As a relative newbe in the world of MCU programming, I am wrestling go get my application running. The origin of the errors is unclear, although I have the impression it is related to conflicts of peripherals or time. I still use CUBEIDE (with more and more additions of Register based code), because I need its features to build an image I can load to my MCU.

My hardware: STM32F401RCT6 as replacement for STM32F401CCU6 (both on a WeAct-3.0 Blackpill), plus a PCB with some frontend electronics.
Software environment: STM_CUBEIDE v1.15, because I'm an auto-didact who discovered the fun(???) of playing with MCU's about 5 years ago.

The project aims to readout light-intensities from a TCD1304 linear CCD with 3694 pixels, in order to measure mechanical displacement with high precision. I apply a 16bit SPI ADC (ADS8319IBDGST) for the analog intensity signal. Once all data is collected, the values must be exported as serial stream. I decided to split the functionality of the application in two phases that won't disturb each other, by means of gating the ADC-trigger. When suppressed, it will not activate the SPI (no updates on the data-array), while the UART outputs the stream. This requires a fifth Timer, also synchronous with the the other ones.

The strategy is: TIM3 (the ADC-trigger) starts the ADC-conversion by its rising edge; it also is configured to fire an interrupt at its falling edge. The related ISR is adapted: it writes a constant uint16_t to SPI-DR. This SPI is configured as Full-Duplex Master, HW NSS, 16bit, 10.5MHz clock and to generate interrupt when RXNE=1. Writing to DR causes the SPI to generate Clock-pulses, which allow the ADC to output its result word to SPI-MOSI. After SPI has received the ADC-word, the RXNE interrupt is fired. The related ISR is also adapted: the DR is copied to SPI.pRxBuffPtr (@ the correct index of the data-array) + the pRxBuffPtr and RxXferCount are updated (Register programmed). This mechanism should handle the time critical part of the code with a limited #instructions, so execution within 8us should be possible for a 84MHz CPU (??) This strategy is my interpretation of the replies by this forum on an earlier request for help.
The SPI ISR checks the RxXferCount to be positive; when 0 is reached, a flag is set to output the data by UART6. At the same moment the gate-pulse will end, stopping the ADC and the SPI, leaving the data-array untouched. The output-flag is polled in the main while-loop, the conversion is non-blocking (HAL_UART_Transmit_DMA(&huart6, ...)).

The debugger shows strange behavior, like running without ever reaching the breakpoint on the main() while-loop'. Does this mean all CPU cycles are consumed by the ISR's?

By close observation of the SPI-SR bits, I found the SPI changed from Master to Slave, directly after enabling. Reading RM0368 again learned me I configured the SPI incorrect: MSTR=1, BIDIMODE=1, BIDIOE=1 and SSOE=1. I had empirically found this combination being required to let the SPI produce 16 Clock-pulses after each ADC-trigger, only during the 'gate' period. However,this combination puts the SPI in 'Tx only' + 'Master-Mode Fault state'. I realized I need a SPI, configured as 'Slave RX-Only', meaning I have to supply the Clock-pulses myself. The only way-out I found was to apply a second SPI as 'Master Tx Only', trigger it as described and use its Clock pulses for the Slave SPI.
I implemented this new approach with some success: the signals on my LogicAnalyzer look OK, just as the values of the SPI-decoding (see attachment 3). However, a closer look at these values learned there are series of ADC-values shifted one bit, equals one clock-pulse.
This is not acceptable and screws up my whole design, at least I fear that.

Resuming: in the past I managed to readout a TCD1304 CCD with a STM32F401CCU6, using the internal ADC with DMA, a number of Timers and the USB_OTG_FS as serial output. In fact, now I add just a SPI peripheral and some (challenging, ok)constraints to handle a separate ADC and it appears impossible to get the application running, at least for me. I sincerely hope there are some enthousiast forum members willing to think with me how to get this project running.

And as additional question: is there a way to check resource conflicts in a STM32 application, other than search for the yellow alert triangles in the 'Pinout & Configuration' view of CUBEIDE?

Thanks for your attention,

Fred Schimmel


PS: I added some screenshots with more detailed information for interested readers.