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.

[参考译文] RTOS/LAUNCHXL-CC26X2R1:CC2642新型 I2S 驱动器

Guru**** 2521010 points
Other Parts Discussed in Thread: CC3200AUDBOOST, CC3200

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

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/798695/rtos-launchxl-cc26x2r1-cc2642-new-i2s-driver

器件型号:LAUNCHXL-CC26X2R1
主题中讨论的其他器件:CC3200AUDBOOSTCC3200

工具/软件:TI-RTOS

对于旧版 I2S 驱动程序的之前 SDK 版本、(https://github.com/ti-simplelink/ble_examples)

它具有以下配置、

/*
 *配置10ms 帧@ 16kHz 采样率。
 *请注意,帧大小变量的最大大小限制为255。
 *它是一个硬件中的8位字段(AIFDMACFG)。
 *
#define FRAME_SIZE                     160

 160/ 16000 = 0.01 S,因此我可以每1秒获得100个音频帧。 我已经在旧 SDK 上验证了这一点。

 

 

关于最新的 SDK、它具有新的 I2S 驱动程序、我希望旧版 SDK 也能获得相同的结果。

我做了一些实验来验证帧间隔、但 我没有得到相同的结果。

我 使用/simplelink_cc13x2_26x2_SDK_3_10_00_53/examples/rtos/CC26X2R1_LAUNCHXL/drivers/i2secho 示例进行了实验。

关于以下实验、我将 BUFSIZE 从1024修改为160。

#define BUFSIZE        160  // I2S 缓冲区大小*/

 

实验1.

仅启动读取事务。

静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){
   read_data_cnt++;

我得到帧计数为~401每1秒。

 

实验2.

仅启动读取事务。

静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){

   I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
   if (transactionFineded!= NULL){

       read_data_cnt =操作已完成-> numberOfCommple;
   }

我得到每1秒~67的帧计数。 


问题1:为什么我在实验1和实验2中得到不同的结果?
问题2:为什么我在新旧 SDK 中获得了不同的结果? 

谢谢。

BR
Trevor

 

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

    尊敬的 Trevor:

    首先、I2S 驱动程序自之前的版本以来已经完全重新设计、其使用方式略有改变。 这起初可能会令人困惑、但您会发现这款新驱动程序提供了许多优势和新功能。

    问题1:您在两个实验中获得了不同的结果、因为您不是在测量相同的东西!

    只需清除、在新的驱动程序中、您会将一些事务放入队列中(您使用 I2S_Transaction_init() List_put ()的 for 循环执行此操作)。 驱动程序负责执行队列中的事务,并在每次启动事务时触发相应的回调(此处为 readCallbackFxn 或 writeCallbackFxn)。 您告诉驱动程序队列中的哪个元素(使用 I2S_setReadQueueHead()读取接口和使用 I2S_setWriteQueueHead()写入接口),然后驱动程序只完成一个事务并考虑下一个事务。 如果您有一个振铃列表(列表中的最后一个项目指向列表中的第一个项目),您将永远阅读/写入(在这里,您有一个振铃列表,感谢 List_tail (&i2sList)->next = List_head (&i2sList);List_head (&i2sList)-> Prev = List_tail (&i2sList);)。

    现在、您已经完成了两个实验来更改事务开始时执行的回调内容:  

    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){
    read_data_cnt++;
    } 

    使用上面的代码、您基本上计算已完成的读取事务数。

     

    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){
    
    I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
    if (transactionFineded!= NULL){
    
    read_data_cnt =操作已完成-> numberOfCommple;
    }
    } 

    使用上面的代码、您现在可以看到完成此特定事务的次数(注意:此处、TransactionPtr 指向刚刚开始的事务、因此 TransactionFinished 指向最后完成的事务)。

    最后、如果您想知道在一秒内收到多少数据、第一种方法是正确的方法。

    另一个备注:如果您未修改示例,则表示您已将6个事务排队。 这里你有401 = 5*67+66 (即你完成了5次交易的67次,6次交易的66次)。

     

    问题2:您获得的结果不同、因为您没有提供相同的参数!

    正如我说过的、使用新的驱动程序、您可以定义事务并将其排队。 每个事务都包含一个缓冲区(包含接收到的或要发送的数据)。 供参考,您使用以下行在要使用的缓冲区上提供指针:i2sTransactionList[k]->bufPtr = i2sBufList[k];(此处,我们已将事务和缓冲区放在表中,以便能够使用 for 循环)。

    话虽如此、您有两个参数用于设置存储的数据量。 首先、您可以修改每个缓冲区的长度(这是您在修改#define BUFSIZE 值时所做的操作)。 其次、您可以修改存储的缓冲区数量(这相当于存储的事务数量):为此、您必须修改#define NUMBUFS 值、声明更多 I2S 缓冲区(例如静态 uint8_t buf7[BUFSIZE];)并声明更多 i2sTransaction (例如 I2S_Transaction i2sTransaction7;)。 不要忘记将新的缓冲区和事务添加到表(i2sBufList i2sTransactionList)中。

    如果我们返回到您的结果:一秒内读取400个缓冲区。 每个缓冲区为160字节(因为您已将 BUFSIZE 设置为160)。

    因此、您在一秒内读取了64000个字节。 这意味着每通道32 000字节(默认情况下、您有两个激活的通道)。 这意味着每通道16位的16 000个样本(默认情况下、每通道读取16位)。 换句话说、您具有16kHz 采样频率(这是为 SAMPLE_RATE 定义的值、并在 I2S 参数[i2sParams.samplingFrequency]中进行设置)。 注意:目前、CC3200音频 Booster Pack (也称为 CC3200AUDBOOST)的编解码器仅支持16kHz 的值。 如果您不使用此 Booster Pack、则可以选择采样频率的"任意"值。

    我真的不知道为什么每秒只需要使用100个缓冲区(这不会改变采样频率或存储的数据量,只是存储数据的方式),但可以将 BUFSIZE 设置为640 (因为,正如我所说的, 您每秒读取64000字节)。

    为了供将来参考、我在此处粘贴 i2secho 示例:

    /*
    版权所有(c) 2015-2019、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    //
    
    /*
    === i2secho.c ===
    */
    #include 
    #include 
    #include 
    
    /* POSIX 头文件*/
    #include 
    #include 
    
    /*驱动程序头文件*/
    #include 
    #include 
    
    /*示例/板头文件*/
    #include "Board.h"
    #include "Audocodec.h"
    
    #define THREADSTACKSIZE 2048
    
    #define SAMPLE_RATE 16000 //仅支持16kHz */
    #define INPUT_OPTION AudioCodec_MIC_LINE_IN
    #define output_option AudioCodec_speaker_HP
    
    #define NUMBUFS 6. /*要循环的缓冲器总数*/
    #define BUFSIZE 1024 /* I2S 缓冲区大小*/
    
    List_List i2sList;
    
    static uint8_t buf1[BUFSIZE];
    static uint8_t buf2[BUFSIZE];
    static uint8_t buf3[BUFSIZE];
    static uint8_t BUF4[BUFSIZE];
    静态 uint8_t buf5[BUFSIZE];
    静态 uint8_t buf6[BUFSIZE];
    静态 uint8_t* i2sBufList[NUMBUFS]={buf1、buf2、buf3、buf4、buf5、 buf6};
    
    I2S_Transaction i2sTransaction1;
    I2S_Transaction i2sTransaction2;
    I2S_Transaction i2sTransaction3;
    I2S_Transaction i2sTransaction4;
    I2S_Transaction i2sTransaction5;
    I2S_Transaction i2sTransaction6;
    static I2S_Transaction * i2sTransactionList[NUMBUFS]={&i2sTransaction1、&i2sTransaction2、&i2sTransaction3、
    i2sTransaction4、&i2sTransaction5、&i2sTransaction6};
    
    I2S_Handle i2sHandle;
    
    静态空 errCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    /*
    *如果发生 I2S 错误,则执行此回调的内容
    *
    I2S_stopClocks (handle);
    I2S_Close (handle);
    }
    
    静态空 writeCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    /*
    *每次启动写事务时都会执行此回调的内容
    */
    }
    
    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    /*
    *每次启动读取事务时都会执行此回调的内容
    */
    }/*
    
    
    === 回声线====
    //
    void *echoThread (void *arg0)
    {
    I2S_Params i2sParams;
    
    /*初始化音频 BP 上的 TLV320AIC3254编解码器*/
    uint8_t status = AudioCodec_open();
    if (AudioCodec_status_Success!= status)
    {
    /*初始化编解码器时出错*/
    while (1);
    }
    
    /*配置编解码器*/
    状态= AudioCodec_config (AudioCodec_TI_3254、AudioCodec_16_bit、
    SAMPLE_RATE、AudioCodec_Stereo、AudioCodec_speaker_HP、
    AudioCodec_MIC_LINE_IN);
    if (AudioCodec_status_Success!= status)
    {
    /*初始化编解码器时出错*/
    while (1);
    }
    
    /*音量控制*/
    AudioCodec_speakerVolCtrl (AudioCodec_TI_3254、AudioCodec_speaker_HP、75);
    AudioCodec_micVolCtrl (AudioCodec_TI_3254、AudioCodec_MIC_Onboard、75);
    
    /*
    *打开 I2S 驱动程序
    *
    I2S_PARAMS_INIT (&i2sParams);
    i2sParams.samplingFrequency = 16000;
    i2sParams.fixedBufferLength = BUFSIZE;
    i2sParams.writeCallback = writeCallbackFxn;
    i2sParams.readCallback = readCallbackFxn;
    i2sParams.errorCallback = errCallbackFxn;
    i2sHandle = I2S_open (Board_I2S0、&i2sParams);
    
    /*
    *初始化 I2S 事务并将其排队
    *
    uint8_t k;
    对于(k = 0;k < NUMBUFS;k++){
    I2S_Transaction_init (i2sTransactionList[k]);
    i2sTransactionList[k]->bufPtr = i2sBufList[k];
    i2sTransactionList[k]->bufSize = BUFSIZE;
    list_put (&i2sList、(List_Elem*)i2sTransactionList[k]);
    }
    
    list_tail (&i2sList)->next = List_head (&i2sList);/* I2S 缓冲区在环形列表中排队*/
    list_head (&i2sList)->prev = List_tail (&i2sList);
    
    I2S_setReadQueueHead (i2sHandle、&i2sTransaction1);
    I2S_setWriteQueueHead (i2sHandle、&i2sTransaction4);
    
    /*
    *启动 I2S 流
    *
    I2S_startClocks (i2sHandle);
    I2S_startRead (i2sHandle);
    I2S_startWrite (i2sHandle);
    
    while (1);
    }
    
    /*
    === mainThread ====
    //
    void * mainThread (void * arg0)
    {
    pthread_t 线程0;
    pthread_attr_t attrs;
    struct sched_param primParam;
    内部 REC;
    内部 detachState;
    
    /*调用驱动程序初始化函数*/
    I2S_INIT ();
    
    //在 CC32XX 上,由于 LED/I2S 引脚冲突而不启用 GPIO */
    #if!(已定义(DeviceFamily_CC3200)||已定义(DeviceFamily_CC3220)||已定义(DeviceFamily_CC3235))
    GPIO_init();
    
    /*配置 LED 引脚*/
    GPIO_setConfig (Board_GPIO_LED0、GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
    /*打开用户 LED */
    GPIO_WRITE (Board_GPIO_LED0、Board_GPIO_LED_ON);
    #endif
    
    /*设置优先级和堆栈大小属性*/
    pthread_attr_init (atttrs);
    priParam.sched_priority = 1;
    
    detachState = pthread_create_detached;
    retc = pthread_attr_setdetachstate (&attrs、detachState);
    如果(retc!= 0){
    /* pthread_attr_setdetachstate()失败*/
    while (1);
    }
    
    pthread_attr_setschedparam (&attrs、&priParam);
    
    retc |= pthread_attr_setstacksize (&attrs、THREADSTACKSIZE);
    如果(retc!= 0){
    /* pthread_attr_setstacksize()失败*/
    while (1);
    }
    
    /*创建接收线程*/
    retc = pthread_create (&thread0、&attrs、echoThread、NULL);
    如果(retc!= 0){
    /* pthread_create()失败*/
    while (1);
    }
    
    返回(NULL);
    }
    

    此致、

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

    您好、Cl é ment、
    非常详细的解释、帮了我很多忙、谢谢。

    我真的不需要每秒精确消耗100帧,这只是旧 SDK 的一个示例。
    我确实需要将新的 I2S 驱动器与 TI VoGP (GATT 语音配置文件)集成。

    示例 流式传输方法 输入方法 输出方法 支持软件压缩 采样速率 帧大小 每帧通知数
    双向音频 双向 模拟麦克风+外部编解码器 外部编解码器+耳机 mSBC、ADPCM 16kHz 100个八位位组 1


    关于 ADPCM 压缩,我需要(192*sizeof (Int16)帧大小。 对于 mSBC 压缩,我需要(120 *sizeof (Int16)帧大小。


    以下问题需要您的帮助、

    问题1:如果我只需要接收单声道音频数据(仅开始读取事务),我尝试将 i2sParams.SD1Channels 设置为 I2S_Channels_Mono,但它不起作用。
            我还必须将 i2sParams.SD0Channels 设置为 I2S_Channels_Mono 才能正常工作。 为什么?


    Q2:关于 I2S 缓冲区数据类型,它在 i2secho.c 中被定义为无符号16位,它是否支持16位有符号 PCM 数据格式?

    问题3:关于 readCallback & writeCallback 函数是从 HWI 中断触发的,对吧? 如果是这样、增加 fixedBufferLength 将减少回调数

           并提高多任务系统的系统性能、对吧?



    Q4:在 i2secho.c 中,它定义了六个缓冲区和六个 I2S_Transactions。 此数字是否有任何限制? 增大或减小此数值是否会产生副作用?

    Q5:在 i2secho.c 中,它声明 BUFSIZE 与 sa fixedBufferLength 相同,但在“模式播放和停止”示例(在 I2S.h 中)中,writeBuf 大小不同

           使用 i2sParams.fixedBufferLength、为什么?

    问6:我做了一个简单的1KHz 音(单声道)回放功能,但声音很奇怪,你有什么建议吗?
          每秒16K 16位单声道通道= 16000 * 2 * 1字节= 32000字节、因此我创建8个缓冲区、大小为4000、然后将1K 音调数据(32000 B)填充到这些缓冲区中。

    静态 uint16_t writeBuf1[4000]={0};
    静态 uint16_t writeBuf2[4000]={0};
    静态 uint16_t writeBuf3[4000]={0};
    静态 uint16_t writeBuf4[4000]={0};
    静态 uint16_t writeBuf5[4000]={0};
    静态 uint16_t writeBuf6[4000]={0};
    静态 uint16_t writeBuf7[4000]={0};
    静态 uint16_t writeBuf8[4000]={0};

    静态 I2S_Transaction i2sWrite1;
    静态 I2S_Transaction i2sWrite2;
    静态 I2S_Transaction i2sWrite3;
    静态 I2S_Transaction i2sWrite4;
    静态 I2S_Transaction i2sWrite5;
    静态 I2S_Transaction i2sWrite6;
    静态 I2S_Transaction i2sWrite7;
    静态 I2S_Transaction i2sWrite8;    

    //初始化 I2S 打开参数
    I2S_PARAMS_INIT (&i2sParams);
    i2sParams.samplingFrequency = 16000;
    i2sParams.fixedBufferLength = 4000;
    i2sParams.writeCallback    = writeCallbackFxn;

    --------------------------------------------------

    //如果我注释这些行,系统将阻止 I2S_startWrite (i2sHandle)函数;为什么???????
    i2sParams.readCallback     = readCallbackFxn;
    i2sParams.errorCallback    = errCallbackFxn;

    --------------------------------------------------
    i2sParams.SD1通道      =   I2S_Channels_Mono;
    i2sParams.SD0Channels      =   I2S_Channels_Mono;
    i2sHandle = I2S_open (Board_I2S0、&i2sParams);

    //初始化写入事务
    I2S_Transaction_init (&i2sWrite1);
    I2S_Transaction_init (&i2sWrite2);
    I2S_Transaction_init (&i2sWrite3);
    I2S_Transaction_init (&i2sWrite4);
    I2S_Transaction_init (&i2sWrite5);
    I2S_Transaction_init (&i2sWrite6);
    I2S_Transaction_init (&i2sWrite7);
    I2S_Transaction_init (&i2sWrite8);

    i2sWrite1.bufPtr          = writeBuf1;
    i2sWrite2.bufPtr          = writeBuf2;
    i2sWrite3.bufPtr          = writeBuf3;
    i2sWrite4.bufPtr          = writeBuf4;
    i2sWrite5.bufPtr          = writeBuf5;
    i2sWrite6.bufPtr          = writeBuf6;
    i2sWrite7.bufPtr          = writeBuf7;
     i2sWrite8.bufPtr          = writeBuf8;

    i2sWrite1.bufSize         = sizeof (writeBuF1);
    i2sWrite2.bufSize         = sizeof (writeBuf2);
    i2sWrite3.bufSize         = sizeof (writeBuf3);
    i2sWrite4.bufSize         = sizeof (writeBuf4);
    i2sWrite5.bufSize         = sizeof (writeBuf5);
    i2sWrite6.bufSize         = sizeof (writeBuf6);
    i2sWrite7.bufSize         = sizeof (writeBuf7);
    i2sWrite8.bufSize         = sizeof (writeBuf8);

    list_clearList (&i2sWriteList);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite1);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite2);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite3);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite4);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite5);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite6);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite7);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite8);

    list_tail (&i2sWriteList)->next = List_head (&i2sWriteList);// I2S 缓冲区在环列表中排队*/
    list_head (&i2sWriteList)->prev = List_tail (&i2sWriteList);
    I2S_setWriteQueueHead (i2sHandle、&i2sWrite1);

    I2S_startClocks (i2sHandle);
    I2S_startWrite (i2sHandle);

     

     

    谢谢。

    BR

    Trevor

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    更新 Q6:
    我声明了错误的数据类型。 进行以下修改、声音的频率是正确的。 但是声音是间歇性的(不是连续的)。

    静态 uint8_t writeBuf1[4000]={0};
    静态 uint8_t writeBuf2[4000]={0};
    静态 uint8_t writeBuf3[4000]={0};
    静态 uint8_t writeBuf4[4000]={0};
    静态 uint8_t writeBuf5[4000]={0};
    静态 uint8_t writeBuf6[4000]={0};
    静态 uint8_t writeBuf7[4000]={0};
    静态 uint8_t writeBuf8[4000]={0};

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

    我很高兴看到我的回答可能对您有所帮助。

    Q1:一般来说、禁用未使用的接口始终是一个好做法。 因此、我的建议是使用 i2sParams 禁用 SD0。 SD0 = I2S_SD0_DISABLED;

    Q2:I2S 驱动程序允许您使用16位有符号数据。 实际上、I2S 驱动程序会读取到达其接口的数据。 之后,由应用程序来解释数据。

    Q3:通过增加 I2S 参数“fixedBufferLength”的值,您可以通过减少传输给定数据量所需的 HWI 数量,来提高系统性能。 但不会减少 readCallback 和 writeCallback 的执行次数。
    事实上,当您将 fixedBufferLength 设置为与其默认值不同的值时,I2S 模块会考虑缓冲区长度是“fixedBufferLength”的倍数。 这样就可以考虑在每个 HWI 中断处传输更多数据。 注意:fixedBufferLength 当然必须与缓冲区的大小保持兼容(相反,您将丢失数据)。
    无论您是否使用 fixedBufferLength、您都不会收到每个 HWI 的回调函数。 因此、通过增加 fixedBufferLength、可以减少 HWI 的数量、但仍然有相同数量的回调执行。 如果要减少回调执行的次数、则必须增加缓冲区的长度。
    为了成为非常精确的原理图(但不是100%精确、尤其是对于非常长的缓冲器):
    -通过将 fixedBufferLength 加倍,可以将 HWI 的频率降低2倍。 但回调的频率保持不变。
    -通过将 I2S 缓冲器的长度加倍,可以将回调频率降低2倍。 但 HWI 的频率保持不变。
    当然、您可以增加 fixedBufferLength 和 I2S 缓冲区的长度来提高系统性能。

    Q4:通常、您可以根据需要增加存储的数据量(通过增加缓冲区的大小或增加其数量)。 但是、您会受到可用内存量的限制(明显)。 请记住、增加队列中的数据量意味着增加传输时间(在队列中添加缓冲区与实际读取/写入缓冲区之间的时间会更长)。

    Q5:首先、您无需选择与缓冲区大小相等的固定缓冲区长度。 如果缓冲区的长度为100字节,则可以选择 fixedBufferLength =20 (因为20*5=100)。 好吧,这不是超级聪明,但你有对的… 但是、如果仍然有100字节的缓冲区、则无法选择 fixedBufferLength = 75 (或者、您可以选择"是"、但您将不会发送/接收缓冲区的最后25个字节、根据其他设置、可能会稍微多一些)。
    考虑到已为读取接口和写入接口设置了 fixedBufferLength、您必须考虑两个接口上选择的缓冲区的大小。 在“播放和停止”示例中,我们有用于读取接口的1000字节缓冲区和用于写入接口的500字节缓冲区。 因此、fixedBufferLength 的最佳值是500 (GCD 为500和1000)。 如果 fixedBufferLength 为250、则所有数据都将按预期进行读取和写入、但您的效率将会降低(每个接口的 I2S HWI 增加两倍)。 如果 fixedBufferLength 为1000,则不会传输任何数据(因为写入缓冲区的大小严格低于 fixedBufferLength)。

    问题6:如果每个激活的接口不提供一个回调函数以及错误回调、则无法正确打开 I2S 驱动程序。 注:您可以对 errorCallback 和 writeCallback (或 readCallback)使用相同的回调。 不建议使用与 writeCallback 和 readCallback 相同的回调(因为您不能区分写入接口触发的回调与读取接口触发的回调)。
    注:您可以使用以下参数停用一个接口:SD0Use 和 SD1Use。 默认情况下、SD0设置为输出、SD1设置为输入(如果需要、您可以更改此设置)。 因此、您可以在此处使用这些参数、而不再需要提供 readCallback (但无论如何、您将需要 errCallback):
    i2sParams。 SD1 = I2S_SD1_DISABLED;
    i2sParams。 SD0 = I2S_SD0_OUTPUT;

    Q6’:间歇性声音。 您应该了解以下几点:
    -缓冲区是否已完全初始化(即您正在传输未初始化的数据)?
    >修复:正确初始化缓冲区
    一段时间后,写缓冲区内的数据是否仍然正确? 没有“空穴”? 没有意外值?
    >修复:验证谁在缓冲区中写入
    用于初始化事务的 bufSize 值是否正确?
    >修复:值必须以字节为单位。 最好使用 sizeof (buffer)。
    -一段时间后,I2S 交易的字段“untransferredBytes”是否等于零?
    >修复:如果此字段与不同、则意味着您不会发送/接收整个缓冲区。 这表明您的 I2S 驱动程序设置不正确。
    -一段时间后,I2S 事务的字段“numberOfCommitions”是否与零不同,且完全相等(1的差异是正常的)
    >修复:如果某些缓冲区没有像其他缓冲区那样频繁传输,这可能意味着您没有将它们排好队
    -I2S 参数 fixedBufferLength 的值是否与缓冲区的长度兼容?
    >修复:尝试设置 fixedBufferLength = 1
    如果这不能解决您的问题,您可以在此处粘贴您的代码,我将查看它:)

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

    您好、Cl é ment、

    我已解决了间歇性声音问题。 根本原因是某些写入缓冲区具有空数据。
    感谢您的建议。

    以下问题仍有一些困惑需要您的帮助:


    问题1;
    关于 CC3200AUDBOOST 板的当前配置、我想知道哪种数据类型正确(16位有符号数据或16位无符号数据)
    我做了一些实验、两种数据类型的结果是相同的。

    静态 uint8_t buf1[BUFSIZE];
    静态 uint8_t buf2[BUFSIZE];
    静态 uint8_t buf3[BUFSIZE];
    静态 uint8_t buf4[BUFSIZE];
    静态 uint8_t buf5[BUFSIZE];
    静态 uint8_t buf6[BUFSIZE];
    静态 uint8_t* i2sBufList[NUMBUFS]={buf1、buf2、buf3、buf4、buf5、 buf6};

    静态 INT8_t buf1[BUFSIZE];
    静态 INT8_t buf2[BUFSIZE];
    静态 INT8_t buf3[BUFSIZE];
    静态 INT8_t buf4[BUFSIZE];
    静态 INT8_t buf5[BUFSIZE];
    静态 INT8_t buf6[BUFSIZE];
    静态 INT8_t* i2sBufList[NUMBUFS]={buf1、buf2、buf3、buf4、buf5、 buf6};


    Q2;
    关于 fixedBufferLength、我仍然对 fixedBufferLength 有些困惑、在 i2secho.c 中、它将 BUFSIZE 定义为1024、因此如果我想的话
    提高系统性能、哪个 fixedBufferLength 值具有更好的性能?   8192、4096、2048、1024、512。
    另一个 questoin、如果我将 fixedBufferLength 设置为2、4和6、则无法输出任何声音。(1和8可以正确输出)  


    问题3:
    我可以理解、如果增加缓冲区的大小、读取/写入时间 将会更长。
    但我不明白为什么增加缓冲区编号、读取/写入时间也会更长。

    我可以理解、如果增大缓冲区的大小、读取/写入时间将会更长。
    我不明白为什么增加缓冲区数量的读取/写入时间也变得更长。

    问题4:
    在 i2secho.c 的以下回调函数中,您说:“您已将6个事务排队。 这里您有401 = 5*67+66 (即您完成了5次交易的67次、第六次交易的66次)。"
    我可以理解您的意思、但如果我开始写入事务、Read_data_cnt 将变为134。

    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){

       I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
       if (transactionFineded!= NULL){

           read_data_cnt =操作已完成-> numberOfCommple;
       }



    问题5:
    关于以下回调函数,如果 NUMBUFS 设置为6,则 bytesTransfer=始终将0减,但如果我将 NUMBUFS 设置为1,则 bytesTrans=始终将 BUFSIZE 减去。 为什么?

    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){

       I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
       if (transactionFineded!= NULL){

           计数=已分次治疗->已按字节转移;
       }

    谢谢。

    BR

    Trevor

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

    尊敬的 Trevor:

    仍然很高兴能够为您提供帮助。

    Q1:I2S 缓冲器应使用哪种数据类型?

    任何数据类型都没关系。 I2S 驱动器需要内存才能工作。 应用程序负责提供此存储器。 之后、I2S 驱动程序只需复制所提供的存储器组中接收到的数据。 (或者 I2S 驱动器对其输出进行写入、数据将显示在给定地址)。

    最后、无论您要声明 uint8_t、int8_t、uint16_t、int16_t、uint32_t…的表、都是如此 考虑到您使用的是16位存储器长度(默认)、您的数据应是16位长度。 (换句话说、如果您有 uint8_t/INT8_t 表、每个样本将占用两个空间。 如果您具有 uint32_t/ int32_t、则每个空间将有两个样本)。

    关于有符号/无符号数据,应用程序有责任对数据进行解释。 对于给定的输入流、无论使用何种类型、写入的存储器的内容都是相同的。 写入操作相同:对于存储器的给定内容、每当修改类型时、都有一个固定输出流。

    因此、如果开发人员知道 I2S 线上传输的数据是16位带符号的、则声明 int16_t 的表 如果您知道 I2S 线上传输的数据是16位无符号的、则声明 uint16_t 的表 同样、如果您声明任何其他类型的数据的表、则 I2S 驱动程序将不会更改任何内容。

    Q2:FixedBufferLength

    让我们从一开始就开始(我可能已经过度简化了这一点)。

    fixedBufferLength 是一个参数、用于保证 I2S 驱动程序、应用程序提供的内存块至少在[fixedBufferLength ]字节上是连续的。 换句话说、您保证 I2S 驱动程序可以顺利地发送/写入存储在 I2S 缓冲区地址的数据以及[fixedBufferLength ]字节。

    让我们看一下这个示例:我声明由1024个连续字节组成的 I2S 缓冲区。

    >如果 fixedBufferLength 设置为1 (默认值):每一个字节(*),I2S 驱动程序将检查它是否仍在缓冲区内。 这将导致1024 (*) HWI 发送缓冲区。

    (*)实际上,I2S 驱动程序认为数据与两个 WCLK 周期所需的数据量是连续的。 (也就是说,如果您处于16位数据长度的“单声道”模式,这对应于2*1*2=4字节)。

    >如果 fixedBufferLength 设置为256 (良好的解决方案但不是最佳):每发送256个字节就会触发一个 HWI。 因此、您需要4个 HWI 来传输1024字节(较好但不理想)

    >如果 fixedBufferLength 设置为1024 (最佳解决方案):驱动程序将考虑第一个 HWI 之后缓冲区的1024个字节。 在第二个 HWI 期间、驱动器将检查并检测他已完成电流缓冲器的使用(并将开始考虑下一个缓冲器)。 因此、您需要一个 HWI 来传输相同数量的数据。

    >如果 fixedBufferLength 设置为800 (解决方案不好,某些数据丢失):驱动程序将考虑缓冲区的前800个字节。 之后、驱动程序将检测到它不能再考虑这个缓冲区中的800个字节、并将考虑下一个缓冲区。 这意味着您会浪费数据(未使用分配的存储器)并可能丢失数据(如果您要发送出去、则不会发送缓冲区的最后224个字节)

    >如果 fixedBufferLength 设置为2000 (非常糟糕-不传输任何内容)。 驱动程序将考虑第一个缓冲区、看到它无法使用数据(1024 < 2000)、然后考虑第二个缓冲区、看到它无法使用数据、等等。

    [编辑]:实际上、驱动程序最终将使用缓冲区、读/写方式的数据过多。 这将导致数据损坏和崩溃。

    最后、通过将 fixedBufferLength 设置为缓冲区长度的最大公共除数(GCD)来优化性能(缓冲区长度必须以字节表示)。 选择缓冲器长度的 GCD 的一个子倍数会导致性能稍低。 选择任何高于缓冲区长度 GCD 的值都会导致数据丢失。

    注意:如果 fixedBufferLength 的值与您的其他设置不兼容、则可能会导致意外的 I2S 行为。 FixedBufferLength 必须是两个 WCLK 周期所需数据量的倍数。

              -在16位数据长度的单声道模式中,fixedBufferLength 必须是2*1*2=4字节的倍数

              -在16位数据长度的立体声模式中,fixedBufferLength 必须是2*2*2=8字节的倍数

    (通过将 fixedBufferLength 设置为2或6、您不符合最后的要求。 (假设您处于单声道模式)、通过将 fixedBufferLength 设置为4、您将处于一个没有实际意义的临界情况下)。

    Q3:增加队列中的数据量的影响

    让我们考虑以下类比。 让我们设想一根管道(由多个连接的管道组成)将水从自来水输送到桶中。 每个管道段都可以被视为具有其长度的缓冲器。 连接管道的数量是排队的缓冲区数量。 最后、您需要相同长度的抽头、方法是10件5米或5件10米。 唯一需要更改的是所需的连接器数量:在本类比中、连接器数量是执行的回调数量。

    现在、水滴从水龙头流出的那一刻到水滴到达水桶的那一刻之间的延迟与整个管道的长度直接相关(即管道段数乘以其长度)。

    如果水循环得更快、会发生什么情况? 这就像增加采样频率、意味着延迟更小。

    通过此类比、我们了解队列中的缓冲区越多、从排队等待缓冲区的那一刻到读取或写入数据的那一刻、延迟就越长。

    Q4:NumberOfCommpleions

    每次读取或写入相应的 I2S 缓冲器时、驱动器都会更新(正在执行+ 1) I2S 事务结构的字段编号 OfComitions。

    在某些应用(例如 i2secho 示例等流应用)中、读取和写入队列中使用相同的 I2S 事务(在某些情况下、您只有一个队列、每个接口开始考虑存储在队列中相反位置的事务: 这就是我们使用  I2S_setReadQueueHead (i2sHandle、&i2sTransaction1);和 I2S_setWriteQueueHead (i2sHandle、&i2sTransaction4)执行的操作。

    这解释了为什么在这些情况下字段 numberOfCompleions 比预期大两倍(numberOfCompleions 由读取和写入接口递增)。

     

    Q5:仅使用一个事务时的限制

    您可以使用仅包含一个事务的队列。 在这种情况下、您还可以将队列设置为环形队列。 但可能会出现一些限制。 例如,(在包含一个事务的振铃列表的情况下)在您的读/写回调中

    /*此代码仅对仅一个缓冲区的振铃列表连接有效*/
    
    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    
    /*以下行...*/
    I2S_Transaction *已完成的治疗=*已完成的治疗 PTr;
    
    /*等效于*/
    //I2S_Transaction *已完成操作=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
    
    /*等效于*/
    //I2S_Transaction *已完成操作=(I2S_Transaction*) List_next (&transactionPtR->queueElement)
    
    }
    

    提醒一下、您不应该在回调函数中访问正在进行的事务。 这意味着在只有一个事务排队的系统中,您无法修改 I2S 缓冲区的内容或其地址。 同样、您不能修改或依赖事务的其他字段。 注:允许您通过 TransactionPtr -> numberOfCommpleions 读取保留的值。

    此致、

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

    您好、Cl é ment、

    感谢您的详细解释、

    关于以下示例:

    >如果 fixedBufferLength 设置为2000 (非常糟糕-不传输任何内容)。 驱动程序将考虑第一个缓冲区、看到它无法使用数据(1024 < 2000)、然后考虑第二个缓冲区、看到它无法使用数据、等等。

    我已将 fixedBufferLength 设置为2000、但它似乎可以正确输出声音、您能帮您在您的一侧尝试一下吗?

    谢谢。

    BR

    Trevor

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

    尊敬的 Trevor:

    我知道您尝试将 fixedBufferLength 设置为2000、而您的缓冲区的长度仅为1024字节。 在此提醒、您使用的 I2S 驱动器不符合其规格。 不建议这样做,也不要更改 I2S 性能(相反)。                                                                                                                                             

    但是、您会听到一些不错的声音(我自己尝试过、通过 i2secho 示例可以获得很好的声音)。 这表明我们很幸运… 或不是。

    实际上、I2S 模块每次可考虑的最大采样数也有限制。 该限制取决于所使用的设置、但对于具有16位数据的立体声模式、该限制正好为1024。 I2S 驱动器会考虑此限制并调整 I2S 模块在每个 HWI 上可考虑的数据量。 新示例: 在具有16位数据的立体声模式下、如果您将 fixedBufferLength 设置为2048、则 I2S 驱动程序将要求 I2S 模块在每个 HWI 上仅考虑1024字节(这是因为2048大于在此模式下 I2S 模块可以一次性考虑的最大数据量)。 这还意味着、如果将 fixedBufferLength 设置为2000 (使用16位数据保持在立体声模式)、I2S 驱动程序将要求 I2S 模块考虑两个 HWI 之间的1000字节。

    如果我们回到您的备注(fixedBufferLength = 2000,而缓冲区的长度为1024字节),I2S 驱动程序会要求 I2S 模块每次考虑1000字节。 第一个 HWI 允许您考虑1000个第一个字节、第二个 HWI 则尝试考虑再增加1000个字节。 这是不可能的、因此 I2S 驱动器会考虑下一个缓冲器。 如果您看一下存储器(例如、使用 CCS 的存储器浏览器)、您会看到未使用每个缓冲区的最后24个字节(在回显示例中、它们保持在0x00)。 [您还可以查看交易的"非转让字节"字段、并看到其值为24]

     

    如果要展示我提到的问题、可以将缓冲区长度设置为500字节、并将 fixedBufferLength 设置为1000。 I2S 模块将在每个 HWI 之间读取/写入1000个字节(意味着修改不应修改的数据)并崩溃。

    (注意:很抱歉、我在上一篇文章中犯了一个错误、说 I2S 驱动器不会传输任何内容。 我已编辑了我之前的帖子、结果如此。)

     

    此致、

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

    您好、Cl é ment、

    感谢您提供调试方法。

    您能否帮助提供"在连续流模式下写入数据"示例的源代码?

    我想在音频数据中添加数字滤波器(麦克风输入->滤波器->耳机输出)。

    谢谢。

    BR

    Trevor  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Trevor:
    我们目前正在更新 I2S 回波示例以引入滤波。 此更新将是 SDK 3_20的一部分(7月发布)。 您可以等待吗?
    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Cl é ment、

    很好、期待您的新 I2S 示例。

    但我们首先需要验证一些功能、那么您能否帮助提供"在连续流模式下写入数据"示例(在 I2S.h 中)的源代码?

    谢谢。

    BR

    Trevor

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

    您好!

    以下是使用 I2S.h 的"在连续流模式下写入数据"示例的代码 如果有任何错误、请告诉我。

    此致、

    /*
    版权所有(c) 2018-2019、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    //
    
    /*
    === example_streaming.c ===
    */
    #include 
    #include 
    #include 
    
    /*驱动程序头文件*/
    #include "AudioCodec.h"
    
    #define TASKSTACKSIZE 640
    #define SAMPLE_RATE 16000 //警告:仅支持16kHz
    
    #include 
    #include 
    
    /* POSIX 头文件*/
    #include 
    #include 
    
    /*驱动程序头文件*/
    #include 
    #include 
    
    #include 
    #include 
    #include 
    #include 
    
    /*示例/板头文件*/
    #include "Board.h"
    
    
    #define THREADSTACKSIZE 2048
    
    /* I2S 缓冲区大小*/
    #define BUFSIZE 1024
    
    //循环的缓冲区总数*/
    #define NUMBUFS 10
    
    /* I2S 缓冲区描述符数*/
    #define NUMDESC 3
    
    static I2S_Handle i2sle_I2s500
    ;
    
    静态 I2uS 配置文件1[static readConfig]
    静态 uint16_t readBuf2[500];
    静态 uint16_t readBuf3[500];
    静态 uint16_t readBuf4[500];
    静态 uint16_t writeBuf1[500];
    静态 uint16_t writeBuf2[500];
    静态 uint16_t writeBuf3[500];
    静态 uint16_t writeBuf4[500];
    
    /*注意:
    *-我们需要至少8个事务才能正确执行回显
    *-可以通过使用较短的缓冲区来减少延迟
    *- i2sReadx 事务将从 i2sReadList 传递到
    * 治疗列表、更改为 i2sWriteList、最后返回
    * i2sReadList (i2sWritex 事务的相同备注、
    * 从 i2sWriteList 传递到 i2sReadList,再传递到 treatmentList...)
    *
    /静态 I2S_Transaction i2sRead1;
    静态 I2S_Transaction i2sRead2;
    静态 I2S_Transaction i2sRead3;
    静态 I2S_Transaction i2sRead4;
    静态 I2S_Transaction i2sWrite1;
    静态 I2S_Transaction i2sWrite2;
    静态 I2S_Transaction i2sWrite3;
    静态 I2S_Transaction i2sWrite4;
    
    List_List i2sReadList;
    List_List i2sWriteList;
    list_List
    
    
    
    结构列表;静态特性任务1Stack[TASKSTACKSIZE];静态 Task_Structtask1Struct;静态 semSemore_Streatt semStruct1;
    静态 Semaphore_handle dataReadyForTreatment;
    
    静态空 writeCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    
    /*我们必须删除之前的事务(当前事务不会结束)*/
    I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
    
    if (transactionFineded!= NULL){
    /*从写入队列中删除已完成的事务*/
    list_remove (&i2sWriteList,(List_Elem*)已完成操作);
    
    /*此事务现在必须馈入读取队列(我们不再需要此事务的数据)*/
    TransactionFined->queueElement.next = NULL;
    list_put (&i2sReadList,(List_Elem*)transactionFinished);
    
    /*我们需要为新事务排队:让我们在治疗队列中处理一个事务*/
    I2S_Transaction * newTransaction =(I2S_Transaction *) List_head (&treatmentList);
    if (newTransaction!= NULL){
    list_remove (&treatmentList、(List_Elem*) newTransaction);
    newTransaction->queueElement.next = NULL;
    list_put (&i2sWriteList,(List_Elem*) newTransaction);
    }
    }
    
    
    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction * transactionPtr){
    
    
    /*我们必须删除之前的事务(当前事务不会结束)*/
    I2S_Transaction *事务已完成=(I2S_Transaction *) List_prev (&transactionPtr ->队列 Element);
    
    if (transactionFineded!= NULL){
    /*完成的事务包含必须处理的数据*/
    list_remove (&i2sReadList,(List_Elem*)transactionFinished);
    TransactionFined->queueElement.next = NULL;
    list_put (&treatmentList、(List_Elem*) transactionFinished);
    
    /*开始处理数据*/
    Semaphore_post (dataReadyForTreatment);
    
    //我们不需要在此处排队处理:writeCallbackFxn 负责处理:)*/
    }
    }
    
    静态空 errCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *transactionPtr){
    
    }
    
    /*
    === myTreatmentThread ====
    //
    void * myTreatmentThread (void * arg0){
    
    int k;
    
    while (1){
    Semaphore_pend (dataReadyForTreatment、BIOS_wait_forever);
    
    /*
    *在此处插入您想要实现的治疗!
    *
    I2S_Transaction * TRANSACTION =(I2S_TRANSACTION *) List_head (&treatmentList);
    uint16_t *buf =事务->bufPtr;
    对于(k=0;k<500;k++){
    buf[k]++;
    }
    
    对于(k=0;k<500;k++){
    buf[k]--;
    }
    }
    }/*
    
    
    === ExamechopleThread ====
    //
    void *echoExampleThread (void *arg0)
    {
    I2S_Params i2sParams;
    
    /*初始化音频 BP 上的 TLV320AIC3254编解码器*/
    uint8_t status = AudioCodec_open();
    if (AudioCodec_status_Success!= status)
    {
    /*初始化编解码器时出错*/
    while (1);
    }
    
    /*配置编解码器*/
    状态= AudioCodec_config (AudioCodec_TI_3254、AudioCodec_16_bit、
    SAMPLE_RATE、AudioCodec_Stereo、AudioCodec_speaker_HP、
    AudioCodec_MIC_LINE_IN);
    if (AudioCodec_status_Success!= status)
    {
    /*初始化编解码器时出错*/
    while (1);
    }
    
    /*音量控制*/
    AudioCodec_speakerVolCtrl (AudioCodec_TI_3254、AudioCodec_speaker_HP、75);
    AudioCodec_micVolCtrl (AudioCodec_TI_3254、AudioCodec_MIC_Onboard、75);
    
    /*初始化治疗列表*/
    list_clearList (&treatmentList);
    
    /*初始化 I2S 打开参数*/
    I2S_PARAMS_INIT (&i2sParams);
    i2sParams.fixedBufferLength = 1000;
    i2sParams.writeCallback = writeCallbackFxn;
    i2sParams.readCallback = readCallbackFxn;
    i2sParams.errorCallback = errCallbackFxn;
    i2sParams.bitsPerWord = 16;
    i2sParams.SD1Channels = I2S_CHANNES_STEREO;
    i2sParams.SD0Channels = I2S_CHANNES_STEREO;
    i2sParams.memorySlotLength = I2S_MEMORY_LENGTH_16位;
    
    i2sHandle = I2S_open (0、&i2sParams);
    
    /*初始化读取事务*/
    I2S_Transaction_init (&i2sRead1);
    I2S_Transaction_init (&i2sRead2);
    I2S_Transaction_init (&i2sRead3);
    I2S_Transaction_init (&i2sRead4);
    i2sRead1.bufPtr = readBuf1;
    i2sRead2.bufPtr = readBuf2;
    i2sRead3.bufPtr = readBuf3;
    i2sRead4.bufPtr = readBuf4;
    i2sRead1.bufSize = sizeof (readBuf1);
    i2sRead2.bufSize = sizeof (readBuf2);
    i2sRead3.bufSize = sizeof (readBuf3);
    i2sRead4.bufSize = sizeof (readBuf4);
    list_clearList (&i2sReadList);
    list_put (&i2sReadList,(List_Elem*)&i2sRead1);
    list_put (&i2sReadList,(List_Elem*)&i2sRead2);
    list_put (&i2sReadList,(List_Elem*)&i2sRead3);
    list_put (&i2sReadList,(List_Elem*)&i2sRead4);
    
    
    I2S_setReadQueueHead (i2sHandle、&i2sRead1);
    
    /*初始化写入事务*/
    I2S_Transaction_init (&i2sWrite1);
    I2S_Transaction_init (&i2sWrite2);
    I2S_Transaction_init (&i2sWrite3);
    I2S_Transaction_init (&i2sWrite4);
    i2sWrite1.bufPtr = writeBuf1;
    i2sWrite2.bufPtr = writeBuf2;
    i2sWrite3.bufPtr = writeBuf3;
    i2sWrite4.bufPtr = writeBuf4;
    i2sWrite1.bufSize = sizeof (writeBuF1);
    i2sWrite2.bufSize = sizeof (writeBuf2);
    i2sWrite3.bufSize = sizeof (writeBuf3);
    i2sWrite4.bufSize = sizeof (writeBuf4);
    list_clearList (&i2sWriteList);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite1);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite2);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite3);
    list_put (&i2sWriteList,(List_Elem*)&i2sWrite4);
    
    I2S_setWriteQueueHead (i2sHandle、&i2sWrite1);
    
    I2S_startClocks (i2sHandle);
    I2S_startWrite (i2sHandle);
    I2S_startRead (i2sHandle);
    
    while (1);
    }
    
    /*
    === mainThread ====
    //
    void * mainThread (void * arg0)
    {
    pthread_t 螺纹1;
    pthread_attr_t attr1;
    struct sched_param priParam1;
    内部 retc1;
    内部 detachStat1;
    
    Semaphore_Params semParams;
    Semaphore_Params_init (semParams);
    Semaphore_struction (&semStruct1、0、&semParams);
    dataReadyForTreatment = semaphore_handle (&semStruct1);
    
    /*调用驱动程序初始化函数*/
    i2sHandle =&i2sConfig;
    I2S_init();
    
    #if 0 //由于 LED/I2S 引脚冲突禁用 GPIO */
    GPIO_init();
    
    /*配置 LED 引脚*/
    GPIO_setConfig (Board_GPIO_LED0、GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
    /*打开用户 LED */
    GPIO_WRITE (Board_GPIO_LED0、Board_GPIO_LED_ON);
    #endif
    
    /*设置优先级和堆栈大小属性*/
    pthread_attr_init (&attr1);
    priParam1.sched_priority = 1;
    
    detachState1 = pthread_create_detached;
    retc1 = pthread_attr_setdetachstate (&attr1、detachState1);
    如果(retc1!= 0){
    /* pthread_attr_setdetachstate()失败*/
    while (1);
    }
    
    pthread_attr_setschedparam (&attats1、&priParam1);
    
    retc1 |= pthread_attr_setstacksize (&attr1、THREADSTACKSIZE);
    如果(retc1!= 0){
    /* pthread_attr_setstacksize()失败*/
    while (1);
    }
    
    /*创建接收线程*/
    retc1 = pthread_create (&thread1、&attr1、echoExampleThread、NULL);
    如果(retc1!= 0){
    /* pthread_create()失败*/
    while (1);
    }
    
    Task_Params taskParams;
    Task_Params_init (&taskParams);
    taskParams.STACKSIZE = TASKSTACKSIZE;
    taskParams.stack =_task1Stack;
    taskParams.priority = 2;
    Task_construct(&task1Struct,(Task_Functr)myTreatmentThread,&taskParams,NULL );
    
    返回(NULL);
    }
    

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

    您好、Cl é ment、

    很好、非常感谢。

    BR

    Trevor  

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

    您好、Cl é ment、

    关于"myTreatmentThread"、我们是否需要添加 Hwip_disable()/Hwip_restore (key)来访问数据?

    谢谢。

    BR

    Trevor

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

    尊敬的 Trevor:

    我们处理存储在特定队列中的某些事务时不需要该操作(我们确保没有人[即读取或写入接口]同时访问相同的数据)。 此外、我们还保证治疗队列的第一个元素不会被修改(写入接口在治疗队列末尾对元素进行排队)。

    注意:使用此 Hwip_disable()/Hwip_restore (key)不会有任何影响、但会略微降低性能。

    此致、

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Cl é ment、
    明白了、谢谢。
    关于默认的 i2secho 示例,我在 readCallbackFxn()中进行了一些修改,并在 printf()函数上设置了一个断点。 然后我检查了 buf1存储器、这个缓冲器全为零、这个行为是否正确?



    静态空 readCallbackFxn (I2S_Handle handle、int_fast16_t status、I2S_Transaction *事务 Ptr){
    /*
    *每次启动读取事务时都会执行此回调的内容
    *
    read_data_cnt++;
    if (read_data_cnt = 1)
    printf ("获得 PCM!!!!!!")



    谢谢。

    BR
    Trevor
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Trevor:
    这种行为完全正常:如果要查看数据、应查看上一个事务所保存的缓冲区。
    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Cl é ment、
    我看到、但前四个回调只能获取空数据。

    谢谢。
    BR
    Trevor
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Trevor:
    在四个第一个缓冲区之后是否有预期的数据? 则可能是由于编解码器启动的时间。
    您是否在输出端具有预期的数据? 那么您不会看到合适的缓冲器。
    此致、
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Cl é ment、  

    我认为编解码器可能还没有 准备好捕获帧。

    关于 您的"在连续流模式下写入数据"示例、它可以工作、但它具有较大的背景噪声(例如白噪声)。   

    你对我有什么建议吗?

    谢谢。

    BR

    Trevor

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Trevor:
    首先、您应该确定是谁在增加该噪声。 是 CC26X2还是编解码器?
    例如,您可以验证设备发出的数据是否正确。 为此,您可以按以下方式继续:
    -卸下 BoosterPack
    -环回 I2S (即将两条数据线连接在一起)
    -用已知数据填充您的写入缓冲区
    -执行程序
    -检查读取的数据是否与写入的数据相同
    -如果您有合适的设备、您也可以查看导线上输出的数据

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

    您好、Cl é ment、

    关于背景噪声、我发现它没有配置 i2sParams.samplingFrequency。

    添加 i2sParams.samplingFrequency=16000后、背景噪声消失了。

    另一件事是、我遇到了新问题、我们需要对音频质量进行一些验证。 首先、我们需要记录 PCM 原始数据并 在 PC 端对其进行分析。

    所以我 在 myTreatmentThread()中添加了 WritetoSDCard()函数,但是录制文件有很大的噪音(我们尝试了很多第三方播放工具),请参阅 随附的文件,您也可以 从以下链接下载免费软件:

    https://www.audacityteam.org/download/

    我 已经验证 了旧 I2S 驱动程序上的 WritetoSDCard()函数,它工作正常。   

    BTW、您认为我们是否需要为音频噪声开辟新的主题?

    e2e.ti.com/.../ti_5F00_pcm.raw.zip

    谢谢。

    BR

    Trevor  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Trevor:
    很好的采样频率捕捉(这肯定是一个错误)!
    对于其余的问题、是的、请打开一个新主题以处理您的新问题。
    此致、