News:

Let's find out together what makes a PIC Tick!

Main Menu

I2COut does it really need 'Control?

Started by Ecoli-557, Mar 14, 2025, 07:54 PM

Previous topic - Next topic

Ecoli-557

I have read the I2COut and understand it - mostly.  Similar to PBP which is what I was using.....
However, I am confused over the 'Control' part of this.  I think I understand its use for addressing and the R/W bit.
But, In my specific need to communicate with a CODEC (WM8940) I don't believe I can use it this way.
Well, my code failure tells me I cannot anyway.
I have it set as a 3-wire mode and have found the following on page 62 of their datasheets.  I do not know how to insert the timing diagram in this forum however..
The high order 8 bit of the register byte controls write or read; a '0' writes to the CODEC, and a '1'reads from the selected register.
Which makes me think I do not need the 'Control. but when I do this:
'Procedure to send data to WM8940
Proc WriteWM8940 (I2outData As Word, CODECReg As byte)
     low CODEC_CS
     I2Cout SDA_Pin, SCL_Pin, I2OutData, [CODECReg]
     high CODEC_CS
EndProc

Registers here (a few):
         Symbol CODEC_RST        0x00        'Soft reset
         Symbol CODEC_Pwr1        0x01        'Power Mgmt-1
         Symbol CODEC_Pwr2        0x02        'Power Mgmt-2
         Symbol CODEC_Pwr3       0x03        'Power Mgmt-3
         Symbol CODEC_AudInt        0x04        'Audio Interface
         Symbol CODEC_CompCtl     0x05        'Companding Control

and when called to init the chip (only a few listed here):
WriteWM8940(0x0000, CODEC_RST)               'Reset the chip
WriteWM8940(0x0003, CODEC_Pwr1)              'VNID=1, Level Shifters=1
WriteWM8940(0x0080, CODEC_Clk)               'Clock Source to MCLK

On my analyzer I can see the CODEC chip select going low but no clock and no data.

Any suggestions?  Please?

RGV250

Hi,
I doubt I can help anyway but it would be better if you supplied a fully working snippet of code rather than just sections of what you have done.

Bob

Frizie

Whether you need the controlbyte depends on the I²C device you have connected.
So look in the datasheet of that device.
Ohm sweet Ohm | www.picbasic.nl

top204

Judging by the datasheet of the WM8940, it supports a 2-wire mode, which is sometimes not fully I2C compatible. However, it does have a fixed slave address of %00110100. According to page 20 of the rev 4.4 datasheet.

If in doubt, use the seperate BusX commands, so Acks and NAcks and Starts and Stops can be controlled more.



Pepe

an example but I don't know what pic is used

' Pin configuration for SPI (3-wire)
Symbol MOSI = PORTC.4  ' SPI MOSI (Master Out Slave In)
Symbol SCK  = PORTC.3  ' SPI Clock (SCK)
Symbol CS   = PORTB.2  ' Chip Select (for selecting WM8940)

' Define codec registers
Symbol CODEC_RST      = 0x00  ' Reset
Symbol CODEC_Pwr1     = 0x01  ' Power Management-1
Symbol CODEC_Pwr2     = 0x02  ' Power Management-2
Symbol CODEC_Pwr3     = 0x03  ' Power Management-3
Symbol CODEC_AudInt   = 0x04  ' Audio Interface
Symbol CODEC_CompCtl  = 0x05  ' Compressor Control
Symbol CODEC_MicGain  = 0x0A  ' Microphone Gain
Symbol CODEC_Mic1Ctrl = 0x10  ' MIC1 Control (Microphone Control 1)
Symbol CODEC_Output   = 0x1A  ' Output Control
Symbol CODEC_Volume   = 0x1E  ' Volume Control
Symbol CODEC_Frequency= 0x20  ' Audio Frequency Control
Symbol CODEC_Rate     = 0x21  ' Sample Rate Control
Symbol CODEC_ClkCtl   = 0x24  ' Clock Control
Symbol CODEC_Headphone= 0x2A  ' Headphone Output Control

' Pin configuration
TRISC.4 = 1  ' MOSI as input
TRISC.3 = 1  ' SCK as input
TRISB.2 = 0  ' CS as output

' Main execution starts here
Init_WM8940  ' Initialize codec

' After the initialization, enter a one-time action, no continuous loop here
' You can perform tasks once, such as configuring settings or adjusting parameters

' Example task after initialization (this part is executed only once)
Dim dato As Word
dato = $01FF  ' Maximum volume
SPIWrite(CODEC_Volume, dato)  ' Set volume

' Now, you can enter a continuous loop for other repetitive tasks if needed.
' For example, monitoring or adjusting other parameters on the codec.
Do
    ' Example: Continuously monitor or adjust the codec
    ' Add your repetitive tasks here, if needed. Otherwise, leave it empty.
Loop

' Initialization procedure for WM8940
proc Init_WM8940
    Dim dato As Word  ' Declare dato as Word type
   
    ' Reset the codec (using CODEC_RST)
    dato = $0000
    SPIWrite(CODEC_RST, dato)

    ' Activate Power Management (using CODEC_Pwr2)
    dato = $0100
    SPIWrite(CODEC_Pwr2, dato)

    ' Microphone configuration
    dato = $0007
    SPIWrite(CODEC_Mic1Ctrl, dato)  ' MIC1 Control (using CODEC_Mic1Ctrl)

    dato = $0040
    SPIWrite(CODEC_MicGain, dato)  ' Activate MIC preamplifier

    dato = $0001
    SPIWrite(CODEC_CompCtl, dato)  ' Compressor Control (using CODEC_CompCtl)

    dato = $01FF
    SPIWrite(CODEC_Output, dato)  ' Set output volume to maximum

    ' Clock and operation mode configuration
    dato = $0005
    SPIWrite(CODEC_ClkCtl, dato)  ' Configure codec clock

    dato = $0001
    SPIWrite(CODEC_AudInt, dato)  ' Audio Interface (using CODEC_AudInt)

    ' Headphone control
    dato = $0080
    SPIWrite(CODEC_Headphone, dato)  ' Enable headphone output
EndProc

' SPI communication procedure using SHOut with MOSI and SCK
proc SPIWrite(register As Byte, dato As Word)
    ' Pull CS low to select the codec
    Low CS
   
    ' Send the register address (send one byte for the register)
    SHOut MOSI, SCK, [register]   ' Send the register address using SHOut

    ' Send the data to the register (dato: high byte and low byte together)
    SHOut MOSI, SCK, [dato.highbyte, dato.lowbyte]  ' Send both high and low byte together
   
    ' Pull CS high to deselect the codec
    High CS
EndProc


Ecoli-557

Thanks for the responses.
RGV250 - The code sits at 4,614 lines as of now.  This is my ethernet (8 sockets) project.  All 8 sockets are fully functional - it is just too large to share.
Frizie - I have studied the data for the WM8940 and it supports 2 and 3 wire I2C and page 62 of the info on this chip looks like it does not need Control as the high-order bit (bit 23) will support READ and Write functions.
Les - I am not using the 2-wire mode but am using the 3-wire mode (Page 62) as it looks fine - I just don't know if the Control byte is needed.  The timing waveforms at the bottom of Page 62 illustrate this.
Pepe - Your example of this chip shows SPI and not I2C, which I would prefer SPI but the chip only has Data and CLock pins so no MISO or MOSI.

I am going to write each command the old-fashioned way as a test such as:
    low CODEC_CS
    I2Cout SDA_Pin, SCL_Pin, I2OutData, [CODECReg]
    high CODEC_CS
as an example to see if that does something for me - maybe its me trying new things like the Procedure (which is cool) and I am not getting it right.
I am learning quite a bit with the assistance from folks like you who responded, Thank you.

top204

If you are using a two wire SPI protocol, the I2C commands cannot be used, because they operate very differently to SPI. With Start, Stop, Ack protocols sent etc, and the open-drain mechanism of them that never makes a line high, it just makes the microcontroller's pin an input and the pull-up resistors make the lines high.

RGV250

Hi,
My point is thought that you do not need a 4614 lines of code to control this device so until you get that working why are you trying to integrate it in to your project. If it were me I would just have a very small program with only the device and the minimum to prove communication worked before integrating it into your project.

From what I can gather you are trying to use I2C but looking at the datasheet it is neither I2C or SPI so I think you will have to write your own routines based on the information in the datasheet. So I doubt the question does it need "control" is relevant.

Regards,
Bob

Pepe

The WM8940 uses I²C for register configuration and I²S or PCM for audio data transmission.

I²C: Used to control and configure the codec, with a 7-bit address (0x1A by default).
I²S or PCM: Used for digital audio transmission, supporting different formats like Left-Justified, Right-Justified, and DSP Mode.

Ecoli-557

Thanks Les, I agree that 3-wire I2C is the best way to go.  It looked like Pepe has code this chip but it was 2-wire SPI which would not give me ACKs or NAKs.
Just saw the new post from Pepe - yes it is I2C for control - I haven't even started on the I2S yet.....
Will continue using I2C protocol and keep trying.

RGV250, good point.  Sometimes when you are focused on the 'project' you forget the sensible way to do things.  It makes sense to strip out the LCD, LED controller, Ethernet stuff and work the project one facet at a time.

All good points, thanks again.
-Steve

Pepe

#10
2 wires

Device = 18F26K22

' Configuration fuses for internal oscillator with PLL (64 MHz)
Config FOSC = INTOSCPLL      ' Internal oscillator with Phase-Locked Loop (PLL)
Config WDT = NOWDT            ' Disable Watchdog Timer
Config LVP = NOLVP            ' Disable Low-Voltage Programming
Config BOR = NOBROWNOUT      ' Disable Brown-Out Reset
Config PWRT = ON              ' Enable Power-Up Timer
Config IESO = NOIESO          ' Disable Oscillator Switch-Over
Config FCMEN = NOFCMEN        ' Disable Fail-Safe Clock Monitor
Config MCLRE = ON            ' Enable Master Clear (MCLR) pin
Config BOREN = OFF            ' Disable Brown-Out Reset
Config CPD = OFF              ' Disable Data EEPROM Protection
Config CCP2MX = PORTC.1      ' Select CCP2 on RC1

' Use internal oscillator at 64 MHz with PLL
Declare Xtal = 64           
Declare I2C_Bitrate 100      ' I²C speed (100 kHz)

' WM8940 I²C address (changed to $1A)
Symbol WM8940_ADDR = $1A      ' New WM8940 write address

' Define I²C pins
Symbol SDA = PORTC.4
Symbol SCL = PORTC.3

' WM8940 register definitions
Symbol WM8940_REG_RESET      = $00  ' Reset register
Symbol WM8940_REG_OSC_CTRL    = $19  ' Oscillator control
Symbol WM8940_REG_CLOCK_CTRL  = $1A  ' Clock control
Symbol WM8940_REG_POWER_CTRL  = $1E  ' Power control
Symbol WM8940_REG_DAC_CTRL    = $0A  ' DAC control
Symbol WM8940_REG_AUDIO_CTRL  = $31  ' Audio control

' WM8940 initialization with I²C address $1A
WM8940_Write(WM8940_REG_RESET, $0000)        ' Reset
WM8940_Write(WM8940_REG_OSC_CTRL, $0002)    ' Enable internal oscillator
WM8940_Write(WM8940_REG_CLOCK_CTRL, $0001)  ' Set clock divider
WM8940_Write(WM8940_REG_POWER_CTRL, $0000)  ' Set system clock

WM8940_Write(WM8940_REG_DAC_CTRL, $00FF)    ' Configure output gain
WM8940_Write(WM8940_REG_AUDIO_CTRL, $00C0)  ' Enable DAC and audio output

' Main loop
Do
    ' Add necessary operations inside the loop
Loop 

' Procedure to write to the WM8940 using I²C address $1A
Proc WM8940_Write(Register As Byte, Data As Word)
    I2COut SDA, SCL, WM8940_ADDR, [Register, Data]  ' Use address $1A in I²C communication
EndProc


Ecoli-557

Pepe, have you actually coded for this chip?  Do you think the 2-wire I2C is the best way to go?
In my final design I will need 8 CODECs using one processor so I can't use the 2-wire solution.
I might start with 2-wire to get some experience with it however.
Have you used this chip?
Regards,
Steve

Pepe

#12
No, but you can use csb to enable each codec

Device = 18F26K22

' Configuration fuses for internal oscillator with PLL (64 MHz)
Config FOSC = INTOSCPLL      ' Internal oscillator with Phase-Locked Loop (PLL)
Config WDT = NOWDT            ' Disable Watchdog Timer
Config LVP = NOLVP            ' Disable Low-Voltage Programming
Config BOR = NOBROWNOUT      ' Disable Brown-Out Reset
Config PWRT = ON              ' Enable Power-Up Timer
Config IESO = NOIESO          ' Disable Oscillator Switch-Over
Config FCMEN = NOFCMEN        ' Disable Fail-Safe Clock Monitor
Config MCLRE = ON            ' Enable Master Clear (MCLR) pin
Config BOREN = OFF            ' Disable Brown-Out Reset
Config CPD = OFF              ' Disable Data EEPROM Protection
Config CCP2MX = PORTC.1      ' Select CCP2 on RC1

' Use internal oscillator at 64 MHz with PLL
Declare Xtal = 64           
Declare I2C_Bitrate 100      ' I²C speed (100 kHz)

' WM8940 I²C address (changed to $1A)
Symbol WM8940_ADDR = $1A      ' New WM8940 write address

' Define I²C pins
Symbol SDA = PORTC.4
Symbol SCL = PORTC.3
Symbol SBC = PORTC.2

' WM8940 register definitions
Symbol WM8940_REG_RESET      = $00  ' Reset register
Symbol WM8940_REG_OSC_CTRL    = $19  ' Oscillator control
Symbol WM8940_REG_CLOCK_CTRL  = $1A  ' Clock control
Symbol WM8940_REG_POWER_CTRL  = $1E  ' Power control
Symbol WM8940_REG_DAC_CTRL    = $0A  ' DAC control
Symbol WM8940_REG_AUDIO_CTRL  = $31  ' Audio control

' WM8940 initialization with I²C address $1A
WM8940_Write(WM8940_REG_RESET, $0000)        ' Reset
WM8940_Write(WM8940_REG_OSC_CTRL, $0002)    ' Enable internal oscillator
WM8940_Write(WM8940_REG_CLOCK_CTRL, $0001)  ' Set clock divider
WM8940_Write(WM8940_REG_POWER_CTRL, $0000)  ' Set system clock

WM8940_Write(WM8940_REG_DAC_CTRL, $00FF)    ' Configure output gain
WM8940_Write(WM8940_REG_AUDIO_CTRL, $00C0)  ' Enable DAC and audio output

' Main loop
Do
    ' Add necessary operations inside the loop
Loop

' Procedure to write to the WM8940 using I²C address $1A
Proc WM8940_Write(Register As Byte, Data As Word)
    Low SBC
    I2COut SDA, SCL, WM8940_ADDR, [Register, Data]  ' Use address $1A in I²C communication
    High SBC
EndProc

Ecoli-557

#13
Thanks Pepe, that is how I am coding for this CODEC.  Which brings me back to the question do you need the 'Control' in I2COut?
When I code this:
'Procedure to send data to WM8940
Proc WriteWM8940 (CODECReg As byte, I2outData As Word)
     low CODEC_CS
     I2Cout SDA_Pin, SCL_Pin, [CODECReg, I2OutData]
     high CODEC_CS
EndProc

I get an error at the I2COut command stating something is missing.

Pepe


Ecoli-557

I do include the address of the Registe, I send it in the data.

One of many Symbols for the Registers:
Symbol CODEC_RST        0x00        'Soft reset

My Procedure:
'Procedure to send data to WM8940
Proc WriteWM8940 (CODECReg As byte, I2outData As Word)
     low CODEC_CS
     I2Cout SDA_Pin, SCL_Pin, [CODECReg, I2OutData]
     high CODEC_CS
EndProc

How I use the Procedure:
WriteWM8940(CODEC_RST, 0x0000)               'Reset the chip

as an example.

Is this not correct?

Pepe

#16
Symbol WM8940W = $9A 

' Procedure to write to the WM8940 using I²C address $9A
Proc WM8940_Write(Register As Byte, Data As Word)
    low CODEC_CS
    I2COut SDA, SCL, WM8940W, [Register, Data]  ' Use address $1A in I²C communication
    high CODEC_CS
EndProc

Pepe

 WM8940 I²C address
 WM8940R = $1A      '  WM8940 read address
 WM8940W = $9A      '  WM8940 write address

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 18F26K22

Config_Start
  FOSC = INTIO67 ;Internal oscillator block
  PLLCFG = On ;Oscillator multiplied by 4
  PRICLKEN = On ;Primary clock enabled
  FCMEN = OFF ;Fail-Safe Clock Monitor disabled
  IESO = OFF ;Oscillator Switchover mode disabled
  PWRTEN = OFF ;Power up timer disabled
  BOREN = OFF ;Brown-out Reset disabled in hardware and software
  BORV = 190 ;VBOR set to 1.90 V nominal
  WDTEN = OFF ;Watch dog timer is always disabled. SWDTEN has no effect.
  WDTPS = 32768 ;1:32768
  CCP2MX = PORTC1 ;CCP2 input/output is multiplexed with RC1
  PBADEN = OFF ;PORTB<5:0> pins are configured as digital I/O on Reset
  CCP3MX = PORTB5 ;P3A/CCP3 input/output is multiplexed with RB5
  HFOFST = On ;HFINTOSC output and ready status are not delayed by the oscillator stable status
  T3CMX = PORTC0 ;T3CKI is on RC0
  P2BMX = PORTB5 ;P2B is on RB5
  MCLRE = INTMCLR ;RE3 input pin enabled; MCLR disabled
  STVREN = OFF ;Stack full/underflow will not cause Reset
  LVP = OFF ;Single-Supply ICSP disabled
  XINST = OFF ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
  Debug = OFF ;Disabled
  Cp0 = OFF ;Block 0 (000800-003FFFh) not code-protected
  CP1 = OFF ;Block 1 (004000-007FFFh) not code-protected
  CP2 = OFF ;Block 2 (008000-00BFFFh) not code-protected
  CP3 = OFF ;Block 3 (00C000-00FFFFh) not code-protected
  CPB = OFF ;Boot block (000000-0007FFh) not code-protected
  CPD = OFF ;Data EEPROM not code-protected
  WRT0 = OFF ;Block 0 (000800-003FFFh) not write-protected
  WRT1 = OFF ;Block 1 (004000-007FFFh) not write-protected
  WRT2 = OFF ;Block 2 (008000-00BFFFh) not write-protected
  WRT3 = OFF ;Block 3 (00C000-00FFFFh) not write-protected
  WRTC = OFF ;Configuration registers (300000-3000FFh) not write-protected
  WRTB = OFF ;Boot Block (000000-0007FFh) not write-protected
  WRTD = OFF ;Data EEPROM not write-protected
  EBTR0 = OFF ;Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
  EBTR1 = OFF ;Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
  EBTR2 = OFF ;Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
  EBTR3 = OFF ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
  EBTRB = OFF ;Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------

Declare Xtal = 64

Declare Create_Coff On
Declare Optimiser_Level = 3
Declare Bootloader off
Declare Dead_Code_Remove = 1        ' Remove dead code
Declare Watchdog Off
Declare Reminders Off

Symbol PLLEN = OSCTUNE.6  ' PLL enable
Symbol PLLRDY = OSCCON2.7 ' PLL run status
           
Declare Hbus_Bitrate 100      ' I²C speed (100 kHz)
Declare HSDA_Pin = PORTC.4
Declare HSCL_Pin = PORTC.3

' WM8940 I²C address (changed to $1A)
Symbol WM8940R = $1A      '  WM8940 read address
Symbol WM8940W = $9A      '  WM8940 write address

Symbol SBC = PORTC.2

' WM8940 register definitions
Symbol WM8940_REG_RESET      = $00  ' Reset register
Symbol WM8940_REG_OSC_CTRL    = $19  ' Oscillator control
Symbol WM8940_REG_CLOCK_CTRL  = $1A  ' Clock control
Symbol WM8940_REG_POWER_CTRL  = $1E  ' Power control
Symbol WM8940_REG_DAC_CTRL    = $0A  ' DAC control
Symbol WM8940_REG_AUDIO_CTRL  = $31  ' Audio control
 
 OSCCON = $7c

  PLLEN = 1                                    ' Enable PLL 4x 16MHz = 64Mhz

  While PLLRDY = 0 : Wend
 

' WM8940 initialization with I²C address $1A
WM8940_Write(WM8940_REG_RESET, $0000)        ' Reset
WM8940_Write(WM8940_REG_OSC_CTRL, $0002)    ' Enable internal oscillator
WM8940_Write(WM8940_REG_CLOCK_CTRL, $0001)  ' Set clock divider
WM8940_Write(WM8940_REG_POWER_CTRL, $0000)  ' Set system clock

WM8940_Write(WM8940_REG_DAC_CTRL, $00FF)    ' Configure output gain
WM8940_Write(WM8940_REG_AUDIO_CTRL, $00C0)  ' Enable DAC and audio output

' Main loop
Do
    ' Add necessary operations inside the loop
Loop

' Procedure to write to the WM8940 using I²C address $1A
Proc WM8940_Write(Register As Byte, Dato As Word)
    Low SBC
    HBusOut  WM8940W, [Register, Dato]  ' Use address $9A in I²C communication
    High SBC
EndProc

Ecoli-557

Thanks Pepe-
I am working code now, will let you know.
So, in looking at your example, I still have to use the 'Control' byte and set it to the default address EVEN though I am using 3-wire I2C with a chip select?

Ecoli-557

#19
Pepe-
I am not transmitting to the 8940 as I should be..... it looks like it only sends two 8-bit bytes at each chip select.  And it sends 0x4D and 0x00 over and over again.
Here is all pertinent info:
Device = 18F67K40
Declare Xtal = 64
On_Hardware_Interrupt GoTo My_IRQ
Declare Optimiser_Level = 0 'DISABLES the Optimiser
'Declare I2C_Slow_Bus On    '64MHz may be too fast for the WM8940

Config_Start
'-------------------------------------------------------------------------------
'**** Added by Fuse Configurator ****
'Use the Fuse Configurator plug-in to change these settings
FEXTOSC = OFF    ;Oscillator not enabled
RSTOSC = HFINTOSC_64MHZ    ;HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
CLKOUTEN = OFF    ;CLKOUT function is disabled
CSWEN = On    ;Writing to NOSC and NDIV is allowed
FCMEN = OFF    ;Fail-Safe Clock Monitor disabled
MCLRE = EXTMCLR    ;If LVP = 0, MCLR pin is MCLR; If LVP = 1, RG5 pin function is MCLR
PWRTE = On    ;Power up timer enabled
LPBOREN = OFF    ;ULPBOR disabled
BOREN = SBORDIS    ;Brown-out Reset enabled , SBOREN bit is ignored
BORV = VBOR_285    ;Brown-out Reset Voltage (VBOR) set to 2.85V
ZCD = OFF    ;ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
PPS1WAY = OFF    ;PPSLOCK bit can be set and cleared repeatedly (subject to the unlock sequence)
STVREN = On    ;Stack full/underflow will cause Reset
Debug = OFF    ;Background debugger disabled
XINST = OFF    ;Extended Instruction Set and Indexed Addressing Mode disabled
WDTCPS = WDTCPS_31    ;Divider ratio 1:65536; software control of WDTPS
WDTE = OFF    ;WDT Disabled
WDTCWS = WDTCWS_7    ;window always open (100%); software control; keyed access not required
WDTCCS = LFINTOSC    ;WDT reference clock is the 31.0 kHz LFINTOSC
WRT0 = OFF    ;Block 0 (000800-003FFFh) not write-protected
WRT1 = OFF    ;Block 1 (004000-007FFFh) not write-protected
WRT2 = OFF    ;Block 2 (008000-00BFFFh) not write-protected
WRT3 = OFF    ;Block 3 (00C000-00FFFFh) not write-protected
WRT4 = OFF    ;Block 4 (010000-013FFFh) not write-protected
WRT5 = OFF    ;Block 5 (014000-017FFFh) not write-protected
WRT6 = OFF    ;Block 6 (018000-01BFFFh) not write-protected
WRT7 = OFF    ;Block 7 (01C000-01FFFFh) not write-protected
WRTC = OFF    ;Configuration registers (300000-30000Bh) not write-protected
WRTB = OFF    ;Boot Block (000000-0007FFh) not write-protected
WRTD = OFF    ;Data EEPROM not write-protected
SCANE = On    ;Scanner module is available for use, SCANMD bit can control the module
LVP = OFF    ;HV on MCLR/VPP must be used for programming
Cp = OFF    ;UserNVM code protection disabled
CPD = OFF    ;DataNVM code protection disabled
EBTR0 = OFF    ;Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
EBTR1 = OFF    ;Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
EBTR2 = OFF    ;Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
EBTR3 = OFF    ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
EBTR4 = OFF    ;Block 4 (010000-013FFFh) not protected from table reads executed in other blocks
EBTR5 = OFF    ;Block 5 (014000-017FFFh) not protected from table reads executed in other blocks
EBTR6 = OFF    ;Block 6 (018000-01BFFFh) not protected from table reads executed in other blocks
EBTR7 = OFF    ;Block 7 (01C000-01FFFFh) not protected from table reads executed in other blocks
EBTRB = OFF    ;Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End
'**** End of Fuse Configurator Settings ****
'PORT D IN USE
ANSELD  = %00000000    'Set all analog pins to digital.
TRISD  = %01000010    'Port D set to outputs except bits 1 & 6
WPUD    = %11111100    'Weak pull-ups enabled except for 0 & 1
ODCOND  = %00000000    '1 = Open Drain, 0 = Push/Pull drive
PORTD  = %00001000    'Clear register. D.3 = 1
LATD    = %00001000    'Clear register. D.3 = 1
SLRCOND = %11111111    'Slew rate limited
INLVLD  = %00000000    '1 = Schmitt Trigger input used for PORT reads and interrupt-on-change
                        '0 = TTL input used for PORT reads and interrupt-on-change

'PORT E IN USE
TRISE = %01100001      'PORTE is mixed
WPUD  = %10010001      'Weak pull-ups enabled except for 0, 4, and 7
ANSELE  = %01100000    ; Set all analog pins to digital EXCEPT BITS 5,6,
TRISE  = %01100001    ; Port E set to Outputs except bits 0,5,6.
WPUE    = %10011111    ; Weak pull-ups enabled except bits 5 & 6
ODCONE  = %00000000    ; 1 = Open Drain, 0 = Push/Pull drive.
PORTE  = %10011111    ; Initialize register.
LATE    = %10011111    ; Set outputs high.
SLRCONE = %11111111    ; Slew rate limited.
INLVLE  = %00000000    ; 1 = Schmitt Trigger input used for PORT reads and interrupt-on-change
                        ; 0 = TTL input used for PORT reads and interrupt-on-change

'3-Wire I2C for the WM8940 CODEC ----------------------------------
WM8940_Pins:
'SDA_Pin, SCL_Pin, CODECReg, [IOutData]
        Symbol SDA_Pin = PORTE.4                'Pin To use For the I2C data
        Symbol SCL_Pin = PORTE.7                'Pin To use For the I2C clock
        Symbol CODEC_CS = PORTD.2                'Pin To use For the I2C CS

'WM8940 CODEC Variables -----------------------------------------------------
WM8940_Regs:
        Dim SPI_Out As Word                      'Out data
        Dim SPI_In As Word                      'In Data
        Dim CODECReg As Byte                    'WM8940 register

        Symbol CODEC_RST        0x00        'Soft reset
        Symbol CODEC_Pwr1        0x01        'Power Mgmt-1
        Symbol CODEC_Pwr2        0x02        'Power Mgmt-2
        Symbol CODEC_Pwr3      0x03        'Power Mgmt-3
        Symbol CODEC_AudInt        0x04        'Audio Interface
        Symbol CODEC_CompCtl    0x05        'Companding Control
        Symbol CODEC_Clk        0x06        'Clock Gen COntrol
        Symbol CODEC_AddlCntl    0x07        'Additional COntrol
        Symbol CODEC_GPIO        0x08        'GPIO stuff
        Symbol CODEC_CtlInt    0x09        'Control Interface
        Symbol CODEC_DAC        0x0A        'DAC Control
        Symbol CODEC_DACvol        0x0B        'DAC Digital volume

        Symbol CODEC_ADC        0x0E        'ADC Control
        Symbol CODEC_ADCvol        0x0F        'ADC Digital volume
        Symbol CODEC_Notch1        0x10        'Notch Filter-1
        Symbol CODEC_Notch2        0x11        'Notch Filter-2
        Symbol CODEC_Notch3    0x12        'Notch Filter-3
        Symbol CODEC_Notch4        0x13        'Notch Filter-4
        Symbol CODEC_Notch5        0x14        'Notch Filter-5
        Symbol CODEC_Notch6        0x15        'Notch Filter-6
        Symbol CODEC_Notch7        0x16        'Notch Filter-7
        Symbol CODEC_Notch8        0x17        'Notch Filter-8
        Symbol CODEC_DACLim1    0x18        'DAC Limiter-1
        Symbol CODEC_DACLim2    0x19        'DAC Limiter-2

        Symbol CODEC_ALC1        0x20        'ALC Control-1
        Symbol CODEC_ALC2        0x21        'ALC Control-2
        Symbol CODEC_ALC3        0x22        'ALC COntrol-3
        Symbol CODEC_NGate      0x23        'Noise Gate
        Symbol CODEC_PLLN        0x24        'PLL N
        Symbol CODEC_PLLK1        0x25        'PLL K-1
        Symbol CODEC_PLLK2        0x26        'PLL K-2
        Symbol CODEC_PLLK3        0x27        'PLL K-3

        Symbol CODEC_ALC4        0x2A        'ALC Control-4

        Symbol CODEC_InCtl        0x2C        'Input Control
        Symbol CODEC_InPGAGain    0x2D        'Input PGA Gain Control

        Symbol CODEC_ADCBOOST    0x2F        'ADC Boost Control

        Symbol CODEC_OutCtl    0x31        'Output Control
        Symbol CODEC_SpkrMix    0x32        'Speaker Mixer Control

        Symbol CODEC_SpkrVol    0x36        'Speaker Volume Control

        Symbol CODEC_MonoMix    0x38        'Mono Mixer Control

        Symbol CODEC_CacheRegNum  0x57

        '/* Clock divider Id's */
        Symbol BCLKDIV          0
        Symbol MCLKDIV          1
        Symbol OPCLKDIV        2

        '/* MCLK clock dividers */
        Symbol MCLKDIV_1        0
        Symbol MCLKDIV_1_5        1
        Symbol MCLKDIV_2        2
        Symbol MCLKDIV_3        3
        Symbol MCLKDIV_4        4
        Symbol MCLKDIV_6        5
        Symbol MCLKDIV_8        6
        Symbol MCLKDIV_12        7

        '/* BCLK clock dividers */
        Symbol BCLKDIV_1        0
        Symbol BCLKDIV_2        1
        Symbol BCLKDIV_4        2
        Symbol BCLKDIV_8        3
        Symbol BCLKDIV_16      4
        Symbol BCLKDIV_32      5

        '/* PLL Out Dividers */
        Symbol OPCLKDIV_1      0
        Symbol OPCLKDIV_2      1
        Symbol OPCLKDIV_3      2
        Symbol OPCLKDIV_4      3

'*******************************************************************************
'Procedure to send data to WM8940
Proc WriteWM8940 (CODECReg As byte, I2outData As Word)
    low CODEC_CS
    I2Cout SDA_Pin, SCL_Pin, 0x9A, [CODECReg, I2OutData]
    high CODEC_CS
EndProc

'*******************************************************************************
' Initialize the WM8940 CODEC
InitWM8940:
'NEW WAY - page 64 of WM8940
WriteWM8940(CODEC_RST, 0x0000)              'Reg 0x00 - Reset the chip
WriteWM8940(CODEC_Pwr1, 0x0003)              'Reg 0x01 - VNID=1, Level Shifters=1
WriteWM8940(CODEC_Clk, 0x0080)              'Reg 0x06 - Clock Source to MCLK
WriteWM8940(CODEC_AddlCntl, 0x0060)          'Reg 0x07 - Enable Power On Bias Control,VMID soft start
WriteWM8940(CODEC_Pwr3, 0x0060)              'Reg 0x03 - Enable SPKPEN, SPKNRN
WriteWM8940(CODEC_Pwr1, 0x0001)              'Reg 0x01 - VMID set for 50k
WriteWM8940(CODEC_Pwr1, 0x000A)              'Reg 0x01 - Enable Analog Amp Bias Control, VMID buffer
WriteWM8940(CODEC_AddlCntl, 0x0010)          'Reg 0x07 - Disable Power on Bias Control, VMID Softstart
WriteWM8940(CODEC_Pwr3, 0x0005)              'Reg 0x03 - Enable DAC, and Spkr Mixer
WriteWM8940(CODEC_SpkrMix, 0x0000)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=-57dB
WriteWM8940(CODEC_SpkrMix, 0x0004)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0008)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x000C)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0010)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0014)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0020)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0028)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0030)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrMix, 0x0034)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=
WriteWM8940(CODEC_SpkrVol, 0x0039)          'Reg 0x32 - Disable Spkr Mute, Spkr Vol=0dB
WriteWM8940(CODEC_DAC, 0x0000)              'Reg 0x0A - Disable DAC SOft Mute
Return

'DAC Loopback - DAC data input fed directly into ADC Output
DAC_Loop:
WriteWM8940(CODEC_CompCtl, 0x0040)          'ADC Out -> DAC Input
Return

And to start:
gosub InitWM8940

Attached is a logic analyzer of what is being sent to the 8940:

I2C to CODEC-1.PNG