This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] PROCESSOR-SDK-AM62X:第二个使用时出现 McASP 捕获失败

Guru**** 2334730 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1515148/processor-sdk-am62x-mcasp-capture-failure-on-second-usage

器件型号:PROCESSOR-SDK-AM62X

工具/软件:

我遇到了本帖子中描述的问题

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1217223/processor-sdk-am62x-audio-capture-dma-issue-repeated-capture-commands-fail

在那篇文章中、提到 TI 计划在后续 SDK 版本中修复它。  我们目前使用的是 SDK 的08.06.00.42版本。 在切换到更新的 SDK 之前、我们想知道此问题是否已修复。 我通读了发行说明、但没有看到明确提及。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我正在回答我自己的问题。 即使在08.06.00.42 SDK 中使用的5.10.X 内核上、也可以修复该问题。 此补丁为我解决了问题

    https://github.com/varigit/ti-linux-kernel/commit/85a4b70c0bbddff31c7a075cf985008f30955f1f

    下面是一个简单的 c 程序,它使用 mmap 来录制32位音频(如果您使用的是 EVK 则更改为16位)。 它可以运行多次

    // mmap-record.c - Records audio using ALSA mmap and writes to S32_LE WAV file
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    #include <alsa/asoundlib.h>
    
    #define SAMPLE_RATE 48000
    #define CHANNELS 2
    #define FORMAT SND_PCM_FORMAT_S32_LE
    #define BUFFER_TIME 500000   // us
    #define PERIOD_TIME 100000   // us
    #define DURATION 5           // seconds
    #define FILENAME "record_mmap.wav"
    #define PCM_DEVICE "hw:0,0"
    
    #define WAV_HEADER_SIZE 44
    
    #define kAudioFrameSamples 256  // This is the audio driver callback rate.  Should not be too huge as it consumes coherent kernel memory.
    #define kNumAlsaBuffers 4
    snd_pcm_uframes_t periodSize = kAudioFrameSamples;
    snd_pcm_uframes_t bufferSize = kAudioFrameSamples * kNumAlsaBuffers; // adjusted in initPcmHandle
    
    
    void write_wav_header(FILE *f, int data_bytes) {
        int32_t sample_rate = SAMPLE_RATE;
        int16_t bits_per_sample = 32;
        int16_t channels = CHANNELS;
        int32_t byte_rate = sample_rate * channels * bits_per_sample / 8;
        int16_t block_align = channels * bits_per_sample / 8;
        int32_t chunk_size = 36 + data_bytes;
    
        uint8_t header[WAV_HEADER_SIZE] = {
            'R','I','F','F',
            chunk_size & 0xFF, (chunk_size >> 8) & 0xFF, (chunk_size >> 16) & 0xFF, (chunk_size >> 24) & 0xFF,
            'W','A','V','E','f','m','t',' ',
            16,0,0,0, // Subchunk1Size
            1,0, // PCM
            channels,0,
            sample_rate & 0xFF, (sample_rate >> 8) & 0xFF, (sample_rate >> 16) & 0xFF, (sample_rate >> 24) & 0xFF,
            byte_rate & 0xFF, (byte_rate >> 8) & 0xFF, (byte_rate >> 16) & 0xFF, (byte_rate >> 24) & 0xFF,
            block_align,0,
            bits_per_sample,0,
            'd','a','t','a',
            data_bytes & 0xFF, (data_bytes >> 8) & 0xFF, (data_bytes >> 16) & 0xFF, (data_bytes >> 24) & 0xFF
        };
        fwrite(header, 1, WAV_HEADER_SIZE, f);
    }
    
    const char *snd_pcm_state_name(snd_pcm_state_t state)
    {
      switch (state)
      {
        case SND_PCM_STATE_OPEN:
          return "SND_PCM_STATE_OPEN";
        case SND_PCM_STATE_SETUP:
          return "SND_PCM_STATE_SETUP";
        case SND_PCM_STATE_PREPARED:
          return "SND_PCM_STATE_PREPARED";
        case SND_PCM_STATE_RUNNING:
          return "SND_PCM_STATE_RUNNING";
        case SND_PCM_STATE_XRUN:
          return "SND_PCM_STATE_XRUN";
        case SND_PCM_STATE_DRAINING:
          return "SND_PCM_STATE_DRAINING";
        case SND_PCM_STATE_PAUSED:
          return "SND_PCM_STATE_PAUSED";
        case SND_PCM_STATE_SUSPENDED:
          return "SND_PCM_STATE_SUSPENDED";
        case SND_PCM_STATE_DISCONNECTED:
          return "SND_PCM_STATE_DISCONNECTED";
        default:
          return "Unknown state";
      }
    }
    
    const char *snd_pcm_stream_name_zz(snd_pcm_t *pcmHandle)
    {
      snd_pcm_stream_t stream = snd_pcm_stream(pcmHandle);
      switch (stream)
      {
        case SND_PCM_STREAM_PLAYBACK:
          return "SND_PCM_STREAM_PLAYBACK";
        case SND_PCM_STREAM_CAPTURE:
          return "SND_PCM_STREAM_CAPTURE";
        default:
          return "Unknown stream";
      }
    }
    
    
    int handlePcmOverOrUnderRun(snd_pcm_t *pcmHandle, int dbgCauseSource)
    {
      // handle overrun or underrun.
      snd_pcm_drop(pcmHandle);
      snd_pcm_recover(pcmHandle, -EPIPE, 0);
      snd_pcm_prepare(pcmHandle);
      usleep(3000);
      snd_pcm_state_t state = snd_pcm_state(pcmHandle);
      printf("Stream %s: state = %s after recovery, source = %d\n",
          snd_pcm_stream_name_zz(pcmHandle), snd_pcm_state_name(state), dbgCauseSource);
    
      state = snd_pcm_state(pcmHandle);
      printf("Stream %s: state = %s after start, source = %d\n",
          snd_pcm_stream_name_zz(pcmHandle), snd_pcm_state_name(state), dbgCauseSource);
    
      usleep(3000);
      return 0;
    }
    
    void hw_init(snd_pcm_t *handle)
    {
      snd_pcm_hw_params_t *hwparams;
        int err;
    
        snd_pcm_hw_params_malloc(&hwparams);
        snd_pcm_hw_params_any(handle, hwparams);
        snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED);
        snd_pcm_hw_params_set_format(handle, hwparams, FORMAT);
        snd_pcm_hw_params_set_rate(handle, hwparams, SAMPLE_RATE, 0);
        snd_pcm_hw_params_set_channels(handle, hwparams, CHANNELS);
        err        = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &periodSize, 0);
        if (err < 0) printf("Error %d with snd_pcm_hw_params_set_period_size_near\n", err);
        bufferSize = periodSize * kNumAlsaBuffers;  // e.g., 4 audio frames in the entire alsa buffer
        err        = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &bufferSize);
        if (err < 0) printf("Error %d with snd_pcm_hw_params_set_buffer_size_near\n", err);
        printf("Using period (audio frame) size: %lu and buffer size %lu\n", periodSize, bufferSize);
        snd_pcm_hw_params(handle, hwparams);    
        snd_pcm_hw_params_free(hwparams);
    }
    
    void sw_init(snd_pcm_t *handle,const int  audio_frame_size)
    {
        snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_malloc(&swparams);
        snd_pcm_sw_params_current(handle, swparams);
        snd_pcm_sw_params_set_avail_min(handle, swparams, audio_frame_size);
        snd_pcm_sw_params_set_start_threshold(handle, swparams, 0);
        snd_pcm_sw_params_set_stop_threshold(handle, swparams, 65536);
        snd_pcm_sw_params(handle, swparams);
        snd_pcm_sw_params_free(swparams);
    
    }
    
    
    void do_capture_samples(snd_pcm_t *handle,const int  audio_frame_size, FILE *fout)
    {
      int dir, err;
      int total_frames = SAMPLE_RATE * DURATION;
      int frame_size = CHANNELS * sizeof(int32_t);
      int recorded_frames = 0;
      int attempts = 0;
      const snd_pcm_channel_area_t *areas;
      snd_pcm_uframes_t offset, frames;
    
      while (recorded_frames < total_frames) 
      {
        frames = audio_frame_size;
        err = snd_pcm_mmap_begin(handle, &areas, &offset, &frames);
        if (err < 0) {
            fprintf(stderr, "mmap_begin error: %s\n", snd_strerror(err));
            break;
        }
    
        snd_pcm_state_t state = snd_pcm_state(handle);
        if (frames == 0)
        {
          err = snd_pcm_mmap_commit(handle, offset, frames);
          // printf ("commit 0 frames err = %d, state =  %s)\n", err,
          //           snd_pcm_state_name(state));
          if (attempts > 500)
          {
            printf ("Not getting audio frames\n");
            attempts = 0;
          }
          if (attempts > 0)
            ++attempts;
          if (state == SND_PCM_STATE_PREPARED)
          {
            printf("Starting pcm capture stream after %d attempts\n", attempts);
            snd_pcm_start(handle);
          }
          else if (state == SND_PCM_STATE_XRUN) 
          {
            printf("XRUN detected, attempting recovery\n");
            handlePcmOverOrUnderRun(handle, 1);
            continue;
          }
          usleep(4000);
          continue;
        }
    
        if ((recorded_frames & 0x3FF) == 0)
          printf ("%d frames\n", recorded_frames);
        if (frames > audio_frame_size)
          frames = audio_frame_size;
    
        if (frames < audio_frame_size) 
        {
          printf ("Short: %d\n", frames);
        }
        // else
        {
    
          int32_t *samples = (int32_t *)((uint8_t *)areas[0].addr + (offset * (areas[0].step / 8)));
          size_t bytes = frames * frame_size;
          fwrite(samples, 1, bytes, fout);
          recorded_frames += frames;
    
          err = snd_pcm_mmap_commit(handle, offset, frames);
          if (err < 0) {
              fprintf(stderr, "mmap_commit error: %s\n", snd_strerror(err));
              break;
          }
          usleep(5000);
        }
        attempts = -1;
      }
    }
    
    int main()
    {
        snd_pcm_t *handle;
        const snd_pcm_channel_area_t *areas;
        snd_pcm_uframes_t offset, frames;
        int dir, err;
        const int audio_frame_size = 256;
    
        int frame_size = CHANNELS * sizeof(int32_t);
        int total_frames = SAMPLE_RATE * DURATION;
        int recorded_frames = 0;
    
        err = snd_pcm_open(&handle, PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0);
            if (err < 0) {
            fprintf(stderr, "Error opening PCM device: %s\n", snd_strerror(err));
            return 1;
        }
    
        hw_init(handle);
        sw_init(handle, audio_frame_size);
    
        FILE *fout = fopen(FILENAME, "wb");
        if (!fout) {
            perror("fopen");
            return 1;
        }
        write_wav_header(fout, total_frames * frame_size);
    
        snd_pcm_prepare(handle);
        do_capture_samples(handle, audio_frame_size, fout);
    
        snd_pcm_pause(handle, 1);
        fclose(fout);
    
        snd_pcm_pause(handle, 1);
        snd_pcm_close(handle);
        printf("Wrote %s\n", FILENAME);
        return 0;
    }
    

    进行编译、方法是为 SDK 的环境设置脚本提供源代码、然后运行

     ${CC}McASP-alsa-recor记录-map-main.c -lasound -lm -o McASP-alsa-mmap-record

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    是、添加了在 RX 通道上强制拆卸以修复连续记录、使其正常工作。  

    但最新的软件版本(10.0以上)已经改进了版本和更简洁的方式来实现音频功能。  

    请使用 SDK 10.0版或更高版本进行验证。

    此致、

    Suren

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢 Suren。 我将查看最新的 SDK 以查看这样是否解决了问题。 但是、我们的团队希望立即避免切换内核和 SDK 版本作为解决方案、因为这种更改太大、无法确定我们在产品发布周期中的状态。 因此、如果 ti 内核有其他相关补丁、您可以建议我们查看、非常感谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Chris、

    https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?h=ti-linux-6.6.y&id=e0a0ce8c2684c13fab0e65be767d036dfa592ee1

    https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?h=ti-linux-6.6.y&id=343c3e2d9d0b49905aac24f9795cb2de5ef0cdaf

    https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?h=ti-linux-6.6.y&id=f08ebde41b3053f02de99e994a2b49dfcb494085

    上述三项内容对于音频功能在 AM62x 上正常工作至关重要。

    如果迁移到最新的 SDK 是一项挑战、请查看您是否可以使用最新的(这些已集成在最新的 SDK 中)进行验证、或将其重新移植。

    希望这些帮助。

    此致、

    Suren

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Suren

    我已经应用了这些修补程序、他们在我们的硬件上运行稳定、这解决了我以前只使用"强制拆卸"修补程序时看到的警告消息。  

    谢谢!

    Chris

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我很高兴这些修补程序有所帮助。 请随时联系以获取任何进一步的支持。 关闭此主题。

    此致、

    Suren