ESP32硬件ISR有时在WiFi传输时不会触发
我试图使用硬件计时器定期从外部设备读取数据。 更具体地说,我意识到使用GPIO进行自定义驱动程序来模拟SPI协议,只要发生硬性器中断,驱动程序就会被调用以读取GPIO状态。计时器设置为2K。
当中断时,ISR应将样本数据放入缓冲区中。当缓冲区已满时,应用程序将暂停计时器并通过MQTT协议发送这些数据。使用信号发生器和示波器,我发现数据很好。整个过程按预期运行。
问题在于样本过程并非连续。当数据通过WiFi发送时,计时器会暂停,并且无法将数据读取为缓冲区。
为了解决这个问题,我创建了一个特殊任务,负责将数据传输出来。然后,我使用乒乓球缓冲区来存储样本数据。当一个缓冲区已满时,通知发送任务以将这些数据发送出去,同时,计时器ISR不断将数据放入另一个缓冲区中。
起初,我想仅从ISR(使用Xqueuesendfromisr())发送通知,该通知被证明是不可靠的。我发现只有少数通知可以发送到发送任务。因此,我有义务使用标志。当一个缓冲区已满时,标志将设置为true,而当特殊任务循环此标志时,只要它发现标志为true,它将通知发送任务。
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)//it will cost 200ms to fill up the buffer
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
transmitting data out using mqtt protocol.
}
}
}
然后,我得到了以下可怕的数据。 terroble data 我使用示波器检查ISR中的GPIO操作。 opcilloscope1 opcilloscope2 因此,似乎有些ISR没有触发?但是发生了什么事?
更奇怪的是:我添加了另一个任务,以通过I2S获取来自音频芯片的数据。再次,我使用了乒乓球缓冲区,并将通知发送到同一发送任务。
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)
}
}
task_3()
{
while(1)
{
i2s_read_to_buffer;
xQueueSend;
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
do something;
transmitting data out using mqtt protocol
}
}
}
}
这次,来自以前的任务的数据转为正常! data_ok
,此外,在我在发送任务中与task2相关的代码之后,变得不好! 那怎么了?有人可以提示吗?
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
// do something;
// transmitting data out using mqtt protocol
}
}
}
}
I tried to use hardware timer to read data from an external device periodically.
More specifically, I realized a custom driver using gpio to simulate SPI protocol, whenever an hardtimer interrupt happens, the driver is called to read gpio status. The timer is set to 2k.
When an interrupt happens, the isr shall put sample data into a buffer. When the buffer is full, the application will pause the timer and send these data out through mqtt protocol. Using signal generator and oscilloscope, I found the data was good. The whole process worked as expected.
The problem is that the sample process is not continual. When data is sending out through wifi, the timer is paused, and no data can be read into buffer.
To solve this problem, I create a special task responsible for transmitting data out. And then I use ping-pong buffers to store sample data. When one buffer is full, the sending task is notified to send these data out, meanwhile the timer isr is continually to put data into another buffer.
At first I wanted to send notify just from the isr (using xQueueSendFromISR()), which was proved not reliable. I found only a few notifies were able to be sent to the sending task. So I am obliged to using a flag. When one buffer is full, the flag is set to true, While a special task is looping this flag, whenever it find the flag is true, it will notify the sending task.
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)//it will cost 200ms to fill up the buffer
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
transmitting data out using mqtt protocol.
}
}
}
Then I got the terrible data as below.
terroble data
I used oscilloscope to check the gpio operation in the isr.
oscilloscope1
oscilloscope2
So it seems like some isr not triggered? but what happened?
More weird thing: I added another task to get data from an audio chip through i2s. Again I used ping-pong buffers and send notify to the same sending task.
timer_isr()
{
read_data_using_gpio;
if(one buffer is full)
{
set the flag to true
}
}
task_1()
{
while(1)
{
if(the flag is true)
{
set the flag to false;
xQueueSend;
}
vTaskDelay(50ms)
}
}
task_3()
{
while(1)
{
i2s_read_to_buffer;
xQueueSend;
}
}
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
do something;
transmitting data out using mqtt protocol
}
}
}
}
And this time the data from former task turned ok!
data_ok
And what's more, after I commened task2-related code in the sending task, Again the data become bad!
So what happened? Can somebody give any hint?
task_2()
{
while(1)
{
xStatus = xQueueReceive;
if(xStatus==pdPASS) // A message from other tasks is received.
{
if(data from task_1)
{
do something;
transmitting data out using mqtt protocol
}
if(data from task_2)
{
// do something;
// transmitting data out using mqtt protocol
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我解决了这个问题。
如果启用电源管理(idf.py menuconfig - >组件配置 - >电源管理),APB(高级外围总线)将自动降低其频率,这是硬件计时器的时钟源。计时器中断不稳定。
只是禁用电源管理。
I have solved this problem.
If you enable power management(idf.py menuconfig-->component config-->power management), the APB(advanced peripheral bus) will low its frequency automatically, which is the clock source of hardware timer.Thus you will see the timer interrupt is not stable.
Just disable the power management.