FRDM K82f uart 中断仅触发约 8 次
FRDM K82f uart interrupt only fires about 8 times
我目前无法让 LPUART 中断在 NXP FRDM K82f board with MCUXpresso IDE using MCUXpresso SDK 上正常工作。
LPUART 中断仅触发 6-8 次,之后再也不会触发。
此行为独立于代码中的当前位置。我通过在程序进入无限循环很久之后发送第一批数据以及在程序开始时发送它(在 lpuart 中断初始化之后)来测试它。两种情况下的行为相同。
这是我的初始化例程和中断处理程序。
#include <stdint.h>
#include "fsl_lpuart.h"
#define OSCERCLK_SOURCE 2U
#define ESP_UART LPUART0
#define UART_IRQ LPUART0_IRQn
#define UART_RECEIVE_INTERRUPT LPUART0_IRQHandler
#define BUFFER_SIZE 2048
volatile uint8_t ringBuffer[BUFFER_SIZE] = {0x00};
volatile uint16_t rxIndex = 0;
volatile uint16_t txIndex = 0;
void init(uint32_t baudRate){
lpuart_config_t config;
CLOCK_SetLpuartClock(OSCERCLK_SOURCE);
LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = baudRate;
config.enableRx = true;
config.enableTx = true;
uint32_t clockFrequency = CLOCK_GetFreq(kCLOCK_Osc0ErClk);
LPUART_Init(ESP_UART, &config, clockFrequency);
LPUART_EnableInterrupts(ESP_UART, kLPUART_RxDataRegFullInterruptEnable);
EnableIRQ(UART_IRQ);
}
void UART_RECEIVE_INTERRUPT(void){
uint8_t data;
uint32_t flags = kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags(ESP_UART);
if (flags){
data = LPUART_ReadByte(ESP_UART);
if((rxIndex + 1) % BUFFER_SIZE != txIndex){
ringBuffer[rxIndex] = data;
rxIndex++;
rxIndex %= BUFFER_SIZE;
}
}
}
有没有人遇到过类似的行为并且能够提供帮助?
编辑:
正如@Lundin 建议的那样,我更正了非标准的 gcc 语法。
还没有成功,但我能够跟踪当 ISR 不再触发时设置了哪些标志。
设置的标志是:
kLPUART_TxDataRegEmptyFlag,
kLPUART_IdleLineFlag,
kLPUART_RxOverrunFlag,
kLPUART_RxFifoEmptyFlag
这对我来说有点模棱两可,因为 RX FIFO 是空的,而且 RX 也溢出了。
您首先需要弄清楚的事情之一是您是在使用 FIFO,还是只是处理单字符接收数据寄存器。如果你没有使用FIFO,那么FIFO标志是无关紧要的,显示为空也就不足为奇了。
关于溢出标志,程序员的手册是不出所料的解释:
Receiver Overrun Flag
OR is set when software fails to prevent the receive data register from overflowing with data. The OR bit is
set immediately after the stop bit has been completely received for the dataword that overflows the buffer
and all the other error flags (FE, NF, and PF) are prevented from setting. The data in the shift register is
lost, but the data already in the LPUART data registers is not affected....
这表明很可能在过去的某个时候您未能在数据被覆盖之前声明数据,从而设置了溢出标志。但是,如果您对原始接收数据中断也有延迟响应,您可能会在没有意识到问题的情况下读取原始数据。但是,如果您这样做了,并且打开了溢出标志,那将是您收到的最后一个数据。
看来你至少需要做三件事:
完全实现或完全忽略可选的先进先出模式
检查溢出标志,清除它看看它是否有所不同,但也想办法指示(设置一个粘性易失性软件标志,一次切换一个范围监视的GPIO触发模式,无论什么)以指示已发生问题,以便您可以采取措施进行调查。
全面分析和测试您的程序是否存在设计错误,这些错误可能会导致无法足够快地响应串行数据。这可能包括诸如在 ISR 中切换 GPIO 并观察它和示波器上的串行数据线、将计时器检查放入代码以及审核所有其他 ISR 和任何必须禁用中断的前台选项之类的事情。也尝试剥离你的程序,直到你只有一些东西可以接收和回显字符并试验它,在终端程序中一次按下一个键,并让程序以保持串行线路 100% 繁忙的速率注入字符串.
还要记住,虽然断点调试非常强大,但对于任何必须响应外部事件的程序,很可能在第一次命中断点后运行将不再正常,所以要以这种方式解决问题,您通常需要设计在遇到断点的点结束的测试,并且您只分析到该点为止收集的状态。有时这意味着您需要一个“if”条件,以便您可以在其中放置一个断点。
问题很可能与接收器溢出标志有关。正如处理器参考手册中所述,设置溢出标志后,即使有足够的空间,也不会再有新数据到达接收器 buffer/FIFO。
不要忘记,即使你不调用 LPUART_ReadByte() 函数,输入到 UART 端口的字符已保存到 UART 缓冲区中,在你调用 ReadByte 后,它首先读取之前输入的字符人物。如果您过度使用 UART 端口并填充其缓冲区,它会设置溢出标志并拒绝从该端口获取更多输入字符。
你应该做的是,在无论如何设置 Overrun 标志后清除它。最好勾选overrun flag,如果设置了,自己手动清除。
if(kLPUART_RxOverrunFlag & LPUART_GetStatusFlags(ESP_UART))
{LPUART_ClearStatusFlags(ESP_UART,kLPUART_RxOverrunFlag);}
您可以在每次要从 UART 读取数据之前检查并清除此标志。
我目前无法让 LPUART 中断在 NXP FRDM K82f board with MCUXpresso IDE using MCUXpresso SDK 上正常工作。
LPUART 中断仅触发 6-8 次,之后再也不会触发。 此行为独立于代码中的当前位置。我通过在程序进入无限循环很久之后发送第一批数据以及在程序开始时发送它(在 lpuart 中断初始化之后)来测试它。两种情况下的行为相同。
这是我的初始化例程和中断处理程序。
#include <stdint.h>
#include "fsl_lpuart.h"
#define OSCERCLK_SOURCE 2U
#define ESP_UART LPUART0
#define UART_IRQ LPUART0_IRQn
#define UART_RECEIVE_INTERRUPT LPUART0_IRQHandler
#define BUFFER_SIZE 2048
volatile uint8_t ringBuffer[BUFFER_SIZE] = {0x00};
volatile uint16_t rxIndex = 0;
volatile uint16_t txIndex = 0;
void init(uint32_t baudRate){
lpuart_config_t config;
CLOCK_SetLpuartClock(OSCERCLK_SOURCE);
LPUART_GetDefaultConfig(&config);
config.baudRate_Bps = baudRate;
config.enableRx = true;
config.enableTx = true;
uint32_t clockFrequency = CLOCK_GetFreq(kCLOCK_Osc0ErClk);
LPUART_Init(ESP_UART, &config, clockFrequency);
LPUART_EnableInterrupts(ESP_UART, kLPUART_RxDataRegFullInterruptEnable);
EnableIRQ(UART_IRQ);
}
void UART_RECEIVE_INTERRUPT(void){
uint8_t data;
uint32_t flags = kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags(ESP_UART);
if (flags){
data = LPUART_ReadByte(ESP_UART);
if((rxIndex + 1) % BUFFER_SIZE != txIndex){
ringBuffer[rxIndex] = data;
rxIndex++;
rxIndex %= BUFFER_SIZE;
}
}
}
有没有人遇到过类似的行为并且能够提供帮助?
编辑: 正如@Lundin 建议的那样,我更正了非标准的 gcc 语法。 还没有成功,但我能够跟踪当 ISR 不再触发时设置了哪些标志。 设置的标志是:
kLPUART_TxDataRegEmptyFlag,
kLPUART_IdleLineFlag,
kLPUART_RxOverrunFlag,
kLPUART_RxFifoEmptyFlag
这对我来说有点模棱两可,因为 RX FIFO 是空的,而且 RX 也溢出了。
您首先需要弄清楚的事情之一是您是在使用 FIFO,还是只是处理单字符接收数据寄存器。如果你没有使用FIFO,那么FIFO标志是无关紧要的,显示为空也就不足为奇了。
关于溢出标志,程序员的手册是不出所料的解释:
Receiver Overrun Flag
OR is set when software fails to prevent the receive data register from overflowing with data. The OR bit is set immediately after the stop bit has been completely received for the dataword that overflows the buffer and all the other error flags (FE, NF, and PF) are prevented from setting. The data in the shift register is lost, but the data already in the LPUART data registers is not affected....
这表明很可能在过去的某个时候您未能在数据被覆盖之前声明数据,从而设置了溢出标志。但是,如果您对原始接收数据中断也有延迟响应,您可能会在没有意识到问题的情况下读取原始数据。但是,如果您这样做了,并且打开了溢出标志,那将是您收到的最后一个数据。
看来你至少需要做三件事:
完全实现或完全忽略可选的先进先出模式
检查溢出标志,清除它看看它是否有所不同,但也想办法指示(设置一个粘性易失性软件标志,一次切换一个范围监视的GPIO触发模式,无论什么)以指示已发生问题,以便您可以采取措施进行调查。
全面分析和测试您的程序是否存在设计错误,这些错误可能会导致无法足够快地响应串行数据。这可能包括诸如在 ISR 中切换 GPIO 并观察它和示波器上的串行数据线、将计时器检查放入代码以及审核所有其他 ISR 和任何必须禁用中断的前台选项之类的事情。也尝试剥离你的程序,直到你只有一些东西可以接收和回显字符并试验它,在终端程序中一次按下一个键,并让程序以保持串行线路 100% 繁忙的速率注入字符串.
还要记住,虽然断点调试非常强大,但对于任何必须响应外部事件的程序,很可能在第一次命中断点后运行将不再正常,所以要以这种方式解决问题,您通常需要设计在遇到断点的点结束的测试,并且您只分析到该点为止收集的状态。有时这意味着您需要一个“if”条件,以便您可以在其中放置一个断点。
问题很可能与接收器溢出标志有关。正如处理器参考手册中所述,设置溢出标志后,即使有足够的空间,也不会再有新数据到达接收器 buffer/FIFO。
不要忘记,即使你不调用 LPUART_ReadByte() 函数,输入到 UART 端口的字符已保存到 UART 缓冲区中,在你调用 ReadByte 后,它首先读取之前输入的字符人物。如果您过度使用 UART 端口并填充其缓冲区,它会设置溢出标志并拒绝从该端口获取更多输入字符。
你应该做的是,在无论如何设置 Overrun 标志后清除它。最好勾选overrun flag,如果设置了,自己手动清除。
if(kLPUART_RxOverrunFlag & LPUART_GetStatusFlags(ESP_UART))
{LPUART_ClearStatusFlags(ESP_UART,kLPUART_RxOverrunFlag);}
您可以在每次要从 UART 读取数据之前检查并清除此标志。