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.

[参考译文] TM4C1233H6PZ:ADC - UDMA 问题

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/826727/tm4c1233h6pz-adc---udma-issue

器件型号:TM4C1233H6PZ

您好!  

我正在尝试使用 ADC 序列发生器读取9个模拟输入、并使用 UDMA 将数据存储在缓冲器中。  两个序列发生器单独工作、但当它们一起配置时、它们开始起作用。  启用两个序列发生器后、整个序列发生器中只有一个将其数据传输到缓冲器。  这种行为也是可预测的。  数据被传输的序列发生器始终是发起 ADC 序列发生器中断的序列发生器。 例如、如果我将序列发生器0配置为启动中断、则缓冲区中只会显示序列0、但如果我将序列发生器1配置为触发中断、则缓冲区中将显示该数据。  以下是我的代码:

/*私有变量 /**
@defgroup _EPPC_ADC_PRIVE_Variables private Variables
*@*/

/**创建一个数组,描述每个模拟输入的用途。
*
*/
analog_inputs_t analogInputs[total_analog_inputs];
/**存储由 uDMA 传输的 ADC 值
*
/
uint32_t u32_aInBuffer[total_analog_inputs];
/**
*@}
*/*

private 函数 /**
@defgroup _EPPC_ADC_PRIVE_FUNCGES PRIVATE PRIVATE FUNCINCINS
*@{
*/

* function:functionName */
**
*@brief 函数说明
*@参数 函数参数
*@retval 返回值
*/

/*
@}
*

//*公共函数 /**
@defgroup _EPPC_ADC_Public_Functions 公共函数
*@{
*/
void ADC_SS1_int_handler (void)
{
//获取中断状态
uint32_t u32_adc0Status = MAP_ADCIntStatusEx (ADC0_base、true);
//清除中断标志
MAP_ADCIntClearEx (ADC0_BASE、u32_adc0Status);

//设置 UDMA 的传输参数
MAP_uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | //ADC 序列0
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_MODE_BASIC、 //执行基本数据传输
(void *)(ADC0_BASE + ADC_O_SSFIFO0)、//数据传输源
u32_aInBuffer、 //数据传输的目的地
8); //数据项数
//启用 uDMA 通道
MAP_uDMAChannelEnable (UDMA_CHANGE_ADC0);

//设置 UDMA 的传输参数
MAP_uDMAChannelTransferSet (UDMA_CHANGE_ADC1 | //ADC 序列1
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_MODE_BASIC、 //执行基本数据传输
(void *)(ADC0_BASE + ADC_O_SSFIFO1)、//数据传输源
u32_aInBuffer[8]、 //数据传输的目的地
1); //数据项数
//启用 uDMA 通道
MAP_uDMAChannelEnable (UDMA_CHANGE_ADC1);
}
/*函数:ADC_Initialize */
//*
@brief 初始化 ADC
*@retval none
*/
void adc_initialize (void)
{
//初始化模拟输入结构
//AIN0
analogInput[0]=(analog_inputs_t){0、false};
//AIN1
analogInputs[1]=(analog_inputs_t){0、false};
//AIN2
analogInput[2]=(analog_inputs_t){0、false};
//AIN3
analogInput[3]=(analog_inputs_t){0、false};
//AIN4
analogInput[4]=(analog_inputs_t){0、false};
//AIN5
analogInput[5]=(analog_inputs_t){0、false};
//AIN6
analogInput[6]=(analog_inputs_t){0、false};
//AIN7
analogInput[7]=(analog_inputs_t){0、false};
//泵电流
analogInput[8]=(analog_inputs_t){0、false};

//启用 ADC0外设
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_ADC0);

//对64个 ADC 样本求平均值以提供更高分辨率的测量
MAP_ADCHardwareOversampleConfigure (ADC0_BASE、64);

//启用外设
MAP_SysCtlPeripheralEnable (AIN_Periph_0TO3);
MAP_SysCtlPeripheralEnable (AIN_Periph_4TO7);
MAP_SysCtlPeripheralEnable (AIN_Periph_pump);

//启用 GPIO 引脚上的模拟输入
MAP_GPIOPinTypeADC (AIN_PORT_0TO3、AIN_PIN_0 | AIN_PIN_1 | AIN_PIN_2 | AIN_PIN_3);
MAP_GPIOPinTypeADC (AIN_PORT_4TO7、AIN_PIN_4 | AIN_PIN_5 | AIN_PIN_6 | AIN_PIN_7);
MAP_GPIOPinTypeADC (AIN_PORT_PUMP、AIN_PIN_PUMP);

//配置 ADC 序列发生器
MAP_ADCSequenceConfigure (ADC0_BASE、 //ADC 基址0
0、 //序列发生器0 (最多捕获8个样本)
ADC_TRIGGER_TIMER、 //ADC 触发器由计时器生成
0); //序列发生器优先级
MAP_ADCSequenceConfigure (ADC0_BASE、 //ADC 基址0
1、 //序列发生器1 (最多捕获4个样本)
ADC_TRIGGER_TIMER、 //ADC 触发器由计时器生成
1); //序列发生器优先级

//配置每个 ADC 序列的步长
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
0、 //序列顺序
AIN_0); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
1、 //序列顺序
AIN_1); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
2、 //序列顺序
AIN_2); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
3、 //序列顺序
AIN_3); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
4、 //序列顺序
AIN_4); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
5、 //序列顺序
AIN_5); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
6、 //序列顺序
AIN_6); //ADC 通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
0、 //序列号
7、 //序列顺序
AIN_7 | ADC_CTL_END);//ADC 通道和序列中的最后一个通道
MAP_ADCSequenceStepConfigure (ADC0_BASE、 //ADC 基准
1、 //序列号
0、 //序列顺序
AIN_PUMP | ADC_CTL_END | ADC_CTL_IE);//ADC 通道和序列中的最后一个通道。
//序列发生器1完成后,它将生成一个中断,告知处理器 FIFO 已填充

//启用 ADC 序列0和1
MAP_ADCSequenceEnable (ADC0_BASE、0);
MAP_ADCSequenceEnable (ADC0_BASE、1);

//为序列0和1启用 DMA
MAP_ADCSequenceDMAEnable (ADC0_BASE、0);
MAP_ADCSequenceDMAEnable (ADC0_BASE、1);



//为 ADC 序列配置 uDMA


//序列0 uDMA 配置
uDMA 通道的//启用属性
MAP_uDMAChannelAttributeEnable (UDMA_CHANGE_ADC0、 //ADC 序列0
uDMA_attr_USEBURST); //将传输限制为仅突发模式
//设置 UDMA 的控制参数
MAP_uDMAChannelControlSet (UDMA_CHANGE_ADC0 | //ADC 序列0
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_SIZE_32 | //32位数据大小
UDMA_SRC_INC_NONE | //无源地址增量
UDMA_DST_INC_32 | //目标地址增量设置为32位
UDMA_ARB_1); //在重新仲裁总线之前发送8个项目
//设置 UDMA 的传输参数
MAP_uDMAChannelTransferSet (UDMA_CHANGE_ADC0 | //ADC 序列0
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_MODE_BASIC、 //执行基本数据传输
(void *)(ADC0_BASE + ADC_O_SSFIFO0)、//数据传输源
u32_aInBuffer、 //数据传输的目的地
8); //数据项数
//启用 uDMA 通道
MAP_uDMAChannelEnable (UDMA_CHANGE_ADC0);

//序列3 uDMA 配置
uDMA 通道的//启用属性
MAP_uDMAChannelAttributeEnable (UDMA_CHANGE_ADC1、 //ADC 序列1
uDMA_attr_USEBURST); //将传输限制为仅突发模式
//设置 UDMA 的控制参数
MAP_uDMAChannelControlSet (UDMA_CHANGE_ADC1 | //ADC 序列1
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_SIZE_32 | //32位数据大小
UDMA_SRC_INC_NONE | //无源地址增量
UDMA_DST_INC_32 | //目标地址增量设置为32位
UDMA_ARB_8); //在重新仲裁总线之前发送1个项目
//设置 UDMA 的传输参数
MAP_uDMAChannelTransferSet (UDMA_CHANGE_ADC1 | //ADC 序列1
UDMA_PRI_SELECT、 //使用主数据结构
UDMA_MODE_BASIC、 //执行基本数据传输
(void *)(ADC0_BASE + ADC_O_SSFIFO1)、//数据传输源
u32_aInBuffer[8]、 //数据传输的目的地
1); //数据项数
//启用 uDMA 通道
MAP_uDMAChannelEnable (UDMA_CHANGE_ADC1);


//为模拟输入配置中断
//在启用前清除序列1中断标志
MAP_ADCIntClearEx (ADC0_BASE、ADC_INT_SS1);
//在外设中启用序列1中断
MAP_ADCIntEnableEx (ADC0_BASE、ADC_INT_SS1);
//在 NVIC 中启用序列1中断
MAP_IntEnable (INT_ADC0SS1);

//配置触发 ADC 的计时器
//启用计时器外设
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_Timer1);
//将系统时钟配置为时钟源
MAP_TimerClockSourceSet (Timer1_base、timer_clock_system);
//将定时器配置为全宽度周期定时器
MAP_TimerConfigure (Timer1_base、TIMER_CFG_PERIODICRACRACASE);
//启用 ADC 触发输出
MAP_TimerControlTrigger (Timer1_base、timer_A、true);
//阻止计时器在调试器停止时计数
MAP_TimerControlStall (Timer1_base、timer_A、true);
频率为1ms 时的//加载计时器
MAP_TimerLoadSet (Timer1_base、timer_A、160000);
//启动 ADC 计时器
MAP_TimerEnable (Timer1_base、timer_A);
} 

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

    即使两个序列都是从同一个计时器触发的、您也应该为序列0和序列1启用中断。 然后是两个中断例程、每个 UDMA 通道一个。  

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

    有什么想法,为什么这种方法不起作用?  我想的过程是将序列发生  器设置在同一个计时器上会触发它们、其中最高优先级序列发生器将首先运行、然后最低优先级将在接下来运行并触发中断。  当时我以为我可以发出两个连续的 uDMA 传输请求

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

    UDMA 突发请求由中断使能位门控。