2013-10-31 42 views
4

我已經使用FreeRTOS一些嵌入式項目的一年時間,它的工作非常完美,直到現在。目前我正面臨一個難題,涉及使用高速中斷FreeRTOS移植到PIC24H,希望大家能幫助我解決這個問題。在此先感謝FreeRTOS錯誤與高速UART中斷在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以230400bps的波特率工作。

運行一些秒或分鐘的程序崩潰,程序跳轉到陷阱後:

_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,Timer中斷做了同樣的處理。

結果是我的程序運行得更順利,時間更長1小時(程序在1-5分鐘後崩潰之前)。但最終在運行1-2小時後仍會崩潰。這意味着我的方法是正確的,但仍然有問題。可能是我錯過了上面的代碼。

如果您對這種情況都有任何理想,請告訴我。

謝謝

+0

好,通過230400波特信令每一個字符一個信號煽動線程切換是一個相當加載。你可以緩衝rx字符,並減少信號量信號? –

+0

親愛的詹姆斯我知道這是更好,但我認爲這個演示案例的FreeRTOS仍然應該正常工作。 –

+0

一個字符,一個調度運行,每43us :(什麼是putchar1()做什麼? –

回答

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)); 
} 
+0

我已經成功移植到ATMEL SAM3X上,它工作正常。 –

1

我有一個類似的問題。

你的uart中斷的優先級是什麼?

它不應該比RTOS內核更高的中斷優先級設置成FreeRTOSConfig.h中具有的默認優先級1,而PIC中斷有3

這是一個默認的優先級似乎已經造成了非常偶然崩潰。

至少如果您正在使用編譯器函數聲明並避免使用_FASTISR或陰影,SAVE_CONTEXT()& RESTORE_CONTEXT()對於PIC來說不是必需的,因爲編譯器會採用該方法。

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