Teensy 3.6 - 8-bit wide SPI slave, interrupt priorities, USB transmit buffer?

Status
Not open for further replies.

neltnerb

Well-known member
I have two high speed ADCs (AD7768) which work by using eight pins for data and one pin for a clock using effectively 8-bit wide SPI. One clock, eight data lines. It can be used in other modes, but using the 8-bit wide data bus increases the maximum sampling rate to where I want it to be.

The ADC acts as the master for clocking data and the ADC sets DRDY low when data is ready.

Since there is just one clock and eight data lines, I believe I am stuck with software based reading, so I am planning to monitor the DCLK signal from the peripheral using a pin with an interrupt and then if DRDY is low, manually read in the 8-bit wide digital data inside the ISR to store in a 32-byte buffer which is then converted to 8x 32-bit values when full. I'll use flags for that to avoid blocking I/O. I have two ADCs, so I plan to use two separate pin interrupts to trigger shifting in a byte of data per ADC.

This will be quite a bit faster if I can do it as a full port-wide read. Other than reserving the TX/RX pins for communicating with another microcontroller, and using the hardware SPI interface to send commands to both ADCs, the Teensy 3.6 pins are free for anything.

Is there a way I can wire the chip so that I can do full-port reads? Which pins do I attach to so that it aligns? What is the register I'd read to access the port data?

Secondly, since I have two ADCs which are synchronized they will likely attempt to send data simultaneously. Will interrupts that are triggered while the code is inside another ISR be ignored or postponed until ISR completes? I do not want to miss the data from one ADC because the other ADC data is being read.

Third, I want to stream this data out over USB as quickly as I can, but without risking missing any new ADC data during USB transmission. Can an ISR interrupt the Serial.write commands? Ideal would be if I could just stream out USB data when available, but rely on the interrupt to ensure that I don't miss any datapoints.

Is there a USB setting I can use to improve this? I've tried using USB.write to send out data before but it seems to return slowly with the big packets I use. Is there some way I can use the USB port so that it will be a near-immediate return? Is it a 64-byte buffer? 2x 64-byte buffers? A single 2-byte buffer?

Is there a way to know whether the buffer has finished sending? I can imagine having the main loop check for a flag that the USB transmit buffer is empty to tell it that it should attempt to send the next set of data from the ADCs so that it doesn't block much. I'd like to be able to use USB transmission with either no blocking of other ISRs or else synchronized timing so that it impacts timing as little as possible.
 
Hello Neltnerb,

nice project, I can't give you any efficient advice, but what you try to do makes me think to Octows2811 lib which uses dma to send some bytes.

You just want to do the inverse action, I mean to read some bytes...

The "spi clock" might trigger the dma transfer...

I can't tell you much more, I am myself turning around dma capabilities to acquire data. Currently I am reading the k66 data sheet...
Scatter/gather feature seems interesting if you need a big circular buffer...

About USB I have no idea...

Good luck, y.j.
 
Thanks Yannick! I'm totally unfamiliar with DMA, other than having heard of it. It sounds very promising.

If anyone else happens along who knows how to use DMA, I'd love to better understand. I don't know enough to know if it makes sense... I found this though:

https://forum.pjrc.com/threads/31566-DMAChannel-triggerAtHardwareEvent-digital-pin-source
https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.h
https://forum.pjrc.com/threads/31541-Interrupt-Jitter

Unfortunately I can't find actual documentation for using DMAChannel. The code in the third link from Xenoamor is encouraging, but without documentation I'm a bit lost.

I think that it setting dmachannel0.destination(GPIOC_PTOR) is... probably the register containing the bits that are on PORT C based on the pin definitions, and it seems to be using triggerAtHardwareEvent to define the interrupt to trigger with? I'm not sure what DMAMUX_SOURCE_PORTA is, nor what transferSize and transferCount do. But it does seem like maybe I can swap the source and destinations to have the interrupt automatically transfer data between the register and the location in memory. And that is what I need to do!

I think I'll start a new thread with a title asking about DMA to make it more likely that someone who knows how to use it will chime in.

https://forum.pjrc.com/threads/48147-Teensy-3-6-DMA-to-read-multiple-digital-inputs-on-pin-interrupt

Thanks so much for the pointer Yannick!
 
Last edited:
Status
Not open for further replies.
Back
Top