Índice
1.1. Inicie a função do agendador de tarefas
1.2. Etapas de implementação do agendador de tarefas
1.3. Função xPortStartScheduler()
2.1. Função prvStartFirstTask()
3.1. Caminho de acionamento da alternância de tarefas
3.2. A interrupção PendSV aciona etapas de troca de tarefas
ilustrar:
Sobre o conteúdo:
1) O conteúdo a seguir é principalmente compreensão conceitual e análise de etapas
2) Ainda não existe um código de amostra pessoal. É usado o código de amostra oficial do FreeRTOS.
3) Se você deseja transplantar o código para teste, procure outro lugar. Não há código de exemplo pessoal para teste no conteúdo a seguir.
Sobre outros:
1) Sistema operacional: ganhe 10
2) Plataforma: Keil 5 MDK
3) Idioma: linguagem c
4) Placa: série STM32 transplantada para FreeRTOS
1. Agendador de tarefas
1.1. Inicie a função do agendador de tarefas
Nome: vTaskStartScheduler(), função: iniciar o agendador de tarefas.Quando o agendador de tarefas for iniciado, o FreeRTOS iniciará o agendamento de tarefas.
1.2. Etapas de implementação do agendador de tarefas
1) Crie uma tarefa ociosa: prvldelTask
Conforme mostrado na Figura 1 abaixo:
figura 1
2) Crie uma tarefa de timer de software: xTimerCreateTimerTask (opcional, ela não será criada se a definição da macro não estiver configurada)
Conforme mostrado na Figura 2 abaixo:
Figura 2
3) Desligue as interrupções (serão ativadas ao iniciar a primeira tarefa)
Conforme mostrado na Figura 3 abaixo:
imagem 3
4) Inicialize variáveis globais
Conforme mostrado na Figura 4 abaixo, como o agendador de tarefas acabou de ser iniciado e não há tarefas em execução neste momento, o tempo de espera é definido para o valor máximo de 8 F, conforme mostrado na Figura 5 abaixo:
Figura 4
Figura 5
5) Inicialize o cronômetro base de tempo da função de estatísticas de tempo de execução da tarefa
Conforme mostrado na Figura 6 abaixo, a função não está realmente implementada, mas uma interface é definida:
Figura 6
6) Chame a função xPortStartScheduler para completar o agendador de tarefas
Conforme mostrado na Figura 7 abaixo:
Figura 7
1.3. Função xPortStartScheduler()
Função: Conclua a parte de configuração relacionada à estrutura de hardware no agendador de tarefas de inicialização e inicie a primeira tarefa.
1) Detecte se a configuração relacionada à interrupção do usuário no arquivo FreeRTOSConfig.h está incorreta
Conforme mostrado na Figura 8 abaixo, há muito conteúdo e algumas partes são interceptadas:
Figura 8
2) Configure a prioridade de interrupção de PendSV e SysTick para a prioridade mais baixa
Conforme mostrado na Figura 9 abaixo, a prioridade é atribuída ao registro:
Figura 9
3) Chame a função vPortSetupTimerinterrupt() para configurar o SysTick
Figura 10 abaixo:
Figura 10
4) Inicialize o contador de aninhamento da seção crítica para 0
Conforme mostrado na Figura 11 abaixo:
Figura 11
5) Chame a função prvStartFirstTask() para iniciar a primeira tarefa
Conforme mostrado na Figura 12 abaixo:
Figura 12
2. Inicie uma tarefa
Como iniciar uma tarefa?
Encontre a tarefa de maior prioridade e coloque o valor do registro da tarefa de maior prioridade no registro da CPU, o que equivale a iniciar a tarefa de maior prioridade.
Por exemplo: a primeira tarefa a ser iniciada é A. O valor do registro da tarefa A é salvo na pilha de tarefas aplicada quando ela é criada. Retire o valor do registro da pilha da tarefa A e coloque-o no registro da CPU.
Perceber:
1) Quando ocorre uma interrupção, o hardware salva e restaura automaticamente PSR, PC (R15, calculadora de programa PC), LR (R14, registro de conexão), R12, R3-R0, enquanto R4-R11 precisa ser salvo e restaurado manualmente. R12 (ponteiro de heap da pilha principal do MSP -> interrupção, ponteiro de heap da pilha do processo PSP)
2) Após inserir a interrupção, o hardware forçará o uso do ponteiro MSP. Neste momento, o valor de LR (R14, registro de conexão) será atualizado automaticamente para o EXC_RETURN especial
2.1. Função prvStartFirstTask()
Função: Inicializar o ambiente antes de iniciar a primeira tarefa, principalmente para zerar o ponteiro MSP e habilitar interrupções globais (ativar PendSV)
O que é ponteiro MSP?
Durante o processo de execução do programa, é necessária uma certa quantidade de espaço de pilha para salvar informações como variáveis locais. Quando as informações são salvas na pilha, o MCU atualizará automaticamente o ponteiro SP e o núcleo ARM Cortex-M fornecerá dois espaços de pilha.
MSP (ponteiro de pilha principal): usado pelo kernel do sistema operacional, rotinas de serviço de exceção e código do aplicativo que requer todo acesso privilegiado;
PSP (Process Stack Pointer): utilizado para código regular da aplicação (quando não está em uma rotina de serviço de exceção);
No FreeRTOS, MSP (pilha principal) é usado para interrupções e PSP (pilha de processos) é usado fora das interrupções.
1) Redefinir o valor inicial do MSP
Conforme mostrado na Figura 13 abaixo:
Figura 13
2) Habilitar interrupções (ativar interrupções)
Conforme mostrado na Figura 14 abaixo:
Figura 14
3) Acione a interrupção SVC (obtenha o bloco de controle de tarefa de maior prioridade atual pxCurrentTCP; coloque o valor do registro da tarefa no registro da CPU; configure o PSP; retorne para r14 e execute a primeira tarefa)
Conforme mostrado na Figura 15 abaixo:
Figura 15
2.2. Função vPortSVCHandler()
1) Obtenha o endereço da pilha de tarefas da tarefa pronta de maior prioridade por meio de pxCurrentTCP. A tarefa pronta de maior prioridade é a tarefa que o sistema executará.
Conforme mostrado na Figura 16 abaixo:
Figura 16
2) Use o ponteiro superior da pilha de tarefas para colocar o conteúdo da pilha de tarefas no registro da CPU. O conteúdo da pilha de tarefas foi inicializado quando a função de tarefa é chamada e o valor PSP é definido.
Figura 17 abaixo:
Figura 17
3) Defina o valor do registro de interrupção de controle para escrever 0 para habilitar interrupções
Conforme mostrado na Figura 18 abaixo:
Figura 18
4) R14 registra o valor de retorno da exceção EXC_RETURN no ISR
O valor legal do valor de retorno da exceção EXC_RETURN é mostrado na Figura 19:
Figura 19
3. Troca de tarefas
Qual é a essência da alternância de tarefas?
Troca de registros da CPU (mudar para o valor do registro dessa tarefa significa executar essa tarefa).
3.1. Caminho de acionamento da alternância de tarefas
A forma equivalente de acionar a interrupção PnedSV é a seguinte:
1) Gatilhos do cronômetro
2) Acione chamando a função da API FreeRTOS, por exemplo: portYIELD()
Essencialmente, a interrupção PendSV é iniciada escrevendo 1 no bit28 do controle de interrupção e registro de status ICSR para suspender PendSV.
3.2. A interrupção PendSV aciona etapas de troca de tarefas
1) O PSP atual é o ponteiro da pilha da tarefa em execução. Leia o ponteiro do processo PSP atual e armazene-o em r0.
2) Empurre a pilha (também chamado de salvar a cena, começando em r0 e descendo)
Conforme mostrado na Figura 20 abaixo:
Figura 20
3) Obtenha o bloco de controle de tarefa de maior prioridade atual
4) Abrir a pilha (também chamado de restauração da cena, fornecendo o valor do registro ao registro da CPU)
Conforme mostrado na Figura 21 abaixo:
Figura 21
5) Atualize o ponteiro da pilha de tarefas comutadas para PSP (ou seja, forneça r0 para PSP)
6) bx r14 executa a função de tarefa de atualização
3.3. Função de implementação de troca de tarefas
Nome: __asm void xPortPendSVHandler(void), função: para implementar a alternância de tarefas
As etapas de implementação são as seguintes:
1) Alinhamento manual de 8 bytes, forneça ao PSP o valor de r0
Conforme mostrado na Figura 22 abaixo:
Figura 22
2) Obtenha a tarefa atual de maior prioridade
Conforme mostrado na Figura 23 abaixo:
Figura 23
3) Obtenha a prioridade mais alta da tarefa atual
Conforme mostrado na Figura 24 abaixo:
Figura 24
4) Ative a interrupção
Conforme mostrado na Figura 25 abaixo:
5) Empurre a pilha
Conforme mostrado na Figura 26 abaixo:
Figura 26
6) Dê o topo da pilha ao PSP
Conforme mostrado na Figura 27 abaixo:
Figura 27