delsauce / ArduinoDueHiFi

An I2S audio codec driver library for the Arduino Due board.
42 stars 10 forks source link

No output on TD #3

Closed michael-hirschmugl closed 9 years ago

michael-hirschmugl commented 9 years ago

I have a little problem when using this library. I have a WM8731 set up for I2S, it's producing a BCLK, TF and RF and also it produces (obviously) random chunks of data on the RD line. I checked that with an oscilloscope. I am running your example code for sine wave output, but the TD line does not output anything from the arduino due. So now I am trying to debug my code and I have a few quick questions for you that I can't answer myself.

  1. Regarding the setup of your library, does the TD line only provide a signal if it gets a proper TF and BCLK or is it always putting out something even if it's not synced? The clock signals look a bit "grungy" and I am wondering if I NEED to even them out anyway before trying something else?
  2. I feed the Codec with a clock signal from the Arduino Due. This signal is a 12MHz signal which lets the Codec communicate and work correctly. My question is, I use the following code to produce this signal: REG_PIOA_WPMR = 0x50494F00; // enable writes REG_PIOA_PDR |= 0x02; // enable peripheral control REG_PIOA_PER &= ~0x02; // Prevents disabling peripheral control of the pin REG_PIOA_ABSR |= 0x02; // B preipherial select REG_PIOA_WPMR = 0x50494F01; // disable writes REG_PMC_WPMR = 0x504D4300; // enable writes REG_PMC_SCER |= 0x100; PMC->PMC_PCK[0] = 0b00000000000000000000000000000001; // master clock = 12Mhz (crystal freq) Since I cannot tell all the dependencies of the SAM processor, do you have any idea if this code might prevent the SSC interface from working correctly?

The problem is: If I remoce the code that generates the Clock signal for the Codec to see if it prevents the CCS from working, I will not have a BCLK or TF signal on the arduino due, and then I can't say where the problem really is. :) I really hope that you can help me out!!

delsauce commented 9 years ago

I am not in front of stuff at the moment but the general jist of it is that the Due needs to be a slave in my version of the library. The reason that it can't be the master is that it can't generate the proper clocks. For I2S stereo audio, three clocks are generally needed: MCLK, TK, and TF.

TF = sample rate (e.g. 44,100 khz) TK = word length * num channels * TF = 44100 * 32 * 2 = 2.8224 MHz MCLK = 256 or 512 * FS, I think used 512, so MCLK = 22.5792 MHz

The just needs the last two, but most codecs need all three. I am not familiar with the WM8731, but it will need to generate TK and TF for the Due to sync to it. Without those clocks you may not get anything out of the Due (question #1).

I can't really tell on number 1 without pouring through the datasheet. You should be able to generate a clock without affecting the SSC though.

Hope that helps.

On Tue, Nov 25, 2014 at 5:33 PM, hirschmensch notifications@github.com wrote:

I have a little problem when using this library. I have a WM8731 set up for I2S, it's producing a BCLK, TF and RF and also it produces (obviously) random chunks of data on the RD line. I checked that with an oscilloscope. I am running your example code for sine wave output, but the TD line does not output anything from the arduino due. So now I am trying to debug my code and I have a few quick questions for you that I can't answer myself.

  1. Regarding the setup of your library, does the TD line only provide a signal if it gets a proper TF and BCLK or is it always putting out something even if it's not synced? The clock signals look a bit "grungy" and I am wondering if I NEED to even them out anyway before trying something else?
  2. I feed the Codec with a clock signal from the Arduino Due. This signal is a 12MHz signal which lets the Codec communicate and work correctly. My question is, I use the following code to produce this signal: REG_PIOA_WPMR = 0x50494F00; // enable writes REG_PIOA_PDR |= 0x02; // enable peripheral control REG_PIOA_PER &= ~0x02; // Prevents disabling peripheral control of the pin REG_PIOA_ABSR |= 0x02; // B preipherial select REG_PIOA_WPMR = 0x50494F01; // disable writes REG_PMC_WPMR = 0x504D4300; // enable writes REG_PMC_SCER |= 0x100; PMC->PMC_PCK[0] = 0b00000000000000000000000000000001; // master clock = 12Mhz (crystal freq) Since I cannot tell all the dependencies of the SAM processor, do you have any idea if this code might prevent the SSC interface from working correctly?

The problem is: If I remoce the code that generates the Clock signal for the Codec to see if it prevents the CCS from working, I will not have a BCLK or TF signal on the arduino due, and then I can't say where the problem really is. :) I really hope that you can help me out!!

— Reply to this email directly or view it on GitHub https://github.com/delsauce/ArduinoDueHiFi/issues/3.

michael-hirschmugl commented 9 years ago

Thanks for the quick response! Well, I have the CODEC set up as a master and it is generating TF, TK. I have the signals connected correctly and still there is no output on TD. So it should be a clock/timing problem?

michael-hirschmugl commented 9 years ago

I checked the data sheet of the WM8731 again. I am powering the Codec with a 12MHz clock from the Arduino Due. The WM8731 has a "USB Mode" in which he generates all sample rates from this 12MHz master clock. Still, the BCLK of the I2S interface runs on 12MHz. So, the CODEC gets 12MHz master clock, for 44,118kHz, BOSR=272fs. Which leads to: TF = sample rate (44,118kHz) TK = 12MHz MCLK = 12MHz

Is this compatible with the setup of the library?

michael-hirschmugl commented 9 years ago

So I just discovered that if I remove the line REG_PIOA_WPMR = 0x50494F01; // disable writes then I get an outout from TD. But only on one side of both channels an it's a sine wave of about 50Hz! Seems like this line of code prevents the Pin from working? Could that be? But the next question is why a 50Hz sine of 3V? I am running on 48kHz sample rate now. Any ideas?

delsauce commented 9 years ago

I really don't know what that line of code does.

I can't really help with your issue since I don't have enough information. Are you using the provided examples or did you write your own?

On Wed, Nov 26, 2014 at 7:16 AM, hirschmensch notifications@github.com wrote:

So I just discovered that if I remove the line REG_PIOA_WPMR = 0x50494F01; // disable writes then I get an outout from TD. But only on one side of both channels an it's a sine wave of about 50Hz! Seems like this line of code prevents the Pin from working? Could that be? But the next question is why a 50Hz sine of 3V? I am running on 48kHz sample rate now. Any ideas?

— Reply to this email directly or view it on GitHub https://github.com/delsauce/ArduinoDueHiFi/issues/3#issuecomment-64659998 .

michael-hirschmugl commented 9 years ago

I am using the provided example except for the code that does the clock output. Do you think it could be a problem that the TK clock is on 12MHz even if the TF clock is still 48kHz? I do not really understand how the I2S communication works, sadly.

delsauce commented 9 years ago

If you're using the SineWaveOut example, then the 50Hz sine wave sounds about right. Should be on both channels though.

The TK clock is usually 64 * TF. If that ratio isn't configured in the registers then you'll have a problem. The I2S peripheral has to know how many TK clock cycles are in TF. Not sure that your TK value is going to work (too high).

On Wed, Nov 26, 2014 at 10:03 AM, hirschmensch notifications@github.com wrote:

I am using the provided example except for the code that does the clock output. Do you think it could be a problem that the TK clock is on 12MHz even if the TF clock is still 48kHz? I do not really understand how the I2S communication works, sadly.

— Reply to this email directly or view it on GitHub https://github.com/delsauce/ArduinoDueHiFi/issues/3#issuecomment-64686644 .

michael-hirschmugl commented 9 years ago

oh I thought it would be a higher frequency! :) Couldn't find the expected value anywhere...

I thought so! That might be the reason why i only get one channel I suppose... Is there a possibility to change the expected TK frequency for the SSC control?

michael-hirschmugl commented 9 years ago

It's working! :) Looks like the other channel is an hardware issue. In the end, after following some forum threads, i wasn't even sure anymore if this can be done with this particular wolfson chip. :D Thank you so much for this great library and your help!

delsauce commented 9 years ago

Great work. This stuff isn't easy... (It will be easier on the Zero when that comes out).

Did you make any changes to the library for the wolfson chip? I know that's a popular IC and others have tried to connect to it...

On Nov 27, 2014, at 2:14 AM, hirschmensch notifications@github.com wrote:

It's working! :) Looks like the other channel is an hardware issue. In the end, after following some forum threads, i wasn't even sure anymore if this can be done with this particular wolfson chip. :D Thank you so much for this great library and your help!

— Reply to this email directly or view it on GitHub.

michael-hirschmugl commented 9 years ago

No i haven't changed the library. Seems like the 12MHz BCLK is resognised and works without any change in the library. But I still encounter some problems. For instance in the passthrough example I see that almost every second sample is 0. I work on 48kHz sample rate and 32 bit samples. Any idea why?

michael-hirschmugl commented 9 years ago

user error... as always. ;) anyway, library works fine with the WM8731!

sriranjanr commented 9 years ago

Hello Hirschmensch,

Can you please post your code. I am trying to get the WM8731 to work with the Due using this library but I am not getting any output on the head phones.I want to read from the microphone and send data out to headphones.I am working with the pass through example.

sriranjanr commented 9 years ago

Here is my modified code based on the passthrough example.

include

include

define LINVOL 23

define RINVOL 23

define LHPVOL 100

define RHPVOL 100

define ADCHPD 0

define SIDEATT 0

define SIDETONE 0

define DACSEL 1

define BYPASS 0

define INSEL 0

define MUTEMIC 1

define MICBOOST 0

define SAMPLE_RATE 44

void codecTxReadyInterrupt(HiFiChannelID_t); void codecRxReadyInterrupt(HiFiChannelID_t);

static uint32_t ldat = 0; static uint32_t rdat = 0;

void AudioCodec_init() {

    int temp_wire1;
    int temp_wire2;

    Wire.begin();
    Wire.beginTransmission(0x1a);
    Wire.write(0x0c); // power reduction register
    Wire.write((uint8_t)0x00); // turn everything on
    temp_wire1 = Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x0e); // digital data format
    //Wire.write(0x03); // 16b SPI mode
    Wire.write(0x02);
    temp_wire2 = Wire.endTransmission();

    Serial.println(temp_wire1);
    Serial.println(temp_wire2);

    Wire.beginTransmission(0x1a);
    Wire.write((uint8_t)0x00); // left in setup register
    Wire.write((uint8_t)LINVOL);
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x02); // right in setup register
    Wire.write((uint8_t)RINVOL);
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x04); // left headphone out register
    Wire.write((uint8_t)LHPVOL);
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x06); // right headphone out register
    Wire.write((uint8_t)RHPVOL);
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x0a); // digital audio path configuration
    Wire.write((uint8_t)ADCHPD);
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x08); // analog audio pathway configuration
    Wire.write((uint8_t)((SIDEATT << 6)|(SIDETONE << 5)|(DACSEL << 4)|(BYPASS << 3)|(INSEL << 2)|(MUTEMIC << 1)|(MICBOOST << 0)));
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x10); // clock configuration
    #if SAMPLE_RATE == 88
      Wire.write(0xbc);
    #elif SAMPLE_RATE == 44
      Wire.write(0xa0);
    #elif SAMPLE_RATE == 22
      Wire.write(0xe0);
    #elif SAMPLE_RATE == 8
      Wire.write(0xac);
    #elif SAMPLE_RATE == 2
      Wire.write(0xce);
    #endif
    Wire.endTransmission();

    Wire.beginTransmission(0x1a);
    Wire.write(0x12); // codec enable
    Wire.write(0x01);
    Wire.endTransmission();

}

void setup() {

// set codec into reset pinMode(7, OUTPUT); digitalWrite(7, LOW); Serial.begin(38400); AudioCodec_init(); delay(2000); HiFi.begin();

// Configure transmitter for 2 channels, external TK/TF clocks, 32 bit per // channel (data less than 32-bit is left justified in the 32 bit word, but // codec config needs 32 clocks per channel). HiFi.configureTx(HIFI_AUDIO_MODE_STEREO, HIFI_CLK_MODE_USE_EXT_CLKS, 32);

// Same config as above, except sync the receiver to transmitter (RK/RF // clock signals not needed) HiFi.configureRx(HIFI_AUDIO_MODE_STEREO, HIFI_CLK_MODE_USE_TK_RK_CLK, 32);

// Since we've decided to sync the receiver to the transmitter, we could // handle both reading and writing in a single interrupt (receive or // transmit). This example uses both just for demonstration purposes. HiFi.onTxReady(codecTxReadyInterrupt); HiFi.onRxReady(codecRxReadyInterrupt);

// release codec from reset digitalWrite(7, HIGH);

// Enable both receiver and transmitter. HiFi.enableRx(true); HiFi.enableTx(true); }

void loop() {

Serial.print(ldat); Serial.print(" "); Serial.println(rdat);

}

void codecTxReadyInterrupt(HiFiChannelID_t channel) { if (channel == HIFI_CHANNEL_ID_1) { // Left channel HiFi.write(ldat);
} else { // Right channel HiFi.write(rdat); } }

void codecRxReadyInterrupt(HiFiChannelID_t channel) { if (channel == HIFI_CHANNEL_ID_1) { // Left channel ldat = HiFi.read(); } else { // Right channel rdat = HiFi.read(); } }

michael-hirschmugl commented 9 years ago

hey sorry for the late response. i'm afraid with the WM8731 it's not that easy. :/ but i will provide a dedicated library soon and keep you posted!

benbiles commented 8 years ago

Hi sriranjanr,

Heres some code using some of your initialisation setup thats working with Passthough example. I changed to 32 bit and 48khz

I'm sorry but the code paste option on github seams to be broken , so check the #includes are there.. they dissapear when i add the code here !!

` // include 2wire ( i2c )

include

// WM8731 setup

define LINVOL 20

define RINVOL 20

define LHPVOL 127

define RHPVOL 127

define ADCHPD 0

define SIDEATT 0

define SIDETONE 0

define DACSEL 1

define BYPASS 0

define INSEL 1

define MUTEMIC 0

define MICBOOST 1

define SAMPLE_RATE 48

// I2S IO library

include

void codecTxReadyInterrupt(HiFiChannelID_t); void codecRxReadyInterrupt(HiFiChannelID_t);

static uint32_t ldat = 0; static uint32_t rdat = 0;

void setup() {

Serial.begin(9600);

Serial.println( "Initializing" ); delay(100);

// Initialize the WM8731

Wire.begin();
Wire.beginTransmission(0x1a);
Wire.write(0x0c); // power reduction register
Wire.write((uint8_t)0x00); // turn everything on
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x07); // digital data format REG 0000111   0x7
Wire.write(0xB2);  // 32bit,MASTER MODE  10110010 
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write((uint8_t)0x00); // left in setup register
Wire.write((uint8_t)LINVOL);
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x02); // right in setup register
Wire.write((uint8_t)RINVOL);
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x04); // left headphone out register
Wire.write((uint8_t)LHPVOL);
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x06); // right headphone out register
Wire.write((uint8_t)RHPVOL);
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x0a); // digital audio path configuration
Wire.write((uint8_t)ADCHPD);
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x08); // analog audio pathway configuration
Wire.write((uint8_t)((SIDEATT << 6)|(SIDETONE << 5)|(DACSEL << 4)|(BYPASS << 3)|(INSEL << 2)|(MUTEMIC << 1)|(MICBOOST << 0)));
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x10); // clock configuration
#if SAMPLE_RATE == 88
  Wire.write(0xbc);
#elif SAMPLE_RATE == 48
  Wire.write(0x00);  
#elif SAMPLE_RATE == 44
  Wire.write(0xa0);
#elif SAMPLE_RATE == 22
  Wire.write(0xe0);
#elif SAMPLE_RATE == 8
  Wire.write(0xac);
#elif SAMPLE_RATE == 2
  Wire.write(0xce);
#endif
Wire.endTransmission();

delay(200);

Wire.beginTransmission(0x1a);
Wire.write(0x12); // codec enable
Wire.write(0x01);
Wire.endTransmission();

delay(200);

Serial.println( "done" ); delay(1000);

// Initialize the Arduino SSC codec ?

// set SSC DUE I2S codec into reset pinMode(7, OUTPUT); digitalWrite(7, LOW);

HiFi.begin();

// Configure transmitter for 2 channels, external TK/TF clocks, 32 bit per // channel (data less than 32-bit is left justified in the 32 bit word, but // codec config needs 32 clocks per channel). HiFi.configureTx(HIFI_AUDIO_MODE_STEREO, HIFI_CLK_MODE_USE_EXT_CLKS, 32);

// Same config as above, except sync the receiver to transmitter (RK/RF // clock signals not needed) HiFi.configureRx(HIFI_AUDIO_MODE_STEREO, HIFI_CLK_MODE_USE_TK_RK_CLK, 32);

// Since we've decided to sync the receiver to the transmitter, we could // handle both reading and writing in a single interrupt (receive or // transmit). This example uses both just for demonstration purposes. HiFi.onTxReady(codecTxReadyInterrupt); HiFi.onRxReady(codecRxReadyInterrupt);

// release codec from reset digitalWrite(7, HIGH);

// Enable both receiver and transmitter. HiFi.enableRx(true); HiFi.enableTx(true); }

void loop() {

if (ldat > 0 & rdat > 0 ) Serial.print(ldat,rdat);
if (ldat > 0 & rdat > 0 ) Serial.println();

}

void codecTxReadyInterrupt(HiFiChannelID_t channel) { if (channel == HIFI_CHANNEL_ID_1) { // Left channel HiFi.write(ldat);
} else { // Right channel HiFi.write(rdat); } }

void codecRxReadyInterrupt(HiFiChannelID_t channel) { if (channel == HIFI_CHANNEL_ID_1) { // Left channel ldat = HiFi.read(); } else { // Right channel rdat = HiFi.read(); } } `