尊敬的 TI 支持:
我们在与 DMA 模块相关的 ADC 模块中发现了一个潜在的错误/未记录的行为。
我们已经找到了一种适合我们的解决方法、但希望您可以查看它或为我们提供替代方法。
首先、让我解释一下我们的设置:
我们使用来自 TMS 的21个 ADC 通道。
17通道在组1中、将由 SW 触发。 通道由任务(SafeRTOS)使用函数 ADC_TMS570LS_getADCValue (请参阅下文)触发
4通道在组2中、由 RTI_COMP_0作为组转换触发。
每次组转换都应触发 DMA 请求、然后将组缓冲器复制到 RAM 中。
DMA 的配置如下:
- 每帧8个元素(= ADC 组2 FIFO 大小)
- 元素大小为32位
- 帧传输
RTI_COMP_0计时器也用作操作系统的 SysTick 中断。 (1000Hz 频率)
我们注意 到、在一段未定义但特定的时间后、G2_Thr 将从8 (=FifoSize = ElementCount)缓慢下降到0。
当 G2_Thr 达到0时、DMA 请求被更频繁地触发、并且 DMA 读取的值无效。
我们已经了解到、如果我们启动转换、G2_Thr 会降低、如果它未被读取、则会再次增加。
我们期望以下行为:
- 每1ms 触发一次 ADC 转换
- 4个有效的 ADC 值被写入组2缓冲器
- 成功地将4个 ADC 值写入组缓冲器后、DMA 被触发
- DMA 将整个组缓冲器(8个元件)复制到已配置的 RAM 部分。
- 因此、每1ms、我们就会在 RAM 中看到4个新的 ADC 值
在我们的系统中、我们还使用 CAN 节点。 如果我们增加 CAN 上的总线负载、我们会注意到 G2_Thr 的值下降得更快。
同时 、由 SW 触发的 ADC 通道更频繁地超时(检查 ADC_TMS570LS_getADCValue)。
对我们来说、似乎有两个问题:
- 软件触发的手动 ADC 转换与直接通过 RTI 触发的自动转换之间可能会发生冲突
- 是否有任何有关可能发生冲突的文档? 如果是,如何防止碰撞?
- 冲突发生后、DMA 请求速度过快
- 我们预计只有在写入4个有效 ADC 值时才会发生 DMA 请求
在确定问题时、我们开发了一种解决方法、该方法对我们有效、但我们需要您进行验证。
- 我们将硬件触发源设置为 NHET-14
- 从而使触发时序发生偏移、并且与 RTI 无关
- 我们在软件中检查 G2_Thr、如果它低于5、则:
- 复位 FIFO: ADC[0]->GxFIFORESETCR[2]= 1;
- 清除转换结束标志和阈值 IRQ 标志、 ADC[0]->GxINTFLG[2]= 9;
- 将阈值计数器设置为8; ADC[0]->GxINTCR[2]= 8;
- 将 G2_Blocks 设置为8: ADC[0]->G2DMACR= 0x0008000D;
- 启用组1转换结束中断使能
- 因此、软件触发的 ADC 转换不会超时。
以下是我们的代码函数:
adc_status_t adc_tms570LS_getADCValue (const adc_SignalConfig*信号、uint16_t* adcValue)
{
adc_status_t adcStatus = adc_FAILRUE;
ADC_DATA_t convData[22]={0};
uint8_t adcPortIndex =(信号->端口=ADC_Porta)? 0:1;
ADC_TMS570LS_startConversion (SIGNAL);/* Aquire Conversion Data */
if ((adcReg[adcPortIndex]->GxSEL[信号->组]!= 0U)
{
uint16_t 超时= 0xFFFF;
//等待完成
while (!ADC_TMS570LS_isConversionComplete (SIGNAL)&& TIMEOUT)
{
超时--;
}
if (超时!= 0U)
{
ADC_TMS570LS_getData (信号、转换数据);
*adcValue = convData[0]。value;
adcStatus = adc_Success;
}
其他
{
adcStatus = adc_timeout;
}
}
返回 adcStatus;
}
ADC_TMS570LS_getData:
静态 uint32_t ADC_TMS570LS_getData (const ADC_SignalConfig*信号、ADC_DATA_t*数据)
{
uint32_t count = uint32_MAX;
uint8_t adcPortIndex =(信号->端口=ADC_Porta)? 0:1;
uint32_t buf;
uint32_t intcr_reg = adcReg[adcPortIndex]->GxINTCR[信号->组]; //多空间 RTE:NIV [对齐]
adc_data_t* ptr =数据;
uint32_t 计数=(intcr_reg >= 256U)? FioSize[adcPortIndex]:(FioSize[adcPortIndex]–(intcr_reg & 0xFFU);
if ((adcReg [(uint8_t) signal->port - 1U]->OPMODECR & 0x80000000U)>0) // if ADC 配置为12位分辨率
{
/**- 获取转换数据和通道/引脚 ID */
for (uint32_t i = 0U;i < count;i++)
{
buf = adcReg[adcPortIndex]->GxBUF[信号->组].BUF0; //多空间 RTE:NIV [对齐]
ptr ->值=(uint16)(buf & 0xFFFU);
ptr -> id =(uint32)((buf >> 16U)& 0x1FU);
PTR++;
}
}
adcReg[adcPortIndex]->GxINTFLG[信号->组]= 9U;
返回计数;
}
此致、
Thorben