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.
您好!
我对 ADC 模块转换结束(EOC)后到 ADC 中断实际执行所经历的时间有疑问。 如 数据表中所述、"如果 ADCCTL1寄存器中的 INTPULSEPOS 位置位、t INT 将与锁存到结果寄存器中的转换结果重合"。 我已经根据数据表计算了采样保持时间和 A/D 转换时间。 但是、当我测量从 SOC 到执行 ADC 中断第一行的时间时、会有一段时间下落不明。 我详细阐述了以下问题:
ADCA 模块被配置为转换一个引脚。 采集窗口设置为75ns (t_SH)。 ADC 时钟以50MHz 的频率运行。 系统时钟以200MHz 运行。 根据数据表、t_EOC 时间将为10.3 ADCCLK 周期。 这会使 t_EOC 达到206ns。 因此、t_SH + t_EOC = 281ns。
EPWM1模块配置为 ADC SOC。 SOC 发生在 CTRU = CMPA 时。 动作限定器配置为将通道设置为 CTR =零、并在 CTRU = CMPA 时清除通道。 在示波器上监控 ePWM 通道。
GPIO 引脚(GPIO93)在 ADC 中断例程的第一行被置位、并在例程结束时被清零。 该引脚在示波器上受到监控。
ePWM 通道清零与 GPIO93集之间的时间差测量值为410ns。 测量 GPIO 引脚上的 SET 指令所需的时间约为25ns。 因此、未计算的时间为(410 - 25 - 281) ns = 104ns。 即使我考虑多使用几个周期来锁存 ADC 结果、仍然有很多时间无法计算。
如果在实施或测量中出现错误、请更正我的错误。 如果我能获得一些参考文档 来解释 多余的时间、那将会有所帮助。
如果需要任何其他信息、请告知我。
谢谢你。
Somenath、
请多给我一天时间来回答您的问题、我相信我有我需要的所有信息。
最棒的
Matthew
Somenath、
我将参考 TRM https://www.ti.com/lit/pdf/spruhm8第1581页上的时序图 、以进行以下计算。
上一页包含 SYSCLK 的时序、因此它将变得更简单、因为我们可以使用下面的5ns 周期。 对于50MHz ADC 时钟、我假设 ADCCTL2.prescale = 6、这样会得到200/4 = 50MHz
根据该表、SYSCLK 中从采样结束到 TLATCH 的时间= 44个周期。 因此、这将是44 * 5ns = 220ns。 将75ns 的采集时间相加、我们得到220ns+75ns =从接收触发器开始的总时间295ns。
如果我们看图、还会有一个标记、用于标记 ADCTRIG 信号被 ADC 锁存、这将是您的情况下的 EPWM ADCSOC、让我们假设发生2个额外 SYSCLK 周期的较差情况、那么我们就会这样做
2ns (锁存触发器的时间)+ 75ns (采样保持时间)+ 220ns (转换和锁存时间)= 297ns
我们在应该观察的内容和 o 范围所捕获的内容方面仍然存在差距
297ns + 25ns (GPIO 切换时间)= 322ns
410ns (观测值)- 322ns (预期值)= 88ns。
对于器件处理 ISR 时发生的操作、我们仍需要考虑一些周期。 发生这种情况时、C28x CPU 必须清空其指令流水线(完成已进入管线 https://www.ti.com/lit/SPRU430 D2阶段的任何操作)、并将寄存器内容推送到堆栈
基本上、在获取 ADC ISR 之前、我们将会发生8个周期的损失、因此我们现在可以:
322ns+(8*5ns)= 362ns
410ns-362ns = 48ns 增量时间。
此时、有~10个 CPU 周期未加说明。 我认为、ADC ISR 指令在获取后需要额外的4-5个 CPU 周期才能执行、但不确定这是否已在 GPIO 时序中进行计数。
您能评论一下您的 ADC ISR 是从闪存还是 RAM 存储器运行吗? 如果我们从闪存运行、在200MHz 时、由于时序原因、它具有3WS、因此这可能会增加一些我们尚未包含的额外周期
另一种可能是、当 ADC ISR 进入 C28x 时运行的代码需要周期才能从闪存或 RAM 完成其操作。
如果您对上述内容有任何其他问题、请告诉我。
最棒的
Matthew
Matthew、
感谢您的详尽和及时的回答。
在回答您的问题时、我正在从 RAM 存储器运行代码。
我从上面的讨论中收集的是、如果我们能够确保触发 ADC 中断时 CPU 处于空闲状态、那么可能需要最少的时间来开始处理 ADC ISR。 在等待中断时、我将在主代码中运行一个空的无限循环。 这应该确保在触发中断时 CPU 不会处理任何指令。 我将报告我的调查结果。
请告诉我是否 应该继续。
谢谢、
Somenath。
Somenath、
如果您确保 CPU 处于空闲状态、从而为 ISR 提供最佳响应时间、则您是正确的。
最棒的
Matthew
Matthew、
我已实施了我在上次答复中提到的修改。 现在无限循环内部没有指令。 这确实减少了测量时间。 现在、总时间已从410ns 减少到395ns。 我将使用 while (1)循环来实现此目的。
谢谢、
Somenath。
Somenath、
我认为、就预期行为而言、我们就在那里。 我在前面的计算中发现了一个错误、从 PWM 锁存 ADCINT 的时间是2个 SYSCLK 周期、而不是2ns。 因此、如果没有任何 ISR 开销、我们应该为370ns。 那么、我们现在有了
395 (测量值)-370ns (预期值)= 25ns 或5个增量周期。 我认为这可能是在 CPU 流水线获取该程序代码地址后从 ADCISC 执行该第一条指令所需的时间内考虑的。
最棒的
Matthew
Matthew、
我认为在上述计算中、执行 ADC ISR 第一行(在本例中为 GPIO 引脚切换)的25ns 或5个周期被考虑两次。
总结到目前为止的讨论、时间安排如下:
从 ePWM SOC 锁存触发器的2个周期:10ns
采样保持时间:75ns
转换和锁存时间(锁存 ADC 结果44个周期):220ns
获取 ADC ISR 前的8个周期损失:40 ns
执行 ISR 第一行的时间(在本例中,GPIO 切换为5个周期):25ns
总时间(计算值):370ns
从示波器测得的时间:395ns
我还对审议44个周期的转换和锁存时间表示怀疑。 参考同一文档、时间 t_INT 被称为41个周期。 我从该信息中收集的是在第41个周期之后、设置 ADC 中断触发器。 但是、转换结果 需要44个周期才能锁存到结果寄存器。 我认为、在我们的计算中、我们应该考虑41个周期、而不是44个周期。 这是因为在 CPU 获得 ADC 中断触发器(位于第41个周期)后、8个周期的损失应该开始。
如果我的计算和假设不正确、请更正我。
谢谢、
Somenath。
Somenath、
我也注意到、让我与其他人核实一下、看看这是41还是44。
最棒的
Matthew
Somenath、
感谢您在这里的耐心等待。 我已经确认表中列出的时序是正确的、因此从采样结束到转换完成的41个 CPU 周期。 此时、较晚的 ADCINT 也将触发、这将有助于抵消我们之前讨论过的 ISR 周期/流水线清除。
这也意味着我还有3个 CPU 周期未加说明、或15ns。
因此、我们测得的值为395ns、而预期值为355ns、或者40ns/5ns = 8个 CPU 周期丢失。
我想尝试使用 Code Composer 周期计数来测量此值、以便将其与范围进行比较。 为此、我们还需要将 ADC 触发器从 PWM 更改为仅使用 SW 中的 ADCSOCFRC 位。 我们可以在该指令设置一个 BP、在 ADC ISR 的第一条指令设置另一个 BP、并观察我们得到的周期计数。 然后、我们可以在 GPIO 切换等之后移动 BP、然后与 o 示波器进行比较。
我已经设置了屏幕上限的 CCS、以展示如何实现这一点。 完成此操作后、您应该会在 CCS 窗口的右下角看到一个小时钟。 一旦您按下 BP、您可以双击时钟进行重置。 这将从 C28x CPU 的角度提供周期计数、并且我们可以减少知道 CPU 时钟的时间。
我只想尽可能消除可变性、然后我们可以向后添加更多代码(PWM 触发器等)、并确保我们得到正确的计数以及它与 o 范围的关系。
最棒的
Matthew
Matthew、
感谢您努力调查此问题。 我尝试了您的建议。 我要附上我用于此目的的代码。
#include "F28x_Project.h" // // Function Prototypes // void ConfigureADC(void); void SetupADC(void); interrupt void adca1_isr(void); void main(void) { InitSysCtrl(); DINT; InitPieCtrl(); IER = 0x0000; IFR = 0x0000; InitPieVectTable(); EALLOW; PieVectTable.ADCA1_INT = &adca1_isr; //function for ADCA interrupt 1 EDIS; ConfigureADC(); SetupADC(); IER |= M_INT1; //Enable group 1 interrupts EINT; // Enable Global interrupt INTM ERTM; // Enable Global realtime interrupt DBGM PieCtrlRegs.PIEIER1.bit.INTx1 = 1; DELAY_US(10000); AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1; while(1) { } } void ConfigureADC(void) { EALLOW; AdcaRegs.ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4 AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; DELAY_US(1000); EDIS; } void SetupADC(void) { EALLOW; AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; //SOC0 will convert pin A0 AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; //sample window 75ns AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; //trigger by S/W only AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; //enable INT1 flag AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared EDIS; } interrupt void adca1_isr(void) { DELAY_US(10000); AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; //clear INT1 flag PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; }
我希望这符合您的建议。 如果实施中出现错误、请更正。
我在 ADC ISR 内的"AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1"行设置了一个 BP、在"DELAY_US (10000);"行设置了下一个 BP。 我在第一个断点处将 CCS 时钟复位为0。 下一个 BP 时钟的读数为93。
我收集这意味着两个 BPS 之间的时间为465 ns (因为系统时钟设置为200 MHz)。 这高于 在 o 示波器上测得的395ns。 我想 ePWM SOC 触发器(在原始实现中)与比较事件在 o 示波器上的实际反射之间可能存在滞后。
Somenath、
感谢您的观看、这正是我想要看到的内容。 正如您所注意到的、我们现在看到的延时时间比以前更大、而这是我们所期望的、说实话、这有点令人惊讶。 在 ADC ISR 中点击 BP 后、您是否可以打开拆分窗口来查看/确认我们没有执行任何其他指令?
对于代码放置、您能否确认代码执行的 RAM 地址? 我需要检查以确保该器件上的所有 RAM 都是0WS (我认为是)、但如果对此有任何疑问、这将有助于我缩小范围。
最棒的
Matthew
Matthew、
我确实观察了两个断点的反汇编。 我正在为两个瞬间附加反汇编窗口的快照。
在进入 ADC ISR 和 ISR 内的第一行代码之间、我观察到17条指令。 但是、我无法理解这些指令的用途。
至于代码放置、我要在链接器文件中附加负责 RAM 分配的代码部分。 如果我弄错了、请原谅我、但我收集您的信息是为了查看代码组件在存储器中的存储位置。
SECTIONS { codestart : > BEGIN, PAGE = 0 .text : >>RAMM0 | RAMD0 | RAMLS0 | RAMLS1 | RAMLS2 | RAMLS3 | RAMLS4, PAGE = 0 .cinit : > RAMM0, PAGE = 0 .pinit : > RAMM0, PAGE = 0 .switch : > RAMM0, PAGE = 0 .reset : > RESET, PAGE = 0, TYPE = DSECT /* not used, */ .stack : > RAMM1, PAGE = 1 .ebss : > RAMLS5, PAGE = 1 .econst : > RAMLS5, PAGE = 1 .esysmem : > RAMLS5, PAGE = 1 Filter_RegsFile : > RAMGS0, PAGE = 1 ramgs0 : > RAMGS0, PAGE = 1 ramgs1 : > RAMGS1, PAGE = 1
希望这对您有所帮助。
谢谢、
Somenath。
Somenath、
欣赏屏幕截图。 这17条指令是任何 ISR 上下文保存的一部分(您还将在 ISR 结束时看到还原)。 当任何函数被声明为 ISR 并且我在之前的计算中没有考虑到这一点时、这些函数会自动生成。
如果你可以在这些开始和结束时设置一个 BP 并测量 CPU 周期计数、我认为这将解决我们从理论到实际的时间增量。 如果我假设每个 CPU 指令都是单个 CPU 指令(乐观)、则总时间为435ns、而您看到的时间为465ns 或6个周期的差异。 正如我提到的、我认为其中的一些指令可能需要一个以上的周期、但配置文件应该会揭示这一点。
另一种优化从 ADC 转换到读取的延迟的方法是使用早期中断(发生在信号采样后、但未转换时)。 我们可以使用上面的信息来确定新的 ADC 结果何时准备就绪、一旦我们进入 ISR 中的代码、并根据需要延迟这几个周期(或者执行其他系统操作)。
最棒的
Matthew
Matthew、
感谢您深入了解上下文保存。 我在 ISR 结束时也会看到它们。 因此、我在这17条指令的开头和末尾放置了 BPS。 但是、在这种情况下、右下角的时钟计数为17。 我想它们都是单周期指令。 我已经连接了一个屏幕盖、将 BPS 放置在拆卸中、并将周期计数放置在底部。
我还通过在 ADCSOCFRC 上放置一个 BP、并 在 while (1)行上放置下一个 BP、测量了 ADCSOCFRC 锁存的周期计数。 这需要4个周期。
总结到目前为止的讨论:
ADCSOCFRC 锁存的4个周期
采样保持时间为15个周期
针对 ADC 转换和 ADC 中断触发的41个周期
获取 ADC ISR 之前的8个周期损失
17个运行环境保存周期
总周期数:85个周期
从 ADCSOCFRC 到 ISR 第一行的测量周期数:93个周期
请告诉我是否遗漏了以前的内容。
我也 很欣赏使用早期中断的建议、我一定会尝试这一点。
谢谢、
Somenath。
Somenath、
感谢您打破循环。 让我在其他几个方面进行回放、看看我们是否可以解释从器件到规格的8周期增量。
最棒的
Matthew
Somenath、
我们对此进行了一些内部讨论、现在对周期进行了以下细分、以便更准确地说明触发 ISR 时发生的 CPU 流水线刷新/重新加载。
ADCSOCFRC 锁存的4个周期
采样保持时间为15个周期
针对 ADC 转换和 ADC 中断触发的41个周期
获取 ADC ISR 之前的14个周期损失(管道刷新、主 CPU 寄存器的硬件上下文保存以及获取/调用 ISR 矢量)
在 ISR 内部保存上下文的17个周期
91个 CPU 周期与测得的93个周期
此时、我想我们可以相信您将通过延迟的 ADCINT 获得最佳/可预测的周转时间。
至于2个周期、我认为这取决于 ADC ISR 进入 C28x CPU 时 CPU 所执行的操作、意识到我们在这里有一些空闲循环、 但是、如果我们看看拆分、我们很可能会看到某种类型的分支指令、这种指令会将其自身的中断连续性引入流水线。
此致、
Matthew
Matthew、
感谢您耐心地解决问题。 您提供的时序摘要实际上让我对该过程有了一些了解。
再次感谢您、
Somenath。