2009-04-02 09:25:10 uClinux+BF537 + AC97 codec (Reset problem)
Pavel Frolov (BELARUS)
Message: 72045
We tested application that swithes sample rate 44100 and 48000, and plaing different sound under linux. Cases the same as http://blackfin.uclinux.org/gf/project/uclinux-dist/forum/?action=ForumBrowse&forum_id=39&_forum_action=ForumMessageBrowse&thread_id=32179.
But sometimes switching rates leads to bad quallity of left channel front DAC (ramp with ~12KHz frequency), while the right front DAC, center, lfe, rear DACs work ok. One of my colleagues wroute test application using VisualDSP that:
1. Initialising SDRAM to place there generated sin samples.
2. AD1980 initialisation the same as for linux.
3. Initialising DMA to play test signal.
4. Reseting codec to start all process from the begining.
He has got bad quallity approximatly ones per 20 tests. After this he found a solution how to avoid such strange behaviour: switching to 96kHz mode and then returning to 48kHz (first bit of 0x2A register) fixes the problem.
I didn't tried to make this fix in linux driver yet.
I'm sending attached file with example from VisualDSP (not full, but it shows all initializing and fix).
Is anybody now what is the problem with codec?
AD1980_bugfix.c
QuoteReplyEditDelete
2009-04-03 02:23:28 Re: uClinux+BF537 + AC97 codec (Reset problem)
Cliff Cai (CHINA)
Message: 72085
Pavel,
The AC97 sound driver in 08r1-rc8 has a workaround allows us to reconfigure the codec when starts a new playback or a new capture. You can use the values stored in sport->codec_reg_cache(lastest written values) to recofigure everything you want.
For example:
void reset_codec( struct sport_device *sport){
u16 *cache = sport->codec_reg_cache;
bf5xx_ac97_write(NULL, 0x0, 0x0);
bf5xx_ac97_write(NULL, AC97_AD_SERIAL_CFG, 0x9900);
bf5xx_ac97_write(NULL, reg_index, (u16)cache[regindex >> 1]);
......
......
}
int sport_tx_start(struct sport_device *sport)
{
unsigned flags;
pr_debug("%s: tx_run:%d, rx_run:%d\n", __FUNCTION__,
sport->tx_run, sport->rx_run);
if (sport->tx_run)
return -EBUSY;
if (sport->rx_run) {
BUG_ON(sport->dma_tx_desc == NULL);
BUG_ON(sport->curr_tx_desc != sport->dummy_tx_desc);
/* Hook the normal buffer descriptor */
local_irq_save(flags);
sport->dummy_tx_desc->next_desc_addr = \
(unsigned long)(sport->dma_tx_desc);
local_irq_restore(flags);
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) - \
sizeof(struct dmasg)) != \
(unsigned long)sport->dma_tx_desc) {}
sport->curr_tx_desc = sport->dma_tx_desc;
} else {
/*add workaround here*/
reset_codec( sport);
sport_tx_dma_start(sport, 0);
/* Let rx dma run the dummy buffer */
sport_rx_dma_start(sport, 1);
sport_start(sport);
}
sport->tx_run = 1;
return 0;
}
this workaround should be added to the same place in int sport_rx_start(struct sport_device *sport)
I'm still trying hard to find out the real cause of the problems.
Cliff
QuoteReplyEditDelete
2009-04-03 04:48:27 Re: uClinux+BF537 + AC97 codec (Reset problem)
Pavel Frolov (BELARUS)
Message: 72098 Sorry, this workaround can't be made. Struct sport_device doesn't have codec_reg_cache fild (and never it was existed), as well as bf5xx_ac97_write function can't work with first parameter equal to NULL. And one note to addition. Even in case of such workaround, after successful warm reset and register configuring, bug with quallity loss on one channel can take place. This is the difference of this strange codec behaviour with the previously discussed bug (reseting registers during long term petiod). Pavel.