打印

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

[复制链接]
57|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xiyaoko2365|  楼主 | 2025-6-27 14:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
多任务冲突根源分析
在 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[ADC_BUFFER_SIZE];
    uint16_t buffer2[ADC_BUFFER_SIZE];
    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[get_buffer_index()] = 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 采样波形
统计长时间运行后的系统稳定性

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

512

帖子

0

粉丝