Monthly Archives: June 2015

VoCore: I2S Sound Card WM8960G 3

Now, I will output some data from I2S data line.

For simple, we do not enable any interrupt, and do not use DMA. Just put some data out.
Screen Shot 2015-06-18 at 19.15.11

We fill the register with a test data, for example 0x12345678.(This output is just noise, real sound data should be get from your wav file.)
Then enable I2S by the following command

Prepare LRCLK and BCLK.

./mems 0x60 0x00400098
./mems 0xa00 0x81004040
./mems 0xa24 0x0E
./mems 0xa20 0x800000aa

Put some DATA into I2S data wire.

./mems 0xa10 0x12345678

Watch the output from Logic Analyzer.


Looks like everything is alright.

Next, we should setup the I2C, to make WM8960G play the noise. :)

First make sure you have i2c-tools, we need command “i2cset”
WM8960G i2c interface is not standard i2c(if there is any standard :) ) For most i2c chip, it is address(7bit) + write/read(1bit) + register address(8bit) + register data(8bit), so command “i2cdump” will work on such chip. Unfortunately, WM8960G is not such chip :P. Its I2C format is address(7bit) + write(1bit, write only) + register address(7bit) + register data(9bit), so we must calculate such register before we use it.

Once you setup this, WM8960 is ready to work. Check WM8960G datasheet for more details about the values.

i2cset -y 0 0x1a 0x1e 0x00
i2cset -y 0 0x1a 0x0e 0x02
i2cset -y 0 0x1a 0x08 0x05
i2cset -y 0 0x1a 0x68 0x07
i2cset -y 0 0x1a 0x6a 0x86
i2cset -y 0 0x1a 0x6c 0xc2
i2cset -y 0 0x1a 0x6e 0x26
i2cset -y 0 0x1a 0x32 0xc0
i2cset -y 0 0x1a 0x35 0xe1
i2cset -y 0 0x1a 0x5e 0x0c
i2cset -y 0 0x1a 0x45 0x00
i2cset -y 0 0x1a 0x4b 0x00
i2cset -y 0 0x1a 0x0a 0x00
i2cset -y 0 0x1a 0x05 0xf8
i2cset -y 0 0x1a 0x07 0xf8

Once you put data into register 0xa10, the headphone(left headphone connect to HP_L and GND, right headphone connect to HP_R and GND) will output some noise. The sound might be loud, be careful :)

If you write a simple app make it read from wav file and keep filling the register 0xa10, there will be some “music” out.

The “music” will not at good quality, due to the FIFO in RT5350 might overflow or underflow.

We must use DMA to make the music be played smoothly, but that is much much harder:

1. DMA have to enable DMA-I2S hardware interrupt, but that interrupt(id:7?) is already taken by openwrt, directly request interrupt will fail.
2. Interrupt must be used in kernel mode, so mems/memv will not work anymore, we can not peacefully play the code in user mode, but must write some “dangerous” code in kernel mode. :)

Next blog will be hard for new learner. Need strong linux kernel develop knowledge.

VoCore: I2S Sound Card WM8960G 2

Its time to make I2S work.

I2S contains three wires for sound:
BCLK: bit clock, basic clock for the data.
LRCLK: left channel/right channel clock.
DATA: used to send data.

My target is to enable BCLK and LRCLK, in I2S master mode.

For simple, I did not have to write a driver but directly write to register by mmap /dev/mem.

Here is a small application to make it easy.
Source Code: mems.c, memv.c
mems is used to set register, memv is used to view register.
PS: I guess there already exists tons of such tools, but I am too lazy to search, just five minutes work. 😀

Compile the source code and upload them to VoCore.

First, we should set pinmux, to make the pinmux from GPIO mode to I2S + GPIO mode.
From RT5350 datasheet, its register is 0x0060.
use memv to get it current value:

memv 0x0060 4


# ./memv 0x0060 4
offset: 0x10000060, size: 0x00000004
ADDR    : +0 +1 +2 +3 +4 +5 +6 +7  +8 +9 +A +B +C +D +E +F    0123456789ABCDEF
00000000: 9C 00 40 00                                         ..@.

so it is 0x0040009C = 0000 0000 0100 0000 0000 0000 1001 1100 in binary.
4:2 bit are 111, it means UARTF_SHARE_MODE is all GPIO.
check datasheet again, I2S + GPIO is 110, so we update it to 0000 0000 0100 0000 0000 0000 1001 1000 = 0x00400098

mems 0x0060 0x00400098

Note: change 4:2 but keep all other bits.

Then, setup I2S register, update PLL to make BCLK output correct clock.
Set LRCLK to 44100Hz, so BCLK = 44100Hz x 16bits x 2channels = 1411200Hz
From datasheet FreqOut = FreqIn *(1/2) *{1 / [DIVINT+DIVCOMP/(512)]}, FreqOut = 1.4112M, FreqIn = 40M.
So DIVINT = 0x0E, DIVCOMP = 0x58, and PLL clock bit enable.

mems 0x0a20 0x80000058
memv 0x0a24 0x0000000E

Final, enable I2S, view its output.

memv 0x0a00 0x81004040

The result looks pretty well :)
If you do not have a logic analyzer, a voltmeter is a simple replacement. If the I2S BCLK and LRCLK output is about 1.65V(3.3V/2), that means I2S circle in VoCore is working.

Next blog I will talk about how to output some real sound data through I2S.