• c语言中调用汇编
    __asm__("b 0x8a000000");
    __asm__ volatile ("blx OS_CPU_SR_Save")

    其中 OS_CPU_SR_Save 是一个汇编函数,用了 .global  OS_CPU_SR_Save 进行标识的。这个是可以成功调用的
  • makefile编译过程中要想不输出编译展开的过程信息,那么加入-s参数即可
    make -s
  • printf函数,%X即可按照十六进制方式打印
    %x即按十六进制输出,英文字母小写,右对齐。
    %02X有以下变化:英文字母变大写,如果输出字符不足两位的,输出两位宽度,右对齐,空的一位补0。超过两位的,全部输出。
  • cortex-a内核的MX6ULL启动汇编文件xx.s中不需要用 IMPORT 或者 EXPORT 进行声明,不然反而报错,有意思,stm32就需要的
  • 有符号数和无符号数之间的强制转换(这里指同位宽的,比如unsigned int和int互相转换),内存中的二进制实体内容不会有改变的。只是这个变量是什么类型,该变量对此处的二进制内容解读不一样罢了,但是二进制实体是一样的,所以不关心数的大小解读情况下,放心转
    int a
    unsigned int b
    int c

    a=-1  //内存中以补码就是1111111...1111存放的
    b=a  //此时b内存中仍然是1111111...1111,只是打印该变量时会认为是一个很大的数显示出来罢了
    c=a  //此时c内存中仍然是1111111...1111
  • 汇编要么全部用大写,要么全部用小写,不然编译会报错
  • cps指令,在特权模式(非用户模式)下使用,可以直接修改cpsr寄存器低5位的值
    cps #0x13 进入SVC模式,允许其他中断再次进去,因此中断处理函数中仍然处于SVC模式
  • 为了成功内联,__attribute__((always_inline)) static inline 才能保证一定内联,因为仅加一个,有些时候它就是不内联,__attribute__是gcc的关键字
  • cortex-a内核的汇编和cortex-m的汇编不太一样,比如
    a系列不支持分号作为注释,ldr加载立即数用=xx,subs等指令采用#xx,
     
  • 发生中断时,lr 保存的是 pc 值(正在取指的值,由于三级流水线,这个是不能直接作为返回用的,用subs pc, lr, #4返回
  • 我们让程序跳转可以直接赋值pc实现,虽然采用bl指令也是这样原理,但是bl指令可以自动装载lr寄存器,如果用blx,还会自动更新cpsr中T位
  • 如果子函数调用,那么lr保存的就是真正的下一条指令的地址了,所以返回直接用 bx lr
  • 全局变量更新,让 OSRunning=1
    非常注意:因为 OSRunning 是u8型,所以只能把r2寄存器的低8位写给OSRunning,不然覆盖掉了多余的数据,程序崩掉了(真的会
        ldr r1, =OSRunning
        ldr r2, =0x01
        strb r2, [r1]
    嵌入式杂记(ucosii在cortex-a7 MX6ULL处理器上的移植笔记)_临界区
  • 任务栈的初始化很重要,因为第二个任务被切换到第一次运行时候,根据上下文切换,cpsr的值会从栈内载入
  • ucosii在cortex-a7上面的移植,需要注意:
    在#include "includes.h"头文件中加入内核相关的访问函数,比如imx6ul.h
  • 任务切换,我不用软中断等方式触发的话,是有些问题的,比如创建的启动任务,进入临界区,任务里面再创建其它任务,然后挂起自己,然后打开临界区。如下:
    //开始任务
    void start_task(void *pdata)
    {
        OS_CPU_SR cpu_sr=0;
        pdata = pdata; 
          OS_ENTER_CRITICAL();            //进入临界区(无法被中断打断)    
         OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);                           
         OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);                        
        OSTaskSuspend(START_TASK_PRIO);    //挂起起始任务.
        OS_EXIT_CRITICAL();                //退出临界区(可以被中断打断)
    }

    由于进入了临界区(关中断的实现方式),而退出临界区是恢复上一次的中断状态,也就是说如果该任务中没有退出临界区,那么中断就一直是关着的。而倒数第二行把自己挂起了,是不是说明任务切换,自己也不会继续往下执行,从而无法打开最开始的中断状态了呢,不是的,因为ucosii任务切换是靠进入中断实现的,而中断一直关着的,因为一直没法任务切换的。因此第一个任务一定会运行到最后的退出临界区,一旦恢复了以前的中断状态(最开始中断是打开的),那么之前想要触发任务调度软中断的,就会立刻进入,发生了任务切换。

    所以为了和ucosii编程兼容,想任务切换,必须触发软中断,然后在软中断中完成任务切换的实现方式,才能符合上面的流程规定。
  • ldmfd sp!, {r0-r12, pc}^ ; 中断返回, ^表示将spsr的值复制到cpsr
  • cmp指令会影响到程序状态寄存器cpsr的bit 30位Z,Z=1代表比较结果为相等,然后ldreq指令就能执行喔
  • 而swi软中断不属于IRQ中断,它不可以被关闭,而且会立即执行,只是用于我们处理器运行模式的切换罢了,以此来实现权限转换,访问cpu所有的寄存器。但是要想任务切换在中断中触发,得找一个可等待中断才行,就是IRQ中的软件中断(这个可以寄存器赋值,从而产生的正常外部中断,就可以用来做任务切换,因为swi软指令中断其实只是起到运行模式切换的作用罢了,然后在此特权模式svc模式下才能进行寄存器写,使得IRQ中的软中断触发,从而进行任务切换)
  • 宏定义,有多行的表示方式,得加大括号
    #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                        \
    {                                                                                            \
    List_t * const pxConstList = ( pxList );                                                    \
        /* Increment the index to the next item and return the item, ensuring */                \
        /* we don't return the marker used at the end of the list.  */                            \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                            \
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )    \
        {                                                                                        \
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                        \
        }                                                                                        \
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                            \
    }