2022-06-29 08:50 PM
Hello,
I use stm32l412b / FreeRTOS.
I use below function to display dubug message.
The MCU is halted and a watchdog reset occurs when the function below is called in interrupt routie.
It works normally if not in interrupt
Would you let me know what is wrong?
Is there a way to display a debug message within an interrupt, even if it's not in the function below?
thanks.
*******************************************************
int uart_debug_send(const char * fmt, ...)
{
va_list ap;
int rvalue;
int retry = UART_RETRY;
uint16_t queue_len = UART_QUEUE_SIZE;
uint16_t item_num = 0;
uint8_t* temp_arry;
int is_isr = __get_IPSR();
int re_err = 0;
UBaseType_t uxSavedInterruptStatus;
// if (is_isr)
// return 0;
while (switching_lock_it_safe(uart_lock,UART_BUSY_WAIT_TIME) < 0)
{
if (retry <= 0)
return -1;
else
{
if(!is_isr)
vTaskDelay(1);
retry--;
}
}
if (!is_isr)
{
taskENTER_CRITICAL();
temp_arry = pvPortMalloc(sizeof(uint8_t) * UART_TX_BUF_LEN);
taskEXIT_CRITICAL();
}
else
{
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
temp_arry = pvPortMalloc(sizeof(uint8_t) * UART_TX_BUF_LEN);
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
}
if(temp_arry <= 0)
{
switching_unlock_it_safe(uart_lock);
return -1;
}
va_start(ap, fmt);
rvalue = vsnprintf((char *) temp_arry,UART_TX_BUF_LEN, fmt, ap);
va_end(ap);
if(rvalue >= UART_TX_BUF_LEN)
rvalue = UART_TX_BUF_LEN;
do {
queue_len = UART_QUEUE_SIZE;
item_num = circ_buf_get_length(g_uart_queue);
queue_len -= item_num;
if( queue_len >= rvalue) {
if(is_isr)
re_err = circ_buf_put_fromISR(g_uart_queue, temp_arry, rvalue);
else
re_err = circ_buf_put(g_uart_queue, temp_arry, rvalue);
if (re_err == 0) {
vPortFree(temp_arry);
switching_unlock_it_safe(uart_lock);
xTimerStart(g_uart_timer, 0);
return 0;
}
}
else
{
// TODO.
// Should check the uart TXE intr.
//
if(item_num > UART_TX_BUF_LEN) item_num = UART_TX_BUF_LEN;
if(is_isr)
re_err = circ_buf_pop_fromISR(g_uart_queue, g_uart->txb, item_num);
else
re_err = circ_buf_pop(g_uart_queue, g_uart->txb, item_num);
g_uart_dev.send(g_uart, item_num);
if(!is_isr)
vTaskDelay(1);
continue;
}
}while (queue_len < rvalue);
vPortFree(temp_arry);
switching_unlock_it_safe(uart_lock);
xTimerStart(g_uart_timer, 0);
return -1;
}
Solved! Go to Solution.
2022-07-06 01:09 AM
Hello,
I modified my code.
It works well.
Thanks.
uint8_t temp_arry[UART_TX_BUF_LEN];
int uart_debug_send(const char * fmt, ...)
{
va_list ap;
int rvalue;
int retry = UART_RETRY;
uint16_t queue_len = UART_QUEUE_SIZE;
uint16_t item_num = 0;
int is_isr = __get_IPSR();
int re_err = 0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#if defined(DEBUG_CRITICAL_SECTION_USE)
UBaseType_t uxSavedInterruptStatus;
#endif
while (switching_lock_it_safe(uart_lock,UART_BUSY_WAIT_TIME) < 0)
{
if (retry <= 0)
return -1;
else
{
if(!is_isr)
vTaskDelay(1);
retry--;
}
}
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
{
taskENTER_CRITICAL();
// taskEXIT_CRITICAL();
}
else
{
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
// taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
}
#endif
#if 0
if(temp_arry <= 0)
{
switching_unlock_it_safe(uart_lock);
return -1;
}
#endif
va_start(ap, fmt);
rvalue = vsnprintf((char *) temp_arry,UART_TX_BUF_LEN, fmt, ap);
va_end(ap);
if(rvalue >= UART_TX_BUF_LEN)
rvalue = UART_TX_BUF_LEN;
do {
queue_len = UART_QUEUE_SIZE;
item_num = circ_buf_get_length(g_uart_queue);
queue_len -= item_num;
if( queue_len >= rvalue) {
if(is_isr)
re_err = circ_buf_put_fromISR(g_uart_queue, temp_arry, rvalue);
else
re_err = circ_buf_put(g_uart_queue, temp_arry, rvalue);
if (re_err == 0) {
switching_unlock_it_safe(uart_lock);
if (!is_isr)
xTimerStart(g_uart_timer, 0);
else
xTimerStartFromISR(g_uart_timer, &xHigherPriorityTaskWoken);
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
taskEXIT_CRITICAL();
else
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
#endif
return 0;
}
}
else
{
// TODO.
// Should check the uart TXE intr.
//
if(item_num > UART_TX_BUF_LEN) item_num = UART_TX_BUF_LEN;
if(is_isr)
re_err = circ_buf_pop_fromISR(g_uart_queue, g_uart->txb, item_num);
else
re_err = circ_buf_pop(g_uart_queue, g_uart->txb, item_num);
g_uart_dev.send(g_uart, item_num);
if(!is_isr)
vTaskDelay(1);
continue;
}
}while (queue_len < rvalue);
switching_unlock_it_safe(uart_lock);
if (!is_isr)
xTimerStart(g_uart_timer, 0);
else
xTimerStartFromISR(g_uart_timer, &xHigherPriorityTaskWoken);
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
taskEXIT_CRITICAL();
else
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
#endif
return -1;
}
2022-06-29 11:36 PM
The code is broken in many ways. For example pvPortMalloc and vPortFree have to be implemented internally to be thread-safe. Wrapping the calls just in this function doesn't help.
In addition usually those heap functions can not be used in ISRs because usually they are not protected by a critical section disabling interrupts way too long.
Critical section are intended to be used for very short pieces of code.
In ISRs you've to use the 'FromISR' FreeRTOS API calls e.g. xTimerStartFromISR (because they can't/shouldn't block in ISRs for obvious reasons).
In general fully blown logging in ISRs (if possible at all) is often a problem and not done because of the serious runtime impact changing the behavior of application.
2022-06-30 02:40 AM
2022-07-06 01:09 AM
Hello,
I modified my code.
It works well.
Thanks.
uint8_t temp_arry[UART_TX_BUF_LEN];
int uart_debug_send(const char * fmt, ...)
{
va_list ap;
int rvalue;
int retry = UART_RETRY;
uint16_t queue_len = UART_QUEUE_SIZE;
uint16_t item_num = 0;
int is_isr = __get_IPSR();
int re_err = 0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#if defined(DEBUG_CRITICAL_SECTION_USE)
UBaseType_t uxSavedInterruptStatus;
#endif
while (switching_lock_it_safe(uart_lock,UART_BUSY_WAIT_TIME) < 0)
{
if (retry <= 0)
return -1;
else
{
if(!is_isr)
vTaskDelay(1);
retry--;
}
}
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
{
taskENTER_CRITICAL();
// taskEXIT_CRITICAL();
}
else
{
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
// taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
}
#endif
#if 0
if(temp_arry <= 0)
{
switching_unlock_it_safe(uart_lock);
return -1;
}
#endif
va_start(ap, fmt);
rvalue = vsnprintf((char *) temp_arry,UART_TX_BUF_LEN, fmt, ap);
va_end(ap);
if(rvalue >= UART_TX_BUF_LEN)
rvalue = UART_TX_BUF_LEN;
do {
queue_len = UART_QUEUE_SIZE;
item_num = circ_buf_get_length(g_uart_queue);
queue_len -= item_num;
if( queue_len >= rvalue) {
if(is_isr)
re_err = circ_buf_put_fromISR(g_uart_queue, temp_arry, rvalue);
else
re_err = circ_buf_put(g_uart_queue, temp_arry, rvalue);
if (re_err == 0) {
switching_unlock_it_safe(uart_lock);
if (!is_isr)
xTimerStart(g_uart_timer, 0);
else
xTimerStartFromISR(g_uart_timer, &xHigherPriorityTaskWoken);
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
taskEXIT_CRITICAL();
else
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
#endif
return 0;
}
}
else
{
// TODO.
// Should check the uart TXE intr.
//
if(item_num > UART_TX_BUF_LEN) item_num = UART_TX_BUF_LEN;
if(is_isr)
re_err = circ_buf_pop_fromISR(g_uart_queue, g_uart->txb, item_num);
else
re_err = circ_buf_pop(g_uart_queue, g_uart->txb, item_num);
g_uart_dev.send(g_uart, item_num);
if(!is_isr)
vTaskDelay(1);
continue;
}
}while (queue_len < rvalue);
switching_unlock_it_safe(uart_lock);
if (!is_isr)
xTimerStart(g_uart_timer, 0);
else
xTimerStartFromISR(g_uart_timer, &xHigherPriorityTaskWoken);
#if defined(DEBUG_CRITICAL_SECTION_USE)
if (!is_isr)
taskEXIT_CRITICAL();
else
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
#endif
return -1;
}
2022-07-06 01:31 AM
In general, try to keep your code in an ISR as short and as simple as possible. I would set simple codes/flags in the ISR and monitor/report the messages in the main code.
2022-07-06 03:12 AM
Of course, many messages are not printed.
It is intended to be used as a degree to understand the overall flow.
Thanks.
2022-07-06 04:14 AM
@MKim.12 You forgot:
"It works well"
Good news.
Now please mark the solution: