First Publish. Works fine.
Dependents: unzen_sample_LPC4088_quickstart
Diff: unzen_hal.cpp
- Revision:
- 14:bdf11487a94b
- Parent:
- 3:707608830793
- Child:
- 15:0db847496bb9
--- a/unzen_hal.cpp Sat May 14 21:37:42 2016 +0000 +++ b/unzen_hal.cpp Sun May 15 07:00:34 2016 +0000 @@ -8,40 +8,37 @@ // - clock must be ready void hal_i2s_setup(void) { - // Setup Audio Clock. Feed the core clock (PLL1, 204Mhz) to audio. - LPC_CGU->BASE_CLK[CLK_BASE_APLL] = - 0 << 1 | // Power down. 1:Power Down, 0:Enabled - 1 <<11 | // Enable auto clocking. 1:Enable. - 9 <<24 ; // 9: PLL1 + // Setup Audio Power + LPC_SC->PCONP |=( 1<<27 ); // set PCOMP.I2S // Assert DAI reset - LPC_I2S0->DAO |= 1 << 4; // I2S_DAI_RESET; - LPC_I2S0->DAI |= 1 << 4; // I2S_DAI_RESET; + LPC_I2S->DAO |= 1 << 4; // I2S_DAI_RESET; + LPC_I2S->DAI |= 1 << 4; // I2S_DAI_RESET; // Deassert DAI reset - LPC_I2S0->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET; - LPC_I2S0->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET; + LPC_I2S->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET; + LPC_I2S->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET; // Assert DAI stop - LPC_I2S0->DAO |= 1 << 3; // I2S_DAI_STOP; - LPC_I2S0->DAI |= 1 << 3; // I2S_DAI_STOP; + LPC_I2S->DAO |= 1 << 3; // I2S_DAI_STOP; + LPC_I2S->DAI |= 1 << 3; // I2S_DAI_STOP; // Kill all DMA - LPC_I2S0->DMA2 = 0; - LPC_I2S0->DMA1 = 0; + LPC_I2S->DMA2 = 0; + LPC_I2S->DMA1 = 0; // Kill all IRQ - LPC_I2S0->IRQ = 0; + LPC_I2S->IRQ = 0; // Kill all clocks - LPC_I2S0->RXRATE = 0; - LPC_I2S0->TXRATE = 0; + LPC_I2S->RXRATE = 0; + LPC_I2S->TXRATE = 0; // Bit rate must be 0 for slave mode. - LPC_I2S0->RXBITRATE = 0; - LPC_I2S0->TXBITRATE = 0; + LPC_I2S->RXBITRATE = 0; + LPC_I2S->TXBITRATE = 0; // Clear mode setting - LPC_I2S0->TXMODE = 0; - LPC_I2S0->RXMODE = 0; + LPC_I2S->TXMODE = 0; + LPC_I2S->RXMODE = 0; // Configure DA0 - LPC_I2S0->DAO = + LPC_I2S->DAO = 3 << 0 | // word width, 3:32bit mode 0 << 2 | // Mono, 1:mono, 0:stereo 1 << 3 | // STOP, 1:stop @@ -50,7 +47,7 @@ 1 << 6 ; // MUTE, 1:mute, 0:normal // Configure DAI - LPC_I2S0->DAI = + LPC_I2S->DAI = 3 << 0 | // word width, 3:32bit mode 0 << 2 | // Mono, 1:mono, 0:stereo 1 << 3 | // STOP, 1:stop @@ -59,20 +56,20 @@ 31 << 6; // WS halfperiod. Not sure what I shoud do when the slave mode. // Configure IRQ At this moment, IRQ is disabled. - LPC_I2S0->IRQ = + LPC_I2S->IRQ = 0 << 0 | // RX IRQ Enable, 1:Enable, 0:Disable 0 << 1 | // TX IRQ Enable, 1:Enable, 0:Disable 2 << 8 | // RX DEPTH IRQ length for triggering interrupt 0 << 16 ; // TX DEPTH IRQ length for triggering interrupt // Set RX module as slave operation to the external signal - LPC_I2S0->RXMODE = + LPC_I2S->RXMODE = 0 << 0 | // RXCLKSEL, 0:SCLK input. The reference manual says this is fractional devider, but in slave mode, it is SCLK. 0 << 2 | // RX4PIN, 1:4pin mode, 0:Clock by RX block itself 0 << 3 ; // RXMCENA, 1:Master clock output, 0:No output // SEt TX module as slave operation to the RX module (4PIN mode ) - LPC_I2S0->TXMODE = + LPC_I2S->TXMODE = 0 << 0 | // TXCLKSEL, 0:SCLK input. Ignored by 4 pin mode. 1 << 2 | // TX4PIN, 1:4pin mode, 0:Clock by TX block itself 0 << 3 ; // TXMCENA, 1:Master clock output, 0:No output @@ -91,31 +88,82 @@ // Pin configuration and sync with WS signal void hal_i2s_pin_config_and_wait_ws(void) { - // See UM10503 LPC4300 UM Rev 2.1 section 16.2.3, chapter 19 - // See https://developer.mbed.org/platforms/LPCXpresso4337/ - // See mbed src lpc43xx.h http://preview.tinyurl.com/lpc43xxh + // See UM10562 LPC408x UM Rev 3 section 7.4.1 + // See https://developer.mbed.org/platforms/EA-LPC4088/#pinout + // See mbed src lpc43xx.h http://preview.tinyurl.com/lpc408xh + + // P0_4 RS_CLK ( P34 of QS LPC4088 ) + // P0_5 RX_WS ( P33 of QS LPC4088 ) + // P0_6 RX_SDA ( P14 of QS LPC4088 ) + // P0_9 TX_SDA ( P11 of QS LPC4088 ) - + unsigned int reserved_p0_mask; + // setup WS pin as GPIO input - LPC_SCU->SFSP[6][1] = SCU_MODE_INBUFF_EN; // P6_1, function 0. GPIO3[0] + LPC_IOCON->P0_5 = + 0 << 0 | // FUNC : GPIO + 0 << 3 | // MODE : No pull up + 0 << 5 | // HYS : No hysterisys + 0 << 6 | // INV : Not invereted input + 0 << 9 | // SLEW : NORMA + 0 << 10 ; // OD : NO Open Drain + + // save the mask register of GPIO 0 + reserved_p0_mask = LPC_GPIO0->MASK; + + // set the P0_5 as input + LPC_GPIO0->DIR &= ~(1<<5); // GPIO0.DIR.bit5 = 0 + + // set the mask register to mask out not relevant bits + LPC_GPIO0->MASK = ~ ( 1<<5 ); // only bit 5 is enabled. P0_5 is I2S\RX_WS // if WS is 1, wait for WS (GPIO3_0) becomes 0 - while ( LPC_GPIO_PORT->B[3][0] == 1 ) + while ( LPC_GPIO0->PIN ) ; // and then, if WS is 0, wait for WS (GPIO3_0) becomes 1 - while ( LPC_GPIO_PORT->B[3][0] == 0 ) + while ( ! LPC_GPIO0->PIN ) ; + + // restore the mask register of GPIO 0 + LPC_GPIO0->MASK = reserved_p0_mask; // Now, we are at the rising edge of WS. // We can setup the I2S without worry of the TX/RX shift. // setup I2S pin configuration. - // for input, bit 6 have to be 1 ( input buffer enable ) - LPC_SCU->SFSP[3][5] = 5; // P3_5, function 5. IS20_TX_SDA - LPC_SCU->SFSP[6][0] = 4 | SCU_MODE_INBUFF_EN; // P6_0, function 4. IS20_RX_SCK - LPC_SCU->SFSP[6][1] = 3 | SCU_MODE_INBUFF_EN; // P6_1, function 3. IS20_RX_WS - LPC_SCU->SFSP[3][2] = 1 | SCU_MODE_INBUFF_EN; // P3_2, function 1. IS20_RX_SDA + LPC_IOCON->P0_4 = + 1 << 0 | // FUNC : I2S_RX_SCK + 0 << 3 | // MODE : No pull up + 0 << 5 | // HYS : No hysterisys + 0 << 6 | // INV : Not invereted input + 0 << 9 | // SLEW : NORMAL + 0 << 10 ; // OD : NO Open Drain + LPC_IOCON->P0_5 = + 1 << 0 | // FUNC : I2S_RX_WS + 0 << 3 | // MODE : No pull up + 0 << 5 | // HYS : No hysterisys + 0 << 6 | // INV : Not invereted input + 0 << 9 | // SLEW : NORMAL + 0 << 10 ; // OD : NO Open Drain + LPC_IOCON->P0_6 = + 1 << 0 | // FUNC : I2S_RX_SDA + 0 << 3 | // MODE : No pull up + 0 << 5 | // HYS : No hysterisys + 0 << 6 | // INV : Not invereted input + 0 << 9 | // SLEW : NORMAL + 0 << 10 ; // OD : NO Open Drain + LPC_IOCON->P0_9 = + 1 << 0 | // FUNC : I2S_TX_SDA + 0 << 3 | // MODE : No pull up + 0 << 5 | // HYS : No hysterisys + 0 << 6 | // INV : Not invereted input + 1 << 7 | // AMODE : 1:Digital mode + 1 << 8 | // FILTER : 1:No filter + 0 << 9 | // SLEW : NORMAL + 0 << 10 ; // OD : NO Open Drain + + } @@ -123,22 +171,22 @@ void hal_i2s_start(void) { //Clear STOP,RESET and MUTE bit - LPC_I2S0->DAO &= ~(1 << 3); // release I2S_DAO_STOP; - LPC_I2S0->DAI &= ~(1 << 3); // release I2S_DAI_STOP; + LPC_I2S->DAO &= ~(1 << 3); // release I2S_DAO_STOP; + LPC_I2S->DAI &= ~(1 << 3); // release I2S_DAI_STOP; - LPC_I2S0->DAO &= ~(1 << 6); // release I2S_DAO_MUTE; - LPC_I2S0->IRQ |= 1 << 0; // set I2S RX IRQ enable + LPC_I2S->DAO &= ~(1 << 6); // release I2S_DAO_MUTE; + LPC_I2S->IRQ |= 1 << 0; // set I2S RX IRQ enable } IRQn_Type hal_get_i2s_irq_id(void) { - return I2S0_IRQn; + return I2S_IRQn; } IRQn_Type hal_get_process_irq_id(void) { - return ( IRQn_Type )30; // LPC4300's unsed interrupt + return Reserved0_IRQn; // LPC4088's unsed interrupt } @@ -175,13 +223,13 @@ // return false when the sample is not ready to read. void hal_get_i2s_rx_data( int & sample) { - sample = LPC_I2S0->RXFIFO; + sample = LPC_I2S->RXFIFO; } // put a sample to I2S TX data regisger void hal_put_i2s_tx_data( int sample ) { - LPC_I2S0->TXFIFO = sample; + LPC_I2S->TXFIFO = sample; } }