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/MSP432P401R:多任务处理赢得#39;t 使用 ADCBuf 连续模式

Guru**** 2553450 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/593435/rtos-msp432p401r-multitasking-won-t-work-with-adcbuf-continuos-mode

器件型号:MSP432P401R

工具/软件:TI-RTOS

CCS 版本 7.1.0.00016

Simplink MSP432 SDK 版本1.30.00.40

大家好、

我正在 MSP-EXP432P401R LaunchPad 上使用 TI-RTOS 和 TI 驱动程序开发一个简单的音频项目。

我有3项任务:

第一个是 ADC 任务。 此任务在连续模式下初始化 ADCBuf 模块、采样频率为48kHz、然后此任务将被终止。 模拟信号将在后台采样、转换为微伏并存储到缓冲器中、让我将其称为 AudioBuffer_in[AUDIO_buffer_size]。 ADC 任务的优先级为3。

ADC 任务的源代码:

//=========== ADCtask.h ========================================

#ifndef SOURCEFILES_TASTS_ADCTASK_H_
#define SOURCEFILES_TASTS_ADCTASK_H_

//*以 Hz 为单位的 ADC 采样频率*/
#define ADC_SAMPLING_FREQ 48000

#endif /* SOURCEFILES_TASTS_ADCTASK_H_*/====================================================================================================================================================================================================================================================================================================================================================



ADCTask.c ===========================

/*标准头文件*/
#include 
#include 
#include 

/* XDC 模块接头*/
#include 
#include 
#include 

/* TI-RTOS 头文件*/
#include 
#include 
#include 

/* TI 驱动程序标题*/
#include 
#include 

/*板接头*/
#include "Board.h"

#include 
#include 

/*
*私有变量
*/
ADCBuf_handle adcBuf;
ADCBuf_Params adcBuf_Params;
ADCBuf_Conversion adcBuf_ContinuousConversion[2];
uint16_t SampleBufferOne[2][AUDIO_buffer_length];
uint16_t sampleBufferTwo[2][AUDIO_buffer_length];

//
*函数声明
*/
void adcTask_function (UArg0、UArg1 arg1);
void adcBuf_callback (ADCBUF_Handle handle、ADCBUF_Conversion *转换、void *完整的 ADCBuffer、 uint32_t 完整通道);

/*
初始化 ADC 线程。
*/
void ADCTask_Init (void){

Task_handle adcTask;
Task_Params adcTask_Params;
ERROR_Block errorBlock;

/*初始化驱动程序*/
ADCBuf_init ();

/*初始化错误块*/
ERROR_INIT (错误块);

/*创建主任务*/
Task_Params_init (&adcTask_Params);
adcTask_Params.STACKSIZE = ADC_TASK_STACK_SIZE;
adcTask_Params.priority = adc_task_priority;
adcTask = Task_create ((Task_FuncPtr) adcTask_function、&adcTask_Params、&errorBlock);
if (adcTask == NULL){
/*无法创建 ADC 任务*/
while (1);
}
}/*


ADC 任务函数。
//
void adcTask_function (UArg0、UArg0 arg1){

/*初始化 ADCBuf 参数*/
ADCBuf_Params_init (&adcBuf_Params);
adcBuf_Params.samplingFrequency = ADC_SAMPLING_FREQ;
adcBuf_Params.RecurrencedMode = ADCBuf_Recurrence_mode_continuous;
adcBuf_Params.returnMode = ADCBuf_return_mode_callback;
adcBuf_Params.callbackFxn = adcBuf_callback;

/*打开 ADCBuf0 */
adcBuf = ADCBuf_open (Board_ADCBUF0、&adcBuf_Params);
如果(!adcBuf){
/* AdcBuf 未正确打开。 *
while (1);
}

/*配置转换结构*/
adcBuf_ContinuousConversion[0].arg = NULL;
adcBuf_ContinuousConversion[0].adcChannel = Board_ADCBUF0CHANNEL0;
adcBuf_ContinuousConversion[0].samplpleBuffer = samplpleBufferOne[0];
adcBuf_ContinuousConversion[0].sampleBufferTwo = sampleBufferTwo[0];
adcBuf_ContinuousConversion[0].samplesRequestedCount = audio_buffer_length;
adcBuf_ContinuousConversion[1].arg = NULL;
adcBuf_ContinuousConversion[1].adcChannel = Board_ADCBUF0CHANNEL1;
adcBuf_ContinuousConversion[1].samplpleBuffer = samplpleBufferOne[1];
adcBuf_ContinuousConversion[1].samplpleBufferTwo = sampleBufferTwo [1];
adcBuf_ContinuousConversion[1].samplesRequestedCount = audio_buffer_length;

/*开始转换*/
if (ADCBuf_convert (adcBuf、adcBuf_ContinuousConversion、2)!= ADCBuf_STATUS_SUCCESS){
/*未正确启动转换过程。 *
while (1);
}
}/*


ADCBuf 回调函数。
//
void adcBuf_callback (ADCBuf_handle、ADCBuf_Conversion *转换、void *完整的 ADCBuffer、uint32_t 完整的通道){
/*调整原始 ADC 值*/
ADCBuf_adjustRawValues (handle、completedADCBuffer、audio_buffer_length、completedChannel);

/*将 ADC 值转换为微伏并将其保存到输入音频缓冲器中*/
ADCBuf_convertAdjustedToMicroVolts (Handle、completedChannel、completedADCBuffer、AudioBuffer_in[completedChannel]、AUDIO_buffer_length);
}

第二个是主任务。 此任务首先初始化其他2个任务、然后进入无限 while 循环。 在 while 循环中、它获取 AudioBuffer_in 中的数据、处理数据并将处理的数据存储到另一个缓冲区 AudioBuffer_out[AUDIO_buffer_size]中。 之后、它将发送一个信标发布信号、通知第三个任务、即 PWM 任务、来完成它们的任务。 主任务的优先级为1。

主任务源代码:

//=================== MainTask.h =================================


#ifndef SOURCEFILES_TASKS_MAINTASK_H_
#define SOURCEFILES_TASKS_MAINTASK_H_

#include 

/*主任务优先级和以字节为单位的堆栈大小*/
#define MAIN_TASK_PRIORITY 1
#define MAIN_TASK_STACK_SIZE 1024

// PWM 任务优先级和以字节为单位的堆栈大小*/
#define PWM_TASK_PRIORITY 2
#define PWM_TASK_STACK_SIZE 1024

/* ADC 任务优先级和以字节为单位的栈大小*/
#define ADC_TASK_PRIORITY 3
#define ADC_TASK_STACK_SIZE 1024

//音频缓冲器长度*/
#define AUDIO_Buffer_length 1024

//全局变量*/
extern semaphore_handle 信号量;
extern uint32_t AudioBuffer_in[2][AUDIO_buffer_length];
extern uint32_t AudioBuffer_out[2][AUDIO_buffer_length];

//初始化主任务*/
extern void MainTask_Init (void);

#endif /* SOURCEFILES_TASTS_MAINTASK_H_*/


//=================== MainTask.c =================================


/*标准头文件*/
#include 
#include 
#include 

/* XDC 模块接头*/
#include 
#include 
#include 

/* TI-RTOS 头文件*/
#include 
#include 
#include 

/* TI 驱动程序标题*/
#include 

/*板接头*/
#include "Board.h"

#include 
#include 
#include 
#include 

/*
全局变量
*/
Semaphore_handle 信标;
uint32_t AudioBuffer_in[2][AUDIO_buffer_length];
uint32_t AudioBuffer_out[2][AUDIO_buffer_length];

/*
私有变量。
//
////*回波效果变量*/
Echoect_Params Effect_Params ={5、200、2};

//
*函数声明。
//
void mainTask_function (UArg0、UArg0 arg1);

//
初始化主线程。
*/
void MainTask_Init (void){

Task_handle 维护任务;
Task_Params mainTask_Params;
ERROR_Block errorBlock;
Semaphore_Params semaphore_Params;

/*初始化驱动程序*/
GPIO_init();

/*初始化错误块*/
ERROR_INIT (错误块);

/*创建主任务*/
Task_Params_init (mainTask_Params);
mainTask_Params.STACKSIZE = main_task_stack_size;
mainTask_Params.priority = main_task_priority;
mainTask = Task_create ((Task_FuncPtr) mainTask_function、mainTask_Params、&errorBlock);
if (mainTask == NULL){
/*创建主任务失败*/
while (1);
}

/*创建信标句柄*/
Semaphore_Params_init (&semaphore_Params);
信号量= Semaphore_create (1、Semaphore_Params、&errorBlock);
if (信标=NULL){
/*无法创建信标对象*/
while (1);
}
}/*


主任务函数。
*/
void mainTask_function (UArg0、UArg0 arg1){

/*初始化 ADC 任务*/
//ADCTask_Init();

/*初始化 PWM 任务*/
PWMTask_Init();

/*永久循环*/
while (1){

GPIO_TOGGLE (Board_GPIO_LED0);

/*应用音频效果*/
EchoEffect_ApplyEffect (AudioBuffer_in[0]、AudioBuffer_out[0]、AUDIO_Buffer_length、&Effechoect_Params);
EchoEffect_ApplyEffect (AudioBuffer_in[1]、AudioBuffer_out[1]、AUDIO_buffer_length、&Effechoect_Params);

/*发布信标*/
Semaphore_post (信标);

睡眠(1);
}
}

我上面提到的第三个任务是 PWM 任务。 此任务首先初始化 PWM 模块、在其 while 环路中、它等待来自主任务的信标信号、同时通过调用信标挂起来阻止信号。 当信号进入时、它获取 AudioBuffer_out 中的数据、计算该缓冲区中每个值所需的占空比、然后更改 PWM 信号的占空比。 PWM 的频率为250kHz。 此任务的优先级为2。

PWM 任务的源代码:

//======================================== PWMTask.h ================================================


#ifndef SOURCEFILES_TASKS_PWMTASK_H_
#define SOURCEFILES_TASKS_PWMTASK_H_

//* PWM 频率(Hz)*/
#define PWM_FREQ 250000

/*初始化 PWM 任务。 */
extern void PWMTask_Init (void);

#endif //* SOURCEFILES_TASKS_PWMTASK_H_*/


//=========================== PWMTask.c =========================================


/*标准头文件*/
#include 
#include 
#include 

/* XDC 模块接头*/
#include 
#include 
#include 

/* TI-RTOS 头文件*/
#include 
#include 
#include 

/* TI 驱动程序标题*/
#include 
#include 

/*板接头*/
#include "Board.h"

#include 
#include 

/*
*函数声明
*/
void pwmTask_function (UARg arg0、UARg arg1);

/*
初始化 PWM 线程。
*/
void PWMTask_Init (void){

Task_handle pwmTask;
Task_Params pwmTask_Params;
ERROR_Block errorBlock;

/*初始化驱动程序*/
PWM_init();

/*初始化错误块*/
ERROR_INIT (错误块);

/*创建主任务*/
Task_Params_init (&pwmTask_Params);
pwmTask_Params.STACKSIZE = PWM_TASK_STACK_SIZE;
pwmTask_Params.priority = PWM_task_priority;
pwmTask = Task_create ((Task_FuncPtr) pwmTask_function、&pwmTask_Params、&errorBlock);
if (pwmTask = NULL){
/*无法创建 PWM 任务*/
while (1);
}
}/*


PWM 任务函数。
//
void pwmTask_function (UArg0、UArg0 arg1){

/* PWM 句柄和参数*/
PWM_Handle PWM[2];
PWM_Params pwmParams;

/*初始化 PWM 参数*/
PWM_PARAMS_INIT (&pwmParams);
pwmParams.idleLevel = PWM_IDLE_LOW;
pwmParams.dutyUnits = PWM_Duty_Fraction;
pwmParams.dutyValue = PWM_Duty_Fraction _MAX / 2;
pwmParams.periodUnits = PWM_PERIOD_Hz;
pwmParams.periodValue = PWM_FREQ;

/*打开并启动 PWM[0]*/
PWM[0]= PWM_OPEN (Board_PWM0、&pwmParams);
if (PWM[0]= NULL){
/*无法打开 PWM0 */
while (1);
}
PWM_START (PWM[0]);

/*打开并启动 PWM[1]*/
PWM[1]= PWM_OPEN (Board_PWM1、&pwmParams);
如果(PWM[1]= NULL){
/*打开 PWM1失败*/
while (1);
}
PWM_START (PWM[1]);

/*永久循环*/
while (1){

/*等待主任务发布信标*/
Semaphore_pend (Semaphore、BIOS_wait_forever);

uint16_t i;

对于(i = 0;i < AUDIO_buffer_length;i++){
PWM_setDuty (PWM[0]、(uint32_t)((((float) AudioBuffer_out[0][i])/ 2500000)* PWM_Duty_Frite_MAX));
PWM_setDuty (PWM[1]、(uint32_t)((((float) AudioBuffer_out[1][i])/ 2500000)* PWM_Duty_Frage_MAX));
}

GPIO_TOGGLE (Board_GPIO_LED1);
}
}

主任务将在 BIOS_start()调用之前初始化。 另外两个将在主任务函数中初始化。

问题是主任务、如果我初始化 ADC 任务、PWM 任务将无法正常工作。 如果我不这么做、主任务和 PWM 任务工作正常、主任务在 AudioBuffer_in 中获取数据(在本例中、所有值等于0)、处理数据并发送信标 POST 信号。 PWM 会立即接收信号、因为它具有更高的优先级。 PWM 任务执行其任务、并通过调用信标挂起而被阻止、而主任务再次运行、依此类推。 让我们看看 主任务函数中的 ADCTask_Init()行。 如果我将其注释掉、这意味着没有 ADC 任务、因此其他任务可以正常工作。

任何人请帮帮我。

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

    感谢您提出这个问题。 我们将对此进行研究。 您是否能够在偶然的情况下发送您正在处理的完整项目文件? 我们希望看到您在 MSP432P401R.c 文件中为 ADC 设置的内容以及其他内容、拥有完整项目将帮助我们更快地开始调查并尝试重新创建您的问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Evan、

    非常感谢您的回复。

    下面随附了我的完整项目文件。 希望您能在这方面为我提供帮助。

    再次感谢 Evan.e2e.ti.com/.../DigitalAudioSignalProcessing_5F00_TIRTOS.rar

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

    您的 MCU 时钟的运行速度有多快?

    请记住、对于48kHz 采样、每个采样只需20uSc (如果是立体声采样、则仅需10uSec)。 在16MHz 时、即320个时钟/样本、但您似乎正在为每个样本执行大量工作。

    ADC 任务的优先级非常重要、因为它会立即结束。 回调从 ISR 运行、因此具有固有的极高优先级、能够完成其他任务。

    一个简单的实验:如果您将采样率减半、那么它的运行情况如何?

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

    您好、Bruce、

    感谢您的回复。

    我的 MCU 以48MHz 的频率运行。 我一直在思考你以前说过什么、但我不确定。

    由于 ADC 回调函数从 ISR 运行、因此当我调试项目时、我看到 ADC 回调函数也运行、并且我在 AudioBuffer_in 中有数据、但由于 ADC 回调第一次运行、其他2个任务将不运行。

    因此、我认为这可能是主要原因、但让我尝试按照您所说的那样更改采样率。

    再次感谢 Bruce。

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

    您好、Bruce、

    我尝试将采样率降低到8kHz、甚至更低、但没有任何变化。 ADC 回调函数始终以更高的优先级运行、因此其他任务没有机会运行。

    您对此有任何建议吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    我认为问题在于驾驶员。 具体而言、如果您查看 driverLib API、MAP_ADC14_enableSampleTimer (ADC_AUTOMATE_DETERMDICTION);、在 primeConvert 函数中使用(C:\ti\simplelink_msp432_sdk_1_30_00_40\sources\ti\drivers\adcbuf\ADCBufMSP432.c)。

    此函数设置 MSC 位、以便在前一次转换完成后立即自动执行采样和转换。 (SLAU356f、表20-4、 www.ti.com/.../slau356f.pdf )

    为了影响采样率而对定时器进行的任何更改都不会影响系统。 您可以尝试操纵转换时间以获得所需的结果。 此外、请注意您选择的电源设置。 请参阅以下摘自 C:\ti\simplelink_msp432_sdk_1_30_00_40\source\ti\drivers\power\PowerMSP432.c 的功耗性能级别 由于 ADC 时钟由 MCLK 驱动、因此只能选择性能级别0和1 (C:\ti\simplelink_msp432_sdk_1_30_00_40\source\ti\drivers\adcbuf\ADCBufMSP432.c 的第270行)。

    /*
    * Power_setPerformanceLevel ()初始实现的注意事项
    *
    * 1)支持四种性能级别:
    *
    *电平 MCLK (MHz) HSMCLK (MHz) SMCLK (MHz) ACLK (Hz)
    *---- ------ ------ ------ ------
    * 0 12. 3. 3. 32768
    * 1 24 6. 6. 32768
    * 2. 48 24 12. 32768
    * 3. 48 48 24 32768
    *
    *仅支持四个性能级别约束:
    *
    * PowerMSP432_disallow_PERFLEVEL_0
    * PowerMSP432_disallow_PERFLEVEL_1
    * PowerMSP432_disallow_PERFLEVEL_2
    * PowerMSP432_disallow_PERFLEVEL_3
    *
    * 2) DCO 是唯一受支持的时钟源(所有时钟都是由此产生的;
    *不使用 LF 和 HF XTAL)
    *
    * 3) ACLK 固定为32768Hz
    *
    * 4)假定 DCDC 可用
    *
    * 5)硬件中断在性能级别变化期间被禁用
    *
    *

    我将查看您本周发布的代码。

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

    尊敬的 Chris:

    感谢您的回复、也感谢您提供的上述大量信息。 现在、我尝试另一种使用音频编解码器芯片的方法、而不是 MCU 上的自 ADC/DAC。

    再次感谢 Chris。