First Publish. Works fine.
Dependents: unzen_sample_LPC4088_quickstart
unzen_hal.cpp
00001 #include "unzen_hal.h" 00002 00003 namespace unzen 00004 { 00005 // Set up I2S peripheral to ready to start. 00006 // By this HAL, the I2S have to become : 00007 // - slave mode 00008 // - clock must be ready 00009 void hal_i2s_setup(void) 00010 { 00011 // Setup Audio Power 00012 LPC_SC->PCONP |=( 1<<27 ); // set PCOMP.I2S 00013 00014 // Assert DAI reset 00015 LPC_I2S->DAO |= 1 << 4; // I2S_DAI_RESET; 00016 LPC_I2S->DAI |= 1 << 4; // I2S_DAI_RESET; 00017 // Deassert DAI reset 00018 LPC_I2S->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET; 00019 LPC_I2S->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET; 00020 // Assert DAI stop 00021 LPC_I2S->DAO |= 1 << 3; // I2S_DAI_STOP; 00022 LPC_I2S->DAI |= 1 << 3; // I2S_DAI_STOP; 00023 00024 // Kill all DMA 00025 LPC_I2S->DMA2 = 0; 00026 LPC_I2S->DMA1 = 0; 00027 // Kill all IRQ 00028 LPC_I2S->IRQ = 0; 00029 // Kill all clocks 00030 LPC_I2S->RXRATE = 0; 00031 LPC_I2S->TXRATE = 0; 00032 // Bit rate must be 0 for slave mode. 00033 LPC_I2S->RXBITRATE = 0; 00034 LPC_I2S->TXBITRATE = 0; 00035 // Clear mode setting 00036 LPC_I2S->TXMODE = 0; 00037 LPC_I2S->RXMODE = 0; 00038 00039 00040 // Configure DA0 00041 LPC_I2S->DAO = 00042 3 << 0 | // word width, 3:32bit mode 00043 0 << 2 | // Mono, 1:mono, 0:stereo 00044 1 << 3 | // STOP, 1:stop 00045 0 << 4 | // RESET, 1:reset 00046 1 << 5 | // WSEL, 1:Slave, 0:Master 00047 1 << 6 ; // MUTE, 1:mute, 0:normal 00048 00049 // Configure DAI 00050 LPC_I2S->DAI = 00051 3 << 0 | // word width, 3:32bit mode 00052 0 << 2 | // Mono, 1:mono, 0:stereo 00053 1 << 3 | // STOP, 1:stop 00054 0 << 4 | // RESET, 1:reset 00055 1 << 5 | // WSEL, 1:Slave, 0:Master 00056 31 << 6; // WS halfperiod. Not sure what I shoud do when the slave mode. 00057 00058 // Configure IRQ At this moment, IRQ is disabled. 00059 LPC_I2S->IRQ = 00060 0 << 0 | // RX IRQ Enable, 1:Enable, 0:Disable 00061 0 << 1 | // TX IRQ Enable, 1:Enable, 0:Disable 00062 2 << 8 | // RX DEPTH IRQ length for triggering interrupt 00063 0 << 16 ; // TX DEPTH IRQ length for triggering interrupt 00064 00065 // Set RX module as slave operation to the external signal 00066 LPC_I2S->RXMODE = 00067 0 << 0 | // RXCLKSEL, 0:SCLK input. The reference manual says this is fractional devider, but in slave mode, it is SCLK. 00068 0 << 2 | // RX4PIN, 1:4pin mode, 0:Clock by RX block itself 00069 0 << 3 ; // RXMCENA, 1:Master clock output, 0:No output 00070 00071 // SEt TX module as slave operation to the RX module (4PIN mode ) 00072 LPC_I2S->TXMODE = 00073 0 << 0 | // TXCLKSEL, 0:SCLK input. Ignored by 4 pin mode. 00074 1 << 2 | // TX4PIN, 1:4pin mode, 0:Clock by TX block itself 00075 0 << 3 ; // TXMCENA, 1:Master clock output, 0:No output 00076 00077 00078 // Fill up tx FIO by 3 stereo samples. 00079 hal_put_i2s_tx_data( 0 ); // left 00080 hal_put_i2s_tx_data( 0 ); // right 00081 hal_put_i2s_tx_data( 0 ); // left 00082 hal_put_i2s_tx_data( 0 ); // right 00083 hal_put_i2s_tx_data( 0 ); // left 00084 hal_put_i2s_tx_data( 0 ); // right 00085 00086 } 00087 00088 // Pin configuration and sync with WS signal 00089 void hal_i2s_pin_config_and_wait_ws(void) 00090 { 00091 // See UM10562 LPC408x UM Rev 3 section 7.4.1 00092 // See https://developer.mbed.org/platforms/EA-LPC4088/#pinout 00093 // See mbed src lpc43xx.h http://preview.tinyurl.com/lpc408xh 00094 00095 // P0_4 RS_CLK ( P34 of QS LPC4088 ) 00096 // P0_5 RX_WS ( P33 of QS LPC4088 ) 00097 // P0_6 RX_SDA ( P14 of QS LPC4088 ) 00098 // P0_9 TX_SDA ( P11 of QS LPC4088 ) 00099 00100 unsigned int reserved_p0_mask; 00101 00102 // setup WS pin as GPIO input 00103 LPC_IOCON->P0_5 = 00104 0 << 0 | // FUNC : GPIO 00105 0 << 3 | // MODE : No pull up 00106 0 << 5 | // HYS : No hysterisys 00107 0 << 6 | // INV : Not invereted input 00108 0 << 9 | // SLEW : NORMA 00109 0 << 10 ; // OD : NO Open Drain 00110 00111 // save the mask register of GPIO 0 00112 reserved_p0_mask = LPC_GPIO0->MASK; 00113 00114 // set the P0_5 as input 00115 LPC_GPIO0->DIR &= ~(1<<5); // GPIO0.DIR.bit5 = 0 00116 00117 // set the mask register to mask out not relevant bits 00118 LPC_GPIO0->MASK = ~ ( 1<<5 ); // only bit 5 is enabled. P0_5 is I2S\RX_WS 00119 00120 // if WS is 1, wait for WS (GPIO3_0) becomes 0 00121 while ( LPC_GPIO0->PIN ) 00122 ; 00123 00124 // and then, if WS is 0, wait for WS (GPIO3_0) becomes 1 00125 while ( ! LPC_GPIO0->PIN ) 00126 ; 00127 00128 // restore the mask register of GPIO 0 00129 LPC_GPIO0->MASK = reserved_p0_mask; 00130 00131 // Now, we are at the rising edge of WS. 00132 // We can setup the I2S without worry of the TX/RX shift. 00133 00134 // setup I2S pin configuration. 00135 LPC_IOCON->P0_4 = 00136 1 << 0 | // FUNC : I2S_RX_SCK 00137 0 << 3 | // MODE : No pull up 00138 0 << 5 | // HYS : No hysterisys 00139 0 << 6 | // INV : Not invereted input 00140 0 << 9 | // SLEW : NORMAL 00141 0 << 10 ; // OD : NO Open Drain 00142 LPC_IOCON->P0_5 = 00143 1 << 0 | // FUNC : I2S_RX_WS 00144 0 << 3 | // MODE : No pull up 00145 0 << 5 | // HYS : No hysterisys 00146 0 << 6 | // INV : Not invereted input 00147 0 << 9 | // SLEW : NORMAL 00148 0 << 10 ; // OD : NO Open Drain 00149 LPC_IOCON->P0_6 = 00150 1 << 0 | // FUNC : I2S_RX_SDA 00151 0 << 3 | // MODE : No pull up 00152 0 << 5 | // HYS : No hysterisys 00153 0 << 6 | // INV : Not invereted input 00154 0 << 9 | // SLEW : NORMAL 00155 0 << 10 ; // OD : NO Open Drain 00156 LPC_IOCON->P0_9 = 00157 1 << 0 | // FUNC : I2S_TX_SDA 00158 0 << 3 | // MODE : No pull up 00159 0 << 5 | // HYS : No hysterisys 00160 0 << 6 | // INV : Not invereted input 00161 1 << 7 | // AMODE : 1:Digital mode 00162 1 << 8 | // FILTER : 1:No filter 00163 0 << 9 | // SLEW : NORMAL 00164 0 << 10 ; // OD : NO Open Drain 00165 00166 00167 } 00168 00169 00170 // Start I2S transfer. Interrupt starts 00171 void hal_i2s_start(void) 00172 { 00173 //Clear STOP,RESET and MUTE bit 00174 LPC_I2S->DAO &= ~(1 << 3); // release I2S_DAO_STOP; 00175 LPC_I2S->DAI &= ~(1 << 3); // release I2S_DAI_STOP; 00176 00177 LPC_I2S->DAO &= ~(1 << 6); // release I2S_DAO_MUTE; 00178 LPC_I2S->IRQ |= 1 << 0; // set I2S RX IRQ enable 00179 } 00180 00181 IRQn_Type hal_get_i2s_irq_id(void) 00182 { 00183 return I2S_IRQn; 00184 } 00185 00186 00187 IRQn_Type hal_get_process_irq_id(void) 00188 { 00189 return Reserved0_IRQn; // LPC4088's unsed interrupt 00190 } 00191 00192 00193 // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... 00194 unsigned int hal_get_i2s_irq_priority_level(void) 00195 { 00196 // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 31. 00197 // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( F**k! ) 00198 // So, 31 is heighest, 0 is lowerest in CMSIS. 00199 // setting 24 as i2s irq priority allows, some other interrupts are higher 00200 // and some others are lower than i2s irq priority. 00201 return 24; 00202 } 00203 00204 00205 // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... 00206 unsigned int hal_get_process_irq_priority_level(void) 00207 { 00208 // LPC4300 has 5 bits priority field. So, heighest is 0, lowest is 31. 00209 // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( S**t! ) 00210 // So, 31 is heighest, 0 is lowerest in CMSIS. 00211 // setting 8 as process priority allows, some other interrupts are higher 00212 // and some other interrupts are lower then process priority. 00213 return 8; 00214 } 00215 00216 // LPC4337 transferes 2 workd ( left and right ) for each interrupt. 00217 unsigned int hal_data_per_sample(void) 00218 { 00219 return 2; 00220 } 00221 00222 // return true when the sample parameter is ready to read. 00223 // return false when the sample is not ready to read. 00224 void hal_get_i2s_rx_data( int & sample) 00225 { 00226 sample = LPC_I2S->RXFIFO; 00227 } 00228 00229 // put a sample to I2S TX data regisger 00230 void hal_put_i2s_tx_data( int sample ) 00231 { 00232 LPC_I2S->TXFIFO = sample; 00233 } 00234 } 00235 00236
Generated on Wed Jul 13 2022 06:48:06 by 1.7.2