A saída digital em microcontroladores parece ser muito simples, principalmente se você está acostumado a programar com a biblioteca Arduino. Com um comando você coloca um pino em nível alto ou baixo. Isso é tudo? Não... vamos ver neste post algumas considerações importantes no caso particular do RP2040 (o microcontrolador usado na Raspberry Pi Pico).
Display de 7 segmentos acionado pela Pi Pico |
Um detalhe: o RP2040 possui 36 pinos de E/S de uso geral (GPIO), divididos em dois bancos. Um destes bancos, com 6 pinos, é normalmente destinado à conexão da Flash onde reside o programa. O que vamos falar aqui se refere principalmente ao outro banco (o "User Bank"), onde estão GPIO0 a GPIO29.
A primeira coisa a lembrar é que um pino de microcontrolador pode ter muitas funções. A figura abaixo mostra a estrutura lógica de um pino, indicando como diversas parte do microcontrolador podem ser ligadas a ele:
Fonte: datasheet do RP2040 |
A saída digital "normal" corresponde ao "GPIO" na figura, que é implementado como SIO (Single-Cycle I/O). Basicamente temos um conjunto de três registradores:
- GPIO_OUT determina o valor do pino, se a saída estiver habilitada e o pino estiver configurado para GPIO
- GPIO_OE se o pino estiver configurado para GPIO, controla se a saída está habilitada (1) ou não (0). Quando a saída não está habilitada ela fica num estado de alta impedância (o que normalmente chamamos de "entrada").
- GPIO_IN indica o nível lógico no pino. Este registrador é atualizado mesmo que a função do pino não seja GPIO.
Este conjunto de registradores é compartilhado pelos dois cores do RP2040. O termo "Single-Cycle" se refere ao fato destes registradores poderem ser acessados de forma atômica pelas instruções SET, CLR e XOR. Isto significa que, atualizando os registradores com estas instruções, não existe problema de concorrência entre os dois cores ou interrupções, é uma operação indivisível. Note que se você ler um registrador, gerar um novo valor e depois escrever (em operações separadas) pode ocorrer de o outro core ou uma interrupção alterar o conteúdo do registrador após a leitura e antes da escrita, gerando problemas.
Voltando à figura lá atrás, repare o bloco "I/O Pad", que representa a interface elétrica entre a lógica interna e o pino propriamente dito:
Fonte: datasheet do RP2040 |
Este módulo possui várias configurações, também controladas por registradores SIO:
- Slew Rate determina a rapidez na mudança de nível
- Drive Strength determina quão "forte" é o sinal gerado
- Podemos ativar resistores internos de pull-up e pull-down (entre 50 e 80 kOhms)
- Podemos habilitar ou desabilitar o buffer de entrada
- Podemos habilitar ou desabilitar a histerese (schmitt trigger) do buffer de entrada. Quando habilitado são usados dois limites de tensão, uma para determinar que o sinal passou do nível alto para baixo e outro para determinar a mudança no sentido contrário. Isso evita oscilações na leitura em caso de variações pequenas.
Os gráficos abaixo mostram o efeito da configuração de drive strength:
Donte: datasheet do RP2040 |
Ou seja, um drive stength mais alto permite obter uma tensão mais próxima da ideal se for solicitada uma corrente alta.
Independente desta configuração, o datasheet indica uma corrente máxima total de 50mA nos pinos de I/O.
Embora o datasheet informe os endereços e bits dos registradores de controle, a recomendação é utilizar as funções do SDK para isso. O exemplo abaixo corresponde a acender todos os segmentos de um display de 7 segmentos de catodo comum. Tanto os segmentos como o catodo comum estão ligados a pinos de GPIO. Resistores de 1K em cada segmento limitam a corrente em cada segmento em 1,4mA (para o display usado para teste), o catodo comum irá fornecer a soma destas correntes (7 x 1,4 = 9,8mA), por isso foi configurado para uma "força" maior.
#include <stdio.h> #include "pico/stdlib.h" #include "hardware/gpio.h" int main() { gpio_init_mask (0xFF); // configura os pinos para GPIO gpio_set_dir_masked (0xFF, 0xFF); // configura os pinos como saída gpio_set_drive_strength (7, GPIO_DRIVE_STRENGTH_12MA); // GPIO7 "vitaminado" gpio_clr_mask (0x7F); // nível baixo nos pinos ligados aos segmentos gpio_set_mask (0x80); // nível alto no anodo comum while (1) ; return 0; }
O código acima usa versões das funções do SDK onde uma máscara de bits seleciona os GPIOs afetados. No meu caso GPIO0 a GPIO6 são os catodos dos segmentos e GPIO7 é o anodo comum.
Detalhes sobre o RP2040 podem ser vistos no datasheet e uma descrição detalhada das funções do SDK estão no respectivo manual. Ambos podem ser vistos em:
https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html
2 comentários:
boa mnoite mesre, eu gostaria de ajuda sobre como criar uma placa multiplexadora com display 4 digitos um comando de incremento e um reset, manualmente, ou seja um contador 0,9999
Carlos augusto, dê uma olhada nestes artigos meus no blog da FilipeFlop:
https://www.filipeflop.com/blog/contador-de-giros-com-sensor-efeito-hall-e-raspberry-pi-pico/
https://www.filipeflop.com/blog/temporizador-shield-arduino-multifuncoes/
Postar um comentário