Meu Kernel Minha Vida - Round-Robin

Este post faz parte da série Meu Kernel, Minha Vida. Leia também os outros posts da série:

Olá caro leitor, tudo bem? Vamos dar continuidade à série de artigos sobre desenvolvimento de Kernel. No último artigo, Meu Kernel Minha Vida, foram apresentados os conceitos básicos de kernel cooperativo e o código-fonte do projeto desenvolvido. Para este artigo serão apresentados conceitos básicos de kernel preemptivo do tipo Round-Robin, o código-fonte do kernel desenvolvido e a aplicação de demonstração.

 

 

Escalonador Round-Robin

O Round-Robin é um algoritmo escalonador de tarefas (processos) que consiste em dividir o tempo de uso da CPU (Central Processing Unit). Cada processo recebe uma fatia de tempo, esse tempo é chamado Time-Slice, também conhecido por Quantum. Os processos são todos armazenados em Fila (Buffer) circular. O escalonador executa cada tarefa pelo tempo determinado pelo Time-Slice e ao fim deste período é executada a troca de contexto, onde o próximo processo fila passa a ser executado pela CPU até percorrer o período do Time-Slice. Após percorrer todos os processos da fila, essas atividades se repetem e o escalonador aponta para a primeira tarefa. A figura a seguir ilustra bem todo esse processo.

 

Buffer Circular
Figura 1 - Buffer Circular

 

 

Kernel Preemptivo

Como dito anteriormente, trata-se de um kernel preemptivo do tipo Round-Round. Antes de descrever sobre o projeto desenvolvido, serão apresentadas as principais características de sistema preemptivo, são elas:

  • O uso de maneira uniforme da CPU entre os processos da aplicação;
  • Troca de contexto.

 

A troca de contexto é um recurso computacional de armazenar e restaurar o estado de uma tarefa em um sistema de múltiplos processos. Por um lado, é uma característica positiva de um sistema preemptivo. Mas a implementação desse recurso é mais complexo em comparação ao sistema cooperativo. E sua implementação está intimamente ligada à arquitetura da CPU, pois é necessária a manipulação de registradores específicos, que mudam de acordo com a CPU utilizada.

 

Outro ponto que pode ser considerado como uma desvantagem nesse tipo de sistema é fazer o uso de linguagem Assembly, manipulando alguns registradores a fim de realizar a troca de contexto.

 

 

O Kernel

 

O kernel desenvolvido é especifico para microcontroladores ARM Cortex-M0. Para utilizar esse código-fonte em outra arquitetura é necessário realizar uma serie de mudanças para realizar a troca de contexto.

 

Os microcontroladores ARM Cortex-M0/M3/M4/M7 possuem alguns recursos que facilita o desenvolvimento de sistemas operacionais. São as seguintes interrupções:

  • SysTick: é um “Timer” periódico utilizado como base de tempo. No artigo passado já utilizamos essa interrupção;
  • PendSV (Pendable SerVice): é uma interrupção que a arquitetura ARM Cortex-M fornece para o uso dos sistemas operacionais realizar a troca de contexto;
  • SVCall (SuperVisor Call): São chamadas de supervisor, normalmente usadas para solicitar operações privilegiadas.

 

A outra característica importante de se destacar nos microcontroladores ARM Cortex-M é que eles possuem dois ponteiros de pilha (Stack Pointers):

  • MSP (Main Stack Pointer): Ponteiro de pilha principal, utilizado para a inicialização do sistema e na função main(). E as interrupções do sistema também fazem uso deste ponteiro;
  • PSP (Process Stack Pointer): Ponteiro de pilha de processo, usado para manipular os processos / tarefas em sistema operacional.

 

O projeto desenvolvido faz uso das interrupções SysTick como base de tempo do kernel. Para realizar as trocas de contexto entre as tarefas é utilizada a interrupção PendSV em conjunto com PSP, passando o endereço de memória que contém as instruções da próxima tarefa.

 

O código-fonte do kernel foi apresentado no artigo Context Switch on the ARM Cortex-M0 do Adam Heinrich em seu Blog com algumas alterações. O projeto desenvolvido para o STM32F0DISCOVERY, utilizando o STM32Cube MX em conjunto com Atollic TrueSTUDIO for STM32 9.0.0.

 

Das alterações que realizei, a mais relevante se encontra na API que adiciona os processos ao kernel. No código-fonte original, a alocação de memória é feita através de Array (vetor), e parâmetros são passados à função. A seguir temos trechos do código-fonte apresentado por Adam Heinrich em seu artigo:

 

 

 

No código-fonte apresentado neste artigo, essa operação é feita na própria API, sem a necessidade de receber um vetor como parâmetro. A alocação de memoria é realizada utilizando a função malloc(), como pode ser observado no trecho de código-fonte abaixo.

 

 

 

O funcionamento do kernel é bem simples, o mesmo contém API’s (Application Programming Interface) para inicializar, adicionar as tarefas da aplicação e para iniciar o escalonador do kernel. A seguir temos os protótipos das funções presente no kernel.

 

 

Uma vez inicializado o Kernel, são adicionadas as tarefas ao Buffer circular. O escalonador assume o controle e passa a gerenciar o processo que deve ser executado pela CPU. O gerenciamento dos processos se dá início pela APIKernel_Start”, onde é configurada a utilização do Ponteiro de Pilha de Processo.

 

A troca de contexto entre as tarefas é realizada a cada ocorrência da interrupção do SysTick, onde é incrementado o index do Buffer e, em seguida, é disparado o Trigger gerar a interrupção do PendSV. O algoritmo que é executado quando ocorre a interrupção do PendSV é: salvar o contexto da tarefa que estava em execução e restaurar as informações da próxima tarefa a ser processada pela CPU. A figura a seguir ilustra com mais detalhes o funcionamento do Kernel.

 

Escalonador do Kernel Round-Robin
Figura 2 - Escalonador do Kernel Round-Robin

 

A seguir será apresentado o código-fonte do Kernel (arquivos kernel.c, kernel.h e kernel.s).

 

 

 

 

 

Aplicação de demonstração

Para demonstrar o funcionamento do kernel, foi desenvolvida uma aplicação com três tarefas. A primeira tarefa ficará executando o algoritmo LED Blinking no LED verde. A segunda tarefa será responsável pelo acionamento do LED azul. E a última tarefa executará o algoritmo de leitura do Push Button.

 

A seguir é apresentado o código-fonte da aplicação, composto pelo main.c, onde temos as funções de inicialização do kernel, e pelos arquivos app.c e app.h.

 

 

 

 

 

Conclusão

 

Neste segundo artigo da série Meu Kernel Minha Vida foram apresentados os conceitos básicos sobre kernel preemptivo e do escalonador Round-Robin. Também foi apresentado o código-fonte do kernel e  da aplicação de demonstração. O objetivo foi trazer a você, caro leitor, mais uma alternativa para o desenvolvimento de firmware.

 

O código-fonte do projeto com a aplicação e kernel está disponível no meu Github. E fica aqui o meu convite a você caro leitor, que se interessou pelo assunto, a contribuir com o projeto, testando e aperfeiçoando o mesmo.

 

 

Saiba mais

 

Desenvolvendo com o Zephyr RTOS: Controlando o Kernel

Implementando elementos de RTOS no Arduino

Desenvolvendo um RTOS: Introdução

 

 

Referências

 

MCU on Eclipse - ARM Cortex-M, Interrupts and FreeRTOS: Part 1
MCU on Eclipse - ARM Cortex-M, Interrupts and FreeRTOS: Part 2
MCU on Eclipse - ARM Cortex-M, Interrupts and FreeRTOS: Part 3
Adam Heinrich - Context Switch on the ARM Cortex-M0
GitHub - Adam Heinrich - Context Switch on the ARM Cortex-M0

Outros artigos da série

<< Meu Kernel - Minha Vida
Este post faz da série Meu Kernel, Minha Vida. Leia também os outros posts da série:

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons
Meu Kernel Minha Vida - Round-Robin por Evandro Teixeira. Esta obra está licenciado com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Evandro Teixeira
Sou formado em Técnico em Mecatrônica pelo Colégio Salesiano Dom Bosco Americana - SP, Graduando em Engenharia Elétrica com Ênfase em Eletrônica pela UNISAL de Americana - SP. Atuando com desenvolvimento de hardware e software para sistema embarcado desde 2010. Experiência com microcontroladores de 8,16 e 32 bits. Atualmente trabalhando com desenvolvimento de equipamentos Eletromédicos.

Deixe um comentário

2 Comentários em "Meu Kernel Minha Vida - Round-Robin"

avatar
 
  Notificações  
recentes antigos mais votados
Notificar
Lucas Zampar Bernardi
Membro
Lucas Zampar Bernardi

Excelente artigo Evandro! Meus parabéns!