Interrupt-based read from ADC, debugging acquired samples - Page 1
Forum section: electronics / general

author: davegravy
author_rank: Regular Contributor
timestamp: December 30, 2021, 09:35:57 pm
content: While I wait for parts, I'm preparing to try and read sample values off an LTC2512-24 ADC using SPI and the STM32U5. At the bottom ofpage 12 of the datasheetyou can see the timing diagram for the ADC.I'll be driving the ADC using an external clock source at 812kHz. I'm looking for the simplest (beginner-friendly) method to do this. My thought was to use the falling edge of the DRL line as an external interrupt and in the ISR initiate the SPI transfer, I understand there may be more power efficient methods I can explore later. The conversion phase of this ADC takes up to 460ns meaning that I have only ~770ns to respond to the interrupt and read 24 bits.It's pretty clear fromwhat others are reportingHAL will be too slow (~1.3us measured latency, although for a different stm32 family). I haven't been able to find any reports on latency when implemented via "bare metal", does anyone have a rough idea if this is worth pursuing? Is there another reasonably simple approach I should consider?Part 2:Once I'm successfully reading samples I can inspect a random subset of samples or reduced datasets/summary info by printing to console. Eventually I'll want to get the full raw bitstream to my development PC for analysis. The ADC output datarate will be 24bit * 51200sps = ~1.3Mbps.I understand ST-LINK which is integrated on the Nucleo-144 board I ordered goes beyond providing an interface to flash firmware on the MCU and exposes a virtual COM port to the OS using one of the USART interfaces on the MCU that can be used for data exchange. From reading the RM I think USART is good up to beyond 6Mbps (in theory, at least). Is this likely the best interface to use for transferring raw samples?

author: Siwastaja
author_rank: Super Contributor
timestamp: January 02, 2022, 02:45:44 pm
content: UART is fine if you can find a suitable UART adapter for your PC. Typical cheap suspects go up to around 1Mbaud/s and then start silently corrupting or losing bytes. It needs to be some deluxe USB UART adapter specified for the high datarate you need, with large enough FIFOs so that your OS won't start dropping bytes. They do exist but not necessarily easy to find. This could still prove easiest, compared to implementing USB or Ethernet.By far, the easiest, i.e. trivial program to get you going is to enable SPI and UART, set up SPI interrupt, and in the ISR, just read the SPI data register and write the content to UART data register; a simple bridge.Didn't look at STM32U5 datasheet but I'm assuming it's new enough so you can configure the SPI peripheral for full 24-bit data width, so you only get one interrupt per sample. If you enable the FIFO mode in UART (assuming it's available), then you can just write the 3 bytes back-to-back without waiting. This gives very manageable interrupt rate of only 51200 interrupts per second (same as the sample rate).Interrupt latency (entry + exit) is approximately 20 CPU clock cycles. SPI doesn't need much babysitting, just read the data register, this is maybe 2-3 CPU cycles. Same for writing to UART. It's entirely possible to keep the whole ISR (including overhead) below 50 clock cycles. You have time to spare.Start simple and go from there.

author: davegravy
author_rank: Regular Contributor
timestamp: January 02, 2022, 06:49:30 pm
content: Great, thanks!My Nucleo board arrived and I've been experimenting. The Stlink V3 has a micro USB connector interface and exposes a virtual com port over USART1. I'm not sure if this qualifies as a "deluxe" according to your definition - I should see if I can find the specs on it.I set it and my client to 1228800 baud and the short test strings I've been transmitting at 1s interval are being received successfully. Maybe I will try generating some mock 24bit sample data (pure sine signal) at 51200hz and see if it can keep up without corruption. I don't like the idea of silent corruption, it will add overhead but maybe I will append CRC bits.I agree I think ISR is the easy way to start. I worked out how to use a one pulse timer triggered from an external pin, which can apparently be used to request DMA xfer. I think this would allow me to trigger off the ADC's DRDY line without an ISR, to process a buffer of samples rather than each individually, and to sleep more. This should probably be a later phase / optimization.

author: davegravy
author_rank: Regular Contributor
timestamp: January 02, 2022, 10:56:33 pm
content: I confirmed it's keeping up at 1.7Mbps using 32 bit dummy data and not corrupting it. This is over the STLINK connection.Is there a popular lightweight software protocol I should consider using to ensure the correct 3 bytes representing each 24bit sample are grouped together properly on the receiving end? Without this if a byte gets dropped then the receiving end will be desynchronized, interpreting samples incorrectly going forward. Some kind of reference frame so the receiver can at least detect if sync was lost, and re-establish it? I don't really want to get into a complicated 2-way communication protocol if I can avoid it.

author: Siwastaja
author_rank: Super Contributor
timestamp: January 03, 2022, 07:02:57 pm
content: I tend to use this simple pattern:Start value (magic byte/word)Payload with fixed lengthCRCOr for more extendable system:Message IDLength of payload (so that the receiver can just skip messages it doesn't understand)PayloadCRCThe first one seems suitable for you.You can even skip the start identifier; it really doesn't help because you can't rely on it for syncing because it could appear in the data.Simplest, by far: just write the 3 payload bytes and CRC8 calculated from them. In the receiving code, just start receiving from any arbitrary point of time. Once you have 4 bytes, calculate CRC from the first three and compare against the 4th (assumed CRC field). If you get CRC error, resync: this means, read more bytes in, one at a time, and after each byte, try to calculate CRC again. Once you get a successful match, you are in sync with the data stream. Whenever you get CRC error, just resync as previously explained.(Failure modes are pretty far-fetched; unless this is a heart surgery space rocket thing, this just works).

author: davegravy
author_rank: Regular Contributor
timestamp: January 03, 2022, 07:43:09 pm
content: I think that should work well, thanks.