欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IAR-FreeRTOS在mega328p中的移植

程序员文章站 2022-06-09 10:58:09
...

一.移植前的准备
1.下载FreeRTOS源码:FreeRTOSv10.0.0

2.参考FreeRTOS提供的示例代码

二.代码移植

    在FreeRTOS的示例中没有mega328p,只有一个mega323的例子(..\FreeRTOSv10.0.0\FreeRTOS\Demo\AVR_ATMega323_IAR);打开这个示例先编译,编译时出现错误,提示:“cannot open source file "stdint.h"。

IAR-FreeRTOS在mega328p中的移植        此时需要配置下编译,IAR默认的是“CLIB”,"CLIB"是C标准库的精简版,这里我们要使用完整版,所以改为“Normal DLIB”即可。

a.

IAR-FreeRTOS在mega328p中的移植b.

IAR-FreeRTOS在mega328p中的移植

c.

IAR-FreeRTOS在mega328p中的移植

      示例代码已经编译通过了,接下来我们要修改这个示例代码,使之能运行在mega328P中;

     由于这个示例包含了多个例程,为了使用方便,我把AVR这部分需要的单独整理了出来,文件结构如下所示:

IAR-FreeRTOS在mega328p中的移植

    接下来在IAR里建立AVR工程,CPU设置为mega328p,并包含freertos文件路径;


1.

IAR-FreeRTOS在mega328p中的移植2.

IAR-FreeRTOS在mega328p中的移植

此时编译还不能通过,还要做如下修改:

1,把所有“#include <iom323.h>”改为“#include <ioavr.h>“,因为示例中使用的是mega323;

2,改写“port.c”中“prvSetupTimerInterrupt()”函数,在mega323中定时器中断寄存器为TIMSK,但在mega328p应改为TIMSK1,并更改中断使能值“portCOMPARE_MATCH_A_INTERRUPT_ENABLE”为0x02;

3.注释“portmacro.s90”中的串口中断跳转“

//EXTERN SIG_UART_RECV
//EXTERN SIG_UART_DATA

.........

//    ORG USART_RXC_vect                    ; Vector address
//        jmp SIG_UART_RECV                ; ISR
//
//    ORG USART_UDRE_vect                    ; Vector address
//        jmp SIG_UART_DATA                ; ISR

4.修改“FreeRTOSConfig.h”文件中如下宏定义"

#define configUSE_PREEMPTION        0//1
#define configUSE_IDLE_HOOK            0//1

"

       修改完成后,编译通过,现在在“main.c”中编写测试程序。

/*****************************************************/
//文 件 名: main.c
//文件功能: 主函数
//参考文档: 无
//创 件 人: 程强刚
//创建日期: 2018/01/07
//修改历史: 
/*****************************************************/
#include "..\config\config.h"

__flash UCHAR ucLed[] = {
  0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};

/*****************************************************/
//函 数 名: task1
//函数功能: demo
//参考文档: 无
//创 件 人: 程强刚
//创建日期: 2018/01/07
//修改历史: 
/*****************************************************/
void task1(void *pvParameters)
{
  UCHAR i;

  i = 1;
  DDRB = 0xff;
  PORTB = 0xff;
  while (1)
  {
      PORTB = ~i;
      i <<= 1;
      if (!i) 
      {
        i = 1;
      }  
      vTaskDelay(10);    
  }
  
}

/*****************************************************/
//函 数 名: task2
//函数功能: demo
//参考文档: 无
//创 件 人: 程强刚
//创建日期: 2018/01/07
//修改历史: 
/*****************************************************/
void task2(void *pvParameters)
{
  UCHAR i;
  
  DDRD = 0xff;
  PORTD = 0xff;

  while (1)
  {
      for (i = 0; i < 8; i++)
      {
        PORTD = ~ucLed[i];
        vTaskDelay(10);
      }
      
  }
}

/*****************************************************/
//函 数 名: task2
//函数功能: demo
//参考文档: 无
//创 件 人: 程强刚
//创建日期: 2018/01/07
//修改历史: 
/*****************************************************/
void task3(void *pvParameters)
{ 
  
  DDRC = 0xff;
  PORTC = 0xff;
  while (1)
  {
      PORTC = 0xf0;
      vTaskDelay(100);
      PORTC = ~0xf0;
      vTaskDelay(100);      
      
  }
}

/*****************************************************/
//函 数 名: main
//函数功能: demo
//参考文档: 无
//创 件 人: 程强刚
//创建日期: 2018/01/07
//修改历史: 
/*****************************************************/
int main( void )
{
 //创建任务1
  xTaskCreate(task1,                                //任务
              "task1",                              //任务名
              128,                                  //栈大小
              NULL,                                 //形参
              1,                                    //优先级
              NULL );                               //句柄
 //创建任务2
  xTaskCreate(task2,                                //任务
              "task2",                              //任务名
              128,                                  //栈大小
              NULL,                                 //形参
              2,                                    //优先级
              NULL );                               //句柄  
 //创建任务3
  xTaskCreate(task3,                                //任务
              "task3",                              //任务名
              128,                                  //栈大小
              NULL,                                 //形参
              3,                                    //优先级
              NULL );                               //句柄    
  vTaskStartScheduler();
  while (1);
        
}
/*****************************************************
*                       end of file
******************************************************/


       生成HEX文件后,在Proteus中却不能运行,可能是TIMER1没有进中断,查看“port.c”没发现问题,但单独编译“port.c”时看到一个警告“Interrupt function has no assigned vector”,可能是“portmacro.s90”中那段定时器中断没有跳转,此时我把“portmacro.s90”中关于定时器中断跳转的代码注释掉了”

//EXTERN SIG_OUTPUT_COMPARE1A

.......

//    ORG TIMER1_COMPA_vect                ; Vector address
//        jmp SIG_OUTPUT_COMPARE1A        ; ISR

然后在“port.c”中的定时器1中断函数前添加中断向量“

    #pragma vector = TIMER1_COMPA_vect                  //添加的中断向量
    __interrupt void SIG_OUTPUT_COMPARE1A( void )
    {
        xTaskIncrementTick();
    }


重新生成HEX文件后,程序运行。

附:port.c修改后的代码

/*
 * FreeRTOS Kernel V10.0.0
 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software. If you wish to use our Amazon
 * FreeRTOS name, please do so in a fair use way that does not cause confusion.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */

#include <stdlib.h>

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

/*-----------------------------------------------------------
 * Implementation of functions defined in portable.h for the AVR/IAR port.
 *----------------------------------------------------------*/

/* Start tasks with interrupts enables. */
#define portFLAGS_INT_ENABLED                    ( ( StackType_t ) 0x80 )

/* Hardware constants for timer 1. */
#define portCLEAR_COUNTER_ON_MATCH                ( ( uint8_t ) 0x08 )
#define portPRESCALE_64                            ( ( uint8_t ) 0x03 )
#define portCLOCK_PRESCALER                        ( ( uint32_t ) 64 )
#define portCOMPARE_MATCH_A_INTERRUPT_ENABLE    ( ( uint8_t ) (1 << 1) )//( ( uint8_t ) 0x10 )

/* The number of bytes used on the hardware stack by the task start address. */
#define portBYTES_USED_BY_RETURN_ADDRESS        ( 2 )
/*-----------------------------------------------------------*/

/* Stores the critical section nesting.  This must not be initialised to 0.
It will be initialised when a task starts. */
#define portNO_CRITICAL_NESTING                    ( ( UBaseType_t ) 0 )
UBaseType_t uxCriticalNesting = 0x50;


/*
 * Perform hardware setup to enable ticks from timer 1, compare match A.
 */
static void prvSetupTimerInterrupt( void );

/*
 * The IAR compiler does not have full support for inline assembler, so
 * these are defined in the portmacro assembler file.
 */
extern void vPortYieldFromTick( void );
extern void vPortStart( void );

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

/*
 * See header file for description.
 */
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
uint16_t usAddress;
StackType_t *pxTopOfHardwareStack;

    /* Place a few bytes of known values on the bottom of the stack.
    This is just useful for debugging. */

    *pxTopOfStack = 0x11;
    pxTopOfStack--;
    *pxTopOfStack = 0x22;
    pxTopOfStack--;
    *pxTopOfStack = 0x33;
    pxTopOfStack--;

    /* Remember where the top of the hardware stack is - this is required
    below. */
    pxTopOfHardwareStack = pxTopOfStack;


    /* Simulate how the stack would look after a call to vPortYield(). */

    /*lint -e950 -e611 -e923 Lint doesn't like this much - but nothing I can do about it. */



    /* The IAR compiler requires two stacks per task.  First there is the
    hardware call stack which uses the AVR stack pointer.  Second there is the
    software stack (local variables, parameter passing, etc.) which uses the
    AVR Y register.

    This function places both stacks within the memory block passed in as the
    first parameter.  The hardware stack is placed at the bottom of the memory
    block.  A gap is then left for the hardware stack to grow.  Next the software
    stack is placed.  The amount of space between the software and hardware
    stacks is defined by configCALL_STACK_SIZE.



    The first part of the stack is the hardware stack.  Place the start
    address of the task on the hardware stack. */
    usAddress = ( uint16_t ) pxCode;
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;

    usAddress >>= 8;
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;


    /* Leave enough space for the hardware stack before starting the software
    stack.  The '- 2' is because we have already used two spaces for the
    address of the start of the task. */
    pxTopOfStack -= ( configCALL_STACK_SIZE - 2 );



    /* Next simulate the stack as if after a call to portSAVE_CONTEXT().
    portSAVE_CONTEXT places the flags on the stack immediately after r0
    to ensure the interrupts get disabled as soon as possible, and so ensuring
    the stack use is minimal should a context switch interrupt occur. */
    *pxTopOfStack = ( StackType_t ) 0x00;    /* R0 */
    pxTopOfStack--;
    *pxTopOfStack = portFLAGS_INT_ENABLED;
    pxTopOfStack--;

    /* Next place the address of the hardware stack.  This is required so
    the AVR stack pointer can be restored to point to the hardware stack. */
    pxTopOfHardwareStack -= portBYTES_USED_BY_RETURN_ADDRESS;
    usAddress = ( uint16_t ) pxTopOfHardwareStack;

    /* SPL */
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;

    /* SPH */
    usAddress >>= 8;
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;




    /* Now the remaining registers. */
    *pxTopOfStack = ( StackType_t ) 0x01;    /* R1 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x02;    /* R2 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x03;    /* R3 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x04;    /* R4 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x05;    /* R5 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x06;    /* R6 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x07;    /* R7 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x08;    /* R8 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x09;    /* R9 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x10;    /* R10 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x11;    /* R11 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x12;    /* R12 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x13;    /* R13 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x14;    /* R14 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x15;    /* R15 */
    pxTopOfStack--;

    /* Place the parameter on the stack in the expected location. */
    usAddress = ( uint16_t ) pvParameters;
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;

    usAddress >>= 8;
    *pxTopOfStack = ( StackType_t ) ( usAddress & ( uint16_t ) 0x00ff );
    pxTopOfStack--;

    *pxTopOfStack = ( StackType_t ) 0x18;    /* R18 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x19;    /* R19 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x20;    /* R20 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x21;    /* R21 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x22;    /* R22 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x23;    /* R23 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x24;    /* R24 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x25;    /* R25 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x26;    /* R26 X */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x27;    /* R27 */
    pxTopOfStack--;

    /* The Y register is not stored as it is used as the software stack and
    gets saved into the task control block. */

    *pxTopOfStack = ( StackType_t ) 0x30;    /* R30 Z */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x031;    /* R31 */

    pxTopOfStack--;
    *pxTopOfStack = portNO_CRITICAL_NESTING;    /* Critical nesting is zero when the task starts. */

    /*lint +e950 +e611 +e923 */

    return pxTopOfStack;
}
/*-----------------------------------------------------------*/

BaseType_t xPortStartScheduler( void )
{
    /* Setup the hardware to generate the tick. */
    prvSetupTimerInterrupt();

    /* Restore the context of the first task that is going to run.
    Normally we would just call portRESTORE_CONTEXT() here, but as the IAR
    compiler does not fully support inline assembler we have to make a call.*/
    vPortStart();

    /* Should not get here! */
    return pdTRUE;
}
/*-----------------------------------------------------------*/

void vPortEndScheduler( void )
{
    /* It is unlikely that the AVR port will get stopped.  If required simply
    disable the tick interrupt here. */
}
/*-----------------------------------------------------------*/

/*
 * Setup timer 1 compare match A to generate a tick interrupt.
 */
static void prvSetupTimerInterrupt( void )
{
uint32_t ulCompareMatch;
uint8_t ucHighByte, ucLowByte;

    /* Using 16bit timer 1 to generate the tick.  Correct fuses must be
    selected for the configCPU_CLOCK_HZ clock. */

    ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;

    /* We only have 16 bits so have to scale to get our required tick rate. */
    ulCompareMatch /= portCLOCK_PRESCALER;

    /* Adjust for correct value. */
    ulCompareMatch -= ( uint32_t ) 1;

    /* Setup compare match value for compare match A.  Interrupts are disabled
    before this is called so we need not worry here. */
    ucLowByte = ( uint8_t ) ( ulCompareMatch & ( uint32_t ) 0xff );
    ulCompareMatch >>= 8;
    ucHighByte = ( uint8_t ) ( ulCompareMatch & ( uint32_t ) 0xff );
    OCR1AH = ucHighByte;
    OCR1AL = ucLowByte;

    /* Setup clock source and compare match behaviour. */
    ucLowByte = portCLEAR_COUNTER_ON_MATCH | portPRESCALE_64;
    TCCR1B = ucLowByte;

    /* Enable the interrupt - this is okay as interrupt are currently globally
    disabled. */
    TIMSK1 |= portCOMPARE_MATCH_A_INTERRUPT_ENABLE;
}
/*-----------------------------------------------------------*/

#if configUSE_PREEMPTION == 1

    /*
     * Tick ISR for preemptive scheduler.  We can use a __task attribute as
     * the context is saved at the start of vPortYieldFromTick().  The tick
     * count is incremented after the context is saved.
     */
    __task void SIG_OUTPUT_COMPARE1A( void )
    {
        vPortYieldFromTick();
        asm( "reti" );
    }

#else

    /*
     * Tick ISR for the cooperative scheduler.  All this does is increment the
     * tick count.  We don't need to switch context, this can only be done by
     * manual calls to taskYIELD();
     *
     * THE INTERRUPT VECTOR IS POPULATED IN portmacro.s90.  DO NOT INSTALL
     * IT HERE USING THE USUAL PRAGMA.
     */
    #pragma vector = TIMER1_COMPA_vect                  //添加的中断向量
    __interrupt void SIG_OUTPUT_COMPARE1A( void )
    {
        xTaskIncrementTick();
    }
#endif
/*-----------------------------------------------------------*/

void vPortEnterCritical( void )
{
    portDISABLE_INTERRUPTS();
    uxCriticalNesting++;
}
/*-----------------------------------------------------------*/

void vPortExitCritical( void )
{
    uxCriticalNesting--;
    if( uxCriticalNesting == portNO_CRITICAL_NESTING )
    {
        portENABLE_INTERRUPTS();
    }
}



附:portmacro.s90修改后的代码

;/*
; * FreeRTOS Kernel V10.0.0
; * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
; *
; * Permission is hereby granted, free of charge, to any person obtaining a copy of
; * this software and associated documentation files (the "Software"), to deal in
; * the Software without restriction, including without limitation the rights to
; * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
; * the Software, and to permit persons to whom the Software is furnished to do so,
; * subject to the following conditions:
; *
; * The above copyright notice and this permission notice shall be included in all
; * copies or substantial portions of the Software. If you wish to use our Amazon
; * FreeRTOS name, please do so in a fair use way that does not cause confusion.
; *
; * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
; * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
; * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
; * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
; * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
; *
; * http://www.FreeRTOS.org
; * http://aws.amazon.com/freertos
; *
; * 1 tab == 4 spaces!
; */

#include <iom323.h>

; Declare all extern symbols here - including any ISRs that are referenced in
; the vector table.

; ISR functions
; -------------
//EXTERN SIG_OUTPUT_COMPARE1A
//EXTERN SIG_UART_RECV
//EXTERN SIG_UART_DATA


; Functions used by scheduler
; ---------------------------
EXTERN vTaskSwitchContext
EXTERN pxCurrentTCB
EXTERN xTaskIncrementTick
EXTERN uxCriticalNesting

; Functions implemented in this file
; ----------------------------------
PUBLIC vPortYield
PUBLIC vPortYieldFromTick
PUBLIC vPortStart


; Interrupt vector table.
; -----------------------
;
; For simplicity the RTOS tick interrupt routine uses the __task keyword.
; As the IAR compiler does not permit a function to be declared using both
; __task and __interrupt, the use of __task necessitates that the interrupt
; vector table be setup manually.
;
; To write an ISR, implement the ISR function using the __interrupt keyword
; but do not install the interrupt using the "#pragma vector=ABC" method.
; Instead manually place the name of the ISR in the vector table using an
; ORG and jmp instruction as demonstrated below.
; You will also have to add an EXTERN statement at the top of the file.

    ASEG


//    ORG TIMER1_COMPA_vect                ; Vector address
//        jmp SIG_OUTPUT_COMPARE1A        ; ISR

//    ORG USART_RXC_vect                    ; Vector address
//        jmp SIG_UART_RECV                ; ISR
//
//    ORG USART_UDRE_vect                    ; Vector address
//        jmp SIG_UART_DATA                ; ISR


    RSEG CODE



; Saving and Restoring a Task Context and Task Switching
; ------------------------------------------------------
;
; The IAR compiler does not fully support inline assembler, so saving and
; restoring a task context has to be written in an asm file.
;
; vPortYield() and vPortYieldFromTick() are usually written in C.  Doing
; so in this case would required calls to be made to portSAVE_CONTEXT() and
; portRESTORE_CONTEXT().  This is dis-advantageous as the context switch
; function would require two extra jump and return instructions over the
; WinAVR equivalent.
;
; To avoid this I have opted to implement both vPortYield() and
; vPortYieldFromTick() in this assembly file.  For convenience
; portSAVE_CONTEXT and portRESTORE_CONTEXT are implemented as macros.

portSAVE_CONTEXT MACRO
    st    -y, r0            ; First save the r0 register - we need to use this.
    in    r0, SREG        ; Obtain the SREG value so we can disable interrupts...
    cli                    ; ... as soon as possible.
    st    -y, r0            ; Store the SREG as it was before we disabled interrupts.

    in    r0, SPL            ; Next store the hardware stack pointer.  The IAR...
    st    -y, r0            ; ... compiler uses the hardware stack as a call stack ...
    in    r0, SPH            ; ...  only.
    st    -y, r0

    st    -y, r1            ; Now store the rest of the registers.  Dont store the ...
    st    -y, r2            ; ... the Y register here as it is used as the software
    st    -y, r3            ; stack pointer and will get saved into the TCB.
    st    -y, r4
    st    -y, r5
    st    -y, r6
    st    -y, r7
    st    -y, r8
    st    -y, r9
    st    -y, r10
    st    -y, r11
    st    -y, r12
    st    -y, r13
    st    -y, r14
    st    -y, r15
    st    -y, r16
    st    -y, r17
    st    -y, r18
    st    -y, r19
    st    -y, r20
    st    -y, r21
    st    -y, r22
    st    -y, r23
    st    -y, r24
    st    -y, r25
    st    -y, r26
    st    -y, r27
    st    -y, r30
    st    -y, r31
    lds r0, uxCriticalNesting
    st    -y, r0                    ; Store the critical nesting counter.

    lds    r26, pxCurrentTCB        ; Finally save the software stack pointer (Y ...
    lds    r27, pxCurrentTCB + 1    ; ... register) into the TCB.
    st    x+, r28
    st    x+, r29

    ENDM


portRESTORE_CONTEXT MACRO
    lds    r26, pxCurrentTCB
    lds    r27, pxCurrentTCB + 1    ; Restore the software stack pointer from ...
    ld    r28, x+                    ; the TCB into the software stack pointer (...
    ld    r29, x+                    ; ... the Y register).

    ld    r0, y+
    sts    uxCriticalNesting, r0
    ld    r31, y+                    ; Restore the registers down to R0.  The Y
    ld    r30, y+                    ; register is missing from this list as it
    ld    r27, y+                    ; has already been restored.
    ld    r26, y+
    ld    r25, y+
    ld    r24, y+
    ld    r23, y+
    ld    r22, y+
    ld    r21, y+
    ld    r20, y+
    ld    r19, y+
    ld    r18, y+
    ld    r17, y+
    ld    r16, y+
    ld    r15, y+
    ld    r14, y+
    ld    r13, y+
    ld    r12, y+
    ld    r11, y+
    ld    r10, y+
    ld    r9, y+
    ld    r8, y+
    ld    r7, y+
    ld    r6, y+
    ld    r5, y+
    ld    r4, y+
    ld    r3, y+
    ld    r2, y+
    ld    r1, y+

    ld    r0, y+                    ; The next thing on the stack is the ...
    out    SPH, r0                    ; ... hardware stack pointer.
    ld    r0, y+
    out    SPL, r0

    ld    r0, y+                    ; Next there is the SREG register.
    out SREG, r0

    ld    r0, y+                    ; Finally we have finished with r0, so restore r0.

    ENDM



; vPortYield() and vPortYieldFromTick()
; -------------------------------------
;
; Manual and preemptive context switch functions respectively.
; The IAR compiler does not fully support inline assembler,
; so these are implemented here rather than the more usually
; place of within port.c.

vPortYield:
    portSAVE_CONTEXT            ; Save the context of the current task.
    call vTaskSwitchContext        ; Call the scheduler.
    portRESTORE_CONTEXT            ; Restore the context of whichever task the ...
    ret                            ; ... scheduler decided should run.

vPortYieldFromTick:
    portSAVE_CONTEXT            ; Save the context of the current task.
    call xTaskIncrementTick        ; Call the timer tick function.
    tst r16
    breq SkipTaskSwitch
    call vTaskSwitchContext        ; Call the scheduler.
SkipTaskSwitch:
    portRESTORE_CONTEXT            ; Restore the context of whichever task the ...
    ret                            ; ... scheduler decided should run.

; vPortStart()
; ------------
;
; Again due to the lack of inline assembler, this is required
; to get access to the portRESTORE_CONTEXT macro.

vPortStart:
    portRESTORE_CONTEXT
    ret


; Just a filler for unused interrupt vectors.
vNoISR:
    reti


    END


附:完整代码下载

相关标签: AVR FreeRTOS IAR