Fast Port Reading inside interrupt with Teensy 3.6

Status
Not open for further replies.

neltnerb

Well-known member
I am implementing a system to work with the AD7768 ADC, which uses a funny communications format. It continually streams clock pulses, and when it actually starts sending data it sends a DRDY pulse. After receiving the falling edge of DRDY, I have to monitor eight data in lines along with a clock line on normal pins to collect 32 bits for each of the eight pins which I then convert to real input voltage values by decoding.

I made this work on an Arduino DUE, but had to avoid using digitalRead because it took waaay too long. Instead I did it using an interrupt that manually read the port that the input data clock is connected to and used polling inside an interrupt to make it fast enough to receive clock pulses at high speed (~1MHz, ideally faster on the Teensy).

Here is my port of the rough idea to the Teensy (interrupt handler only):

Code:
unsigned long ADCData[8];
volatile unsigned long ADCDataBuffer[32][4];
volatile boolean ADCDataReady = false;

void ADCDataHandler() {
  while((GPIOC_PDOR) & (1<<9));
  ADCDataBuffer[31][0] = GPIOA_PDOR;
  ADCDataBuffer[31][1] = GPIOB_PDOR;
  ADCDataBuffer[31][2] = GPIOC_PDOR;
  ADCDataBuffer[31][3] = GPIOE_PDOR;
  while(!(GPIOC_PDOR & (1<<9)));
  while((GPIOC_PDOR) & (1<<9));
  ADCDataBuffer[31][0] = GPIOA_PDOR;
  ADCDataBuffer[31][1] = GPIOB_PDOR;
  ADCDataBuffer[31][2] = GPIOC_PDOR;
  ADCDataBuffer[31][3] = GPIOE_PDOR;
  while(!(GPIOC_PDOR & (1<<9)));
  ...
}

which then continues to buffer all the port data to memory with the while statements guaranteeing the clock state when reading. I originally tried clock interrupts but that was a disaster, it couldn't hit the interrupt routine fast enough and lost the early bits if I ran the DCLK too fast. This was the fastest I was able to make it, though I haven't investigated manually setting up the interrupt handler on the Arduino Due.

What I am wondering is if I can use DMA on the Teensy 3.6 to speed this up by reducing four port reads to at least a single captured byte with one bit for each channel (my eight data inputs are connected to different ports so I must capture all four -- I will do this differently next time). I've never written code with a DMA system before, so I'm not really quite sure if this is feasible or how to go about it. The handler is triggered by the falling edge of the DRDY pulse indicating the start of a data frame and then has to use polling for the high speed clock pulses coming in.

So basically if I can have it automatically map:
PTC8 -> DMA0
PTE25 -> DMA1
PTE24 -> DMA2
PTA15 -> DMA3
PTA16 -> DMA4
PTB18 -> DMA5
PTB19 -> DMA6
PTB10 -> DMA7
and then simply do ADCDataBuffer[31] = DMA to put those eight selected input bits from the GPIO into a byte with only one instruction cycle.

Even better if this can be made to automatically update on a falling edge of PTC9.

Thanks for any help!
 
Status
Not open for further replies.
Back
Top