Gera Senoide

Este projeto está relacionado com Gerar Senóide.

Versão usando ESP-IDF Puro…

Resumo

A idéia é criar uma pequena rotina que:

 

Arquitetura usada

Arqutetura usada:

Estrutura geral do programa

A arquitetura preve po bloco principal: GPTimer + ISR a 10 kHz para gerar a senoide, e adicionalmente o contador TickCount dentro da ISR que permite confirmar o bom andamento da ISR via comunicação serial.

Comparando programação usando Arduino-IDE vs ESP-IDF Puro:

IDE-ArduinoESP-IDF Puro
setup()app_main()
loop()duas tasks FreeRTOS:
buttonTask() para leitura/debounce do botão usado para ligar/desligar geração da senóide
statusTask() para mostrar o conteúdo de TickCount a cada segundo, via comunicação seral;
digitalWrite()gpio_set_level()
digitalRead()gpio_get_level()
dacWrite()dac_output_voltage().
Serial.print()printf()
delay()vTaskDelay()
millis()Não usado.

Há ainda um ponto importante: no código Arduino, TickCount é zerado pela loop() enquanto a ISR pode incrementá-lo simultaneamente. No ESP-IDF continua com esse comportamento funcional, mas faz a leitura/zeragem de forma adequada para uma variável compartilhada com a ISR.

 

Fluxo do programa:

 

Código ESP-IDF Puro

Segue cópia de: ~/Documents/ESP32/Projetos/Senoide2/main/main.c:

Se você quiser ver um exemplo de compilação do programa ver Exemplo de Compilação de Projeto.

 

Observações

Note que estamos chamando dac_oneshot_output_voltage() a cada 100 μs.

A documentação atual do DAC Digital To Analog Converter (DAC) diz explicitamente que dac_oneshot_output_voltage() pode ser chamado em ISR — isso é conveniente. Ela também informa que a chamada normalmente leva 7–11 µs no ESP32.

A chamada do DAC não é, por si só, o problema mas o processamento sinf() dentro de uma ISR de 10 kHz é preocupante.

Para uma senoide de 440 Hz, temos somente:

e isso já sugere uma solução muito melhor: usar uma tabela de seno (lookup table) ou outra técnica de geração de seno, em vez de calcular sinf() dentro da interrupção. Isso também deixaria a ISR muito mais curta e previsível.

Por isto foi configurado um pino na GPIO para DEBUG (pino livre 26). Se for conectado um osciloscópio ao mesmo, deve ser detectada uma onda quadrada de 10 KHz (mesma frequência usada para amostrar a senóide), mas o período de tempo em que este pino passa em nível lógico algo (seu “duty-cycle”) permite ter uma idéia real do tempo de processamento gasto para executar a tarefa onTime() (ou a ISR via chamada IRAM_ATTR). No osciloscópio deve ser observado algo como:

O resultado deve ser algo como:

Frequência

Deve ser aproximadamente:

f=1100μs=10KHz

Duty cycle

Se, por exemplo, o osciloscópio mostrar:

então:

D=12100=12%

Ou seja, aproximadamente 12% de cada período de amostragem está sendo consumido pela ISR.

Note: A função IRAM_ATTR, é apropriada para uma callback que roda em contexto de interrupção quando se pretende comportamento “IRAM-safe”. A documentação da Espressif também chama atenção para o fato de que as funções chamadas pela callback precisam ser adequadas a esse contexto (execução de rápidas tarefas periódicas).

Para saber mais sobre IRAM & IRAM Safe, clique aqui.

Você tmabém pode se aprofundar mais da documentaçao da Espressif sobre: Digital To Analog Converter (DAC) e sobre IRAM Safe.

A gpio_set_level() é uma função que pode ser usada nesse contexto; a documentação do driver GPIO prevê inclusive a possibilidade de colocá-la em IRAM para execução durante cache desabilitado com CONFIG_GPIO_CTRL_FUNC_IN_IRAM.

 

<< Voltar para tópico de origem: Gerar Senóide | Ver Versão usando Arduíno-IDE.


Fernando Passold, em 14/09/2026.