| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- /*!
- * Copyright (C) 2008 by egnite GmbH.
- * Copyright (C) 2007 by egnite Software GmbH.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \file tlv320dac.c
- * \brief DAC routines.
- *
- * \verbatim
- * $Id: tlv320dac.c 4473 2012-08-20 15:12:45Z haraldkipp $
- * \endverbatim
- */
- #include <dev/board.h>
- #include <dev/irqreg.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <stdlib.h>
- #include <string.h>
- #include <memdebug.h>
- #include <dev/tlv320dac.h>
- #ifndef TWI_SLA_DAC
- #define TWI_SLA_DAC 0x1A
- #endif
- /*
- * Initial volume.
- */
- #ifndef TLV320DAC_VOL
- #define TLV320DAC_VOL 0x18
- #endif
- /*
- * Number of PCM buffers.
- */
- #ifndef SAMPLE_BUFFERS
- #if defined (AT91SAM9260_EK)
- #define SAMPLE_BUFFERS 32
- #else
- #define SAMPLE_BUFFERS 3
- #endif
- #endif
- /*
- * Select TWI pins for bit-banging
- */
- #if defined(AT91SAM9260_EK)
- #ifndef TWI_SCL_BASE
- #define TWI_SCL_BASE PIOB_BASE
- #endif
- #ifndef TWI_SDA_BASE
- #define TWI_SDA_BASE PIOB_BASE
- #endif
- #ifndef TWI_SCL_BIT
- #define TWI_SCL_BIT 13
- #endif
- #ifndef TWI_SDA_BIT
- #define TWI_SDA_BIT 12
- #endif
- #ifndef TWI_DELAY
- #define TWI_DELAY 16
- #endif
- #elif defined(AT91SAM7X_EK)
- #ifndef TWI_SCL_BASE
- #define TWI_SCL_BASE PIOA_BASE
- #endif
- #ifndef TWI_SDA_BASE
- #define TWI_SDA_BASE PIOA_BASE
- #endif
- #ifndef TWI_SCL_BIT
- #define TWI_SCL_BIT 11
- #endif
- #ifndef TWI_SDA_BIT
- #define TWI_SDA_BIT 10
- #endif
- #endif
- /*
- * Select I2S pins.
- */
- #if defined (MCU_AT91SAM9260) /* _EK */
- #define DACI2S_PIO_ID PIOB_ID
- #define DACI2S_PINS_A _BV(PB18_TD0_A) | _BV(PB17_TF0_A) | _BV(PB16_TK0_A)
- #define DACI2S_PINS_B 0
- #else /* _EK */
- #define DACI2S_PIO_ID PIOA_ID
- #define DACI2S_PINS_A _BV(PA23_TD_A) | _BV(PA21_TF_A) | _BV(PA22_TK_A)
- #define DACI2S_PINS_B 0
- #endif /* _EK */
- /*
- * Determine PIO used by I2S.
- */
- #if DACI2S_PIO_ID == PIOA_ID /* DACI2S_PIO_ID */
- #define DACI2S_PDR PIOA_PDR
- #define DACI2S_ASR PIOA_ASR
- #define DACI2S_BSR PIOA_BSR
- #elif DACI2S_PIO_ID == PIOB_ID /* DACI2S_PIO_ID */
- #define DACI2S_PDR PIOB_PDR
- #define DACI2S_ASR PIOB_ASR
- #define DACI2S_BSR PIOB_BSR
- #endif /* DACI2S_PIO_ID */
- /*!
- * \brief I2S event queue.
- */
- static HANDLE i2s_que;
- /*!
- * \brief Number of channels.
- */
- #define PCM_CHANS 2
- /*!
- * \brief Number of bits per sample.
- */
- #define PCM_BITS 16
- /*!
- * \brief PCM buffer type.
- */
- typedef struct _PCM_BUFFER {
- u_short *wbf_dat; /*!< Pointer to PCM data. */
- int wbf_siz; /*!< Buffer size. */
- int wbf_len; /*!< Number of valid bytes buffered. */
- } PCM_BUFFER;
- /* PCM buffer queue. */
- static PCM_BUFFER pcm_bufq[SAMPLE_BUFFERS];
- /* PCM buffer read index. */
- static volatile unsigned int brd_idx;
- /* PCM buffer read position. */
- static volatile int brd_pos;
- /* PCM buffer write index. */
- static unsigned int bwr_idx;
- #if defined(TWI_SCL_BASE) && defined(TWI_SDA_BASE)
- #define TWI_ENABLE() { \
- outr(TWI_SCL_BASE + PIO_SODR_OFF, _BV(TWI_SCL_BIT)); \
- outr(TWI_SCL_BASE + PIO_PER_OFF, _BV(TWI_SCL_BIT)); \
- outr(TWI_SCL_BASE + PIO_OER_OFF, _BV(TWI_SCL_BIT)); \
- outr(TWI_SDA_BASE + PIO_SODR_OFF, _BV(TWI_SDA_BIT)); \
- outr(TWI_SDA_BASE + PIO_PER_OFF, _BV(TWI_SDA_BIT)); \
- }
- #define SDA_LOW() { \
- outr(TWI_SDA_BASE + PIO_CODR_OFF, _BV(TWI_SDA_BIT)); \
- outr(TWI_SDA_BASE + PIO_OER_OFF, _BV(TWI_SDA_BIT)); \
- }
- #define SDA_HIGH() { \
- outr(TWI_SDA_BASE + PIO_SODR_OFF, _BV(TWI_SDA_BIT)); \
- outr(TWI_SDA_BASE + PIO_ODR_OFF, _BV(TWI_SDA_BIT)); \
- }
- #define SCL_LOW() outr(TWI_SCL_BASE + PIO_CODR_OFF, _BV(TWI_SCL_BIT))
- #define SCL_HIGH() outr(TWI_SCL_BASE + PIO_SODR_OFF, _BV(TWI_SCL_BIT))
- #define SDA_STAT() (inr(TWI_SCL_BASE + PIO_PDSR_OFF) & _BV(TWI_SDA_BIT))
- #else
- #define TWI_ENABLE()
- #define SDA_LOW()
- #define SDA_HIGH()
- #define SCL_LOW()
- #define SCL_HIGH()
- #define SDA_STAT() (1)
- #endif
- #ifndef TWI_DELAY
- #define TWI_DELAY 8
- #endif
- /*
- * Short delay.
- *
- * Our bit banging code relies on pull-up resistors. The I/O ports mimic
- * open collector outputs by switching to input mode for high level and
- * switching to output mode for low level. This is much slower than
- * switching an output between low to high. Thus we need some delay.
- */
- static void TwBitDelay(int nops)
- {
- while (nops--) {
- _NOP();
- }
- }
- /*
- * Falling edge on the data line while the clock line is high indicates
- * a start condition.
- *
- * Entry: SCL any, SDA any
- * Exit: SCL low, SDA low
- */
- static void TwBitStart(void)
- {
- SDA_HIGH();
- TwBitDelay(TWI_DELAY);
- SCL_HIGH();
- TwBitDelay(TWI_DELAY);
- SDA_LOW();
- TwBitDelay(TWI_DELAY);
- SCL_LOW();
- TwBitDelay(TWI_DELAY);
- }
- /*
- * Rising edge on the data line while the clock line is high indicates
- * a stop condition.
- *
- * Entry: SCL low, SDA any
- * Exit: SCL high, SDA high
- */
- static void TwBitStop(void)
- {
- SDA_LOW();
- TwBitDelay(TWI_DELAY);
- SCL_HIGH();
- TwBitDelay(2 * TWI_DELAY);
- SDA_HIGH();
- TwBitDelay(8 * TWI_DELAY);
- }
- /*
- * Toggles out a single byte in master mode.
- *
- * Entry: SCL low, SDA any
- * Exit: SCL low, SDA high
- */
- static int TwBitPut(uint8_t octet)
- {
- int i;
- for (i = 0x80; i; i >>= 1) {
- /* Set the data bit. */
- if (octet & i) {
- SDA_HIGH();
- } else {
- SDA_LOW();
- }
- /* Wait for data to stabelize. */
- TwBitDelay(TWI_DELAY);
- /* Toggle the clock. */
- SCL_HIGH();
- TwBitDelay(2 * TWI_DELAY);
- SCL_LOW();
- TwBitDelay(TWI_DELAY);
- }
- /* Set data line high to receive the ACK bit. */
- SDA_HIGH();
- /* ACK should appear shortly after the clock's rising edge. */
- SCL_HIGH();
- TwBitDelay(2 * TWI_DELAY);
- if (SDA_STAT()) {
- i = -1;
- } else {
- i = 0;
- }
- SCL_LOW();
- return i;
- }
- /*
- * Toggles in a single byte in master mode.
- *
- * Entry: SCL low, SDA any
- * Exit: SCL low, SDA high
- */
- static uint8_t TwBitGet(void)
- {
- uint8_t rc = 0;
- int i;
- /* SDA is input. */
- SDA_HIGH();
- TwBitDelay(TWI_DELAY);
- for (i = 0x80; i; i >>= 1) {
- TwBitDelay(TWI_DELAY);
- /* Data should appear shortly after the clock's rising edge. */
- SCL_HIGH();
- TwBitDelay(2 * TWI_DELAY);
- /* SDA read. */
- if (SDA_STAT()) {
- rc |= i;
- }
- SCL_LOW();
- }
- return rc;
- }
- /*
- * Toggles out an acknowledge bit in master mode.
- *
- * Entry: SCL low, SDA any
- * Exit: SCL low, SDA high
- */
- static void TwBitAck(void)
- {
- SDA_LOW();
- TwBitDelay(TWI_DELAY);
- SCL_HIGH();
- TwBitDelay(2 * TWI_DELAY);
- SCL_LOW();
- TwBitDelay(TWI_DELAY);
- SDA_HIGH();
- }
- static int TwBitInit(uint8_t sla)
- {
- TWI_ENABLE();
- return 0;
- }
- static int TwBitMasterTransact(uint8_t sla, const void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
- {
- int rc = 0;
- uint8_t *cp;
- if (txlen) {
- TwBitStart();
- /* Send SLA+W and check for ACK. */
- if ((rc = TwBitPut(sla << 1)) == 0) {
- for (cp = (uint8_t *)txdata; txlen--; cp++) {
- if ((rc = TwBitPut(*cp)) != 0) {
- break;
- }
- }
- }
- }
- if (rc == 0 && rxsiz) {
- TwBitStart();
- /* Send SLA+R and check for ACK. */
- if ((rc = TwBitPut((sla << 1) | 1)) == 0) {
- for (cp = rxdata;; cp++) {
- *cp = TwBitGet();
- if (++rc >= rxsiz) {
- break;
- }
- TwBitAck();
- }
- }
- }
- TwBitStop();
- return rc;
- }
- /*!
- * \brief Set PDC pointer and counter registers.
- *
- * SSC interrupts must have been disabled befor calling this function.
- */
- static void I2sPdcFill(void)
- {
- if (brd_idx != bwr_idx) {
- if (inr(SSC_TNCR) == 0) {
- if (++brd_idx >= SAMPLE_BUFFERS) {
- brd_idx = 0;
- }
- outr(SSC_TNPR, (unsigned int) pcm_bufq[brd_idx].wbf_dat);
- outr(SSC_TNCR, pcm_bufq[brd_idx].wbf_len);
- }
- }
- }
- /*!
- * \brief SSC interrupt handler.
- *
- * Called when PDC transmission done.
- */
- static void I2sInterrupt(void *arg)
- {
- I2sPdcFill();
- NutEventPostFromIrq(&i2s_que);
- }
- /*!
- * \brief Read value from specified DAC register.
- *
- * Not implemented, because the TLV320AIC23B is a write-only device.
- *
- * \param reg DAC register address.
- *
- * \return Always 0xFF.
- */
- u_char Tlv320DacReadReg(unsigned int reg)
- {
- return 0xFF;
- }
- /*!
- * \brief Write value to specified DAC register.
- *
- * Communicates with the DAC chip via TWI.
- *
- * \param reg DAC register address.
- * \param val Value to store in specified register.
- */
- void Tlv320DacWriteReg(unsigned int reg, unsigned int val)
- {
- u_char txdata[2];
- txdata[0] = (u_char)(reg << 1) | (u_char)(val >> 8);
- txdata[1] = (u_char)val;
- TwBitMasterTransact(TWI_SLA_DAC, txdata, 2, NULL, 0, 0);
- }
- /*!
- * \brief Enable I2S interface with a given rate.
- *
- * \param rate PCM sample rate in Hertz.
- *
- * \return Always 0.
- */
- static int Tlv320I2sEnable(unsigned int rate)
- {
- /* Enable SSC clock. */
- outr(PMC_PCER, _BV(SSC_ID));
- /* Select SSC peripheral functions. */
- outr(DACI2S_ASR, DACI2S_PINS_A);
- outr(DACI2S_BSR, DACI2S_PINS_B);
- /* Enable SSC peripheral pins. */
- outr(DACI2S_PDR, DACI2S_PINS_A | DACI2S_PINS_B);
- /* Configure 16-bit stereo I2S transmit format. */
- outr(SSC_CMR, 0);
- outr(SSC_TCMR, /* Set transmit clock mode. */
- SSC_CKS_PIN | /* Use external clock at TK. */
- SSC_START_EDGE_RF | /* Start transmission on any edge. */
- (1 << SSC_STTDLY_LSB)); /* Delay start by 1 cycle. */
- outr(SSC_TFMR, /* Set transmit frame mode. */
- ((PCM_BITS - 1) << SSC_DATLEN_LSB) | /* Transmit 16 bits. */
- SSC_MSBF); /* Most significant bit first. */
- /* Enable transmitter in PDC mode. */
- outr(SSC_PTCR, PDC_TXTEN);
- outr(SSC_CR, SSC_TXEN);
- return 0;
- }
- /*!
- * \brief Disable I2S interface.
- *
- * \return Always 0.
- */
- static int Tlv320I2sDisable(void)
- {
- /* Disable all interrupts. */
- outr(SSC_IDR, 0xFFFFFFFF);
- /* Disable SSC interrupt. */
- NutIrqDisable(&sig_SSC);
- /* Disable SSC clock. */
- outr(PMC_PCDR, _BV(SSC_ID));
- /* Reset receiver and transmitter. */
- outr(SSC_CR, SSC_SWRST | SSC_RXDIS | SSC_TXDIS);
- outr(SSC_RCMR, 0);
- outr(SSC_RFMR, 0);
- outr(SSC_PTCR, PDC_RXTDIS);
- outr(SSC_PTCR, PDC_TXTDIS);
- outr(SSC_TNCR, 0);
- outr(SSC_TCR, 0);
- return 0;
- }
- /*!
- * \brief Configure the SSC for I2S mode.
- *
- * \param rate Sampling rate in Hertz.
- *
- * \return Always 0.
- */
- static int Tlv320I2sInit(unsigned int rate)
- {
- /* Register SSC interrupt handler. */
- NutRegisterIrqHandler(&sig_SSC, I2sInterrupt, 0);
- Tlv320I2sDisable();
- Tlv320I2sEnable(rate);
- /* Enable SSC interrupt. */
- NutIrqEnable(&sig_SSC);
- return 0;
- }
- int Tlv320DacSetRate(unsigned int rate)
- {
- switch(rate) {
- case 8000:
- #ifdef AT91SAM7X_EK
- Tlv320DacWriteReg(DAC_SRATE, (3 << DAC_SRATE_SR_LSB));
- #else
- Tlv320DacWriteReg(DAC_SRATE, (3 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
- #endif
- break;
- case 8021:
- Tlv320DacWriteReg(DAC_SRATE, (11 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
- break;
- case 44100:
- Tlv320DacWriteReg(DAC_SRATE, (8 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
- break;
- case 48000:
- Tlv320DacWriteReg(DAC_SRATE, (0 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
- break;
- case 88200:
- Tlv320DacWriteReg(DAC_SRATE, (15 << DAC_SRATE_SR_LSB) | DAC_SRATE_BOSR | DAC_SRATE_USB);
- break;
- case 96000:
- Tlv320DacWriteReg(DAC_SRATE, (7 << DAC_SRATE_SR_LSB) | DAC_SRATE_USB);
- break;
- default:
- return -1;
- }
- return 0;
- }
- /*!
- * \brief Initialize TLV320AIC23B DAC interface.
- *
- * \param rate Sample rate.
- *
- * \return 0 on success, -1 otherwise.
- */
- int Tlv320DacInit(unsigned int rate)
- {
- /* Initialize TWI. */
- TwBitInit(0);
- Tlv320DacWriteReg(DAC_RESET, 0);
- /* Power down line in. */
- Tlv320DacWriteReg(DAC_PWRDN, DAC_PWRDN_LINE);
- Tlv320DacWriteReg(DAC_PWRDN, 0);
- /* Set sampling rate. */
- if (Tlv320DacSetRate(rate)) {
- Tlv320DacWriteReg(DAC_RESET, 0);
- return -1;
- }
- Tlv320DacWriteReg(DAC_ANA_PATH, DAC_ANA_PATH_DAC | DAC_ANA_PATH_INSEL | DAC_ANA_PATH_MICB);
- Tlv320DacWriteReg(DAC_DIG_PATH, 0);
- /* I2S master. */
- Tlv320DacWriteReg(DAC_DAI_FMT, DAC_DAI_FMT_MS | DAC_DAI_FMT_FOR_I2S);
- Tlv320DacWriteReg(DAC_DI_ACT, DAC_DI_ACT_ACT);
- Tlv320DacWriteReg(DAC_LHP_VOL, DAC_LHP_VOL_LRS | (0x60 << DAC_LHP_VOL_LHV_LSB));
- /* Initialize I2S. */
- return Tlv320I2sInit(rate);
- }
- /*!
- * \brief Start transmitting audio samples.
- *
- * \return Always 0.
- */
- static int Tlv320DacStart(void)
- {
- NutIrqDisable(&sig_SSC);
- outr(SSC_IDR, SSC_TXEMPTY);
- /* Enable transmitter in PDC mode. */
- outr(SSC_PTCR, PDC_TXTEN);
- I2sPdcFill();
- outr(SSC_IER, SSC_ENDTX);
- /* Enable transmitter. */
- outr(SSC_CR, SSC_TXEN);
- NutIrqEnable(&sig_SSC);
- return 0;
- }
- /*!
- * \brief Wait until all buffered samples have been transmitted.
- *
- * \return Always 0.
- */
- int Tlv320DacFlush(void)
- {
- int rc = 0;
- while (bwr_idx != brd_idx) {
- if ((rc = NutEventWait(&i2s_que, 100)) != 0) {
- Tlv320DacStart();
- }
- }
- return rc;
- }
- /*!
- * \brief Add audio samples to the TLV320AIC23B transmit queue.
- *
- * \param buf Points to PCM data.
- * \param len Number of samples.
- *
- * \return 0 on success or -1 if out of memory.
- */
- int Tlv320DacWrite(void *buf, int len)
- {
- unsigned int idx;
- /* Move to the next buffer to write to. */
- idx = bwr_idx + 1;
- if (idx >= SAMPLE_BUFFERS) {
- idx = 0;
- }
- /* If all buffers are filled, wait for an event posted by the
- interrupt routine. */
- while (idx == brd_idx) {
- if (NutEventWait(&i2s_que, 100)) {
- Tlv320DacStart();
- }
- }
- /*
- * Check, if the current buffer size is too small or not allocated.
- */
- if (pcm_bufq[idx].wbf_siz < len) {
- if (pcm_bufq[idx].wbf_siz) {
- free(pcm_bufq[idx].wbf_dat);
- pcm_bufq[idx].wbf_siz = 0;
- }
- pcm_bufq[idx].wbf_dat = malloc(len * 2);
- if (pcm_bufq[idx].wbf_dat == NULL) {
- /* Out of memory. */
- return -1;
- }
- pcm_bufq[idx].wbf_siz = len;
- }
- /*
- * At this point we got an available buffer with sufficient size.
- * Move the data to it, set the number of valid bytes and update
- * the write (producer) index.
- */
- memcpy(pcm_bufq[idx].wbf_dat, buf, len * 2);
- pcm_bufq[idx].wbf_len = len;
- bwr_idx = idx;
- return 0;
- }
- /*!
- * \brief Set volume.
- *
- * Sets the master playback gain. Range is +6..-73 dB.
- *
- * \param left Left channel gain in dB.
- * \param right Right channel gain in dB.
- *
- * \return 0 on success, -1 otherwise.
- */
- int Tlv320DacSetVolume(int left, int right)
- {
- /* Cut to limits. */
- if (left > DAC_MAX_VOLUME) {
- left = DAC_MAX_VOLUME;
- }
- else if (left < DAC_MIN_VOLUME) {
- left = DAC_MIN_VOLUME;
- }
- if (right > DAC_MAX_VOLUME) {
- right = DAC_MAX_VOLUME;
- }
- else if (right < DAC_MIN_VOLUME) {
- right = DAC_MIN_VOLUME;
- }
- Tlv320DacWriteReg(DAC_LHP_VOL, (unsigned int)(left + 121));
- Tlv320DacWriteReg(DAC_RHP_VOL, (unsigned int)(right + 121));
- return 0;
- }
|