Teensy 4.1/4.0 with external ADC using SPI

Hi Everyone,

I'm hoping someone can help who has far more coding experience than me. I'm trying to communicate to an AD7490 ADC (https://www.analog.com/media/en/technical-documentation/data-sheets/AD7490.pdf) over SPI. As I understand it, the way SPI works is that data is communicated at the same time over MISO and MOSI. My naïve question is that, how do you extract the data when you have information coming from the ADC? I have to send a control register which is my struct union. but then the ADC should be sending me information back but I'm not entirely sure how to break it down.


I've including my code in case anyone asks questions or yells at me for not including the code. It's still extremely rough, may not totally make sense either but I'm trying.



Code:
/*







*/

#include <AD7490.h>
#include <SPI.h>

uint8_t i;

/*Initial setup code, will only run once at system initialization
*/
void setup()

{
  pinMode(CS_AD7490, OUTPUT);
  SPI.begin();
  SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
  initialize_AD7490();

}

void loop()
{
  readADC_AD7490();
  displaychannels_AD7490();
  delay(10);


}

/*Sends dummby conversions to external ADC (Analog Devices AD7490)
*/

void initialize_AD7490()
{

  AD7490ControlReg startconfig = {.reg = 0xFFFF};
  startconfig.WRITE = 0b1;
  startconfig.ADDR = 0b0;
  startconfig.PM1 = 0b1;
  startconfig.PM0 = 0b1;
  startconfig.WEAK_TRI = 0b1;
  digitalWrite(CS_AD7490, LOW);
  SPI.transfer16(startconfig.reg);
  delay(20);
  SPI.transfer16(startconfig.reg);
  digitalWrite(CS_AD7490, HIGH);

}

/*Collects samples from external ADC (Analog Devices AD7490)
*/

void readADC_AD7490()
{
  AD7490ControlReg request = {.reg = 0x0};
  request.WRITE = 0b1;
  request.ADDR = 0b0;
  request.PM1 = 0b1;
  request.PM0 = 0b1;
  request.WEAK_TRI = 0b1;
  request.CODING = 0b1;

  /*Collects samples from external ADC (Analog Devices AD7490)
  */

  digitalWrite(CS_AD7490, LOW);
  SPI.transfer16(request.reg);
  

  
  for (i = 0; i < AD7490_CHANNELS; i++) {
    request.ADDR = i + 1; // Set up ADDR for next read in sequence
    Serial.println(i);
    

  }

  digitalWrite(CS_AD7490, HIGH);
}

void displaychannels_AD7490()
{
  
  Serial.println("Channel_00:");
  Serial.println("Channel_01:");
  Serial.println("Channel_02:");
  Serial.println("Channel_03:");
  Serial.println("Channel_04:");
  Serial.println("Channel_05:");
  Serial.println("Channel_06:");
  Serial.println("Channel_07:");
  Serial.println("Channel_08:");
  Serial.println("Channel_09:");
  Serial.println("Channel_10:");
  Serial.println("Channel_11:");
  Serial.println("Channel_12:");
  Serial.println("Channel_13:");
  Serial.println("Channel_14:");
  Serial.println("Channel_15:");
}

If you can help or even poke holes in what I'm doing so far, I'd appreciate a kick in the right direction.
 
Well no bites. Let me rephrase my question.

How does one extract the data from the MISO pin should there be data available? My thought was that SPI.transfer(somedata) is being used only to transmit data from Master to Slave? Did I miss something?
 
Sometimes easiest to look at the SPI documentation, like the Arduino documents: https://www.arduino.cc/en/Reference/SPITransfer

With SPI when you do something like: uint8_t retval = SPI.transfer(val);
It transfers the data stored in val are clocked out (with SCK pin 13) out the MOSI pin (11) and at the same time the values in the MISO pin are clocked in and the value is returned by the transfer function.

There are several varieties of the transfer function that are part of the Teensy SPI library.

The simple transfer 8 bits as I mentioned above: uint8_t retval = SPI.transfer(val);
Simple transfer of 16 bit value: uint16_t retval = SPI.transfer16(val);

The old buffer form, which I don't like: SPI.transfer(my_buffer, count);
Which will transfer the count number of bytes out, and the contents of the my_buffer will be overwritten by the results.

The form I use: SPI.transfer(out_buffer, in_buffer, count);
It transfers the count number of byte out of the out_buffer, and the return values will be stored in in_buffer. If out_buffer is a nullptr (0) the system will output a constant value that defaults to 0 but can be set. If in_buffer is null the results are tossed.

...
 
Sometimes easiest to look at the SPI documentation, like the Arduino documents: https://www.arduino.cc/en/Reference/SPITransfer

With SPI when you do something like: uint8_t retval = SPI.transfer(val);
It transfers the data stored in val are clocked out (with SCK pin 13) out the MOSI pin (11) and at the same time the values in the MISO pin are clocked in and the value is returned by the transfer function.

There are several varieties of the transfer function that are part of the Teensy SPI library.

The simple transfer 8 bits as I mentioned above: uint8_t retval = SPI.transfer(val);
Simple transfer of 16 bit value: uint16_t retval = SPI.transfer16(val);

The old buffer form, which I don't like: SPI.transfer(my_buffer, count);
Which will transfer the count number of bytes out, and the contents of the my_buffer will be overwritten by the results.

The form I use: SPI.transfer(out_buffer, in_buffer, count);
It transfers the count number of byte out of the out_buffer, and the return values will be stored in in_buffer. If out_buffer is a nullptr (0) the system will output a constant value that defaults to 0 but can be set. If in_buffer is null the results are tossed.

...

Thanks Kurt, I was reading the arduino SPI stuff and looking at the barometer example, did not come across the SPI Transfer explanation. Definitely helps!
 
Back
Top