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@14:bdf11487a94b, 2016-05-15 (annotated)
- Committer:
- shorie
- Date:
- Sun May 15 07:00:34 2016 +0000
- Revision:
- 14:bdf11487a94b
- Parent:
- 3:707608830793
- Child:
- 15:76871e578c10
working on Quick Start LPC4088
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
shorie | 0:5ac19c994288 | 1 | #include "unzen_hal.h" |
shorie | 0:5ac19c994288 | 2 | |
shorie | 0:5ac19c994288 | 3 | namespace unzen |
shorie | 0:5ac19c994288 | 4 | { |
shorie | 0:5ac19c994288 | 5 | // Set up I2S peripheral to ready to start. |
shorie | 0:5ac19c994288 | 6 | // By this HAL, the I2S have to become : |
shorie | 0:5ac19c994288 | 7 | // - slave mode |
shorie | 0:5ac19c994288 | 8 | // - clock must be ready |
shorie | 2:6613e62da521 | 9 | void hal_i2s_setup(void) |
shorie | 0:5ac19c994288 | 10 | { |
shorie | 14:bdf11487a94b | 11 | // Setup Audio Power |
shorie | 14:bdf11487a94b | 12 | LPC_SC->PCONP |=( 1<<27 ); // set PCOMP.I2S |
shorie | 2:6613e62da521 | 13 | |
shorie | 0:5ac19c994288 | 14 | // Assert DAI reset |
shorie | 14:bdf11487a94b | 15 | LPC_I2S->DAO |= 1 << 4; // I2S_DAI_RESET; |
shorie | 14:bdf11487a94b | 16 | LPC_I2S->DAI |= 1 << 4; // I2S_DAI_RESET; |
shorie | 0:5ac19c994288 | 17 | // Deassert DAI reset |
shorie | 14:bdf11487a94b | 18 | LPC_I2S->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET; |
shorie | 14:bdf11487a94b | 19 | LPC_I2S->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET; |
shorie | 0:5ac19c994288 | 20 | // Assert DAI stop |
shorie | 14:bdf11487a94b | 21 | LPC_I2S->DAO |= 1 << 3; // I2S_DAI_STOP; |
shorie | 14:bdf11487a94b | 22 | LPC_I2S->DAI |= 1 << 3; // I2S_DAI_STOP; |
shorie | 0:5ac19c994288 | 23 | |
shorie | 0:5ac19c994288 | 24 | // Kill all DMA |
shorie | 14:bdf11487a94b | 25 | LPC_I2S->DMA2 = 0; |
shorie | 14:bdf11487a94b | 26 | LPC_I2S->DMA1 = 0; |
shorie | 0:5ac19c994288 | 27 | // Kill all IRQ |
shorie | 14:bdf11487a94b | 28 | LPC_I2S->IRQ = 0; |
shorie | 0:5ac19c994288 | 29 | // Kill all clocks |
shorie | 14:bdf11487a94b | 30 | LPC_I2S->RXRATE = 0; |
shorie | 14:bdf11487a94b | 31 | LPC_I2S->TXRATE = 0; |
shorie | 0:5ac19c994288 | 32 | // Bit rate must be 0 for slave mode. |
shorie | 14:bdf11487a94b | 33 | LPC_I2S->RXBITRATE = 0; |
shorie | 14:bdf11487a94b | 34 | LPC_I2S->TXBITRATE = 0; |
shorie | 0:5ac19c994288 | 35 | // Clear mode setting |
shorie | 14:bdf11487a94b | 36 | LPC_I2S->TXMODE = 0; |
shorie | 14:bdf11487a94b | 37 | LPC_I2S->RXMODE = 0; |
shorie | 0:5ac19c994288 | 38 | |
shorie | 0:5ac19c994288 | 39 | |
shorie | 0:5ac19c994288 | 40 | // Configure DA0 |
shorie | 14:bdf11487a94b | 41 | LPC_I2S->DAO = |
shorie | 0:5ac19c994288 | 42 | 3 << 0 | // word width, 3:32bit mode |
shorie | 0:5ac19c994288 | 43 | 0 << 2 | // Mono, 1:mono, 0:stereo |
shorie | 0:5ac19c994288 | 44 | 1 << 3 | // STOP, 1:stop |
shorie | 0:5ac19c994288 | 45 | 0 << 4 | // RESET, 1:reset |
shorie | 0:5ac19c994288 | 46 | 1 << 5 | // WSEL, 1:Slave, 0:Master |
shorie | 0:5ac19c994288 | 47 | 1 << 6 ; // MUTE, 1:mute, 0:normal |
shorie | 0:5ac19c994288 | 48 | |
shorie | 0:5ac19c994288 | 49 | // Configure DAI |
shorie | 14:bdf11487a94b | 50 | LPC_I2S->DAI = |
shorie | 0:5ac19c994288 | 51 | 3 << 0 | // word width, 3:32bit mode |
shorie | 0:5ac19c994288 | 52 | 0 << 2 | // Mono, 1:mono, 0:stereo |
shorie | 0:5ac19c994288 | 53 | 1 << 3 | // STOP, 1:stop |
shorie | 0:5ac19c994288 | 54 | 0 << 4 | // RESET, 1:reset |
shorie | 0:5ac19c994288 | 55 | 1 << 5 | // WSEL, 1:Slave, 0:Master |
shorie | 0:5ac19c994288 | 56 | 31 << 6; // WS halfperiod. Not sure what I shoud do when the slave mode. |
shorie | 0:5ac19c994288 | 57 | |
shorie | 0:5ac19c994288 | 58 | // Configure IRQ At this moment, IRQ is disabled. |
shorie | 14:bdf11487a94b | 59 | LPC_I2S->IRQ = |
shorie | 0:5ac19c994288 | 60 | 0 << 0 | // RX IRQ Enable, 1:Enable, 0:Disable |
shorie | 0:5ac19c994288 | 61 | 0 << 1 | // TX IRQ Enable, 1:Enable, 0:Disable |
shorie | 0:5ac19c994288 | 62 | 2 << 8 | // RX DEPTH IRQ length for triggering interrupt |
shorie | 0:5ac19c994288 | 63 | 0 << 16 ; // TX DEPTH IRQ length for triggering interrupt |
shorie | 0:5ac19c994288 | 64 | |
shorie | 0:5ac19c994288 | 65 | // Set RX module as slave operation to the external signal |
shorie | 14:bdf11487a94b | 66 | LPC_I2S->RXMODE = |
shorie | 0:5ac19c994288 | 67 | 0 << 0 | // RXCLKSEL, 0:SCLK input. The reference manual says this is fractional devider, but in slave mode, it is SCLK. |
shorie | 0:5ac19c994288 | 68 | 0 << 2 | // RX4PIN, 1:4pin mode, 0:Clock by RX block itself |
shorie | 0:5ac19c994288 | 69 | 0 << 3 ; // RXMCENA, 1:Master clock output, 0:No output |
shorie | 0:5ac19c994288 | 70 | |
shorie | 0:5ac19c994288 | 71 | // SEt TX module as slave operation to the RX module (4PIN mode ) |
shorie | 14:bdf11487a94b | 72 | LPC_I2S->TXMODE = |
shorie | 0:5ac19c994288 | 73 | 0 << 0 | // TXCLKSEL, 0:SCLK input. Ignored by 4 pin mode. |
shorie | 0:5ac19c994288 | 74 | 1 << 2 | // TX4PIN, 1:4pin mode, 0:Clock by TX block itself |
shorie | 0:5ac19c994288 | 75 | 0 << 3 ; // TXMCENA, 1:Master clock output, 0:No output |
shorie | 0:5ac19c994288 | 76 | |
shorie | 0:5ac19c994288 | 77 | |
shorie | 2:6613e62da521 | 78 | // Fill up tx FIO by 3 stereo samples. |
shorie | 2:6613e62da521 | 79 | hal_put_i2s_tx_data( 0 ); // left |
shorie | 2:6613e62da521 | 80 | hal_put_i2s_tx_data( 0 ); // right |
shorie | 2:6613e62da521 | 81 | hal_put_i2s_tx_data( 0 ); // left |
shorie | 2:6613e62da521 | 82 | hal_put_i2s_tx_data( 0 ); // right |
shorie | 2:6613e62da521 | 83 | hal_put_i2s_tx_data( 0 ); // left |
shorie | 2:6613e62da521 | 84 | hal_put_i2s_tx_data( 0 ); // right |
shorie | 0:5ac19c994288 | 85 | |
shorie | 0:5ac19c994288 | 86 | } |
shorie | 0:5ac19c994288 | 87 | |
shorie | 2:6613e62da521 | 88 | // Pin configuration and sync with WS signal |
shorie | 2:6613e62da521 | 89 | void hal_i2s_pin_config_and_wait_ws(void) |
shorie | 1:9710fb328a08 | 90 | { |
shorie | 14:bdf11487a94b | 91 | // See UM10562 LPC408x UM Rev 3 section 7.4.1 |
shorie | 14:bdf11487a94b | 92 | // See https://developer.mbed.org/platforms/EA-LPC4088/#pinout |
shorie | 14:bdf11487a94b | 93 | // See mbed src lpc43xx.h http://preview.tinyurl.com/lpc408xh |
shorie | 14:bdf11487a94b | 94 | |
shorie | 14:bdf11487a94b | 95 | // P0_4 RS_CLK ( P34 of QS LPC4088 ) |
shorie | 14:bdf11487a94b | 96 | // P0_5 RX_WS ( P33 of QS LPC4088 ) |
shorie | 14:bdf11487a94b | 97 | // P0_6 RX_SDA ( P14 of QS LPC4088 ) |
shorie | 14:bdf11487a94b | 98 | // P0_9 TX_SDA ( P11 of QS LPC4088 ) |
shorie | 2:6613e62da521 | 99 | |
shorie | 14:bdf11487a94b | 100 | unsigned int reserved_p0_mask; |
shorie | 14:bdf11487a94b | 101 | |
shorie | 2:6613e62da521 | 102 | // setup WS pin as GPIO input |
shorie | 14:bdf11487a94b | 103 | LPC_IOCON->P0_5 = |
shorie | 14:bdf11487a94b | 104 | 0 << 0 | // FUNC : GPIO |
shorie | 14:bdf11487a94b | 105 | 0 << 3 | // MODE : No pull up |
shorie | 14:bdf11487a94b | 106 | 0 << 5 | // HYS : No hysterisys |
shorie | 14:bdf11487a94b | 107 | 0 << 6 | // INV : Not invereted input |
shorie | 14:bdf11487a94b | 108 | 0 << 9 | // SLEW : NORMA |
shorie | 14:bdf11487a94b | 109 | 0 << 10 ; // OD : NO Open Drain |
shorie | 14:bdf11487a94b | 110 | |
shorie | 14:bdf11487a94b | 111 | // save the mask register of GPIO 0 |
shorie | 14:bdf11487a94b | 112 | reserved_p0_mask = LPC_GPIO0->MASK; |
shorie | 14:bdf11487a94b | 113 | |
shorie | 14:bdf11487a94b | 114 | // set the P0_5 as input |
shorie | 14:bdf11487a94b | 115 | LPC_GPIO0->DIR &= ~(1<<5); // GPIO0.DIR.bit5 = 0 |
shorie | 14:bdf11487a94b | 116 | |
shorie | 14:bdf11487a94b | 117 | // set the mask register to mask out not relevant bits |
shorie | 14:bdf11487a94b | 118 | LPC_GPIO0->MASK = ~ ( 1<<5 ); // only bit 5 is enabled. P0_5 is I2S\RX_WS |
shorie | 1:9710fb328a08 | 119 | |
shorie | 2:6613e62da521 | 120 | // if WS is 1, wait for WS (GPIO3_0) becomes 0 |
shorie | 14:bdf11487a94b | 121 | while ( LPC_GPIO0->PIN ) |
shorie | 2:6613e62da521 | 122 | ; |
shorie | 2:6613e62da521 | 123 | |
shorie | 2:6613e62da521 | 124 | // and then, if WS is 0, wait for WS (GPIO3_0) becomes 1 |
shorie | 14:bdf11487a94b | 125 | while ( ! LPC_GPIO0->PIN ) |
shorie | 2:6613e62da521 | 126 | ; |
shorie | 14:bdf11487a94b | 127 | |
shorie | 14:bdf11487a94b | 128 | // restore the mask register of GPIO 0 |
shorie | 14:bdf11487a94b | 129 | LPC_GPIO0->MASK = reserved_p0_mask; |
shorie | 2:6613e62da521 | 130 | |
shorie | 2:6613e62da521 | 131 | // Now, we are at the rising edge of WS. |
shorie | 2:6613e62da521 | 132 | // We can setup the I2S without worry of the TX/RX shift. |
shorie | 2:6613e62da521 | 133 | |
shorie | 2:6613e62da521 | 134 | // setup I2S pin configuration. |
shorie | 14:bdf11487a94b | 135 | LPC_IOCON->P0_4 = |
shorie | 14:bdf11487a94b | 136 | 1 << 0 | // FUNC : I2S_RX_SCK |
shorie | 14:bdf11487a94b | 137 | 0 << 3 | // MODE : No pull up |
shorie | 14:bdf11487a94b | 138 | 0 << 5 | // HYS : No hysterisys |
shorie | 14:bdf11487a94b | 139 | 0 << 6 | // INV : Not invereted input |
shorie | 14:bdf11487a94b | 140 | 0 << 9 | // SLEW : NORMAL |
shorie | 14:bdf11487a94b | 141 | 0 << 10 ; // OD : NO Open Drain |
shorie | 14:bdf11487a94b | 142 | LPC_IOCON->P0_5 = |
shorie | 14:bdf11487a94b | 143 | 1 << 0 | // FUNC : I2S_RX_WS |
shorie | 14:bdf11487a94b | 144 | 0 << 3 | // MODE : No pull up |
shorie | 14:bdf11487a94b | 145 | 0 << 5 | // HYS : No hysterisys |
shorie | 14:bdf11487a94b | 146 | 0 << 6 | // INV : Not invereted input |
shorie | 14:bdf11487a94b | 147 | 0 << 9 | // SLEW : NORMAL |
shorie | 14:bdf11487a94b | 148 | 0 << 10 ; // OD : NO Open Drain |
shorie | 14:bdf11487a94b | 149 | LPC_IOCON->P0_6 = |
shorie | 14:bdf11487a94b | 150 | 1 << 0 | // FUNC : I2S_RX_SDA |
shorie | 14:bdf11487a94b | 151 | 0 << 3 | // MODE : No pull up |
shorie | 14:bdf11487a94b | 152 | 0 << 5 | // HYS : No hysterisys |
shorie | 14:bdf11487a94b | 153 | 0 << 6 | // INV : Not invereted input |
shorie | 14:bdf11487a94b | 154 | 0 << 9 | // SLEW : NORMAL |
shorie | 14:bdf11487a94b | 155 | 0 << 10 ; // OD : NO Open Drain |
shorie | 14:bdf11487a94b | 156 | LPC_IOCON->P0_9 = |
shorie | 14:bdf11487a94b | 157 | 1 << 0 | // FUNC : I2S_TX_SDA |
shorie | 14:bdf11487a94b | 158 | 0 << 3 | // MODE : No pull up |
shorie | 14:bdf11487a94b | 159 | 0 << 5 | // HYS : No hysterisys |
shorie | 14:bdf11487a94b | 160 | 0 << 6 | // INV : Not invereted input |
shorie | 14:bdf11487a94b | 161 | 1 << 7 | // AMODE : 1:Digital mode |
shorie | 14:bdf11487a94b | 162 | 1 << 8 | // FILTER : 1:No filter |
shorie | 14:bdf11487a94b | 163 | 0 << 9 | // SLEW : NORMAL |
shorie | 14:bdf11487a94b | 164 | 0 << 10 ; // OD : NO Open Drain |
shorie | 14:bdf11487a94b | 165 | |
shorie | 14:bdf11487a94b | 166 | |
shorie | 1:9710fb328a08 | 167 | } |
shorie | 1:9710fb328a08 | 168 | |
shorie | 1:9710fb328a08 | 169 | |
shorie | 0:5ac19c994288 | 170 | // Start I2S transfer. Interrupt starts |
shorie | 2:6613e62da521 | 171 | void hal_i2s_start(void) |
shorie | 0:5ac19c994288 | 172 | { |
shorie | 0:5ac19c994288 | 173 | //Clear STOP,RESET and MUTE bit |
shorie | 14:bdf11487a94b | 174 | LPC_I2S->DAO &= ~(1 << 3); // release I2S_DAO_STOP; |
shorie | 14:bdf11487a94b | 175 | LPC_I2S->DAI &= ~(1 << 3); // release I2S_DAI_STOP; |
shorie | 2:6613e62da521 | 176 | |
shorie | 14:bdf11487a94b | 177 | LPC_I2S->DAO &= ~(1 << 6); // release I2S_DAO_MUTE; |
shorie | 14:bdf11487a94b | 178 | LPC_I2S->IRQ |= 1 << 0; // set I2S RX IRQ enable |
shorie | 0:5ac19c994288 | 179 | } |
shorie | 0:5ac19c994288 | 180 | |
shorie | 2:6613e62da521 | 181 | IRQn_Type hal_get_i2s_irq_id(void) |
shorie | 0:5ac19c994288 | 182 | { |
shorie | 14:bdf11487a94b | 183 | return I2S_IRQn; |
shorie | 0:5ac19c994288 | 184 | } |
shorie | 0:5ac19c994288 | 185 | |
shorie | 0:5ac19c994288 | 186 | |
shorie | 2:6613e62da521 | 187 | IRQn_Type hal_get_process_irq_id(void) |
shorie | 0:5ac19c994288 | 188 | { |
shorie | 14:bdf11487a94b | 189 | return Reserved0_IRQn; // LPC4088's unsed interrupt |
shorie | 0:5ac19c994288 | 190 | } |
shorie | 0:5ac19c994288 | 191 | |
shorie | 2:6613e62da521 | 192 | |
shorie | 2:6613e62da521 | 193 | // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... |
shorie | 2:6613e62da521 | 194 | unsigned int hal_get_i2s_irq_priority_level(void) |
shorie | 0:5ac19c994288 | 195 | { |
shorie | 2:6613e62da521 | 196 | // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7. |
shorie | 3:707608830793 | 197 | // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( F**k! ) |
shorie | 3:707608830793 | 198 | // So, 7 is heighest, 0 is lowerest in CMSIS. |
shorie | 3:707608830793 | 199 | // setting 6 as i2s irq priority allows, some other interrupts are higher |
shorie | 2:6613e62da521 | 200 | // and some others are lower than i2s irq priority. |
shorie | 3:707608830793 | 201 | return 6; |
shorie | 2:6613e62da521 | 202 | } |
shorie | 2:6613e62da521 | 203 | |
shorie | 2:6613e62da521 | 204 | |
shorie | 2:6613e62da521 | 205 | // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2... |
shorie | 2:6613e62da521 | 206 | unsigned int hal_get_process_irq_priority_level(void) |
shorie | 2:6613e62da521 | 207 | { |
shorie | 2:6613e62da521 | 208 | // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7. |
shorie | 3:707608830793 | 209 | // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( S**t! ) |
shorie | 3:707608830793 | 210 | // So, 7 is heighest, 0 is lowerest in CMSIS. |
shorie | 3:707608830793 | 211 | // setting 1 as process priority allows, some other interrupts are higher |
shorie | 2:6613e62da521 | 212 | // and some other interrupts are lower then process priority. |
shorie | 3:707608830793 | 213 | return 1; |
shorie | 0:5ac19c994288 | 214 | } |
shorie | 0:5ac19c994288 | 215 | |
shorie | 0:5ac19c994288 | 216 | // LPC4337 transferes 2 workd ( left and right ) for each interrupt. |
shorie | 2:6613e62da521 | 217 | unsigned int hal_data_per_sample(void) |
shorie | 0:5ac19c994288 | 218 | { |
shorie | 0:5ac19c994288 | 219 | return 2; |
shorie | 0:5ac19c994288 | 220 | } |
shorie | 0:5ac19c994288 | 221 | |
shorie | 0:5ac19c994288 | 222 | // return true when the sample parameter is ready to read. |
shorie | 0:5ac19c994288 | 223 | // return false when the sample is not ready to read. |
shorie | 2:6613e62da521 | 224 | void hal_get_i2s_rx_data( int & sample) |
shorie | 0:5ac19c994288 | 225 | { |
shorie | 14:bdf11487a94b | 226 | sample = LPC_I2S->RXFIFO; |
shorie | 0:5ac19c994288 | 227 | } |
shorie | 0:5ac19c994288 | 228 | |
shorie | 0:5ac19c994288 | 229 | // put a sample to I2S TX data regisger |
shorie | 2:6613e62da521 | 230 | void hal_put_i2s_tx_data( int sample ) |
shorie | 0:5ac19c994288 | 231 | { |
shorie | 14:bdf11487a94b | 232 | LPC_I2S->TXFIFO = sample; |
shorie | 0:5ac19c994288 | 233 | } |
shorie | 0:5ac19c994288 | 234 | } |
shorie | 0:5ac19c994288 | 235 | |
shorie | 0:5ac19c994288 | 236 |