PIC24H中高速UART中断的FreeRTOS错误

时间:2013-10-31 08:11:19

标签: c multithreading stm32 mplab freertos

我已经将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))

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

__ U1RXInterrupt:         ;将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小时后仍然会崩溃。这意味着我的方法是正确的,但仍然有问题。可能是我错过了上面的代码。

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

由于

3 个答案:

答案 0 :(得分:1)

我遇到了类似的问题。

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

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

这似乎引起了偶尔的崩溃。

SAVE_CONTEXT()& PIC不需要RESTORE_CONTEXT(),因为编译器可以解决这个问题,至少在使用编译器函数声明并避免使用_FASTISR或阴影的情况下。

答案 1 :(得分:0)

尝试使用队列。 LPC1769上的示例。你可以轻松地为你的mcu移植它。

  

定义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 ) );
}

答案 2 :(得分:0)

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

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

由于当中断启动时任何任务都可能正在运行,这会导致偶发行为,因为任务在中断点的堆栈使用不同。

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

// 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();
}