[alsa-devel] DMA buffer alignment
Hi, I'm working with a SoC sound hw that requires that all the data written into the DMA memory is aligned a 64 byte boundary. Actually the alignment is required since the format of the data into the DMA memory is (for a 2 channel 16bit audio): 16 samples for the left channel followed by 16 samples for the right channel. If I try to write anything that is not aligned to the 64 bytes I got audio corruption (high pitched noise). Several user-space programs (like aplay) work well with my hw, since the buffer sent from the user-space is always (padded) of period-size bytes, that is aligned to my 64 bytes boundary. Others (like speaker-test) are not working because sometimes they snd_pcm_writei() a buffer that is not multiple of 64 bytes. In general every time I write into the DMA area a buffer that is not aligned, my hw pointer is not aligned anymore with the 64 bytes and the noise starts.
IIUC it is not possible to force the user-space programs to send buffers with a fixed size so the problem should be solved in kernel-space (am I wrong on this point?). Any suggestion on how to tackle this problem?
Thanks,
Carlo Caione wrote:
Several user-space programs (like aplay) work well with my hw, since the buffer sent from the user-space is always (padded) of period-size bytes, that is aligned to my 64 bytes boundary. Others (like speaker-test) are not working because sometimes they snd_pcm_writei() a buffer that is not multiple of 64 bytes.
When a program writes two chunks of 32 bytes each, the final contents of the memory are the same. So what exactly is the problem?
Regards, Clemens
On Thu, Dec 4, 2014 at 5:20 PM, Clemens Ladisch clemens@ladisch.de wrote:
Carlo Caione wrote:
Several user-space programs (like aplay) work well with my hw, since the buffer sent from the user-space is always (padded) of period-size bytes, that is aligned to my 64 bytes boundary. Others (like speaker-test) are not working because sometimes they snd_pcm_writei() a buffer that is not multiple of 64 bytes.
When a program writes two chunks of 32 bytes each, the final contents of the memory are the same. So what exactly is the problem?
Hi Clemens, let's say that our application sends uning snd_pcm_writei() a buffer that is exactly 64 bytes and that our hwoff (appl_ofs) is pointing to a memory location 0 in the DMA area. When this buffer is taken from the SoC sound driver, the .copy callback writes this buffer as follow: 32 bytes (left channel) to memory locations from *hwoff to *hwoff+31, and 32 bytes (right channel) for *hwoff+32 to *hwoff+63. Problem is when my buffer is not multiple of 64 bytes, for example if the buffer size is < 64. If I receive a buffer of lenght 32 byte than my DMA memory is filled as follows: 16 bytes from *hwoff to *hwoff+15 and 16 bytes from *hwoff+32 to *hwoff+47, leaving 32 bytes in the block not initialized. My hardware is always expecting to read a block of data (64 byte) for *hwoff to *hwoff+63 and it actually does, reading rubbish from the memory locations not initialized. Even worst my hw requires that the hw pointer is always aligned to 64 bytes and now my new hw pointer is at *hwoff+32 that is not aligned on the boundary. In some way I should always guarantee that the size of the buffer passed to my .copy callback is multiple of 64 bytes.
I hope this clarifies a bit,
Carlo Caione wrote:
let's say that our application sends uning snd_pcm_writei() a buffer that is exactly 64 bytes and that our hwoff (appl_ofs)
The hardware and the software (appl) pointers are independent.
is pointing to a memory location 0 in the DMA area. When this buffer is taken from the SoC sound driver, the .copy callback writes this buffer as follow: 32 bytes (left channel) to memory locations from *hwoff to *hwoff+31, and 32 bytes (right channel) for *hwoff+32 to *hwoff+63. Problem is when my buffer is not multiple of 64 bytes, for example if the buffer size is < 64. If I receive a buffer of lenght 32 byte than my DMA memory is filled as follows: 16 bytes from *hwoff to *hwoff+15 and 16 bytes from *hwoff+32 to *hwoff+47, leaving 32 bytes in the block not initialized.
These bytes are written later. And if they are not written fast enough, you get an underrun. This is no difference from any other sound card.
In some way I should always guarantee that the size of the buffer passed to my .copy callback is multiple of 64 bytes.
The .copy callback just copies samples to memory; this is possible with any alignment.
The DMA runs asynchronously, and uses its own pointer.
Regards, Clemens
Hi, I'm working with a SoC sound hw that requires that all the data written into the DMA memory is aligned a 64 byte boundary. Actually the alignment is required since the format of the data into the DMA memory is (for a 2 channel 16bit audio): 16 samples for the left channel followed by 16 samples for the right channel.
Do you mean the sound card only support non interleaved mode ?
If I try to write anything that is not aligned to the 64 bytes I got audio corruption (high pitched noise). Several user-space programs (like aplay) work well with my hw, since the buffer sent from the user-space is always (padded) of period-size bytes, that is aligned to my 64 bytes boundary. Others (like speaker-test) are not working because sometimes they snd_pcm_writei() a buffer that is not multiple of 64 bytes. In general every time I write into the DMA area a buffer that is not aligned, my hw pointer is not aligned anymore with the 64 bytes and the noise starts.
You need to add constraint to restrict period bytes to 64
enum dma_residue_granularity { DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, DMA_RESIDUE_GRANULARITY_SEGMENT = 1, DMA_RESIDUE_GRANULARITY_BURST = 2, };
Can it report DMA_RESIDUE_GRANULARITY_SEGMENT or DMA_RESIDUE_GRANULARITY_BURST ?
IIUC it is not possible to force the user-space programs to send buffers with a fixed size so the problem should be solved in kernel-space (am I wrong on this point?). Any suggestion on how to tackle this problem?
pulseaudio seem not support non interleaved mode ?
participants (3)
-
Carlo Caione
-
Clemens Ladisch
-
Raymond Yau