read data from SPI

Hi guys,

i have begun with arduino programming a few weeks ago and last few days i am struggling with SPI.
I am trying to read data from digital microphone ADMP441 (24 bits
via SPI with my arduino.
I sniff communication (look at att jpeg) and it look like that data are generated but i am not able to read them and check them e.g. via serial [ Serial.println(in); ] i get value 0 all the time.

this is my code:
#include <SPI.h> // include the SPI library

const byte slaveSelectPin = 10; // digital pin 10 for /CS
void setup() {

Serial.begin(9600);
pinMode (slaveSelectPin, OUTPUT);
digitalWrite(slaveSelectPin,HIGH);
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.begin();
Serial.println("Test");
}

void loop() {
long int in = SpiRead();
Serial.println(in);
} // end main loop
long int SpiRead(void) {

long result = 0;
long int b;
digitalWrite(slaveSelectPin,LOW);
delayMicroseconds(1);

b = SPI.transfer(255); // B2
result = b<<8;

b = SPI.transfer(255); // B1
result |= b;
result = result<<8;

b = SPI.transfer(255); // B0
result |= b;

digitalWrite(slaveSelectPin,HIGH);
return(result);
}

best regards

thnx

Jan

I don't think you are communicating with that IC correctly. Here is the online datasheet:

Take a look at page 9. The communication requires 64 bits (8 bytes). The first 4 bytes are for the left channel, and the second 4 bytes are for the right channel, depending on the state of the WS line. The WS line is not the CS line. It should be a separate line. The CS line is not connected to the IC, only the WS line. The WS line should be LOW for the first 4 bytes and HIGH for the second 4 bytes.

edit: And how the IC responds depends on the state of the L/R line. If the L/R line is LOW, it responds during the WS line LOW (first 4 bytes), and if it is HIGH, it responds during the WS line HIGH (second 4 bytes).

If the slaveSelectPin (D10) is connected to the WS line of the IC, I would try this:

  digitalWrite(slaveSelectPin,LOW);   
  delayMicroseconds(1);              
   
  byte LeftOne = SPI.transfer(255);
  byte LeftTwo = SPI.transfer(255);
  byte LeftThree = SPI.transfer(255);
  byte LeftFour = SPI.transfer(255);
  
  digitalWrite(slaveSelectPin,HIGH);

  byte RightOne = SPI.transfer(255);
  byte RightTwo = SPI.transfer(255);
  byte RightThree = SPI.transfer(255);
  byte RightFour = SPI.transfer(255);

That's chip has an I2S interface, that's not SPI although SPI may be close enough to work with some pin twiddling as SurferTim has shown.


Rob

Hi guys

thnx for your quick replies. I have to admit, i cannot really simulate I2S via SPI.
I researched timing again and I have decided to make it up in the other way.

best regards

John

In general, this did not help:

    SPI.setBitOrder(MSBFIRST);  << needs to go after SPI.begin();
    SPI.setDataMode(SPI_MODE0);  << needs to go after SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV4); << needs to go after SPI.begin();
    SPI.begin();

At the same time, those are the default settings, so likely it didn't really hurt the effort.
Trying to do I2C with SPI pins is not the best.

I2C is 100KHz/400KHz, SPI/4 = 4 MHz, likely an issue as well 8)

Hi CrossRoads

CrossRoads:
I2C is 100KHz/400KHz, SPI/4 = 4 MHz, likely an issue as well 8)

I need I2S not I2C, but thnx for reply. It was just a experiment :frowning:

I wanted to use something what was developted.

I think I2S protocol has been not implemented for arduino yet.

Johny

You can always "bit-bang" an I2S interface. Perhaps looking at a bit-bang SPI interface will give you a very good starting point.
Susan

hi,

maybe ARDUINO is a bit slow for SPI interface. I am begginer in this area, so Its only my idea. :slight_smile:
Does anybody have a clue about some implementation SPI for the board ?

John

Did you see my edit/code addition to reply#1 above?

The Arduino SPI may be too fast if not slowed up a bit. See CrossRoads post above.

    SPI.setClockDivider(SPI_CLOCK_DIV8); 
// or even down to
    SPI.setClockDivider(SPI_CLOCK_DIV32);

edit: The max frequency in the datasheet for SCK is 3.2MHz. You are trying 4MHz. That is too fast.

Hi SurferTim

yeah u r right with clock.
but how to solve the issue, that MSB bit is during 2nd clock period after WS goes log.1 -> log. 0 :~

Does the SCK pin still work as GPIO when in SPI mode? If so you could toggle it once yourself with a couple of digitalWrites().


Rob

I did not notice the SPI mode was incorrect. You should use mode 3. Clock HIGH and pulsed LOW, capturing data on the rising edge.

   SPI.setDataMode(SPI_MODE3);

edit: It may still be OK with MODE0 according to the timing. Print the values returned from these SPI.transfer() calls to see how the data is transferred.

You must do an extra "shift left one bit" to align those bits into a 24 bit value.

Hey SurferTim

I attached outputs from both MODEs.

SurferTim:
You must do an extra "shift left one bit" to align those bits into a 24 bit value.

but i dont have a clue, where i should make "shift left one bit". I think i need one more clock period. :~

John

I would stick with mode 0 after examining the SPI timing. The SCK line should be LOW when the WS line goes LOW. That is mode 0. The timing diagram was a bit misleading at first glance.

I would try this code. It builds a long variable using the byte values returned in my suggested code above. It shifts left 8 bit places three times, then shifts right 7 bit places once. It will be a 24 bit value in a 32 bit variable.

long LeftChannel = LeftOne;
LeftChannel = LeftChannel << 8;
LeftChannel = LeftChannel | LeftTwo;
LeftChannel = LeftChannel << 8;
LeftChannel = LeftChannel | LeftThree;
LeftChannel = LeftChannel << 8;
LeftChannel = LeftChannel | LeftFour;
LeftChannel = LeftChannel >> 7;

Same with the right channel.

Hey SurferTim

Thank you very much for hints. But I wasnt successful. :~
Look at output from sniffer.
I used lower SCK freq., cos due to microphone datasheet max. SCK is 3.2 MHz, now is SPI running on 2 MHz.
I have noticed SD output (level H) lasts only 25 ns, isnt it too little ? because I got only 0 values from SpiRead all the time.
(for test i put log. 1 to MISO pin and got 1111...., so code is OK. )
I have generated TEST ouput from ARDU and log. 1 lasted 500 ns.

best regards

John

code_v02.txt (1.4 KB)

Are you using a logic level translator between the Arduino and the ADMP441? According to the datasheet, the max input to any pin on that device is 3.3v.

For this moment I have to stop my experiment cos i destroy my ADMP441 =( (today i have a bad day). The other one doesnt work at all. So I will have to order new one.

NOTE: I dont have logic level trans., I have Crowduino model, which can be switched to 3.3V power mode, so i can try it then (with new ADMP441) with this setting.

thx for this moment

John