我打算用ecap模块来捕获方波的频率,并按照ecap_ex2_capture_pwm例程来修改了代码。在调试过程中我发现如果将断点打在某些位置会导致捕获到的数据出错,类似以下位置:
但如果将断点打在延时函数后,就不会产生错误。
这种情况不是第一次出现了,我之前在调试串口通信时发现如果断点打在串口发送函数之后,会导致发送的数据丢失最后两个比特。我很疑惑为什么会产生这种情况,对于串口,我认为是在中断时串口的发送缓冲区里的数据并未发出,所以会导致比特丢失。但对于ecap模块的这个情况,我理解不了错误产生的原因。
我的代码如下:
#include "F28x_Project.h" #include "driverlib.h" #include "device.h" #include "uart.h" #include "user_ecap.h" volatile uint32_t cap1Count2; volatile uint32_t cap1Count3; volatile uint32_t cap1Count4; volatile uint32_t cap2Count2; volatile uint32_t cap2Count3; volatile uint32_t cap2Count4; volatile uint16_t cap1_flag; volatile uint16_t cap2_flag; volatile uint16_t f1_flag; volatile uint16_t f2_flag; volatile float pulse_f1; volatile float pulse_f2; volatile uint32_t time = 0; void initEcapGpio(XBAR_InputNum input, uint16_t pin, uint32_t pinConfig); void initECAP(uint32_t base, XBAR_InputNum input, uint16_t pin); void CapPulse(uint32_t base); void EnableEcapInterrupt(uint32_t interruptNumber, void (*handler)(void)); __interrupt void ecap1ISR(void); __interrupt void ecap2ISR(void); void main(void) { // Initialize device clock and peripherals Device_init(); // Initialize GPIO and configure the GPIO pin as a push-pull output Device_initGPIO(); #ifdef _STANDALONE #ifdef _FLASH // Send boot command to allow the CPU2 application to begin execution Device_bootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH); #else // Send boot command to allow the CPU2 application to begin execution Device_bootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_RAM); #endif // _FLASH #endif // _STANDALONE // Initialize PIE and clear PIE registers. Disables CPU interrupts. Interrupt_initModule(); // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). Interrupt_initVectorTable(); EnableEcapInterrupt(INT_ECAP1, &ecap1ISR); EnableEcapInterrupt(INT_ECAP2, &ecap2ISR); // Enable Global Interrupt (INTM) and realtime interrupt (DBGM) EINT; ERTM; GPIO_setPadConfig(92, GPIO_PIN_TYPE_PULLUP); // Enable pullup on GPIO92 GPIO_writePin(92, 1); // Load output latch GPIO_setPinConfig(GPIO_92_GPIO92); // GPIO92 = GPIO92 GPIO_setDirectionMode(92, GPIO_DIR_MODE_OUT); // GPIO92 = output //initIPC(IPC_CPU1_L_CPU2_R, IPC_FLAG31); initEcapGpio(XBAR_INPUT7, 32, GPIO_32_GPIO32); initEcapGpio(XBAR_INPUT8, 34, GPIO_34_GPIO34); initECAP(ECAP1_BASE, XBAR_INPUT7, 32); initECAP(ECAP2_BASE, XBAR_INPUT8, 34); f1_flag = 0; f2_flag = 0; cap1_flag = 0; cap2_flag = 0; for (;;) { if (!cap1_flag) { CapPulse(ECAP1_BASE); DEVICE_DELAY_US(1000); cap1_flag = 1; } if (!cap2_flag) { CapPulse(ECAP2_BASE); DEVICE_DELAY_US(1000); cap2_flag = 1; } if (f1_flag) { uint32_t temp = 0; cap1Count2 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2); cap1Count3 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3); cap1Count4 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4); temp = cap1Count2 + cap1Count3 + cap1Count4; temp /= 3; pulse_f1 = 200000000.0 / (float)temp; f1_flag = 0; cap1_flag = 0; } if (f2_flag) { uint32_t temp = 0; cap2Count2 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_2); cap2Count3 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_3); cap2Count4 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_4); temp = cap2Count2 + cap2Count3 + cap2Count4; temp /= 3; pulse_f2 = 200000000.0 / (float)temp; f2_flag = 0; cap2_flag = 0; } //如果中断打在这里会导致捕获数据出错 DEVICE_DELAY_US(500000); //如果中断打在延时函数后数据就是正确的 time++; if (time > 2097152) { GPIO_togglePin(92); time = 0; } // Software breakpoint. // Hit run again to get updated conversions. //ESTOP0; } } void initEcapGpio(XBAR_InputNum input, uint16_t pin, uint32_t pinConfig) { XBAR_setInputPin(input, pin); GPIO_setPinConfig(pinConfig); GPIO_setPadConfig(pin, GPIO_PIN_TYPE_PULLUP); GPIO_setDirectionMode(pin, GPIO_DIR_MODE_IN); GPIO_setQualificationMode(pin, GPIO_QUAL_ASYNC); } void initECAP(uint32_t base, XBAR_InputNum input, uint16_t pin) { // Disable ,clear all capture flags and interrupts ECAP_disableInterrupt(base, (ECAP_ISR_SOURCE_CAPTURE_EVENT_1 | ECAP_ISR_SOURCE_CAPTURE_EVENT_2 | ECAP_ISR_SOURCE_CAPTURE_EVENT_3 | ECAP_ISR_SOURCE_CAPTURE_EVENT_4 | ECAP_ISR_SOURCE_COUNTER_OVERFLOW | ECAP_ISR_SOURCE_COUNTER_PERIOD | ECAP_ISR_SOURCE_COUNTER_COMPARE)); ECAP_clearInterrupt(base, (ECAP_ISR_SOURCE_CAPTURE_EVENT_1 | ECAP_ISR_SOURCE_CAPTURE_EVENT_2 | ECAP_ISR_SOURCE_CAPTURE_EVENT_3 | ECAP_ISR_SOURCE_CAPTURE_EVENT_4 | ECAP_ISR_SOURCE_COUNTER_OVERFLOW | ECAP_ISR_SOURCE_COUNTER_PERIOD | ECAP_ISR_SOURCE_COUNTER_COMPARE)); // Disable CAP1-CAP4 register loads ECAP_disableTimeStampCapture(base); // // Configure eCAP // Enable capture mode. // One shot mode, stop capture at event 4. // Set polarity of the events to rising, rising, rising, rising edge. // Set capture in time difference mode. // Select input from XBAR7. // Enable eCAP module. // Enable interrupt. // ECAP_stopCounter(base); ECAP_enableCaptureMode(base); ECAP_setCaptureMode(base, ECAP_ONE_SHOT_CAPTURE_MODE, ECAP_EVENT_4); ECAP_setEventPolarity(base, ECAP_EVENT_1, ECAP_EVNT_RISING_EDGE); ECAP_setEventPolarity(base, ECAP_EVENT_2, ECAP_EVNT_RISING_EDGE); ECAP_setEventPolarity(base, ECAP_EVENT_3, ECAP_EVNT_RISING_EDGE); ECAP_setEventPolarity(base, ECAP_EVENT_4, ECAP_EVNT_RISING_EDGE); ECAP_enableCounterResetOnEvent(base, ECAP_EVENT_1); ECAP_enableCounterResetOnEvent(base, ECAP_EVENT_2); ECAP_enableCounterResetOnEvent(base, ECAP_EVENT_3); ECAP_enableCounterResetOnEvent(base, ECAP_EVENT_4); XBAR_setInputPin(input, pin); ECAP_enableLoadCounter(base); ECAP_setSyncOutMode(base, ECAP_SYNC_OUT_SYNCI); ECAP_startCounter(base); ECAP_enableTimeStampCapture(base); ECAP_reArm(base); ECAP_enableInterrupt(base, ECAP_ISR_SOURCE_CAPTURE_EVENT_4); } void EnableEcapInterrupt(uint32_t interruptNumber, void (*handler)(void)) { Interrupt_register(interruptNumber, handler); Interrupt_enable(interruptNumber); } void CapPulse(uint32_t base) { // Start eCAP ECAP_reArm(base); } // eCAP 1 ISR #pragma CODE_SECTION(ecap1ISR, ".TI.ramfunc"); __interrupt void ecap1ISR(void) { f1_flag = 1; // Get the capture counts. //cap1Count2 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2); //cap1Count3 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3); //cap1Count4 = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4); // Clear interrupt flags for more interrupts. ECAP_clearInterrupt(ECAP1_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4); ECAP_clearGlobalInterrupt(ECAP1_BASE); // Acknowledge the group interrupt for more interrupts. Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4); } // eCAP 2 ISR #pragma CODE_SECTION(ecap2ISR, ".TI.ramfunc"); __interrupt void ecap2ISR(void) { f2_flag = 1; //uint32_t temp=0; // Get the capture counts. //cap2Count2 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_2); //cap2Count3 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_3); //cap2Count4 = ECAP_getEventTimeStamp(ECAP2_BASE, ECAP_EVENT_4); // Clear interrupt flags for more interrupts. ECAP_clearInterrupt(ECAP2_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4); ECAP_clearGlobalInterrupt(ECAP2_BASE); // Acknowledge the group interrupt for more interrupts. Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4); }
希望能有大佬帮忙分析以下。
不胜感激!
您好
1.外围设备的实时特性: - ECAP 模块和 UART 都是独立于 CPU 运行的实时外设 -当你遇到一个断点, CPU 停止执行代码,但这些外设继续运行基于他们的仿真模式,如 eCAP 你可以保持 TSCTR 停止时断点, TSCTR 运行到0,或自由运行。
-这可能导致与时间有关的问题和数据损坏
2. UART 数据丢失:
-对于 UART 来说,当你在串行发送函数之后遇到一个断点时,最后的位会丢失,因为:
- CPU 在断点停止
- UART 外设继续从其缓冲区传输数据
-如果缓冲区在您到达断点时没有完全传输,剩余的数据可能会丢失或损坏
-这对于最后的位尤其如此、因为它们可能尚未完全载入 UART 移位寄存器
3. ECAP 模块问题:
- ECAP 模块用于捕获事件的精确计时
-当你遇到一个断点时:
基于 eCAP 模块设置的仿真模式影响 TSCTR。 在默认情况下、如果 CPU 暂停、在到达断点时 TSCTR 将停止。
这可能会导致 CPU 对 ECAP 事件的处理与实际捕获事件之间发生时序错位
-捕获的数据可能会失效,因为 CPU 在断点停止时无法实时处理 ECAP 事件。
4.调试的最佳做法:
-对于 UART:
-等待传输完成,然后再设置断点
-使用状态标志确认传输完成
-对于 ECAP:
-尽量避免在活动捕获操作期间出现断点
-考虑使用其他调试方法,如:
-数据记录到内存
-将仿真模式更改为自由运行,即使 CPU 已暂停
-使用调试缓冲区
-在捕获序列完成后设置断点