I am using the QP framework for project development with the STM32F446 chip and the Arduino framework. I am utilizing the SysTick, an encoder (using the encoder mode of the TIM2 timer), and an Ethernet module (SPI Ethernet module with the W5500 chip).
I am currently encountering an issue. I found that the w5500 library does not use SPI interrupts but instead uses traditional while loop polling, such as the following code:
This function uses many while loops. My encoder uses interrupts, and when a pulse from the encoder arrives, the encoder interrupt calls a callback function and then sends the event to the active object. My systick works the same way, sending systick events to the active object. The problem arises when I rotate the encoder quickly, which means a large number of events are published to the active object, and then the QP framework asserts.
I feel that under the dual pressure of the encoder and systick (triggered every 1ms), the qp state machine has crashed. QP probably doesn't have time to execute QF_run(). Is my guess correct? Is there any way to solve this problem? Can the qp+FreeRTOS method solve this problem? Can qp allow some simple blocking?
best greetings.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The issue has been resolved. I have four levels of nested states, and the innermost fourth-level state handles TIME_TICK. After processing, it returns to the third level. The third, second, and first levels do not handle TIME_TICK. Therefore, I added a TIME_TICK event in the third level to consume TIME_TICK as quickly as possible, preventing it from reaching the top level and wasting CPU resources. Since the fourth level handles MPG_TICK, and the arrival speed of MPG_TICK is irregular, the QP state machine will keep propagating TIME_TICK from the fourth level upwards while also frequently handling MPG_TICK in the fourth level. This may result in delayed event processing, causing event accumulation and eventually leading to event pool overflow and assertion failure.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This seems to me a very common problem of mixing the heavy sequential programming with polling/blocking and lightweight event-driven programming that should not block (or poll). Mixing the two paradigms gives you the worst of both worlds. On the one hand, you have very high CPU utlization caused by polling, but you also have event-driven state machines that must react quickly.
My recommendation is always to avoid such situations and never mix blocking/polling with the event-driven paradigm in the same thread of execution. Just make up your mind and use one or the other.
And also, several posts to this forum show that people publish the frequent events. Again, publishing is more expensive than direct posting of events. So, don't do this for events that are so frequently produced.
I hope that these comments makes sense to you.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Harry,
Yes, the very reason why the "dual-mode" QXK has been designed is to enable hybrid approach, where part of the system is event-driven, and the other part is traditional sequential blocking code.
However, and this is crucial, even with a "dual-mode" kernel like QXK, event-driven Active Objects should never block internally. Blocking must be confined to the traditional threads only (QXThreads in QXK).
An alternative to QXK is any traditional RTOS kernel, such as ThreadX, embOS, Zephyr, or FreeRTOS. QP ports to these 3rd-party RTOS are provided, but are not as efficient as QXK, which has been specifically designed to reuse as much of QP as possible. But again, with 3rd-party RTOS also blocking must be strictly avoided inside Active Objects.
Thanks for the comment and an opportunity to clarify this point.
--MMS
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
However, and this is crucial, even with a "dual-mode" kernel like QXK, event-driven Active Objects should never block internally. Blocking must be confined to the traditional threads only (QXThreads in QXK).
Yeah, I should have clarified that with QXK, you just stick the blocking 3rd party code into a thread with an interface to handle events and call the appropriate blocking functions only from that thread.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
HI.
I am using the QP framework for project development with the STM32F446 chip and the Arduino framework. I am utilizing the SysTick, an encoder (using the encoder mode of the TIM2 timer), and an Ethernet module (SPI Ethernet module with the W5500 chip).
I am currently encountering an issue. I found that the w5500 library does not use SPI interrupts but instead uses traditional while loop polling, such as the following code:
This function uses many while loops. My encoder uses interrupts, and when a pulse from the encoder arrives, the encoder interrupt calls a callback function and then sends the event to the active object. My systick works the same way, sending systick events to the active object. The problem arises when I rotate the encoder quickly, which means a large number of events are published to the active object, and then the QP framework asserts.
I feel that under the dual pressure of the encoder and systick (triggered every 1ms), the qp state machine has crashed. QP probably doesn't have time to execute QF_run(). Is my guess correct? Is there any way to solve this problem? Can the qp+FreeRTOS method solve this problem? Can qp allow some simple blocking?
best greetings.
The issue has been resolved. I have four levels of nested states, and the innermost fourth-level state handles TIME_TICK. After processing, it returns to the third level. The third, second, and first levels do not handle TIME_TICK. Therefore, I added a TIME_TICK event in the third level to consume TIME_TICK as quickly as possible, preventing it from reaching the top level and wasting CPU resources. Since the fourth level handles MPG_TICK, and the arrival speed of MPG_TICK is irregular, the QP state machine will keep propagating TIME_TICK from the fourth level upwards while also frequently handling MPG_TICK in the fourth level. This may result in delayed event processing, causing event accumulation and eventually leading to event pool overflow and assertion failure.
This seems to me a very common problem of mixing the heavy sequential programming with polling/blocking and lightweight event-driven programming that should not block (or poll). Mixing the two paradigms gives you the worst of both worlds. On the one hand, you have very high CPU utlization caused by polling, but you also have event-driven state machines that must react quickly.
My recommendation is always to avoid such situations and never mix blocking/polling with the event-driven paradigm in the same thread of execution. Just make up your mind and use one or the other.
And also, several posts to this forum show that people publish the frequent events. Again, publishing is more expensive than direct posting of events. So, don't do this for events that are so frequently produced.
I hope that these comments makes sense to you.
--MMS
Miro, correct me if I'm wrong but one way to mix blocking and non-blocking "safely" seems to be to use the QXK kernel instead of QV or QK.
Hi Harry,
Yes, the very reason why the "dual-mode" QXK has been designed is to enable hybrid approach, where part of the system is event-driven, and the other part is traditional sequential blocking code.
However, and this is crucial, even with a "dual-mode" kernel like QXK, event-driven Active Objects should never block internally. Blocking must be confined to the traditional threads only (QXThreads in QXK).
An alternative to QXK is any traditional RTOS kernel, such as ThreadX, embOS, Zephyr, or FreeRTOS. QP ports to these 3rd-party RTOS are provided, but are not as efficient as QXK, which has been specifically designed to reuse as much of QP as possible. But again, with 3rd-party RTOS also blocking must be strictly avoided inside Active Objects.
Thanks for the comment and an opportunity to clarify this point.
--MMS
Yeah, I should have clarified that with QXK, you just stick the blocking 3rd party code into a thread with an interface to handle events and call the appropriate blocking functions only from that thread.