First Publish. Works fine.

Dependents:   unzen_sample_LPC4088_quickstart

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers unzen_hal.cpp Source File

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