First Publish. Works fine.

Dependents:   unzen_sample_lpcxpresso_4337_callbacks

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 Clock. Feed the core clock (PLL1, 204Mhz) to audio.
00012         LPC_CGU->BASE_CLK[CLK_BASE_APLL] = 
00013                             0 << 1 |    // Power down. 1:Power Down, 0:Enabled
00014                             1 <<11 |    // Enable auto clocking. 1:Enable.
00015                             9 <<24 ;    // 9: PLL1
00016             
00017             // Assert DAI reset
00018         LPC_I2S0->DAO |= 1 << 4;    // I2S_DAI_RESET;
00019         LPC_I2S0->DAI |= 1 << 4;    // I2S_DAI_RESET;
00020             // Deassert DAI reset
00021         LPC_I2S0->DAO &= ~ ( 1<<4 ); // I2S_DAI_RESET;
00022         LPC_I2S0->DAI &= ~ ( 1<<4 ); // I2S_DAI_RESET;
00023             // Assert DAI stop
00024         LPC_I2S0->DAO |= 1 << 3;    // I2S_DAI_STOP;
00025         LPC_I2S0->DAI |= 1 << 3;    // I2S_DAI_STOP;
00026                 
00027             // Kill all DMA
00028         LPC_I2S0->DMA2 = 0;
00029         LPC_I2S0->DMA1 = 0;
00030             // Kill all IRQ
00031         LPC_I2S0->IRQ = 0;
00032             // Kill all clocks
00033         LPC_I2S0->RXRATE = 0;
00034         LPC_I2S0->TXRATE = 0;
00035             // Bit rate must be 0 for slave mode.
00036         LPC_I2S0->RXBITRATE = 0;    
00037         LPC_I2S0->TXBITRATE = 0;
00038             // Clear mode setting
00039         LPC_I2S0->TXMODE = 0;
00040         LPC_I2S0->RXMODE = 0;
00041 
00042 
00043             // Configure DA0
00044         LPC_I2S0->DAO =
00045                 3 <<  0 |   // word width, 3:32bit mode        
00046                 0 <<  2 |   // Mono, 1:mono, 0:stereo
00047                 1 <<  3 |   // STOP, 1:stop
00048                 0 <<  4 |   // RESET, 1:reset
00049                 1 <<  5 |   // WSEL, 1:Slave, 0:Master
00050                 1 <<  6 ;   // MUTE, 1:mute, 0:normal 
00051 
00052             // Configure DAI
00053         LPC_I2S0->DAI =
00054                 3 <<  0 |   // word width, 3:32bit mode        
00055                 0 <<  2 |   // Mono, 1:mono, 0:stereo
00056                 1 <<  3 |   // STOP, 1:stop
00057                 0 <<  4 |   // RESET, 1:reset
00058                 1 <<  5 |   // WSEL, 1:Slave, 0:Master
00059                 31 <<  6;   // WS halfperiod. Not sure what I shoud do when the slave mode.
00060                 
00061             // Configure IRQ At this moment, IRQ is disabled. 
00062         LPC_I2S0->IRQ =
00063                 0 << 0  |   // RX IRQ Enable, 1:Enable, 0:Disable
00064                 0 << 1  |   // TX IRQ Enable, 1:Enable, 0:Disable
00065                 2 << 8  |   // RX DEPTH IRQ length for triggering interrupt  
00066                 0 << 16 ;   // TX DEPTH IRQ length for triggering interrupt
00067 
00068             // Set RX module as slave operation to the external signal
00069         LPC_I2S0->RXMODE =
00070                 0 << 0  |   // RXCLKSEL, 0:SCLK input. The reference manual says this is fractional devider, but in slave mode, it is SCLK.
00071                 0 << 2  |   // RX4PIN, 1:4pin mode, 0:Clock by RX block itself
00072                 0 << 3  ;   // RXMCENA, 1:Master clock output, 0:No output
00073                 
00074             // SEt TX module as slave operation to the RX module (4PIN mode )
00075         LPC_I2S0->TXMODE =
00076                 0 << 0  |   // TXCLKSEL, 0:SCLK input. Ignored by 4 pin mode.
00077                 1 << 2  |   // TX4PIN, 1:4pin mode, 0:Clock by TX block itself
00078                 0 << 3  ;   // TXMCENA, 1:Master clock output, 0:No output
00079 
00080 
00081             //  Fill up tx FIO by 3 stereo samples.
00082         hal_put_i2s_tx_data( 0 ); // left
00083         hal_put_i2s_tx_data( 0 ); // right
00084         hal_put_i2s_tx_data( 0 ); // left
00085         hal_put_i2s_tx_data( 0 ); // right
00086         hal_put_i2s_tx_data( 0 ); // left
00087         hal_put_i2s_tx_data( 0 ); // right
00088 
00089     }
00090     
00091         // Pin configuration and sync with WS signal
00092     void hal_i2s_pin_config_and_wait_ws(void)
00093     {
00094             // See UM10503 LPC4300 UM Rev 2.1 section 16.2.3, chapter 19
00095             // See https://developer.mbed.org/platforms/LPCXpresso4337/
00096             // See mbed src lpc43xx.h http://preview.tinyurl.com/lpc43xxh
00097             
00098             
00099             // setup WS pin as GPIO input
00100         LPC_SCU->SFSP[6][1] = SCU_MODE_INBUFF_EN;       // P6_1, function 0. GPIO3[0]
00101         
00102             // if WS is 1, wait for WS (GPIO3_0) becomes 0
00103         while ( LPC_GPIO_PORT->B[3][0] == 1 )
00104             ;
00105             
00106             // and then, if WS is 0, wait for WS (GPIO3_0) becomes 1
00107         while ( LPC_GPIO_PORT->B[3][0] == 0 )
00108             ;
00109             
00110         // Now, we are at the rising edge of WS. 
00111         // We can setup the I2S without worry of the TX/RX shift.
00112 
00113             // setup I2S pin configuration.
00114             // for input, bit 6 have to be 1 ( input buffer enable )
00115         LPC_SCU->SFSP[3][5] = 5;                        // P3_5, function 5. IS20_TX_SDA
00116         LPC_SCU->SFSP[6][0] = 4 | SCU_MODE_INBUFF_EN;   // P6_0, function 4. IS20_RX_SCK
00117         LPC_SCU->SFSP[6][1] = 3 | SCU_MODE_INBUFF_EN;   // P6_1, function 3. IS20_RX_WS
00118         LPC_SCU->SFSP[3][2] = 1 | SCU_MODE_INBUFF_EN;   // P3_2, function 1. IS20_RX_SDA
00119     }
00120 
00121     
00122         // Start I2S transfer. Interrupt starts  
00123     void hal_i2s_start(void)
00124     {
00125             //Clear STOP,RESET and MUTE bit
00126         LPC_I2S0->DAO &= ~(1 << 3);    // release I2S_DAO_STOP;
00127         LPC_I2S0->DAI &= ~(1 << 3);    // release I2S_DAI_STOP;
00128         
00129         LPC_I2S0->DAO &= ~(1 << 6);    // release I2S_DAO_MUTE;
00130         LPC_I2S0->IRQ |= 1 << 0;       // set I2S RX IRQ enable
00131     }
00132  
00133     IRQn_Type hal_get_i2s_irq_id(void)
00134     {
00135         return I2S0_IRQn;
00136     }
00137     
00138     
00139     IRQn_Type hal_get_process_irq_id(void)
00140     {
00141         return ( IRQn_Type )30;   // LPC4300's unsed interrupt
00142     }
00143     
00144     
00145          // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2...
00146     unsigned int hal_get_i2s_irq_priority_level(void)
00147     {
00148            // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7.
00149            // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( F**k! )
00150            // So, 7 is heighest, 0 is lowerest in CMSIS.
00151            // setting 6 as i2s irq priority allows, some other interrupts are higher 
00152            // and some others are lower than i2s irq priority.
00153         return 6;
00154     }
00155 
00156 
00157         // The returned value must be compatible with CMSIS NVIC_SetPriority() API. That mean, it is integer like 0, 1, 2...
00158     unsigned int hal_get_process_irq_priority_level(void)
00159     {
00160            // LPC4300 has 3 bits priority field. So, heighest is 0, lowest is 7.
00161            // But CMSIS NVIC_SetPriority() inverse the priority of the interupt ( S**t! )
00162            // So, 7 is heighest, 0 is lowerest in CMSIS.
00163            // setting 1 as process priority allows, some other interrupts are higher 
00164            // and some other interrupts are lower then process priority.
00165         return 1;   
00166     }
00167  
00168         // LPC4337 transferes 2 workd ( left and right ) for each interrupt.
00169     unsigned int hal_data_per_sample(void)
00170     {
00171         return 2;
00172     }
00173 
00174         // return true when the sample parameter is ready to read.
00175         // return false when the sample is not ready to read.
00176     void hal_get_i2s_rx_data( int & sample)
00177     {
00178         sample = LPC_I2S0->RXFIFO;
00179     }
00180     
00181         // put a sample to I2S TX data regisger
00182     void hal_put_i2s_tx_data( int sample )
00183     {
00184         LPC_I2S0->TXFIFO = sample;
00185     }
00186 }
00187 
00188