/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * i2s.h * * Thu Aug 21 18:09:54 CEST 2014 * Copyright 2014 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Pedal2Metal. * * Pedal2Metal is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Pedal2Metal is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pedal2Metal; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef __PEDAL2METAL_I2S_H__ #define __PEDAL2METAL_I2S_H__ #include /** * Set power of I²S circuit. * @param power Integer value 0 is off, nonzero values are on. */ void i2s_set_power(int power); /** * Clock selection mode. See table 41, pg. 57. * CCLK is the CPU clock rate (ie. 100Mhz on LPC1768) */ typedef enum { I2S_CCLK_4 = 0b00, ///< PCLK_peripheral = CCLK/4 (default) I2S_CCLK = 0b01, ///< PCLK_peripheral = CCLK I2S_CCLK_2 = 0b10, ///< PCLK_peripheral = CCLK/2 I2S_CCLK_8 = 0b11, ///< PCLK_peripheral = CCLK/8 } i2s_clksel_t; #define I2S_CCLK_6 ((i2s_clksel_t)0b11) ///< For CAN1, CAN2, and CAN filtering when 0b11 selects = CCLK/6. /** * Set clock selection for I²S circuit. * @param sel Clock selection mode. */ void i2s_set_clksel(i2s_clksel_t sel); /** * Set pin selection for I²S circuit. * RX: * - P0.4: I2SRX_CLK * - P0.5: I2SRX_WS * - P0.6: I2SRX_SDA * - P?.?: RX_MCLK (currently not set) * TX: * - P0.7: I2STX_CLK * - P0.8: I2STX_WS * - P0.9: I2STX_SDA * - P4.28: TX_MCLK */ void i2s_set_pinsel(); typedef enum { I2S_WW_8_BIT = 0b00, // 8-bit data I2S_WW_16_BIT = 0b01, // 16-bit data //I2S_WW_RESERVED = 0b10, // Reserved, do not use this setting I2S_WW_32_BIT = 0b11, // 32-bit data } i2s_wordwidth_t; typedef enum { I2S_CH_MONO = 0b1, // Data is mono format I2S_CH_STEREO = 0b0, // Data is stereo format } i2s_channels_t; /** * Sets DAO register values and stops/resets the bus. * @param ww Word width of pcm values. * @param ch Number of channels (mono/stereo) * @param ws_halfperiod The width of a word select period in bitclock ticks * divided by two. */ void i2s_set_dao_register(i2s_wordwidth_t ww, i2s_channels_t ch, int ws_halfperiod); /** * Sets DAI register values and stops/resets the bus. * @param ww Word width of pcm values. * @param ch Number of channels (mono/stereo) * @param ws_halfperiod The width of a word select period in bitclock ticks * divided by two. */ void i2s_set_dai_register(i2s_wordwidth_t ww, i2s_channels_t ch, int ws_halfperiod); /** * Set clock transmit rate as PCLK_I2S * (X/Y) / 2 * @param x_div I²S transmit MCLK rate numerator. This value is used to * multiply PCLK by to produce the transmit MCLK. A value of 0 stops the clock. * Eight bits of fractional divide supports a wide range of possibilities. * @param y_div I²S transmit MCLK rate denominator. This value is used to * divide PCLK to produce the transmit MCLK. Eight bits of fractional divide * supports a wide range of possibilities. A value of 0 stops the clock. * Note: the resulting ratio X/Y is divided by 2. * Note: y must be greater than or equal to x. */ void i2s_set_tx_rate(uint8_t x_div, uint8_t y_div); /** * Set clock receive rate as PCLK_I2S * (X/Y) / 2 * @param x_div I²S receive MCLK rate numerator. This value is used to multiply * PCLK by to produce the receive MCLK. A value of 0 stops the clock. Eight * bits of fractional divide supports a wide range of possibilities. * @param y_div I²S receive MCLK rate denominator. This value is used to divide * PCLK to produce the receive MCLK. Eight bits of fractional divide supports * a wide range of possibilities. A value of 0 stops the clock. * Note: the resulting ratio X/Y is divided by 2. * Note: y must be greater than or equal to x. */ void i2s_set_rx_rate(uint8_t x_div, uint8_t y_div); /** * I²S transmit bit rate. * @param bitrate This value plus one is used to divide TX_MCLK to produce the * transmit bit clock. */ void i2s_set_tx_clock_bitrate(uint8_t bitrate); /** * I²S receive bit rate. * @param bitrate This value plus one is used to divide RX_MCLK to produce the * receive bit clock. */ void i2s_set_rx_clock_bitrate(uint8_t bitrate); typedef enum { CLK_TX_SRC = 0b00, ///< Select the TX fractional rate divider clock output as the source CLK_RX_MCLK = 0b10, ///< Select the RX_MCLK signal as the TX_MCLK clock source } i2s_tx_clksel_t; /** * */ void i2s_set_tx_mode_control(i2s_tx_clksel_t c, int _4pin, int mcena); typedef enum { CLK_RX_SRC = 0b00, ///< Select the RX fractional rate divider clock output as the source CLK_TX_MCLK = 0b10, ///< Select the TX_MCLK signal as the RX_MCLK clock source } i2s_rx_clksel_t; /** * */ void i2s_set_rx_mode_control(i2s_rx_clksel_t c, int _4pin, int mcena); void i2s_tx_reset_fifo(); void i2s_tx_stop(); void i2s_tx_start(); void i2s_rx_reset_fifo(); void i2s_rx_stop(); void i2s_rx_start(); /* * A data sample in the FIFO consists of: * - 1×32 bits in 8-bit or 16-bit stereo modes. * - 1×32 bits in mono modes. * - 2×32 bits, first left data, second right data, in 32-bit stereo modes. * * I2STXFIFO: 0x400A 8008 - 8 x 32 bit (see table 407, pg 477) * I2SRXFIFO: 0x400A 800C - 8 x 32 bit (see table 408, pg 478) * * See figure 113, pg. 489, for examples. */ /** * Write to TXFIFO * I2STXFIFO: 0x400A 8008 - 8 x 32 bit (see table 407, pg 477) */ #define TF(t, n) t *n = (t*)0x400A8008 static inline void i2s_write_pcm_8_mono(int8_t s) { TF(int8_t, t); t[0] = s; } static inline void i2s_write_pcm_16_mono(int16_t s) { TF(int16_t, t); t[0] = s; } static inline void i2s_write_pcm_32_mono(int32_t s) { TF(int32_t, t); t[0] = s; } static inline void i2s_write_pcm_8_stereo(int8_t l, int8_t r) { TF(int8_t, t); t[0] = l; t[1] = r; } static inline void i2s_write_pcm_16_stereo(int16_t l, int16_t r) { TF(int16_t, t); t[0] = l; t[1] = r; } static inline void i2s_write_pcm_32_stereo(int32_t l, int32_t r) { TF(int32_t, t); t[0] = l; t[1] = r; } /** * Read from RXFIFO * I2SRXFIFO: 0x400A 800C - 8 x 32 bit (see table 408, pg 478) */ #define RF(t, n) t *n = (t*)0x400A800C static inline void i2s_read_pcm_8_mono(int8_t *s) { RF(int8_t, t); *s = t[0]; } static inline void i2s_read_pcm_16_mono(int16_t *s) { RF(int16_t, t); *s = t[0]; } static inline void i2s_read_pcm_32_mono(int32_t *s) { RF(int32_t, t); *s = t[0]; } static inline void i2s_read_pcm_8_stereo(int8_t *l, int8_t *r) { RF(int8_t, t); *l = t[0]; *r = t[1]; } static inline void i2s_read_pcm_16_stereo(int16_t *l, int16_t *r) { RF(int16_t, t); *l = t[0]; *r = t[1]; } static inline void i2s_read_pcm_32_stereo(int32_t *l, int32_t *r) { RF(int32_t, t); *l = t[0]; *r = t[1]; } /** * Convenience function for power, pin, clock and register configuration. * @param pclkdiv Value of pclkdiv as found by the clkcalc tool. * @param bitrate Value of bitrate as found by the clkcalc tool. * @param x Value of x as found by the clkcalc tool. * @param y Value of y as found by the clkcalc tool. * @param bitwidth Width of each sample in bits (8, 16 or 32). * @param channels Number of channels (1 or 2). * @return 0 on success, 1 on error. */ int i2s_init(int pclkdiv, int bitrate, int x, int y, int bitwidth, int channels); /** * Enables accesses on FIFOs, places the transmit channel in unmute mode. */ void i2s_tx_start(); /** * Disables accesses on FIFOs, places the transmit channel in mute mode. */ void i2s_tx_stop(); /** * This bit reflects the presence of Receive Interrupt or Transmit Interrupt. * This is determined by comparing the current FIFO levels to the rx_depth_irq * and tx_depth_irq fields in the I2SIRQ register. */ int i2s_get_state_irq(); /** * This bit reflects the presence of Receive or Transmit DMA Request 1. This is * determined by comparing the current FIFO levels to the rx_depth_dma1 and * tx_depth_dma1 fields in the I2SDMA1 register. */ int i2s_get_state_dmareq1(); /** * This bit reflects the presence of Receive or Transmit DMA Request 2. This is * determined by comparing the current FIFO levels to the rx_depth_dma2 and * tx_depth_dma2 fields in the I2SDMA2 register. */ int i2s_get_state_dmareq2(); /** * Reflects the current level of the Receive FIFO. */ int i2s_get_state_rx_level(); /** * Reflects the current level of the Transmit FIFO. */ int i2s_get_state_tx_level(); /** * Calculate and initialise clk values based on samplerate, channel number and * number of bits per sample. * @param fs The samplerate in Hz. * @param bw The bitwidth, ie. number of bits pr. sample. * @param ch The number of channels. * @return 0 on success, 1 on error. */ int i2s_clkcalc_init(int fs, int bw, int ch); #if 1 #define I2S_DMA_ENABLED 1 #define BUFSIZE 0x200 //(1097 * sizeof(short) * 2)/*stereo*/ //((int)(sizeof(samples) * 2/*stereo*/)) #define RXFIFO_EMPTY 0 #define TXFIFO_FULL 8 extern void I2S_IRQHandler( void ); extern void I2SStart( void ); extern void I2SStop( void ); extern void I2SInit( void ); #endif #endif/*__PEDAL2METAL_I2S_H__*/