WM8731 codec in Arduino Due (SPI and Wire libraries)

Hi,

I was trying to make this board (Audio Codec Board from MikroElektronika) working, but by the moment it doesn't.

So this board use two serial interfaces, one "two wire" interface (compatible with I2C, this should work with the Wire library) for the chip configuration, and another interface for the data transmission (SPI protocol should work).

I used two sources for my code, the library from the "Codec Shield" that Sparkfun sells and the example that MikroElektronika brings in their website (example for PIC). So the AudioCodec_init function initializes both interfaces (the I2C only works inside the function).

The Wire library by default works at 100 KHz I think (at least with the other Arduinos), the device address is 0x1a, first I send the register address then the data. For the first two registers I read the return of the endTransmission function and it always return "2". According to the documentation this should be an error, but I found on the internet that this is a bug, that this function only returns the number of bytes sent and I confirmed this with the source code of the library, so actually the "2" returned is correct. This and the return of the write function (that I also checked and it returns "1" that is alright) are the only source of feedback for this library.

The SPI library is configured for the pin 10, MSB first, clock divider of 21 and in SPI_MODE0 (I am not sure if this mode of operation is correct, I just copied it from the "Codec Shield" library). Now, the feedback for this interface is the data read from the chip. This data is always FF.

So this is the code:

#include <[color=#CC6600]Wire[/color].h>
#include <[color=#CC6600]SPI[/color].h>

#define LINVOL 23
#define RINVOL 23
#define LHPVOL 121
#define RHPVOL 121
#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

volatile [color=#CC6600]boolean[/color] l;

[color=#CC6600]unsigned[/color] [color=#CC6600]int[/color] temp = 0;
[color=#CC6600]int[/color] temp_spi[4];

[color=#7E7E7E]//TC1 ch 0[/color]
[color=#CC6600]void[/color] TC3_Handler()
{
        TC_GetStatus(TC1, 0);

        temp = [color=#CC6600]random[/color](65535);
        temp_spi[0] = [color=#CC6600]SPI[/color].transfer(10,[color=#CC6600]highByte[/color](temp),[color=#006699]SPI_CONTINUE[/color]);
        temp_spi[1] = [color=#CC6600]SPI[/color].transfer(10,[color=#CC6600]lowByte[/color](temp),[color=#006699]SPI_CONTINUE[/color]);
        temp_spi[2] = [color=#CC6600]SPI[/color].transfer(10,[color=#CC6600]highByte[/color](temp),[color=#006699]SPI_CONTINUE[/color]);
        temp_spi[3] = [color=#CC6600]SPI[/color].transfer(10,[color=#CC6600]lowByte[/color](temp),SPI_LAST);
}

[color=#CC6600]void[/color] startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect([color=#CC6600]false[/color]);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
        uint32_t rc = VARIANT_MCK/128/frequency;
        TC_SetRA(tc, channel, rc/2);
        TC_SetRC(tc, channel, rc);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
}

[color=#CC6600]void[/color] AudioCodec_init() {
        [color=#CC6600]randomSeed[/color]([color=#CC6600]analogRead[/color](0));
        [color=#CC6600]SPI[/color].[color=#CC6600]begin[/color](10);
        [color=#CC6600]SPI[/color].setBitOrder([color=#006699]MSBFIRST[/color]);
        [color=#CC6600]SPI[/color].[color=#CC6600]setClockDivider[/color](10,21); [color=#7E7E7E]// select to ss pin 10, 4 MHz[/color]
        [color=#CC6600]SPI[/color].setDataMode(10,SPI_MODE0);
        
        [color=#CC6600]int[/color] temp_wire1;
        [color=#CC6600]int[/color] temp_wire2;
        
        [color=#CC6600]Wire[/color].[color=#CC6600]begin[/color]();
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x0c); [color=#7E7E7E]// power reduction register[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)0x00); [color=#7E7E7E]// turn everything on[/color]
        temp_wire1 = [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x0e); [color=#7E7E7E]// digital data format[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x03); [color=#7E7E7E]// 16b SPI mode[/color]
        temp_wire2 = [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]println[/color](temp_wire1);
        [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]println[/color](temp_wire2);
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)0x00); [color=#7E7E7E]// left in setup register[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)LINVOL);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x02); [color=#7E7E7E]// right in setup register[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)RINVOL);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x04); [color=#7E7E7E]// left headphone out register[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)LHPVOL);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x06); [color=#7E7E7E]// right headphone out register[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)RHPVOL);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x0a); [color=#7E7E7E]// digital audio path configuration[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)ADCHPD);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x08); [color=#7E7E7E]// analog audio pathway configuration[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color]((uint8_t)((SIDEATT << 6)|(SIDETONE << 5)|(DACSEL << 4)|(BYPASS << 3)|(INSEL << 2)|(MUTEMIC << 1)|(MICBOOST << 0)));
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x10); [color=#7E7E7E]// clock configuration[/color]
        #if SAMPLE_RATE == 88
          [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0xbc);
        #elif SAMPLE_RATE == 44
          [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0xa0);
        #elif SAMPLE_RATE == 22
          [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0xe0);
        #elif SAMPLE_RATE == 8
          [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0xac);
        #elif SAMPLE_RATE == 2
          [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0xce);
        #endif
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
      
        [color=#CC6600]Wire[/color].[color=#CC6600]beginTransmission[/color](0x1a);
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x12); [color=#7E7E7E]// codec enable[/color]
        [color=#CC6600]Wire[/color].[color=#CC6600]write[/color](0x01);
        [color=#CC6600]Wire[/color].[color=#CC6600]endTransmission[/color]();
        
}

[color=#CC6600]void[/color] [color=#CC6600][b]setup[/b][/color](){
  
        [color=#CC6600][b]Serial[/b][/color].[color=#CC6600]begin[/color](9600);
        AudioCodec_init();
        startTimer(TC1, 0, TC3_IRQn, 44100); [color=#7E7E7E]
}

[color=#CC6600]void[/color] [color=#CC6600][b]loop[/b][/color](){
}

Sorry for the extention of the post, I don't know what to do now, the only think I can do is check the interfaces with an oscilloscope, I have access to oscilloscopes at work so I think this week I should try it. Did anyone try any of this libraries with the Due? Help, please :frowning:

Sorry, the code above isn't readable. Here it is again

#include <Wire.h>
#include <SPI.h>

#define LINVOL 23
#define RINVOL 23
#define LHPVOL 121
#define RHPVOL 121
#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

volatile boolean l;

unsigned int temp = 0;
int temp_spi[4];

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);

        temp = random(65535);
        temp_spi[0] = SPI.transfer(10,highByte(temp),SPI_CONTINUE);
        temp_spi[1] = SPI.transfer(10,lowByte(temp),SPI_CONTINUE);
        temp_spi[2] = SPI.transfer(10,highByte(temp),SPI_CONTINUE);
        temp_spi[3] = SPI.transfer(10,lowByte(temp),SPI_LAST);
        Serial.println(temp_spi[0]);
        Serial.println(temp_spi[1]);
        Serial.println(temp_spi[2]);
        Serial.println(temp_spi[3]);
}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect(false);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
        uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
        TC_SetRA(tc, channel, rc/2); //50% high, 50% low
        TC_SetRC(tc, channel, rc);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
}

void AudioCodec_init() {
        randomSeed(analogRead(0));
        SPI.begin(10);
        SPI.setBitOrder(MSBFIRST);
        SPI.setClockDivider(10,21); // select to ss pin 10, 4 MHz
        SPI.setDataMode(10,SPI_MODE0);
        
        // setup i2c pins and configure codec
        // the new Wire library has trouble with 0x00, so (uint8_t) is added
        // To change the Wire interface speed, go to:
        // <path_from_arduino>\hardware\arduino\sam\libraries\Wire\Wire.h
        // and change the parameters TWI_CLOCK, RECV_TIMEOUT and XMIT_TIMEOUT
        // to the desire frequency.
        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
        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(){
  
        Serial.begin(9600);
        AudioCodec_init();
        startTimer(TC1, 0, TC3_IRQn, 44100); //startTimer(TC1, 0, TC3_IRQn, 44100); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}

Hi, did you ever get this code working for Codec / Arduino Due?

found a solution / wire hack for arduino Uno but not Due ..