8 Comentários

Buffer circular para sistemas embarcados

Buffer circular para sistemas embarcados

Olá caro leitor. Com este artigo pretendemos expor um recurso muito legal de ser implementado em software embarcado que pode ser utilizado para as mais diversas aplicações, em especial para gerenciamento de dados vindos de controladores de comunicação, o Buffer Circular.

Buffer circular, deixe que ele ordene os dados por você

O buffer circular é conhecido por desenvolvedores experientes por ser uma estrutura de dados que possui uma política de inserção e retirada de dados do tipo FIFO, que em tradução livre significa: primeiro a entrar, primeiro a sair.

Em termos práticos, os pacotes de dados que são inseridos nesse buffer serão ordenados por chegada, de forma que a retirada será feita nessa mesma ordem. O grande diferencial do buffer circular está no ponto em que virtualmente não ocorre overflow (estouro) da área de dados reservada para depositar as variáveis, pois caso o controle de inserção encontre o fim da área de dados, ele automaticamente aponta para o começo dessa mesma área e sobrescreve o conteúdo mais antigo.

Com isso problemas conhecidos como exceções geradas pelo processador que ocorrem quando tentamos depositar dados numa área de memória maior do que o que foi previamente alocada deixa de ocorrer. A figura abaixo demonstra como funciona de forma intuitiva (e canônica um buffer circular).

Buffer circular para sistemas embarcados
Fugura 1: Buffer Circular

A figura ainda aponta que os controladores de inserção (índices) se movimentam na mesma direção, de forma que o índice de remoção "persegue" o de inserção, e ambos respeitam a regra, e ao chegar no final da área de memória, voltam ao início. De forma adicional controles de estouro da quantidade de dados escritos ou retirados podem ser implementados para prevenção de perda de conteúdo.

Interessante, mas onde posso usar o buffer circular?

O comportamento do buffer circular é ideal para implementação de qualquer estrutura de dados que seja estaticamente alocada e que se comporte como FIFO. Como exemplo, mailboxes e filas podem ser implementados utilizando o buffer circular como kernel. O professor Rodrigo Almeida já deu um uso especial do buffer circular, construção de um gerenciador de tarefas para uso em um sistema operacional de tempo real. Para acessar o seu artigo sobre isso clique aqui.

Nos meus artigos sobre DSP e controle digital, você, leitor, perceberá que a implementação dos filtros e equações de diferenças ocorrem na forma de buffers circulares. As aplicações não param por aí, buffers circulares podem ser utilizados para armazenamento temporário de dados vindos de controladores de comunicação. O melhor exemplo disso é a recepção de dados de uma UART, conforme ilustrado na figura abaixo:

Buffer Circular: UART
Figura 2: Buffer Circular: UART

Com o buffer circular, podemos colocar nossa UART apenas para fazer o que ela deve fazer, receber dados. Com isso, a cada byte recebido, este é colocado no buffer circular. Dessa forma aplicações que precisem dos dados da UART, podem fazer o acesso a eles ou mesmo aguardar o preenchimento do buffer para ler os dados depois. Além disso essa abordagem mantém a linha temporal de chegada dos dados, ou seja, dados que chegam primeiro serão processados primeiro.

Quero um exemplo de Buffer Circular!

A ideia deste artigo é resolver um problema apresentando um recurso para isso, logo falar sobre as melhores implementações de buffer circular fogem ao seu escopo. Nos arquivos buffer_circ.c e .h o leitor vai encontrar uma implementação básica do buffer circular. Ele contém as rotinas para inserção, remoção e checagem de buffer cheio ou vazio. Além disso prove uma macro para declarar uma estrutura de buffer inicializada. Vejam os arquivos:

A constante BUFFER_SIZE determina em bytes a quantidade de memória reservada para uso, podendo ser alterada de acordo com a necessidade do usuário.

Reparem nas linhas 28 e 53 desse arquivo, essa operação é chamada de incremento circular. Sua função é incrementar o índice em uma unidade, e, em caso de encontro com fim da área de memória, o resultado dessa operação será o índice 0, ou seja, o início da área reservada.

Conclusão

Buffers circulares são recursos interessantes, seguros e evitam problemas de vazamento de memória. Por exemplo, são poderosos podendo servir de base para estruturas de dados mais complexas, são versáteis, suas aplicações vão de sistemas operacionais a processamento digital de sinais. O exemplo acima possui funções de operações básicas, além de servir de ponto de partida para implementações mais complexas.

Links úteis

Clique aqui para acessar repositório no Github com código e exemplo

Outros artigos da série

Fila circular para sistemas embarcados >>
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

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

Software » Buffer circular para sistemas embarcados
Talvez você goste:
Comentários:

8
Deixe um comentário

avatar
3 Comentários
5 Respostas
0 Seguidores
 
Discussão de maior alcance
Discussão mais quente
4 Autores de comentários
Fernando RochaFelipe NevesLeonardo Verona da SilvaJose Souza Comentários recentes
  Notificações  
recentes antigos mais votados
Notificar
Fernando Rocha
Visitante
Fernando Rocha

Muito interessante o artigo!
Creio que o incremento circular dos índices de leitura e escrita do buffer se encontra nas linhas 28 e 53.

Felipe Neves
Visitante
Felipe Neves

Obrigado Fernando, artigo corrigido 🙂

Felipe

Leonardo Verona da Silva
Visitante
Leonardo Verona da Silva

Boa tarde, receio não ter entendido o porque do segundo IF na função "buffer_retrieve" presente no arquivo .C. Por favor me corrija se eu estiver errado, mas você copiou esse teste da função "buffer_insert" que inseri dados no buffer e esse mesmo teste verifica se com o número atual de itens + o número de itens a serem "Guardados" no Buffer não irá causar um Overflow. Neste caso eu consigo compreender o teste. No caso da função "buffer_retrieve" esse teste não teria lógica ao meu ver, visto que se o meu buffer é de 10 posições de memória (BUFFER_SIZE =… Leia mais »

Felipe Neves
Visitante
Felipe Neves

Leonardo, obrigado pela leitura, você está corretísssimo, subi a versão de desenvolvimento e atualizei apenas o github. Atualizei o código que está inline no artigo.

O teste realmente não faz sentido, o que se pode ocorrer é se o usuário passar um size maior do que o existente a retirada de bytes vai se repetir até o número de items caia a zero.

Felipe

Jose Souza
Visitante
Zeh Ortigoza

"Com isso problemas conhecidos como "memory leak" que ocorre quando
tentamos depositar dados numa área de memória maior do que o que foi
previamente alocada deixa de ocorrer"

Na verdade seria "buffer overflow"

Felipe Neves
Visitante
Felipe Neves

Zeh, obrigado pela leitura.

Voce esta correto, buffer overflow é um tipo de vazamento de memória. A unica diferença sutil é que o oveflow mais se refere a ultrapassagem do limite reservado logicamente para um dado stream ao passo que o memory leak é a consequência desse evento.

Jose Souza
Visitante
Zeh Ortigoza

memory leak é quando você aloca memória dinâmica(heap) e nunca libera ela.

buffer overflow é quando você esta acessando mais memória do que você alocou, alterando a memória de outra variável do seu processo ou causando um crash no aplicativo quando você tenta acessar um endereço de memória que o sistema operacional não alocou para o seu processo.

Felipe Neves
Visitante
Felipe Neves

Zeh, obrigado pelo comentário, a confusão de conceitos foi minha 🙂

O Artigo será corrigido.

Felipe

Séries



Outros da Série

Menu