xiyaoko2365 发表于 2025-6-27 14:14

GD32W515PIQ6 的特性,探讨任务调度优化策略

多任务冲突根源分析
在 FreeRTOS 等实时操作系统中,ADC 采样与 WiFi 任务可能存在以下冲突:
资源竞争
总线资源:SPI/DMA 被同时请求
内存资源:数据缓冲区访问冲突
中断资源:高优先级中断打断关键操作
时序冲突
WiFi 射频发射时的电源波动影响 ADC 采样
长耗时 WiFi 任务导致 ADC 采样周期超时
优先级倒置
低优先级 WiFi 任务持有互斥锁时被高优先级任务抢占
二、任务优先级优化策略
1. 优先级分配原则
基于任务实时性要求,建议优先级分配如下:
plaintext
+----------------------+------------+
|       任务类型       | 优先级设置 |
+----------------------+------------+
| ADC采样任务          | 高(3)      |
| WiFi数据接收任务   | 中(2)      |
| WiFi数据发送任务   | 中(2)      |
| 数据处理与显示任务   | 低(1)      |
+----------------------+------------+
2. 动态优先级调整
在关键 ADC 采样阶段临时提升优先级:
c
运行
// FreeRTOS动态优先级调整示例
void vAdcTask(void *pvParameters) {
    for(;;) {
      // 正常优先级
      vTaskPrioritySet(NULL, ADC_NORMAL_PRIORITY);

      // 等待采样触发信号
      ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

      // 提升优先级执行关键采样
      vTaskPrioritySet(NULL, ADC_HIGH_PRIORITY);

      // 执行ADC采样
      perform_critical_adc_sampling();

      // 恢复正常优先级
      vTaskPrioritySet(NULL, ADC_NORMAL_PRIORITY);

      // 处理采样数据
      process_adc_data();
    }
}
三、时间片分配优化
1. 非对称时间片分配
根据任务执行时间特性分配时间片:
c
运行
// 任务创建时指定栈深度和时间片
xTaskCreate(
    vAdcTask,                // 任务函数
    "ADC_Task",            // 任务名称
    ADC_STACK_SIZE,          // 栈深度(大)
    NULL,                  // 参数
    ADC_TASK_PRIORITY,       // 优先级
    &xAdcTaskHandle          // 任务句柄
);

xTaskCreate(
    vWiFiTask,               // 任务函数
    "WiFi_Task",             // 任务名称
    WIFI_STACK_SIZE,         // 栈深度(小)
    NULL,                  // 参数
    WIFI_TASK_PRIORITY,      // 优先级
    &xWiFiTaskHandle         // 任务句柄
);
2. 协同式调度策略
通过任务通知实现协同工作:
c
运行
// 协同式调度示例
void vAdcTask(void *pvParameters) {
    for(;;) {
      // 等待WiFi任务就绪
      ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

      // 执行ADC采样
      perform_adc_sampling();

      // 通知WiFi任务可以继续
      xTaskNotifyGive(xWiFiTaskHandle);
    }
}

void vWiFiTask(void *pvParameters) {
    for(;;) {
      // 执行非关键WiFi操作
      process_wifi_data();

      // 通知ADC任务可以采样
      xTaskNotifyGive(xAdcTaskHandle);

      // 等待ADC采样完成
      ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

      // 执行关键WiFi发送
      send_wifi_packet();
    }
}
四、中断处理优化
1. 中断服务函数 (ISR) 优化
保持 ISR 简短,使用任务通知替代直接处理:
c
运行
// ADC中断服务函数
void ADC0_1_IRQHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 读取ADC数据
    uint16_t adc_value = ADC_RDATA(ADC0);

    // 发送任务通知
    vTaskNotifyGiveFromISR(xAdcTaskHandle, &xHigherPriorityTaskWoken);

    // 如果需要唤醒更高优先级任务,则触发上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
2. 中断优先级分组
合理设置 NVIC 中断优先级分组:
c
运行
// 设置中断优先级分组
void configure_interrupt_priority_group(void) {
    // 设置为4位抢占优先级,0位响应优先级
    NVIC_SetPriorityGrouping(0x00);

    // 设置ADC中断优先级(最高)
    NVIC_SetPriority(ADC0_1_IRQn, 0);

    // 设置WiFi中断优先级(中等)
    NVIC_SetPriority(WiFi_IRQn, 1);
}
五、资源保护机制
1. 互斥锁与信号量
使用互斥锁保护共享资源:
c
运行
// 创建互斥锁
SemaphoreHandle_t xSpiMutex;

// 初始化互斥锁
xSpiMutex = xSemaphoreCreateMutex();

// SPI资源访问示例
void access_spi_resource(void) {
    // 请求互斥锁
    if(xSemaphoreTake(xSpiMutex, portMAX_DELAY) == pdTRUE) {
      // 访问SPI资源
      spi_transfer_data();

      // 释放互斥锁
      xSemaphoreGive(xSpiMutex);
    }
}
2. 双重缓冲区设计
使用双重缓冲区减少数据访问冲突:
c
运行
// 双重缓冲区结构
typedef struct {
    uint16_t buffer1;
    uint16_t buffer2;
    uint8_t active_buffer;
    SemaphoreHandle_t buffer_semaphore;
} AdcBuffer;

// ADC数据写入
void write_adc_data(uint16_t value) {
    AdcBuffer *pBuffer = get_adc_buffer();

    // 获取当前活动缓冲区
    uint16_t *current_buffer = (pBuffer->active_buffer == 0) ?
                               pBuffer->buffer1 : pBuffer->buffer2;

    // 写入数据
    current_buffer = value;

    // 缓冲区满时切换
    if(buffer_is_full()) {
      pBuffer->active_buffer = !pBuffer->active_buffer;
      xSemaphoreGive(pBuffer->buffer_semaphore);
    }
}
六、实时性保障策略
1. 任务执行时间监测
使用 FreeRTOS 的运行时间统计功能:
c
运行
// 初始化运行时间统计
void vConfigureTimerForRunTimeStats(void) {
    // 配置定时器提供10kHz的时基
    RCC_ClocksTypeDef xClocks;
    RCC_GetClocksFreq(&xClocks);

    /* 配置TIM2 */
    TIM_TimeBaseInitTypeDef TIM_InitStruct;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_InitStruct.TIM_Period = 1000;
    TIM_InitStruct.TIM_Prescaler = xClocks.HCLK_Frequency / 1000000 - 1;
    TIM_InitStruct.TIM_ClockDivision = 0;
    TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_InitStruct);

    TIM_Cmd(TIM2, ENABLE);
}

// 获取任务运行时间
uint32_t get_task_run_time(TaskHandle_t xTask) {
    TaskStatus_t xTaskStatus;
    vTaskGetInfo(xTask, &xTaskStatus, pdTRUE, eInvalid);
    return xTaskStatus.ulRunTimeCounter;
}
2. 超时处理机制
为关键操作设置超时限制:
c
运行
// 带超时的SPI操作
bool spi_transfer_with_timeout(uint8_t *data, uint16_t length, TickType_t xTicksToWait) {
    bool result = false;
    TickType_t xTimeOut = xTaskGetTickCount() + xTicksToWait;

    // 等待SPI就绪
    while(!spi_is_ready() && (xTaskGetTickCount() < xTimeOut)) {
      taskYIELD();
    }

    // 执行传输
    if(spi_is_ready()) {
      spi_start_transfer(data, length);
      result = true;
    }

    return result;
}
七、功耗与性能平衡
1. 动态功耗管理
根据任务负载调整系统时钟:
c
运行
// 动态频率调整
void adjust_system_frequency(void) {
    uint32_t load = calculate_system_load();

    if(load < LOW_LOAD_THRESHOLD) {
      // 低负载时降低频率
      set_system_clock(LOW_CLOCK_FREQ);
    } else if(load > HIGH_LOAD_THRESHOLD) {
      // 高负载时提高频率
      set_system_clock(HIGH_CLOCK_FREQ);
    }
}
2. 睡眠模式优化
在任务空闲期进入低功耗模式:
c
运行
// 低功耗模式管理
void enter_low_power_mode(void) {
    // 检查是否所有任务都空闲
    if(all_tasks_idle()) {
      // 进入深度睡眠模式
      HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
    }
}
八、优化效果验证
1. 测试指标
ADC 采样误差率
WiFi 数据包丢失率
任务响应时间抖动
系统平均功耗
2. 验证方法
使用逻辑分析仪监测 SPI 总线活动
通过串口输出任务调度日志
使用示波器观察 ADC 采样波形
统计长时间运行后的系统稳定性

页: [1]
查看完整版本: GD32W515PIQ6 的特性,探讨任务调度优化策略