[alsa-devel] Stale data interleaved in capture driver
Rob Nertney
rob at rob-otics.com
Wed Aug 3 23:39:13 CEST 2016
Thanks Clemens, sorry for the delay, this got sent to spam for some reason
I've made changes to remove the high-frequency. I originally tried that
method because my DMA IRQ fires whenever it writes 1/2 frame (it doesn't
have coalescing support yet). Ive noticed that whatever I set my
buffer/periods to, i always get one good buffer-size chunk in the WAV file,
then it displays the very first half-frame of data, then correctly
continues onward, but interleaving two sets of incrementing data. I think
it might be when I increment buf_pos for the pointer callback, or maybe
something else.
Here's how I have the hardware/driver right now:
I have a DMA which is looping across 64Kbytes. I verified this is correctly
in simulation.
The DMA is configured to interrupt at 32Bytes (A half frame. My Full frame
is 16ch, S32LE = 64Bytes).
The driver counts the 32Byte IRQs until it reaches one period worth. From
what I can tell (please correct me if I'm wrong), the periods_min and
periods_max are up to me to define, since i don't interrupt on a period
boundary. I divide the 64K buffer into 8 periods of 8KB each. Since my
frame is 64Bytes, that is 128 frames/period. Since the DMA fires at each
half frame (due to FPGA configuration), This is 256 IRQs I need to count
to, before I call snd_pcm_period_elapsed.
//pertinent snd_pcm_hardware lines:
.buffer_bytes_max = 65536,
.period_bytes_min = 65536/8,
.period_bytes_max = 65536/8,
.periods_min = 8,
.periods_max = 8,
static irqreturn_t my_dma_irq(int irq, void *dev_id)
{
struct my_device *dev = dev_id;
unsigned int last_ptr, size;
spin_lock(&dev->lock);
dev->irq_count++;
dev->buf_pos += 32; //32 bytes have been transferred
if(dev->buf_pos >= (dev->pcm_buffer_size))
dev->buf_pos = 0;
if(dev->irq_count == 256){ //256 IRQs elapsed==128 frames == 8Kbytes ==
1/8 max_buffer
spin_unlock(&dev->lock);
snd_pcm_period_elapsed(dev->substream);
spin_lock(&dev->lock);
dev->irq_count = 0;
}
}
handle_irq();
spin_unlock(&dev->lock);
return IRQ_HANDLED;
On Sun, Jul 31, 2016 at 11:34 PM, Clemens Ladisch <clemens at ladisch.de>
wrote:
> Rob Nertney wrote:
> > an IRQ every 32Bytes (half-frame)
> >
> > I wrote my handler as described in the high-frequency interrupts
> described
> > here:
> > http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ch05s07.html
>
> This does not make sense; you need a timer only when you do not have
> a proper interrupt. Why do you think you need to do it this way?
>
> > My data is valid until 1/4 buffer full, then it interleaves stale (lower
> > numbers) in, replacing the desired numbers. It's sporadic, and it appears
> > to repeat, as if ALSA never returns to the 0-offset of dma_area.
>
> ALSA just reports what your driver tells it; this sounds like a bug
> in your driver or in the hardware.
>
>
> Regards,
> Clemens
>
More information about the Alsa-devel
mailing list