From e1f7dada40559a47f4496381426f71c88cd9605b Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Tue, 15 Jul 2014 18:36:40 +0200 Subject: Almost complete wm8523 api. Initial experiments with I2S. --- firmware/drivers/wm8523.c | 403 ++++++++++++++++++++++++++++++++++++++++------ firmware/drivers/wm8523.h | 349 ++++++++++++++++++++++++++++++++++++++- firmware/src/p2m.c | 93 +++++++++-- firmware/src/sample.h | 4 + 4 files changed, 787 insertions(+), 62 deletions(-) diff --git a/firmware/drivers/wm8523.c b/firmware/drivers/wm8523.c index f8cad99..96d5cae 100644 --- a/firmware/drivers/wm8523.c +++ b/firmware/drivers/wm8523.c @@ -26,74 +26,381 @@ */ #include "wm8523.h" -#if 1 +#include +#include +#include -#include -#include +#define READ_BIT 0b1 +#define WRITE_BIT 0b0 -#include "spi.h" +// Registers: +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 -#define WM8523_WRITE 0 -#define WM8523_READ 1 +typedef struct __attribute__ ((packed)) { + uint8_t reg:7; + uint8_t rw:1; + uint8_t msbyte; + uint8_t lsbyte; +} _reg_t; -typedef union { - struct __attribute__ ((packed)) { - uint8_t rw:1; ///< See WM8523_WRITE and WM8523_READ - uint8_t reg:7; ///< See page 35 in the WM8523 manual. - uint16_t data; - } val; - uint8_t data[3]; -} WM8523_transfer_t; +static void reg_read(uint8_t portnum, char reg, uint8_t *buf, int size) +{ + _reg_t data; + data.rw = READ_BIT; + data.reg = reg; + + GPIOSetValue(0, 16, 0); + SSPSend(portnum, (uint8_t *)&data, 1); // write register number and read bit + SSPReceive(portnum, (uint8_t *)&data.msbyte, 2); // read 16bit register value + GPIOSetValue(0, 16, 1); -void WM8523_init() -{ - //cli_write("sizeof: %d", sizeof(WM8523_transfer_t)); - spi_init(); + if(size == 1) { + buf[0] = data.lsbyte; + } else if(size == 2) { + buf[0] = data.lsbyte; + buf[1] = data.msbyte; + } else { + // Error + return; + } } -void WM8523_deinit() +static void reg_write(uint8_t portnum, char reg, const uint8_t *buf, int size) { - spi_deinit(); + _reg_t data; + data.rw = WRITE_BIT; + data.reg = reg; + switch(size) { + case 0: + data.lsbyte = 0; + data.msbyte = 0; + break; + case 1: + data.lsbyte = buf[0]; + data.msbyte = 0; + break; + case 2: + data.lsbyte = buf[0]; + data.msbyte = buf[1]; + break; + default: + // Error... + return; + } + + GPIOSetValue(0, 16, 0); + SSPSend(portnum, (uint8_t *)&data, sizeof(data)); + GPIOSetValue(0, 16, 1); } -void WM8523_write(uint8_t reg, uint16_t data) +/** + * Prepare I2S, SSP and GPIO. + */ +void wm8523_init(uint8_t portnum, wm8523_samplerate_t fs) { - WM8523_transfer_t t; - t.val.rw = WM8523_WRITE; - t.val.reg = reg; - t.val.data = data; + // Init SPI + GPIOSetDir(0, 16, 1); + GPIOSetValue(0, 16, 1); + + if(portnum == 0) SSP0Init(); + else SSP1Init(); + + I2SInit(); + + // pg. 482 + // I2STXMODE 0x400A 8030 + // bit 3 Enable for the TX_MCLK output. When 0, output of TX_MCLK is not enabled. When 1, output of TX_MCLK is enabled. + // set to 1, default is 0 + uint32_t *i2stxmode = (uint32_t*)0x400a8030; + *i2stxmode |= + (0b1 << 3) // Enable TX_MCLK output. + ; + + // pg. 477 + // I2SDAO 0x400A 8000 + // bit 5 When 0, the interface is in master mode. When 1, the interface is in slave mode. + // set to 0, default is 1 + uint32_t *i2sdao = (uint32_t*)0x400a8030; + *i2sdao &= + ~(0b1 << 5) // Set I2S in master mode. + ; + + + // pg. 481 + // I2STXBITRATE 0x400A 8028 + // bit 0-5 I2S transmit bit rate. This value plus one is used to divide TX_MCLK to produce the transmit bit clock. + // set to 31 (divide by 32): stereo (2) * 16bit + uint32_t *i2stxbirate = (uint32_t *)0x400a8028; + *i2stxbirate = 7; - WM8523_transfer_t r; - r.val.data = 0xffff; + // bitclock = mclock / (divider+1) + // samplerate = mclock / bitclock - spi_read_write(t.data, r.data, 3); + + (void)fs; + /* + WM8523_FS_8K, + WM8523_FS_32K, + WM8523_FS_44K1, + WM8523_FS_48K, + WM8523_FS_88K2, + WM8523_FS_96K, + WM8523_FS_176K4, + WM8523_FS_192K, + */ + uint32_t *pclksel1 = (uint32_t *)0x400fc1ac; + *pclksel1 |= + (0b10 << 22) // Select I2S clock: PCLK/2 see pg. 57 table 41/42 + ; + + uint32_t *pinsel9 = (uint32_t *)0x4002c024; + *pinsel9 |= + (0b01 << 26) // Select p4.29 as TX_MCLK + ; + + /* + uint32_t *pinsel3 = (uint32_t *)0x4002c00c; + *pinsel3 |= + (0b01 << 22) // config p1.27 as CLKOUT + ; + + // Set up master clock see pg. 66 + uint32_t *clkcfg = (uint32_t *)0x400fc1c8; + *clkcfg = + (0b0000 << 0) | // Select RTC as clock source + (0b1111 << 4) | // Divide by 16 + (0b1 << 8) // Enable + ; + */ } -uint16_t WM8523_read(uint8_t reg) +unsigned short wm8523_get_chip_id(uint8_t portnum) { - WM8523_transfer_t t; - t.val.rw = WM8523_READ; - t.val.reg = reg; - t.val.data = 0xffff; - - WM8523_transfer_t r; + unsigned short id; + reg_read(portnum, R0, (uint8_t*)&id, sizeof(id)); + return id; +} - spi_read_write(t.data, r.data, 3); - - return r.data[0] | (r.data[1] << 8);//r.val.data; +void wm8523_reset_registers(uint8_t portnum) +{ + reg_write(portnum, R0, 0, 0); } -/** -Volume update registers R06h and R07h are unavailable in SPI control mode. -To use volume update in software control mode, I2C mode must be used. -*/ -void WM8523_configure() +uint8_t wm8523_get_hardware_revision(uint8_t portnum) +{ + uint8_t rev; + reg_read(portnum, R1, &rev, sizeof(rev)); + return rev; +} + +wm8523_power_mode_t wm8523_get_power_mode(uint8_t portnum) +{ + wm8523_power_mode_t mode; + reg_read(portnum, R2, (uint8_t*)&mode, sizeof(mode)); + return mode; +} + +void wm8523_set_power_mode(uint8_t portnum, wm8523_power_mode_t mode) +{ + reg_write(portnum, R2, (uint8_t*)&mode, sizeof(mode)); +} + +void wm8523_set_aif_ctrl1(uint8_t portnum, wm8523_aif_ctrl1_t aif_ctrl1) +{ + aif_ctrl1.blank = aif_ctrl1.reserved = 0; + reg_write(portnum, R3, (uint8_t*)&aif_ctrl1, sizeof(aif_ctrl1)); +} + +wm8523_aif_ctrl1_t wm8523_get_aif_ctrl1(uint8_t portnum) +{ + wm8523_aif_ctrl1_t aif_ctrl1; + + reg_read(portnum, R3, (uint8_t*)&aif_ctrl1, sizeof(aif_ctrl1)); + + return aif_ctrl1; +} + +void wm8523_set_aif_ctrl2(uint8_t portnum, wm8523_aif_ctrl2_t aif_ctrl2) +{ + reg_write(portnum, R4, (uint8_t*)&aif_ctrl2, sizeof(aif_ctrl2)); +} + +wm8523_aif_ctrl2_t wm8523_get_aif_ctrl2(uint8_t portnum) +{ + wm8523_aif_ctrl2_t aif_ctrl2; + + reg_read(portnum, R4, (uint8_t*)&aif_ctrl2, sizeof(aif_ctrl2)); + + return aif_ctrl2; +} + +void wm8523_set_dac_ctrl3(uint8_t portnum, wm8523_dac_ctrl3_t dac_ctrl3) +{ + reg_write(portnum, R5, (uint8_t*)&dac_ctrl3, sizeof(dac_ctrl3)); +} + +wm8523_dac_ctrl3_t wm8523_get_dac_ctrl3(uint8_t portnum) +{ + wm8523_dac_ctrl3_t dac_ctrl3; + + reg_read(portnum, R5, (uint8_t*)&dac_ctrl3, sizeof(dac_ctrl3)); + + return dac_ctrl3; +} + +#include "dma.h" +#include + +extern volatile uint8_t *I2STXBuffer, *I2SRXBuffer; +extern volatile uint32_t I2SReadLength; +extern volatile uint32_t I2SWriteLength; +extern volatile uint32_t I2SRXDone, I2STXDone; +extern volatile uint32_t I2SDMA0Done, I2SDMA1Done; + +short signal(int x) { - // spi_init(); + static short v = 0; + if((x / 1000) % 2) v++; + else v--; + return x % 0xffff; +} + +#if 0 +// +// Sine approximation using taylor series +// http://en.wikipedia.org/wiki/Taylor_series +// +#define M_PI 3.14159265359 +float expand(float x, int e) +{ + + int fak = 1; + while(e) { + x *= x; + fak *= e; + e--; + } - uint16_t id = WM8523_read(0); // Read chip id from reg0. - (void)id; - // cli_write("=%d=", id); // should be 34595 (0x8523) + return x / (float)fak; } -#endif/*0*/ +float _sin(float x) +{ + return x - expand(x, 3) + expand(x, 5) - expand(x, 7); +} +#endif + +#include "../src/sample.h" + +void wm8523_tone() +{ + // I2SSTATE 0x400A 8010 + // bit 16-19 Reflects the current level of the Transmit FIFO. + uint32_t *i2sstate = (uint32_t *)0x400a8010; + (void)i2sstate; + + // I2STXFIFO 0x400A 8008 + // 8 × 32-bit transmit FIFO. + uint32_t *i2stxfifo = (uint32_t*)0x400a8008; + + // Not DMA mode, enable I2S interrupts. + NVIC_EnableIRQ(I2S_IRQn); + + // RX FIFO depth is 1, TX FIFO depth is 8. + I2SStart(); + LPC_I2S->I2SIRQ = (8 << 16) | (1 << 8) | (0x01 << 0); + + //uint32_t val = 0; + uint32_t cnt = 0; + while(1) { + while((*i2sstate & (0b1111 << 16)) != 0) { } + + *i2stxfifo = samples[(cnt ++) % sizeof(samples)]; + } + + +#if 0 + int i; + + short *pcm = (short*)I2STXBuffer; + + /// Configure temp register before reading + int pcm_size = BUFSIZE / sizeof(short) / 2; // 2 channels + for ( i = 0; i < pcm_size; i++ ) { // Clear buffer + //float s = _sin((float)i / 44100 * 2 * M_PI * 440); + short s = signal(i); + pcm[2 * i] = s * 1234567890;//s * 32000;//samples[i]; + pcm[2 * i + 1] = s * 1234567890;//s * 32000;//samples[i]; + //I2SRXBuffer[i] = 0; + } + + // I2SInit(); // Initialize I2S + + #if I2S_DMA_ENABLED + DMA_Init(); + + // Select secondary function(I2S) in DMA channels + LPC_SC->DMAREQSEL = (0x1<DMACCConfig |= (0x18001|(0x00<<1)|(DMA_I2S_REQ0<<6)|(0x01<<11)); + + //DMAChannel_Init( 1, P2M ); + // LPC_GPDMACH1->CConfig |= (0x08001|(DMA_I2S_REQ1<<1)|(0x00<<6)|(0x02<<11)); + + NVIC_EnableIRQ(DMA_IRQn); + + I2SStart(); + + // Channel 2 is for RX, enable RX first. + //LPC_I2S->I2SDMA2 = (0x01<<0) | (0x08<<8); + + // Channel 1 is for TX. + LPC_I2S->I2SDMA1 = (0x01<<1) | (0x01<<16); + + // Wait for both DMA0 and DMA1 to finish before verifying. + while(!I2SDMA0Done/* || !I2SDMA1Done*/); +#else + + // this does not compile + + // Not DMA mode, enable I2S interrupts. + NVIC_EnableIRQ(I2S_IRQn); + + // RX FIFO depth is 1, TX FIFO depth is 8. + I2SStart(); + LPC_I2S->I2SIRQ = (8 << 16) | (1 << 8) | (0x01 << 0); + + while(I2SWriteLength < BUFSIZE) { + while (((LPC_I2S->I2SSTATE >> 16) & 0xFF) == TXFIFO_FULL); + LPC_I2S->I2STXFIFO = I2STXBuffer[I2SWriteLength++]; + } + + I2STXDone = 1; + + // Wait for RX and TX complete before comparison + while(!I2SRXDone || !I2STXDone); +#endif + /* + // Validate TX and RX buffer + for(i=1; i -void WM8523_init(); -void WM8523_configure(); -uint16_t WM8523_read(uint8_t reg); -void WM8523_write(uint8_t reg, uint16_t data); + +typedef enum { + WM8523_FS_8K, + WM8523_FS_32K, + WM8523_FS_44K1, + WM8523_FS_48K, + WM8523_FS_88K2, + WM8523_FS_96K, + WM8523_FS_176K4, + WM8523_FS_192K, +} wm8523_samplerate_t; +/** + * Prepare I2S, SSP and GPIO. + */ +void wm8523_init(uint8_t portnum, wm8523_samplerate_t fs); + +/** + * Read chip ID. + * Is always 0x8523 + * Register: R0 [0:15] (read) + * Default: 1000 0101 0010 0011 + */ +#define WM8532_CHIP_ID 0b1000010100100011 +unsigned short wm8523_get_chip_id(uint8_t portnum); + +/** + * Reset all register values to their defaults. + * Register: R0 [0:15] (write) + */ +void wm8523_reset_registers(uint8_t portnum); + +/** + * Read hardware revision counter. + * Register: R1 [0:2] (read) + */ +uint8_t wm8523_get_hardware_revision(uint8_t portnum); + +typedef enum __attribute__ ((packed)) { + WM8523_PWR_OFF = 0b00, + WM8523_PWR_POWER_DOWN = 0b01, + WM8523_PWR_POWER_UP_TO_MUTE = 0b10, + WM8523_PWR_POWER_UP_TO_UNMUTE = 0b11, +} wm8523_power_mode_t; + +/** + * Get current power mode. + * Register: R2 [0:1] (read) + */ +wm8523_power_mode_t wm8523_get_power_mode(uint8_t portnum); + +/** + * Set power mode. + * Register: R2 [0:1] (write) + */ +void wm8523_set_power_mode(uint8_t portnum, wm8523_power_mode_t mode); + +/* +R3 [0:1] +Audio Data Interface Format +00 = Right justified +01 = Left justified +10 = I2S format +11 = DSP mode +*/ +typedef enum __attribute__ ((packed)) { + WM8523_FMT_RIGHT = 0b00, // Right justified + WM8523_FMT_LEFT = 0b01, // Left justified + WM8523_FMT_I2S = 0b10, // I2S format + WM8523_FMT_DSP = 0b11, // DSP mode +} wm8523_audio_data_interface_format_t; + +/* +R3 [3:4] +Audio Data Word Length +00 = 16 bits +01 = 20 bits +10 = 24 bits +11 = 32 bits +*/ +typedef enum __attribute__ ((packed)) { + WM8523_WLEN_16 = 0b00, // 16 bit word length + WM8523_WLEN_20 = 0b01, // 20 bit word length + WM8523_WLEN_24 = 0b10, // 24 bit word length + WM8523_WLEN_32 = 0b11, // 32 bit word length +} wm8523_audio_data_word_length_t; + +/* +R3 [5] +BCLK Inversion Control +Slave mode: +0 = Use rising edge +1 = Use falling edge +Master mode: +0 = BCLK normal +1 = BCLK inverted +*/ +typedef enum __attribute__ ((packed)) { + // Slave mode: + WM8523_INVCTL_SLAVE_RISING = 0b0, // Use rising edge + WM8523_INVCTL_SLAVE_FALLING = 0b1, // Use falling edge + + // Master mode: + WM8523_INVCTL_MASTER_NORMAL = 0b0, // BCLK normal + WM8523_INVCTL_MASTER_INVERTED = 0b1, // BCLK inverted +} wm8523_bclk_inversion_control_t; + +/* +R3 [6] +LRCLK Inversion Control +0 = Normal polarity +1 = Inverted polarity +When AIF_FMT[2:0]=011 (DSP Mode): +0 = Mode A (2nd clock) +1 = Mode B (1st clock) +*/ +typedef enum __attribute__ ((packed)) { + // Slave mode: + WM8523_LRCLKINVCTL_SLAVE_NORMAL = 0b0, // Normal polarity + WM8523_LRCLKINVCTL_SLAVE_INVERTED = 0b1, // Inverted polarity + + // Master mode: + WM8523_LRCLKINVCTL_MASTER_MODE_A = 0b0, // Mode A (2nd clock) + WM8523_LRCLKINVCTL_MASTER_MODE_B = 0b1, // Mode B (1st clock) +} wm8523_lrclk_inversion_control_t; + +/* +R3 [7] +Master/Slave Select +0 = Slave mode +1 = Master mode +*/ +typedef enum __attribute__ ((packed)) { + WM8523_MODESEL_SLAVE = 0b0, // Slave mode + WM8523_MODESEL_MASTER = 0b1, // Master mode +} wm8523_slave_master_mode_sel_t; + +/* +R3 [8] +DAC De-emphasis Control +0 = No de-emphasis +1 = De-emphasis enabled +*/ +typedef enum __attribute__ ((packed)) { + WM8523_DEEMPH_DISABLED = 0b0, // No de-emphasis + WM8523_DEEMPH_ENABLED = 0b1, // De-emphasis enabled +} wm8523_dac_deemphasis_control_t; + +typedef struct __attribute__ ((packed)) { + wm8523_audio_data_interface_format_t fmt:2; + int reserved:1; + wm8523_audio_data_word_length_t wlen:2; + wm8523_bclk_inversion_control_t invctl:1; + wm8523_lrclk_inversion_control_t lrclkinvctl:1; + wm8523_slave_master_mode_sel_t modesel:1; + wm8523_dac_deemphasis_control_t deemp:1; + uint16_t blank:7; +} wm8523_aif_ctrl1_t; + +void wm8523_set_aif_ctrl1(uint8_t portnum, wm8523_aif_ctrl1_t aif_ctrl1); +wm8523_aif_ctrl1_t wm8523_get_aif_ctrl1(uint8_t portnum); + +/* +R4 [0:2] +MCLK:LRCLK Ratio +000 = Auto detect +001 = 128fs +010 = 192fs +011 = 256fs +100 = 384fs +101 = 512fs +110 = 768fs +111 = 1152fs +*/ +typedef enum __attribute__ ((packed)) { + WM8523_CLKRATIO_AUTO = 0b000, // Auto detect + WM8523_CLKRATIO_128_FS = 0b001, // 128fs + WM8523_CLKRATIO_192_FS = 0b010, // 192fs + WM8523_CLKRATIO_256_FS = 0b011, // 256fs + WM8523_CLKRATIO_384_FS = 0b100, // 384fs + WM8523_CLKRATIO_512_FS = 0b101, // 512fs + WM8523_CLKRATIO_768_FS = 0b110, // 768fs + WM8523_CLKRATIO_1152_FS = 0b111, // 1152fs +} wm8523_mclk_lrclk_ratio_t; + +/* +R4 [3:5] +BCLK Divider Control (Master Mode) +000 = MCLK/4 +001 = MCLK/8 +010 = 32fs +011 = 64fs +100 = 128fs +101 - 111 reserved +*/ +typedef enum __attribute__ ((packed)) { + WM8523_CLKDIV_MCLK_4 = 0b000, // MCLK/4 + WM8523_CLKDIV_MCLK_8 = 0b001, // MCLK/8 + WM8523_CLKDIV_32_FS = 0b010, // 32fs + WM8523_CLKDIV_64_FS = 0b011, // 64fs + WM8523_CLKDIV_128_FS = 0b100, // 128fs +} wm8523_bclk_divider_control_t; + +/* +R4 [6:7] +Digital Monomix Control +00 = Stereo (normal operation) +01 = Mono (Left data to DACR) +10 = Mono (Right data to DACL) +11 = Digital monomix, (L+R)/2 +*/ +typedef enum __attribute__ ((packed)) { + WM8523_MIX_STEREO = 0b00, // Stereo (normal operation) + WM8523_MIX_MONO_LEFT = 0b01, // Mono (Left data to DACR) + WM8523_MIX_MONO_RIGHT = 0b10, // Mono (Right data to DACL) + WM8523_MIX_MONO_MIXED = 0b11, // Digital monomix, (L+R)/2 +} wm8523_digital_monomix_control_t; + +typedef struct __attribute__ ((packed)) { + wm8523_mclk_lrclk_ratio_t clkratio:3; + wm8523_bclk_divider_control_t clkdiv:3; + wm8523_digital_monomix_control_t mix:2; +} wm8523_aif_ctrl2_t; + +void wm8523_set_aif_ctrl2(uint8_t portnum, wm8523_aif_ctrl2_t aif_ctrl2); +wm8523_aif_ctrl2_t wm8523_get_aif_ctrl2(uint8_t portnum); + +/* +R5 [0] +DAC Digital Volume Decrease Control +0 = Apply volume decreases instantly (step) +1 = Ramp volume decreases +*/ +typedef enum __attribute__ ((packed)) { + WM8523_VOL_DOWN_RAMP = 0b00, // Apply volume decreases instantly (step) + WM8523_VOL_DOWN_INSTANT = 0b01, // Ramp volume decreases +} wm8523_dac_vol_down_ramp_t; + +/* +R5 [1] +DAC Digital Volume Increase Control +0 = Apply volume increases instantly (step) +1 = Ramp volume increases +*/ +typedef enum __attribute__ ((packed)) { + WM8523_VOL_UP_RAMP = 0b00, // Apply volume increases instantly (step) + WM8523_VOL_UP_INSTANT = 0b01, // Ramp volume increases +} wm8523_dac_vol_up_ramp_t; + +/* +R5 [2] +Left DAC Mute +0 = Normal operation +1 = Mute +*/ +typedef enum __attribute__ ((packed)) { + WM8523_DACL_UNMUTE = 0b00, // Normal operation + WM8523_DACL_MUTE = 0b01, // Mute +} wm8523_dacl_mute_t; + +/* +R5 [3] +Right DAC Mute +0 = Normal operation +1 = Mute +*/ +typedef enum __attribute__ ((packed)) { + WM8523_DACR_UNMUTE = 0b00, // Normal operation + WM8523_DACR_MUTE = 0b01, // Mute +} wm8523_dacr_mute_t; + +/* +R5 [4] +Zero Cross Enable +0 = Do not use zero cross +1 = Use zero cross +*/ +typedef enum __attribute__ ((packed)) { + WM8523_ZERO_CROSSING_DISABLED = 0b00, // Do not use zero cross + WM8523_ZERO_CROSSING_ENABLED = 0b01, // Use zero cross +} wm8523_dac_zc_t; + +typedef struct __attribute__ ((packed)) { + wm8523_dac_vol_down_ramp_t downramp:1; + wm8523_dac_vol_up_ramp_t upramp:1; + wm8523_dacl_mute_t lmute:1; + wm8523_dacr_mute_t rmute:1; + wm8523_dac_zc_t dac_zc:1; +} wm8523_dac_ctrl3_t; + +void wm8523_set_dac_ctrl3(uint8_t portnum, wm8523_dac_ctrl3_t dac_ctrl3); +wm8523_dac_ctrl3_t wm8523_get_dac_ctrl3(uint8_t portnum); + +/* +R6 [0:8] +Left DAC Digital Volume Control +0 0000 0000 = -100dB +0 0000 0001 = -99.75dB +0 0000 0010 = -99.5dB +...0.25dB steps +1 1001 0000 = 0dB +...0.25dB steps +1 1011 1110 = +11.75dB +1 11XX XXXX = +12dB +*/ + +/* +R6 [9] +Left DAC Digital Volume Update +0 = Latch Left DAC volume setting into register map but do not update volume +1 = Latch Left DAC volume setting into register map and update left and right channels simultaneously +*/ + +/* +R7 [0:8] +Right DAC Digital Volume Control +0 0000 0000 = -100dB +0 0000 0001 = -99.75dB +0 0000 0010 = -99.5dB +...0.25dB steps +1 1001 0000 = 0dB +...0.25dB steps +1 1011 1110 = +11.75dB +1 11XX XXXX = +12dB +*/ + +/* +R7 [9] +Right DAC Digital Volume Update +0 = Latch Right DAC volume setting into register map but do not update volume +1 = Latch Right DAC volume setting into register map and update left and right channels simultaneously +*/ + +/* +R8 [0] +Zero Detect Count Control +0 = 1024 +1 = 2048 +*/ + + +void wm8523_tone(); + +//void wm8523_configure(); +//uint16_t wm8523_read(uint8_t reg); +//void wm8523_write(uint8_t reg, uint16_t data); #endif/*__PEDAL2METAL_WM8523_H__*/ diff --git a/firmware/src/p2m.c b/firmware/src/p2m.c index d44a01c..aa5250d 100644 --- a/firmware/src/p2m.c +++ b/firmware/src/p2m.c @@ -9,8 +9,8 @@ //#define IRQ_BLINKY //#define BLINKY //#define BLINKY -//#define WM8523 -#define SPI +#define WM8523 +//#define SPI #ifdef DMA @@ -136,7 +136,8 @@ int main (void) #ifdef WM8523 -#include +#include +#include #include #include @@ -147,20 +148,92 @@ int main (void) LED_Init(); - _delay(1 << 22); + uint8_t portnum = 0; + + wm8523_init(portnum, WM8523_FS_44K1); + + if(wm8523_get_chip_id(portnum) != WM8532_CHIP_ID) goto fail; - WM8523_init(); + wm8523_reset_registers(portnum); - _delay(1 << 22); + wm8523_power_mode_t pwr = WM8523_PWR_POWER_UP_TO_UNMUTE; + wm8523_set_power_mode(portnum, pwr); - WM8523_configure(); + wm8523_aif_ctrl1_t ctl1; + ctl1.fmt = WM8523_FMT_I2S; + ctl1.wlen = WM8523_WLEN_32; + ctl1.invctl = WM8523_INVCTL_SLAVE_RISING; + ctl1.lrclkinvctl = WM8523_LRCLKINVCTL_SLAVE_NORMAL; + ctl1.modesel = WM8523_MODESEL_SLAVE; + ctl1.deemp = WM8523_DEEMPH_ENABLED; + wm8523_set_aif_ctrl1(portnum, ctl1); + + wm8523_aif_ctrl2_t ctl2; + ctl2.clkratio = WM8523_CLKRATIO_AUTO; + ctl2.clkdiv = WM8523_CLKDIV_MCLK_4; + ctl2.mix = WM8523_MIX_STEREO; + wm8523_set_aif_ctrl2(portnum, ctl2); + + wm8523_dac_ctrl3_t ctl3; + ctl3.downramp = WM8523_VOL_DOWN_INSTANT; + ctl3.upramp = WM8523_VOL_UP_INSTANT; + ctl3.lmute = WM8523_DACL_UNMUTE; + ctl3.rmute = WM8523_DACR_UNMUTE; + ctl3.dac_zc = WM8523_ZERO_CROSSING_DISABLED; + wm8523_set_dac_ctrl3(portnum, ctl3); + + /* + // Init SPI + GPIOSetDir(0, 16, 1); + GPIOSetValue(0, 16, 1); + + SSP0Init(); + + uint8_t src_addr[16]; //16 byte Write buffer + uint8_t portnum = 0; + + // Set bitwidth to 16 + // Set interface format to I2S + GPIOSetValue(0, 16, 0); + src_addr[0] = 0x0 << 7 | 0x3; // write bit (0) | register 3 + src_addr[1] = + 0x2 << 0 | // Set I2S mode + 0x0 << 2 | // Reserved + 0x0 << 3; // Set 16 bit + // The rest are 0 as default which is correct + + SSPSend(portnum, (uint8_t *)src_addr, 2); + GPIOSetValue(0, 16, 1); + + _delay(1 << 5); + + // Power up and unmute + GPIOSetValue(0, 16, 0); + src_addr[0] = 0x0 << 7 | 0x2; // write bit (0) | register 2 (power register) + src_addr[1] = 0x2; // Set power mode: "power up and unmute" + SSPSend(portnum, (uint8_t *)src_addr, 2); + GPIOSetValue(0, 16, 1); + */ + + + //wm8523_init(); + + // WM8523_configure(); + + //_delay(1 << 5); + + wm8523_tone(); // Indicate that we didn't crash before the end... - int i = 0; - while(1) { + while(1) { // slow blink LED_toggle(); _delay(1 << 21); - i = 1 - i; + } + +fail: + while(1) { // fast blink + LED_toggle(); + _delay(1 << 17); } } diff --git a/firmware/src/sample.h b/firmware/src/sample.h index 8ac9f46..5d96ba7 100644 --- a/firmware/src/sample.h +++ b/firmware/src/sample.h @@ -27,6 +27,8 @@ short samples[] = { 444, 367, 346, +}; +#if 0 408, 394, 330, @@ -1106,3 +1108,5 @@ short samples[] = { 486, 485 }; + +#endif -- cgit v1.2.3