Biblioteca de Timeout e Delay para MSP430

Introdução

 

Dependendo do projeto que estamos desenvolvendo e seu nível de complexidade, pode ser necessário mensurar o intervalo de tempo entre duas funções, ou mesmo gerar temporização para permitir o gerenciamento e execução das tarefas, como em um kernel cooperativo. Você pode encontrar mais informações sobre essas características no artigo “Desenvolvendo um RTOS: Introdução” do Rodrigo Almeida e no artigo “Gerenciador de tarefas em um PIC 8-bits”.

 

O timer é um periférico básico presente em todo microcontrolador moderno e que permite gerar temporizações com grande precisão e exatidão, ou seja, com pouca variação (jitter) e valor muito próximo do ideal.

 

Com o aumento na complexidade do projeto, pode ser necessário um elevado número de timers, e mesmo que estes estejam disponíveis, pode-se tornar complicado de manipular todas as interrupções. Neste ponto podemos tirar proveito de um soft timer.

 

 

A implementação

 

A ideia é relativamente simples e muito interessante. Gerar uma base de tempo bem definida e estável e, a partir do contador associado (e um pouco de código), conseguir obter temporizações diferentes.

 

Um exemplo bastante comum são as funções “micros()” e “millis()” do Arduino, que retornam o tempo de funcionamento, e através de subtrações dos valores entre dois pontos é possível se calcular o tempo decorrido. Um adendo interessante, a função “micros()” não possui resolução de 1us como muitos devem pensar (inclusive eu achava isso até estudar um pouco sobre sua implementação), mas sim de aproximadamente 4us, isso devido às limitações do microcontrolador utilizado. Além disso, a implementação é um tanto diferente da apresentada a seguir.

 

A biblioteca apresentada a seguir tem como base o artigo “Biblioteca rápida de Timer, Delay e Timeout sem desperdícios” do Felipe Lavratti. Através de um timer de 32 bits com ticks (incrementos) a cada 1us (1MHz) geramos a base tempo.

 

Como o foco é a utilização nos microcontroladores MSP430, surgem dois pontos a serem considerados:

  • Com exceção do Watchdog timer, os timers disponíveis são de 16 bits;
  • Gerar interrupções a 1MHz (a cada 1us) pode “prender” nossa aplicação em ficar servindo a ISR do timer, em especial se você utilizar um clock baixo de 1MHz.

 

Para transpor essas limitações, apliquei certas modificações na biblioteca original. A primeira foi utilizar um timer de 16 bits e, através de suas interrupções, incrementar uma variável de 32 bits, simulando um timer de 32 bits.

 

Aqui surge um novo fator a ser considerado. Trabalhar com variáveis de tamanho diferente ao nativo da plataforma consome mais recursos, ou seja, operações realizadas com variáveis de 32 bits irão consumir mais ciclos da CPU, e isso é algo a ser considerado.

 

Para evitar sobrecarregar a CPU com as interrupções, decidi diminuir a frequência dos ticks. Neste ponto, para tornar a biblioteca mais flexível, adicionei uma função que calcula automaticamente o valor de comparação do timer de acordo com a frequência de interrupção e também da frequência de clock do timer (que pode ser derivada de três fontes principais, MCLK, SMCLK e ACLK, neste caso usando SMCLK como clock).

 

O leitor fica livre para testar o valor mais adequado para sua aplicação, mas deixo como dica utilizar 10kHz para as interrupções do timer (mesmo valor do exemplo). Com isso obtemos uma resolução de 100us, bastante interessante para maioria das aplicações, ao mesmo tempo em que não sobrecarregamos a CPU com o serviço de ISR.

 

Um único adendo, a constante que ajuda a retornar o valor real de cada tick é obtida da seguinte maneira: timer_Constant_Uint = timer_us_Freq / timerFreq;  timer_us_Freq é igual a 1000000 (1MHz). Como nossa constante é um número inteiro, irá descartar eventuais frações e isso levará a erros na contagem de tempo. Para evitar esse problema é só definir frequências para os ticks que gerem constantes inteiras, por exemplo, 10kHz levará ao valor inteiro “100”.

 

 

Principais Funções

 

  • Calcula e seta o valor de comparação do timer de acordo com a frequência desejada para os ticks e o clock do timer.

 

  • Inicializa o timer.

 

  • Criam delay em us e ms (seguram a CPU dentro de um loop).

 

  • Retornam quanto tempo se passou desde que o timer foi iniciado (ou resetado).

 

  • Retorna a semente que alimenta as comparações das funções de timeout.
  • Sempre que ocorrer uma execução esta função deverá ser chamada e seu valor armazenado em uma variável para as próximas comparações.

 

  • Retornam 1 caso tenha se passado o tempo, 0 caso o tempo não tenha sido atingido.
  • “seed” é o valor fornecido pela função timeoutInit().

 

Um exemplo de uso das funções de milissegundos é apresentado a seguir.

 

Este exemplo foi testado em uma Launchpad EXP430F5529LP. Inicialmente os dois leds são alternados 4 vezes utilizando a função “delayMs()”, após isso os leds piscam em diferentes frequências utilizando as funções “getTime_ms()” e “timeoutCheck_ms()”. O resultado no analisador lógico é apresentado a seguir.

 

Sinais no analisador lógico - Biblioteca de Timeout no MSP430
Figura 1 - Sinais no analisador lógico

 

A biblioteca e o exemplo está disponível no meu Github. Aproveito para deixar também o link de um thread no fórum 43oh sobre a biblioteca. Em breve irei adicionar novos exemplos e também melhorias conforme forem surgindo.

 

Sintam-se à vontade em compartilhar e contribuir com esta biblioteca. Um abraço e até a próxima.

Doutorando em Eng. Elétrica pela Poli-USP, mestre em Eng. Elétrica pela UNESP-Bauru e graduado em Tecnologia em Sistemas Biomédicos pela FATEC-Bauru.Um apaixonado por eletrônica que adora passar seu tempo "queimando alguns componentes" e escovando alguns bits. Entre outras paixões estão a música, uma boa reunião com os amigos, papear sobre tecnologia e afins.

Deixe um comentário

Seja o Primeiro a Comentar!

Notificar
avatar
 
wpDiscuz