Acelere o desenvolvimento de software embarcado com IA
Introdução
No desenvolvimento de software embarcado, os desafios técnicos estão presentes do dia 1 até o fim do projeto. O profissional desta área precisa achar o ponto de equilíbrio entre as restrições de hardware (presente em 100% dos projetos) com o desempenho esperado do software embarcado e da solução como um todo.
Porém, existem tarefas que consomem um tempo significativo do desenvolvedor, tarefas estas que podem ser delegadas a um agente paralelo, como uma IA generativa. Como exemplo de tarefas assim, é o desenvolvimento de software para interfacear com HAL (Hardware Abstract Layers) do fabricante do microcontrolador. Como o desenvolvedor vai lidar com dezenas (as vezes, centenas) de microcontroladores diferentes durante sua carreira, o tempo gasto para aprender como fazer esta interface é, sim, bastante significativo. Outras tarefas que são grandes consumidoras de tempo e que também podem ser delegadas a uma IA são a geração de documentação clara do código-fonte, análise de erros de sintaxe e criação de testes unitários.
Neste artigo, mostro como a IA pode beneficiar desenvolvedores, utilizando como microcontrolador de exemplo o ESP32, programado com ESP-IDF.
Pontos de atenção
Antes de iniciar, é importante ressaltar que:
- A IA nem sempre acerta. É NECESSÁRIO que o desenvolvedor de software embarcado confira e reflita se o que a IA sugeriu faz sentido. Nunca confie cegamente na IA.
- Por IA, entende-se IA generativa, como o ChatGPT, Google AI Studio e afins.
- A qualidade da sua pergunta para a IA é diretamente proporcional à qualidade da resposta que ela fornece. Não economize palavras e clareza na hora de escrever os prompts e solicitações.
- Sempre se lembre que você é o profissional e está usando a IA apenas como ferramenta para acelerar e delegar tarefas que consomem muito tempo.
- Não compartilhe seu código-fonte inteiro com a IA, seja seletivo. Compartilhe apenas trechos que não revelem segredos de negócio. Lembre-se que a IA aprende com seu código, e não seria nada legal ela saber de um trecho super sigiloso da sua solução e fornecer a qualquer um.
- Use a IA como ferramenta para poupar tempo em coisas delegáveis. Assim você pode focar no desenvolvimento da solução.
- Nunca se esqueça do item 1.
Geração de código para interfacear com HAL
Configurar e interfacear periféricos do microcontrolador – tais como UART, PWM e afins – é algo trabalhoso. Cada fabricante possui uma HAL distinta e, logo, uma forma diferente de configurar o periférico e fazer interface com ele na sua aplicação no software embarcado. Este é, talvez, uma das tarefas delegáveis a uma IA que mais consomem tempo do desenvolvedor.
Tome como exemplo a UART, periférico usado em praticamente 100% dos sistemas embarcados. Este periférico possui uma HAL diferente para cada microcontrolador, com parâmetros como baudrate, GPIOs para TX e RX, callback de interrupções, clock-base, e por aí vai. Imagine em, um ano, fazendo essa mesma configuração mais de 100 vezes, uma para cada microcontrolador de fabricante e modelo diferente. Mesmo que você for um desenvolvedor experiente, erros podem acontecer devido a um parâmetro ser um pouco diferente em um microcontrolador aqui e outro ali. Em um ano, o tempo perdido nisso será grande.
Neste quesito, a IA pode ajudar muito, pois ela tem conhecimento das HALs e pode já fornecer o caminho das pedras para você só adaptar e usar.
Para exemplificar, considere a configuração de PWM para um LED no ESP32. Imagine que o desenvolvedor precise configurar um pino GPIO para saída PWM, cuja frequência base é de 1 kHz e o duty cycle inicial é de 50%. Um possível prompt para isso é:
Gerar um código para servir de base para a configuração de PWM para controlar um LED ligado a um, GPIO do ESP32. O ESP32 será programado com ESP-IDF, na versão 4.4. Considere o canal 0 de PWM, que a frequência do PWM é de 1 kHz, que a resolução é de 10 bits (ou seja, duty cycle controlado com valores de 0 a 1024), que o duty cycle inicial é de 50%, use low speed mode e que o GPIO utilizado para esse PWM é o 4. Este código deve conter tanto a programação do timer que o PWM vai usar, tanto a configuração do PWM em si, sendo que o timer usado é o 0. Encapsule isso na forma de uma função, chamada init_pwm.
Que resulta o seguinte código:
#include "driver/ledc.h"
void init_pwm() {
ledc_timer_config_t timer_config = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.timer_num = LEDC_TIMER_0,
.duty_resolution = LEDC_TIMER_10_BIT,
.freq_hz = 1000,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer_config);
ledc_channel_config_t channel_config = {
.gpio_num = 4,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.duty = 512, // 50% de duty cycle
};
ledc_channel_config(&channel_config);
}
Note que o código gerado foi claro, atendeu às exigências contidas no prompt e já consideram o uso da HAL do ESP-IDF (na versão 4.4). Assumindo que você não tenha experiência prévia com o ESP32, você levaria algumas dezenas de minutos para aprender isso, enquanto usando a IA para acelerar o processo você teria o código em poucos segundos.
Verificação de erros de sintaxe
Por lidar com múltiplos microcontroladores de múltiplos fabricantes diferentes, uma coisa que todos desenvolvedores de software embarcado passam na hora de usar as HALs ou APIs de sistemas operacionais embarcados é a sintaxe. Invariavelmente, a sintaxe muda de fabricante para fabricante (algumas vezes, entre modelos do mesmo fabricante), fazendo os desenvolvedores gastar um tempo corrigindo sintaxe.
Ao se deparar com erros de sintaxe, a IA pode ser um grande auxílio para poupar tempo, já indicando exatamente o que está errado e onde. Dessa forma, o tempo de correção de sintaxe é reduzido a poucos segundos.
Como exemplo, vamos dizer que você está em dúvida com a sintaxe da criação de uma tarefa no FreeRTOS com ESP32, e deseja saber se a sintaxe que pensou está correta ou não. Um possível prompt para isso é:
Verifique a sintaxe da chamada abaixo, para criar uma tarefa no FreeRTOS, considerando que o microcontrolador a ser usado é o ESP32, programado com ESP-IDF versão 4.4. Desejo que além da sintaxe, seja verificado se algum (ou alguns) dos parâmetros está incorreto ou em um formato inesperado.
Chamada: xTaskCreatePinnedToCore(task_function, “TaskName”, 512, NULL, 5, NULL, 0);
Como resultado, tem-se:
Sua sintaxe está correta, mas há um probema quanto ao tamanho da stack da task. O tamanho de 512 bytes para uma task no ESP32 (programado com ESP-IDF na versão 4.4) pode ser insuficiente, especialmente se a tarefa utiliza bibliotecas que demandam mais memória. É recomendado usar, pelo menos, 2048 bytes, como a seguir:
xTaskCreatePinnedToCore(task_function, “TaskName”, 2048, NULL, 5, NULL, 0);
Note que, além de verificar a sintaxe, a IA encontrou um parâmetro que poderia causar um problema em runtime (stack overflow ou stack smash), prevenindo tempo de debug. Isso com certeza poupa um tempo considerável do desenvolvedor de software embarcado.
Auxílio para documentar código-fonte
A falta de documentação ou documentação sem clareza são problemas comuns em softwares embarcados. Apesar de muitos acharem que documentação é “perfumaria”, ou ainda que o próprio código é a documentação, esses pensamentos são muito ruins, pois códigos-fonte com documentação fraca ou inexistente têm sua manutenção bastante prejudicada.
A IA pode gerar documentação técnica com base no código existente, economizando tempo e promovendo melhores práticas. Como exemplo, suponha que você deseja gerar documentação sobre o que uma função de configuração de GPIOs faz, também considerando o ESP32 programado com ESP-IDF. Um possível prompt é:
Gere a documentação para o trecho de código abaixo, de forma a ficar claro o que é feito com o GPIO identificado como GPIO_RELE. A documentação deve ser feita no formato de múltiplas linhas e prezar pela clareza e legibilidade. Se possível, adote o padrão do Doxygen.
Trecho:
gpio_set_direction(GPIO_RELE, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_RELE, 1);
Como resultado, a IA responde:
/**
* @brief Configura o GPIO_RELE como saída digital e define o nível inicial como alto.
*
* Detalhes:
* - GPIO_RELE: Pino configurado como saída.
* - gpio_set_level: Define o nível lógico como 1 (alto).
*/
A resposta foi uma documentação bem feita e clara o suficiente para ser usada, de fato, no código-fonte da solução.
Mas relembrando dos pontos de atenção no início deste artigo, tenha cuidado: não compartilhe seu código-fonte inteiro com a IA, seja seletivo. Compartilhe apenas trechos que não revelem segredos de negócio.
Criação de testes unitários
Em software embarcado, a possibilidade de fazer testes unitários poupa muito tempo e dificuldade para debug em campo das soluções desenvolvidas. Muitas vezes é possível detectar em bancada alguns erros que levariam a problemas grandes em campo. Entretanto, gerar testes unitários pode ser uma tarefa repetitiva e, em alguns casos, tediosa.
A IA pode ajudar nessa parte, gerando testes unitários considerando APIs do próprio SDK fornecida pelo fabricante do microcontrolador, por exemplo. Considerando novamente o ESP32 programado com ESP-IDF, um possível prompt é:
Faça uma rotina de testes unitários para as funções ledc_get_freq e ledc_get_duty, considerando o microcontrolador sendo o ESP32, programado com ESP-IDF versão 4.4. Os testes unitários devem considerar o máximo de APIS para esse fim já presentes no ESP-IDF (versão 4.4), e tais testes unitários devem ser encapsulados numa função chamada test_pwm_init. Para os testes funcionarem corretamente, é importante inicializar o PWM a partir da chamada de init_pwm.
Neste caso, a IA apresenta como resultado:
void test_pwm_init() {
init_pwm();
TEST_ASSERT_EQUAL(1000, ledc_get_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_0));
TEST_ASSERT_EQUAL(512, ledc_get_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0));
}
A resposta foi bastante completa e atendeu às exigências do prompt. Obviamente, este foi um exemplo pequeno, mas a IA pode ser usada para gerar testes unitários muito mais extensos e completos podem em poucos segundos, poupando um tempo considerável de desenvolvimento de software embarcado.
Conclusão
A inteligência artificial generativa oferece uma nova perspectiva, permitindo a aceleração do desenvolvimento de softwares embarcados. Ao automatizar tarefas repetitivas e delegáveis a uma IA, identificar erros, documentar código e gerar códigos para interfacear com HALs de fabricantes e modelos de microcontroladores específicos, a IA permite que os desenvolvedores de software embarcado concentrem seus esforços no que realmente precisam: desenvolvimento da solução como um todo.
No contexto do ESP32 com ESP-IDF, os exemplos demonstraram como a IA pode ser uma ferramenta valiosa para agilizar o trabalho e aumentar a produtividade do desenvolvedor de software embarcado. Seguindo as dicas e sugestões mostradas neste artigo, desenvolvedores de software embarcado têm a oportunidade de elevar a qualidade e a produtividade de seus projetos em pouquíssimo tempo.
Quer saber mais sobre IA e programação? Veja isso
Se você gostou deste artigo e deseja saber mais sobre o uso de IA na programação, eu recomendo ler os seguintes livros:
- Programação Utilizando IA: Otimizando as etapas de planejamento, programação, testes e implantação
- INTELIGÊNCIA ARTIFICIAL GENERATIVA E ATIVA: DESVENDANDO MITOS E OPORTUNIDADES
Fala mestre!
Acabei de ler seu artigo.
Uma palavra para resumir: EXCELENTE!
Você abordou uma série de aspectos que experimentei na prática.
Seu artigo está bem completo, didático e com excelente abordagem técnica que nos faz entender muito bem os aspectos da IA na geração de codigos.
Parabéns Pedro.
Posso compartilhar?
Show
Luiz, muito obrigado pela leitura e elogios!
Fique a vontade para compartilhar.