4

私はすでにFreeRTOSいくつかの組み込みプロジェクトに数年間使用しており、今までは本当に完璧に機能していました。FreeRTOS現在、への移植で高速割り込みを使用することに関連する難しい問題に直面してPIC24Hいます。この問題を解決するために皆さんが私を助けてくれることを願っています。前もって感謝します

簡単にテストできるように、小さなデモ プロジェクトを作成しました。

2 つのタスク:

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

   }
}

上記の 2 つのタスクを実行するには、one Timer& oneUARTを使用してそれらにセマフォを与えます。

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時間実行した後でもクラッシュします。つまり、私のアプローチは正しいのですが、それでも何か問題があります。上記のコードで何かが足りないかもしれません。

この状況の理想があれば教えてください。

ありがとう

4

3 に答える 3

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 ) );
}
于 2014-01-02T07:22:10.977 に答える