First Publish. Works fine.
Dependents: unzen_sample_nucleo_f746 unzen_delay_sample_nucleo_f746 skeleton_unzen_nucleo_f746 ifmag_noise_canceller ... more
Nucleo F746ZG用のオーディオ・フレームワークです。フレームワーク地震の詳細は『雲仙』オーディオ・フレームワークを参照してください。
参考リンク
- skeleton_unzen_nucleo_f746 Nucleo F746ZGおよびUI基板を使う場合のスケルトンプログラム。F746を使う方はここから読み始めると良いでしょう。
unzen_hal.cpp
- Committer:
- shorie
- Date:
- 2016-05-15
- Revision:
- 14:bdf11487a94b
- Parent:
- 3:707608830793
- Child:
- 15:76871e578c10
File content as of revision 14:bdf11487a94b:
#include "unzen_hal.h" namespace unzen { // Set up I2S peripheral to ready to start. // By this HAL, the I2S have to become : // - slave mode // - clock must be ready void hal_i2s_setup(void) { // Setup Audio Power LPC_SC->PCONP |=( 1<<27 ); // set PCOMP.I2S // Assert DAI reset LPC_I2S->DAO |= 1 << 4; // I2S_DAI_RESET; LPC_I2S->DAI |= 1 << 4; // I2S_DAI_RESET; // Deassert DAI reset LPC_I2S->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET; LPC_I2S->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET; // Assert DAI stop LPC_I2S->DAO |= 1 << 3; // I2S_DAI_STOP; LPC_I2S->DAI |= 1 << 3; // I2S_DAI_STOP; // Kill all DMA LPC_I2S->DMA2 = 0; LPC_I2S->DMA1 = 0; // Kill all IRQ LPC_I2S->IRQ = 0; // Kill all clocks LPC_I2S->RXRATE = 0; LPC_I2S->TXRATE = 0; // Bit rate must be 0 for slave mode. LPC_I2S->RXBITRATE = 0; LPC_I2S->TXBITRATE = 0; // Clear mode setting LPC_I2S->TXMODE = 0; LPC_I2S->RXMODE = 0; // Configure DA0 LPC_I2S->DAO = 3 << 0 | // word width, 3:32bit mode 0 << 2 | // Mono, 1:mono, 0:stereo 1 << 3 | // STOP, 1:stop 0 << 4 | // RESET, 1:reset 1 << 5 | // WSEL, 1:Slave, 0:Master 1 << 6 ; // MUTE, 1:mute, 0:normal // Configure DAI LPC_I2S->DAI = 3 << 0 | // word width, 3:32bit mode 0 << 2 | // Mono, 1:mono, 0:stereo 1 << 3 | // STOP, 1:stop 0 << 4 | // RESET, 1:reset 1 << 5 | // WSEL, 1:Slave, 0:Master 31 << 6; // WS halfperiod. Not sure what I shoud do when the slave mode. // Configure IRQ At this moment, IRQ is disabled. 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_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_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 // Fill up tx FIO by 3 stereo samples. hal_put_i2s_tx_data( 0 ); // left hal_put_i2s_tx_data( 0 ); // right hal_put_i2s_tx_data( 0 ); // left hal_put_i2s_tx_data( 0 ); // right hal_put_i2s_tx_data( 0 ); // left hal_put_i2s_tx_data( 0 ); // right } // Pin configuration and sync with WS signal void hal_i2s_pin_config_and_wait_ws(void) { // 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_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_GPIO0->PIN ) ; // and then, if WS is 0, wait for WS (GPIO3_0) becomes 1 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. 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 } // Start I2S transfer. Interrupt starts void hal_i2s_start(void) { //Clear STOP,RESET and MUTE bit LPC_I2S->DAO &= ~(1 << 3); // release I2S_DAO_STOP; LPC_I2S->DAI &= ~(1 << 3); // release I2S_DAI_STOP; 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 I2S_IRQn; } IRQn_Type hal_get_process_irq_id(void) { return Reserved0_IRQn; // LPC4088's unsed interrupt } // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... unsigned int hal_get_i2s_irq_priority_level(void) { // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7. // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( F**k! ) // So, 7 is heighest, 0 is lowerest in CMSIS. // setting 6 as i2s irq priority allows, some other interrupts are higher // and some others are lower than i2s irq priority. return 6; } // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... unsigned int hal_get_process_irq_priority_level(void) { // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7. // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( S**t! ) // So, 7 is heighest, 0 is lowerest in CMSIS. // setting 1 as process priority allows, some other interrupts are higher // and some other interrupts are lower then process priority. return 1; } // LPC4337 transferes 2 workd ( left and right ) for each interrupt. unsigned int hal_data_per_sample(void) { return 2; } // return true when the sample parameter is ready to read. // return false when the sample is not ready to read. void hal_get_i2s_rx_data( int & sample) { sample = LPC_I2S->RXFIFO; } // put a sample to I2S TX data regisger void hal_put_i2s_tx_data( int sample ) { LPC_I2S->TXFIFO = sample; } }