• Lv0
    粉丝0

积分0 / 贡献0

提问1答案被采纳0文章0

作者动态

    基于cortex-m4移植OpenHarmony3.0无法触发任务切换

    W1sperZ 显示全部楼层 发表于 2024-10-9 15:28:10

    【问题描述】

    1. 介绍问题现象和发生的背景 已经成功编译和烧录系统,打印正常,systick打印出来看起来也是正常在运行,但是无法触发任务切换 current Tick0 236253 OsGetCurrSchedTimeCycle();1 357691 OsGetCurrSchedTimeCycle();2 598186 上述是打印systick

    2. 相关的代码(请勿使用截图)

      这是部分代码

      
      VOID TaskSampleEntry2(VOID)
      {
          while (1) {
              printf("TaskSampleEntry2 running...\n");
              (VOID)LOS_TaskDelay(2000); /* 2000 millisecond */
          }
      }
      
      VOID TaskSampleEntry1(VOID)
      {
          while (1) {
              printf("TaskSampleEntry1 running...\n");
              (VOID)LOS_TaskDelay(2000); /* 2000 millisecond */
          }
      }
      VOID TaskSample(VOID)
      {
          UINT32 uwRet;
          UINT32 taskID1;
          UINT32 taskID2;
          TSK_INIT_PARAM_S stTask = {0};
      
          stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;
          stTask.uwStackSize = 0x800;
          stTask.pcName = "TaskSampleEntry1";
          stTask.usTaskPrio = 6; /* Os task priority is 6 */
          uwRet = LOS_TaskCreate(&taskID1, &stTask);
          if (uwRet != LOS_OK) {
              printf("Task1 create failed\n");
          }
      
          stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry2;
          stTask.uwStackSize = 0x800;
          stTask.pcName = "TaskSampleEntry2";
          stTask.usTaskPrio = 6; /* Os task priority is 6 */
          uwRet = LOS_TaskCreate(&taskID2, &stTask);
          if (uwRet != LOS_OK) {
              printf("Task2 create failed\n");
          }
      }
      /**
       * @brief This is the ohos entry, and you could call this in your main funciton after the
       *        necessary hardware has been initialized.
       */
      void OHOS_Boot(void)
      {
          UINT32 ret;
          before_ohos_run();
          ret = LOS_KernelInit();
          if (ret == LOS_OK) {
              OHOS_SystemInit();
              TaskSample();
              LOS_Start();
          }
          return;  // and should never come here
      }
    3. 运行结果、错误截图 这是运行结果

      image.png

    4. 我尝试过的解决方法和结果

    5. 我想要达到的结果

      能正常进行线程切换

    【运行环境】

    硬件:

    corex-m4 ROM版本:OpenHarmony 3.0 DevEvoStudio版本: SDK版本:OpenHarmony 3.0

    您尚未登录,无法参与评论,登录后可以:
    参与开源共建问题交流
    认同或收藏高质量问答
    获取积分成为开源共建先驱

    精彩评论3

    W1sperZ

    沙发 发表于 前天 11:50

    基于cortex-m4移植OpenHarmony3.0无法触发任务切换

    我尝试检查向量表,其中代码如下

    #define ISR_VECTOR_START_ADDRESS 0x00000000  // 中断向量表的起始地址
    #define NUM_INTERRUPTS 16                    // 向量表中的中断数目 (可以根据需求调整)
    // 函数指针类型,用于表示中断处理函数
    typedef void (*ISRHandler)(void);
    
    void PrintVectorTable(void)
    {
        ISRHandler *vectorTable = (ISRHandler *)ISR_VECTOR_START_ADDRESS;
    
        // 遍历并打印中断向量表中每个中断处理函数的地址
        for (int i = 0; i < NUM_INTERRUPTS; i++) {
            printf("Interrupt %04d handler address: %p\n", i, (void *)vectorTable[i]);
        }
    }

    打印结果如下

    Interrupt 0000 handler address: 20002C0C
    Interrupt 0001 handler address: 00000941
    Interrupt 0002 handler address: 00000AC9
    Interrupt 0003 handler address: 00000AD5
    Interrupt 0004 handler address: 00000B8B
    Interrupt 0005 handler address: 00000B67
    Interrupt 0006 handler address: 00000BAF
    Interrupt 0007 handler address: 00000000
    Interrupt 0008 handler address: 00000000
    Interrupt 0009 handler address: 00000000
    Interrupt 0010 handler address: 00000000
    Interrupt 0011 handler address: 0000098F
    Interrupt 0012 handler address: 0000098F
    Interrupt 0013 handler address: 00000000
    Interrupt 0014 handler address: 00000A2F
    Interrupt 0015 handler address: 00001DC5

    打印出的结果和 Interrupt 0014 handler address: 00000A2F和map文件中的 HalPendSV的地址是一直的 0x0000000000000a2e HalPendSV,由于 ARM Cortex-M 处理器使用的是 Thumb 指令集,所以函数地址的最低有效位(LSB,最低位)通常用于标识这是一个 Thumb 函数。也就是说,当地址为 0x0000012F 时,处理器会认为这是 0x0000012E 地址上的 Thumb 函数,并忽略最低位的 1,仍然能够正确执行 HalPendSV。所以第一点 PendSV中断处理函数是正确的

    W1sperZ

    板凳 发表于 前天 11:55

    基于cortex-m4移植OpenHarmony3.0无法触发任务切换

    其次我又验证了调度,首先在创建完成线程之后打印出系统中所有的线程

    TID  Priority   Status StackSize WaterLine StackPoint TopOfStack EventMask  SemID  TaskEntry name
     ---  -------- -------- --------- --------- ---------- ---------- --------- ------ ---------- ----
       0       31     Ready     0x400      0xcc 0x20004614 0x200042e0         0 0xffff    0x393d IdleCore000                   
       1        6     Ready     0x800      0xcc 0x20004e1c 0x200046e8         0 0xffff    0x6921 TaskSampleEntry1              
       2        6     Ready     0x800      0xcc 0x20005624 0x20004ef0         0 0xffff    0x68f5 TaskSampleEntry2

    在线程 TaskSampleEntry1中获得了下一个要执行的线程的id,并且打印出来

    TaskSampleEntry1 running...  currTime 12201708 next task 2

    再结合内核调试信息

    VOID LOS_Schedule(VOID)
    {
        PRINTK("Entry function %s   ", __FUNCTION__);
        if (OsCheckKernelRunning()) {
            PRINTK("schedule\r\n");
            ArchTaskSchedule();
            PRINTK("end schedule\r\n");
        }
    }

    以及结果,可以证明完全走完所有调度流程

    TaskSampleEntry1 running...  currTime 12583571 next task 2
    Entry function LOS_Schedule   schedule
    end schedule

    W1sperZ

    地板 发表于 前天 11:59

    基于cortex-m4移植OpenHarmony3.0无法触发任务切换

    再之后,我怀疑是中断设置不正确,又添加了如下的调试代码

    #define OS_NVIC_PENDSVSET    0x10000000     // 设置PendSV的位
    #define OS_NVIC_INT_CTRL     0xE000ED04     // 中断控制状态寄存器
    #define OS_NVIC_PENDSV_PRI   0xF0000000     // PendSV优先级掩码
    #define OS_NVIC_SYSPRI2      0xE000ED20     // PendSV优先级寄存器
    
    // 获取PendSV优先级并确保其为最低优先级
    void CheckPendSVPriority(void) {
        uint32_t regVal = *((volatile uint32_t *)OS_NVIC_SYSPRI2);
        uint8_t pendSVPriority = (regVal >> 16) & 0xFF;
    
        if (pendSVPriority != 0xF0) {
            // 如果优先级不是最低,设置为最低优先级 (0xF0)
            regVal &= ~OS_NVIC_PENDSV_PRI;      // 清除优先级位
            regVal |= (0xF0 << 16);             // 设置最低优先级
            *((volatile uint32_t *)OS_NVIC_SYSPRI2) = regVal;
            printf("PendSV priority was incorrect 0x%x, fixed to 0xF0\n", pendSVPriority);
        } else {
            printf("PendSV priority is correct (0xF0)\n");
        }
    }
    
    // 检查PendSV是否触发
    uint8_t CheckPendSVStatus(void) {
        uint32_t regVal = *((volatile uint32_t *)OS_NVIC_INT_CTRL);
        if (regVal & OS_NVIC_PENDSVSET) {
            printf("PendSV is set\n");
            return 1;   // PendSV已触发
        } else {
            printf("PendSV is not set\n");
            return 0;   // PendSV未触发
        }
    }
    
    // 检查PRIMASK是否禁用了全局中断
    uint8_t CheckInterruptStatus(void) {
        uint32_t primask;
        __asm volatile ("MRS %0, PRIMASK" : "=r" (primask));
        if (primask == 0) {
            printf("Interrupts are enabled\n");
            return 1;  // 中断已启用
        } else {
            printf("Interrupts are disabled\n");
            return 0;  // 中断被禁用
        }
    }
    
    
    // 函数返回 1 表示中断被禁用,返回 0 表示中断启用
    uint32_t CheckPrimaskStatus(void) {
        uint32_t primask;
        __asm volatile ("MRS %0, PRIMASK" : "=r" (primask));  // 将 PRIMASK 的值存储到 primask 变量中
        return primask;
    }
    
    // 主检查函数,检查PendSV设置、优先级和中断状态
    void CheckSystemStatus(void) {
    
        printf("CheckSystemStatus\r\n");
    
        // 检查并修正 PendSV 优先级
        CheckPendSVPriority();
    
        //检查 PendSV 中断是否触发
        if (!CheckPendSVStatus()) {
            // 如果未触发,尝试手动触发 PendSV
            printf("Manually triggering PendSV...\n");
            *((volatile uint32_t *)OS_NVIC_INT_CTRL) = OS_NVIC_PENDSVSET;
        }
    
        // 检查 PRIMASK 状态确认全局中断是否启用
        if (CheckPrimaskStatus()) {
            // 如果中断被禁用,启用中断
            __asm volatile ("CPSIE i");  // 使能中断
            printf("Interrupts were disabled, now enabled\n");
        } else {
            // 中断已经启用
            printf("Interrupts are enabled\n");
        }
    }

    其结果如下所示

    CheckSystemStatus
    PendSV priority was incorrect 0x0, fixed to 0xF0
    PendSV is not set
    Manually triggering PendSV...
    Interrupts were disabled, now enabled

    函数执行的位置在 LOS_KernelIni之后

    void OHOS_Boot(void)
    {
        UINT32 ret;
        before_ohos_run();
        ret = LOS_KernelInit();
        if (ret == LOS_OK) {
            TaskSample();
            PrintVectorTable();
            OsGetAllTskInfo();
            CheckSystemStatus();
            LOS_Start();
        }
        return;  // and should never come here
    }
    int main(void)
    {
        int i = 0;
        hal_clock_init(hal_clk_150M);
        uart3_init();
        systick_init();
        OHOS_Boot();
    
        while(1);
        return 0;
    }

    Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

    返回顶部