4

我已经FreeRTOS在一些嵌入式项目中使用了一年的时间,直到现在它工作得非常完美。目前我面临一个与使用高速中断FreeRTOS移植到相关的难题PIC24H,希望大家能帮助我解决这个问题。提前致谢

我创建了一个小型演示项目以便于测试:

两个任务:

// Task 1

if (xTaskCreate(RTOSTask_1, (signed char) "[T1]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 1, &hTask1) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
  LREP("\r\nCannot create Task 1.");   
  Display_Error(1000);
}

// Task 2

if (xTaskCreate(RTOSTask_2, (signed char) "[T2]", configMINIMAL_STACK_SIZE2, NULL, tskIDLE_PRIORITY + 2, &hTask2) == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
{
  LREP("\r\nCannot create Task 2."); 
  Display_Error(1000);  
}

任务执行:

void RTOSTask_1(void* pvParameter)
{ 
  while(1)
  {

    if (xSemaphoreTake(hTask1Semaphore, portMAX_DELAY) == pdTRUE)
    { 
      putchar1('1');
    } 
  }
}

void RTOSTask_2(void* pvParameter)
{
  while(1)
  {
    if (xSemaphoreTake(hTask2Semaphore, portMAX_DELAY) == pdTRUE)
    { 
       putchar1('2');
    } 

   }
}

为了让上述两个任务运行,我使用一个Timer和一个UART给他们信号量:

void attribute((interrupt, auto_psv)) _T2Interrupt (void)
{ 
  _T2IF = 0;
  static signed portBASE_TYPE xTaskWoken = pdFALSE;
  xSemaphoreGiveFromISR(hTask1Semaphore, &xTaskWoken );

  if( xTaskWoken != pdFALSE )
  {
    taskYIELD();
  }
}

void attribute((interrupt, auto_psv)) _U1TXInterrupt()
{

  _U1TXIF = 0;
  putchar1('E');
} 

void attribute((interrupt, auto_psv)) _U1RXInterrupt()
{

  _U1RXIF = 0;
  if(U1STAbits.URXDA == 1)
  {
    uint8 u8Recv = U1RXREG;
  }

  static signed portBASE_TYPE xTaskWoken;

  xTaskWoken = pdFALSE;

  xSemaphoreGiveFromISR(hTask2Semaphore, &xTaskWoken);


  if( xTaskWoken != pdFALSE )
  {
    taskYIELD();
  }
}

我的定时器每 100us 中断一次,UART 以 230400 bps 的波特率工作。

运行几秒钟或几分钟后,程序崩溃并且程序跳转到 Traps:

_AddressError或者

_StackError

我不知道这个问题怎么会发生。经过长时间的调查和测试,我认为问题发生在程序运行和运行中断服务例程(ISR)时。看来我们需要几个SAVE_CONTEXT()&RESTORE_CONTEXT()函数。但是在 PIC24 端口上没有这样的。

请你给我一些关于这个问题的建议

谢谢你们 !


我想我已经发现了我的问题。当 PIC24H 进入和退出中断服务程序时会引入问题,这里它们是 UART RX、TX、定时器中断。

目前我不使用这样的 ISR:

无效属性((中断,auto_psv))

我用汇编代码自己创建了一个机制,而不是它:

__U1RX中断:;将 CPU 寄存器推入堆栈

    PUSH    SR          
PUSH    W0
PUSH    W1          
PUSH.D  W2
PUSH.D  W4
PUSH.D  W6
PUSH.D  W8
PUSH.D  W10
PUSH.D  W12
PUSH    W14
PUSH    RCOUNT
PUSH    TBLPAG
PUSH    CORCON
PUSH    PSVPAG

    ; Call my ISR
    call _UART1_RxISRHandler        

    ; Pop out CPU registers
POP PSVPAG
POP CORCON
POP TBLPAG
POP RCOUNT                  
POP W14
POP.D   W12
POP.D   W10
POP.D   W8
POP.D   W6
POP.D   W4
POP.D   W2
POP.D   W0
POP SR


retfie      

UART1_RxISRHandler 是我的 ISR 实现。我对 TX、定时器中断也是如此。

结果是我的程序运行更顺畅,时间更长 1 小时(仅在 1-5 分钟后程序崩溃)。但最后它在运行1-2小时后仍然崩溃。这意味着我的方法是正确的,但仍然有问题。可能是我错过了上面的代码。

如果大家对这种情况有任何理想,请告诉我。

谢谢

4

3 回答 3

1

我有一个类似的问题。

你的UART中断的优先级是什么?

它不应高于在 FreeRTOSConfig.h 中设置的 RTOS 内核中断优先级,该优先级的默认优先级为 1,而 PIC 中断的默认优先级为 3。

这似乎导致了非常偶然的崩溃。

PIC 不需要 SAVE_CONTEXT() 和 RESTORE_CONTEXT(),因为编译器会处理这些问题,至少在您使用编译器函数声明并避免使用 _FASTISR 或遮蔽的情况下。

于 2014-01-03T14:34:14.380 回答
0

这可能是堆栈溢出。你为每个任务分配了多少堆栈?

由于 FreeRTOS 中断处理程序与 FreeRTOS 任务共享一个堆栈(AFAIK,没有系统堆栈),因此当任务和处理程序的堆栈使用量加起来时,很容易导致溢出。

由于任何任务都可以在中断启动时运行,这会导致零星的行为,因为任务在中断点的堆栈使用情况不同。

要检查它,您可以简单地增加所有任务的堆栈分配大小,包括隐式创建的空闲任务(和其他系统任务,如果配置为使用一个)。或者,您可以在代码中添加以下内容以捕获堆栈溢出:

// in FreeRTOSConfig.h
#define configCHECK_FOR_STACK_OVERFLOW 1

=== somewhere in your code ===
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
    // Embed assembler code to put your processor into debughalt state.
    // I'm not familiar with PIC24 asm, but
    //
    // - http://www.microchip.com/forums/tm.aspx?m=434136
    //
    // may help.
    MACRO_TO_DEBUG_HALT();
}
于 2014-02-27T00:32:53.397 回答
0

尝试使用队列。LPC1769 上的示例。您可以轻松地将其移植到您的单片机上。

定义 mainQUEUE_LENGTH ( 1 )

这将修复可以存储在队列中的最大字节数。根据您的要求修改它,因此将免受堆栈错误或地址错误的影响:

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

/* Priorities at which the tasks are created. */
#define mainQUEUE_RECEIVE_TASK_PRIORITY     ( tskIDLE_PRIORITY + 2 )
#define mainQUEUE_SEND_TASK_PRIORITY        ( tskIDLE_PRIORITY + 1 )

/* The bit of port 0 that the LPCXpresso LPC13xx LED is connected. */
#define mainLED_BIT                         ( 22 )

/* The rate at which data is sent to the queue, specified in milliseconds. */
#define mainQUEUE_SEND_FREQUENCY_MS         ( 500 / portTICK_RATE_MS )

/* The number of items the queue can hold.  This is 1 as the receive task
will remove items as they are added, meaning the send task should always find
the queue empty. */
#define mainQUEUE_LENGTH                    ( 1 )

/*
 * The tasks as described in the accompanying PDF application note.
 */
static void prvQueueReceiveTask( void *pvParameters );
static void prvQueueSendTask( void *pvParameters );

/*
 * Simple function to toggle the LED on the LPCXpresso LPC17xx board.
 */
static void prvToggleLED( void );

/* The queue used by both tasks. */
static xQueueHandle xQueue = NULL;

/*-----------------------------------------------------------*/

int main(void)
{
    /* Initialise P0_22 for the LED. */
    LPC_PINCON->PINSEL1 &= ( ~( 3 << 12 ) );
    LPC_GPIO0->FIODIR |= ( 1 << mainLED_BIT );

    /* Create the queue. */
    xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );

    if( xQueue != NULL )
    {
        /* Start the two tasks as described in the accompanying application
        note. */
        xTaskCreate( prvQueueReceiveTask, ( signed char * ) "Rx", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
        xTaskCreate( prvQueueSendTask, ( signed char * ) "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );

        /* Start the tasks running. */
        vTaskStartScheduler();
    }

    /* If all is well we will never reach here as the scheduler will now be
    running.  If we do reach here then it is likely that there was insufficient
    heap available for the idle task to be created. */
    for( ;; );
}
/*-----------------------------------------------------------*/

static void prvQueueSendTask( void *pvParameters )
{
portTickType xNextWakeTime;
const unsigned long ulValueToSend = 100UL;

    /* Initialise xNextWakeTime - this only needs to be done once. */
    xNextWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        /* Place this task in the blocked state until it is time to run again.
        The block state is specified in ticks, the constant used converts ticks
        to ms.  While in the blocked state this task will not consume any CPU
        time. */
        vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );

        /* Send to the queue - causing the queue receive task to flash its LED.
        0 is used as the block time so the sending operation will not block -
        it shouldn't need to block as the queue should always be empty at this
        point in the code. */
        xQueueSend( xQueue, &ulValueToSend, 0 );
    }
}
/*-----------------------------------------------------------*/

static void prvQueueReceiveTask( void *pvParameters )
{
unsigned long ulReceivedValue;

    for( ;; )
    {
        /* Wait until something arrives in the queue - this task will block
        indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
        FreeRTOSConfig.h. */
        xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );

        /*  To get here something must have been received from the queue, but
        is it the expected value?  If it is, toggle the LED. */
        if( ulReceivedValue == 100UL )
        {
            prvToggleLED();
        }
    }
}
/*-----------------------------------------------------------*/

static void prvToggleLED( void )
{
unsigned long ulLEDState;

    /* Obtain the current P0 state. */
    ulLEDState = LPC_GPIO0->FIOPIN;

    /* Turn the LED off if it was on, and on if it was off. */
    LPC_GPIO0->FIOCLR = ulLEDState & ( 1 << mainLED_BIT );
    LPC_GPIO0->FIOSET = ( ( ~ulLEDState ) & ( 1 << mainLED_BIT ) );
}
于 2014-01-02T07:22:10.977 回答