Introdução
WiringX é uma biblioteca que permite aos desenvolvedores controlar o GPIO de diversas plataformas com funções genéricas e uniformes. Ao usar o WiringX, o mesmo código será executado em todas as plataformas suportadas pelo WiringX, nativamente.
Este artigo será dividido nas quatro partes a seguir para apresentar como desenvolver aplicações no Duo usando o wireingX:
- APIs de WiringX
- Demonstração de código de uso básico
- Configuração do ambiente de compilação da aplicação baseado em WiringX
- Introdução a algumas demonstrações e projetos implementados usando WiringX
Se você já está familiarizado com o uso do WiringX, pode consultar diretamente nosso código de exemplo: duo-examples
Observe que muitas funções de pinos da série Duo são multiplexadas. Ao usar wiringX
para controlar as funções de cada pino, é importante confirmar o estado atual do pino para garantir que ele corresponda à funcionalidade desejada. Caso contrário, você pode usar o comando duo-pinmux
para mudar para a função desejada.
Consulte as instruções de uso detalhadas para obter mais informações: pinmux .
Números do WiringX Duo/Duo256
Os números dos pinos do WiringX do Duo e Duo256M são consistentes com os números dos nomes dos pinos. No entanto, o pino de controle do LED azul não está disponível na pinagem física de 40 pinos e o número do pino do WiringX é 25
.
Números do WiringX DuoS
Os números dos pinos do WiringX do DuoS são consistentes com os números dos pinos físicos. O pino de controle do LED azul não está nos pinos físicos de 40PIN e seu número de WiringX é 0
.
HEADER J3
GPIO Header J3
usa níveis lógicos de 3,3 V.
wiringX | PIN NAME | PIN# | PIN# | PIN NAME | wiringX |
---|---|---|---|---|---|
3V3 | 1 | 2 | VSYS(5V) | ||
3 | B20 | 3 | 4 | VSYS(5V) | |
5 | B21 | 5 | 6 | GND | |
7 | B18 | 7 | 8 | A16 | 8 |
GND* | 9 | 10 | A17 | 10 | |
11 | B11 | 11 | 12 | B19 | 12 |
13 | B12 | 13 | 14 | GND | |
15 | B22 | 15 | 16 | A20 | 16 |
3V3 | 17 | 18 | A19 | 18 | |
19 | B13 | 19 | 20 | GND | |
21 | B14 | 21 | 22 | A18 | 22 |
23 | B15 | 23 | 24 | B16 | 24 |
GND | 25 | 26 | A28 | 26 |
GND*: O pino 9 é um GPIO de baixo nível na versão V1.1 do hardware e é GND na versão V1.2 e posterior.
HEADER J4
GPIO Header J4
usa níveis lógicos de 1,8V.
wiringX | PIN NAME | PIN# | PIN# | PIN NAME | wiringX |
---|---|---|---|---|---|
VSYS(5V) | 52 | 51 | AUDIO_OUT_R | ||
50 | B1 | 50 | 49 | AUDIO_OUT_L | |
48 | B2 | 48 | 47 | AUDIO_IN_R | |
46 | B3 | 46 | 45 | AUDIO_IN_L | |
44 | E2 | 44 | 43 | 3V3 | |
42 | E1 | 42 | 41 | C18 | 41 |
40 | E0 | 40 | 39 | C19 | 39 |
GND | 38 | 37 | GND | ||
36 | C20 | 36 | 35 | C16 | 35 |
34 | C21 | 34 | 33 | C17 | 33 |
GND | 32 | 31 | GND | ||
30 | C14 | 30 | 29 | C12 | 29 |
28 | C15 | 28 | 27 | C13 | 27 |
A maioria dos pinos neste conector possui funções dedicadas, como sinais MIPI DSI, sinais de tela sensível ao toque e sinais de áudio. Se não houver nenhum requisito especial, não é recomendado usar os pinos deste cabeçalho como GPIO.
1. CÓDIGO EXEMPLO
Exemplo de uso de GPIO
Aqui está um exemplo de trabalho com GPIO. Ele alternará o pino 20 no Duo a cada 1 segundo, puxando-o para HIGH e depois para LOW. O número do pino físico para o pino 20 está 15
no sistema de numeração WiringX.
#include <stdio.h>#include <unistd.h>
#include <wiringx.h>
int main() { int DUO_GPIO = 15;
// Duo: milkv_duo // Duo256M: milkv_duo256m // DuoS: milkv_duos if(wiringXSetup("milkv_duo", NULL) == -1) { wiringXGC(); return -1; }
if(wiringXValidGPIO(DUO_GPIO) != 0) { printf("Invalid GPIO %d\n", DUO_GPIO); }
pinMode(DUO_GPIO, PINMODE_OUTPUT);
while(1) { printf("Duo GPIO (wiringX) %d: High\n", DUO_GPIO); digitalWrite(DUO_GPIO, HIGH); sleep(1); printf("Duo GPIO (wiringX) %d: Low\n", DUO_GPIO); digitalWrite(DUO_GPIO, LOW); sleep(1); }
return 0;}
Após compilar e rodar no Duo, você pode usar um multímetro ou osciloscópio para medir o estado do pino 20 e verificar se ele corresponde ao comportamento esperado.
Você também pode usar o pino do LED integrado para verificar o comportamento. Observando o estado ligado/desligado do LED, você pode determinar intuitivamente se o programa está sendo executado corretamente. O número do pino WiringX para o LED é 25
. Simplesmente modifique o código mencionado acima substituindo pin 15
por pin 25
. No entanto, observe que o firmware padrão possui um script para controlar o piscar do LED na inicialização, que precisa ser desativado. Você pode consultar o exemplo de explicação para blink abaixo para obter instruções sobre como desativá-lo.
Exemplo de uso I2C
Aqui está um exemplo de comunicação I2C:
#include <stdio.h>#include <unistd.h>#include <stdint.h>
#include <wiringx.h>
#define I2C_DEV "/dev/i2c-1"
#define I2C_ADDR 0x04
int main(void){ int fd_i2c; int data = 0;
// Duo: milkv_duo // Duo256M: milkv_duo256m // DuoS: milkv_duos if(wiringXSetup("milkv_duo", NULL) == -1) { wiringXGC(); return -1; }
if ((fd_i2c = wiringXI2CSetup(I2C_DEV, I2C_ADDR)) <0) { printf("I2C Setup failed: %d\n", fd_i2c); wiringXGC(); return -1; }
// TODO}
Exemplo de uso de SPI
Aqui está um exemplo de comunicação SPI:
#include <stdio.h>#include <unistd.h>#include <stdint.h>
#include <wiringx.h>
int main(void){ int fd_spi;
// Duo: milkv_duo // Duo256M: milkv_duo256m // DuoS: milkv_duos if(wiringXSetup("milkv_duo", NULL) == -1) { wiringXGC(); return -1; }
if ((fd_spi = wiringXSPISetup(0, 500000)) <0) { printf("SPI Setup failed: %d\n", fd_spi); wiringXGC(); return -1; }
// TODO}
Exemplo de uso de UART
Aqui está um exemplo de comunicação UART usando UART4 nos pinos 4/5:
#include <stdio.h>#include <unistd.h>
#include <wiringx.h>
int main() { struct wiringXSerial_t wiringXSerial = {115200, 8, 'n', 1, 'n'}; char buf[1024]; int str_len = 0; int i; int fd;
// Duo: milkv_duo // Duo256M: milkv_duo256m // DuoS: milkv_duos if(wiringXSetup("milkv_duo", NULL) == -1) { wiringXGC(); return -1; }
if ((fd = wiringXSerialOpen("/dev/ttyS4", wiringXSerial)) < 0) { printf("Open serial device failed: %d\n", fd); wiringXGC(); return -1; }
wiringXSerialPuts(fd, "Duo Serial Test\n");
while(1) { str_len = wiringXSerialDataAvail(fd); if (str_len > 0) { i = 0; while (str_len--) { buf[i++] = wiringXSerialGetChar(fd); } printf("Duo UART receive: %s\n", buf); } }
wiringXSerialClose(fd);
return 0;}
Método de teste:
O RX do cabo conversor USB para serial está conectado ao pino 4 (UART4_TX) do Duo, o TX do cabo serial está conectado ao pino 5 (UART4_RX) do Duo, e o GND do cabo serial está conectado ao GND do Duo. No computador, configure a porta COM e os parâmetros usando uma ferramenta de depuração serial.
O executável compilado do programa acima é denominado uart_test
. Depois de fazer o upload para o Duo via SSH e executá-lo, você poderá ver a string Duo Serial Test
recebida na ferramenta serial do seu computador. Se você enviar a string Hello World
da ferramenta serial, também verá a string correspondente recebida no terminal do Duo. Isto confirma que a comunicação serial está funcionando corretamente.
2. Configuração do Ambiente de Desenvolvimento
Você também pode usar Ubuntu instalado em uma máquina virtual, Ubuntu instalado via WSL no Windows ou sistemas baseados em Ubuntu usando Docker.
Instale as ferramentas que compilam dependências
sudo apt-get install wget git make
Obtenha exemplo de código-fonte
git clone https://github.com/milkv-duo/duo-examples.git
Preparar ambiente de compilação
cd duo-examplessource envsetup.shNa primeira vez que você o adquirir, o pacote SDK necessário será baixado automaticamente, com aproximadamente 180 MB de tamanho. Depois de baixado, ele será extraído automaticamente para o diretório
duo-examples
com o nomeduo-sdk
. Na próxima vez, se o diretório já existir, ele não será baixado novamente.Teste de compilação
Tomemos hello-world como exemplo, entre no diretório hello-world e execute make:
cd hello-worldmakeApós a compilação ser bem-sucedida, envie o programa executável gerado
helloworld
para o dispositivo Duo através da porta de rede ou da rede RNDIS. Por exemplo, o método RNDIS suportado pelo firmware padrão , o IP do Duo é 192.168.42.1, o nome de usuário éroot
e a senha émilkv
.scp helloworld root@192.168.42.1:/root/
Após o envio com sucesso, execute
./helloworld
no terminal logado via ssh ou porta serial, e ele irá imprimirHello, World!
[root@milkv]~# ./helloworldHello, World!Neste ponto, nosso ambiente de compilação e desenvolvimento está pronto para uso.
Como criar seu próprio projeto
Você pode simplesmente copiar os exemplos existentes e fazer as modificações necessárias. Por exemplo, se você precisar manipular um GPIO, você pode consultar o exemplo blink
. A intermitência do LED é obtida controlando o nível de tensão do GPIO. O SDK atual utiliza a biblioteca WiringX para operações GPIO, que foi adaptada especificamente para Duo. Você pode encontrar a inicialização da plataforma e os métodos de controle GPIO no código blink.c
para referência.
- Crie seu próprio diretório de projeto chamado
my-project
. - Copie os arquivos
blink.c
eMakefile
do exemploblink
para o diretóriomy-project
. - Renomeie
blink.c
com o nome desejado, comogpio_test.c
. - Modifique
Makefile
alterandoTARGET=blink
paraTARGET=gpio_test
. - Modifique
gpio_test.c
para implementar sua própria lógica de código. - Execute o comando
make
para compilar. - Envie o programa executável gerado
gpio_test
ao Duo para execução.
Observação:
- A criação de um novo diretório de projeto não é obrigatória para ser colocado dentro do diretório
duo-examples
. Você pode escolher qualquer local com base em sua preferência. Antes de executar o comando de compilaçãomake
, basta carregar o ambiente de compilação do diretórioduo-examples
(source /PATH/TO/duo-examples/envsetup.sh). - Dentro do terminal onde o ambiente de compilação (envsetup.sh) é carregado, evite compilar projetos Makefile para outras plataformas como ARM ou X86. Se precisar compilar projetos para outras plataformas, abra um novo terminal.
3. Explicação de cada exemplo
Hello-world
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/hello-world
Um exemplo simples que não interage com os periféricos Duo, apenas imprime a saída “Hello, World!” para verificar o ambiente de desenvolvimento.
Blink
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/blink
Este exemplo demonstra como controlar um LED conectado a um pino GPIO. Ele usa a biblioteca WiringX para alternar o nível de tensão do pino GPIO, fazendo com que o LED pisque.
O código blink.c
inclui inicialização da plataforma e métodos de manipulação GPIO da biblioteca WiringX.
Para testar o exemplo blink
, que envolve LED piscando, é necessário desabilitar o script responsável pelo piscar automático do LED no firmware padrão do Duo. No terminal Duo, execute o seguinte comando:
mv /mnt/system/blink.sh /mnt/system/blink.sh_backup && sync
Este comando renomeia o script de LED piscando. Após reiniciar o Duo, o LED não piscará mais.
Depois de terminar de testar o programa blink
implementado em C, se quiser restaurar o script de piscar do LED, você pode renomeá-lo usando o seguinte comando e reiniciar o Duo:
mv /mnt/system/blink.sh_backup /mnt/system/blink.sh && sync
ADC
adcRead lê a tensão elétrica
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/adc
A leitura do valor medido do ADC é dividida em duas versões: shell script e linguagem C. Após iniciar, selecione o ADC a ser lido de acordo com os prompts de saída. Após a seleção, o valor da tensão medido pelo ADC será impresso em loop.
I2C
Diretório de código-fonte I2C: https://github.com/milkv-duo/duo-examples/tree/main/i2c
Sensor de barômetro e de temperatura BMP280
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/i2c/bmp280_i2c
Este código de exemplo mostra como fazer a interface do Milk-V Duo com o popular sensor de temperatura e pressão de ar BMP280 fabricado pela Bosch.
Sensor de distância de tempo de voo VL53l0X
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/i2c/vl53l0x_i2c
Use o módulo sensor de distância TOF VL53L0X através da interface I2C para ler a distância medida.
OLEDS SSD1306
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/i2c/ssd1306_i2c
Exibir strings no display OLED SSD1306 via interface I2C.
ADXL345 - Sensor de aceleração de 3 eixos
Pelo I2C, leia a cada 1 segundo e imprima o resultado na tela.
Módulo de exibição LCM1602
Código fonte: https://github.com/milkv-duo/duo-examples/blob/main/i2c/lcm1602_i2c
Exiba strings na tela LCD 1602 por meio da interface I2C.
Módulo de exibição LCM2004
Código fonte: https://github.com/milkv-duo/duo-examples/blob/main/i2c/lcm2004_i2c
String de exibição na tela LCD de 2004 via interface I2C.
Sensor de cores TCS34725
Código fonte: https://github.com/milkv-duo/duo-examples/blob/main/i2c/tcs34725_i2c
Leia o sensor de cores TCS34725 através da interface I2C e produza os dados obtidos.
SPI
Diretório de código-fonte SPI: https://github.com/milkv-duo/duo-examples/tree/main/spi
Sensor de temperatura MAX6675
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/spi/max6675_spi
Conecte o módulo de medição de termopar tipo K MAX6675 através da interface SPI para medir a temperatura atual no sensor.
Módulo de identificação por radiofrequência RC522
Código fonte: https://github.com/milkv-duo/duo-examples/tree/main/spi/rc522_spi
Conecte o módulo de leitura e gravação RFID RC522 por meio da interface SPI para ler o ID e tipo do cartão e então exibi-lo na tela.
4. Compilando WiringX
O firmware Duo já contém a biblioteca wiringX compilada (/usr/lib/libwiringx.so) e pode ser usado diretamente. Se você precisar compilar o código-fonte do wiringX para gerar a biblioteca, poderá compilá-lo da seguinte maneira.
Nós o compilamos em um host Ubuntu ou outra distribuição Linux ou WSL.
*Observação: parte do código wiringX do Duo ainda não foi integrada ao repositório wiringX upstream. No uso real, dê prioridade ao uso da biblioteca wiringX no firmware Duo.
Baixe
git clone https://github.com/wiringX/wiringX.git
Modifique
Digite o diretório do código:
cd wiringX
O projeto wiringX é compilado usando cmake. Você precisa modificar CMakeLists.txt por meio do editor vi
ou outros para adicionar o conjunto de ferramentas de compilação cruzada e os parâmetros de compilação:
diff --git a/CMakeLists.txt b/CMakeLists.txtindex 8909393..6918181 100644--- a/CMakeLists.txt+++ b/CMakeLists.txt@@ -17,6 +17,11 @@ set(CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=/usr/local/lib/,-rpath=/usr/lib/,-rpath= set(CMAKE_SHARED_LINKER_FLAGS " -Wl,-rpath=/usr/local/lib/,-rpath=/usr/lib/,-rpath=/lib/") set(CMAKE_MODULE_LINKER_FLAGS " -Wl,-rpath=/usr/local/lib/,-rpath=/usr/lib/,-rpath=/lib/")
+set(CMAKE_C_COMPILER "${CMAKE_CURRENT_SOURCE_DIR}/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-gcc")
+set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_SOURCE_DIR}/host-tools/gcc/riscv64-linux-musl-x86_64/bin/riscv64-unknown-linux-musl-g++")
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcpu=c906fdv -march=rv64imafdcv0p7xthead -mcmodel=medany -mabi=lp64d")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64")
+ # Start uninstaller generator function(WRITE_UNINSTALL_TARGET_SCRIPT) # Create uninstall target template file, if it doesn't exist...
Existem duas variáveis que precisam ser anotadas e configuradas de acordo com o seu próprio caminho de arquivo:
- CMAKE_C_COMPILER : O caminho para o gcc no conjunto de ferramentas de compilação cruzada
- CMAKE_CXX_COMPILER : caminho para g++ na cadeia de ferramentas de compilação cruzada
Link para download do conjunto de ferramentas de compilação cruzada: host-tools.tar.gz . Você pode baixá-lo e descompactá-lo através do comando wget:
wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/03/07/16/host-tools.tar.gztar -xf host-tools.tar.gz
Se você já compilou duo-buildroot-sdk , o diretório host-tools
em seu diretório raiz é o diretório da cadeia de ferramentas cruzada. Não há necessidade de fazer download novamente, você pode modificar diretamente o campo CMAKE_CURRENT_SOURCE_DIR
para especificar o diretório. Ou crie um link virtual apontando para o diretório.
Modifique o código
Como as definições relacionadas ao tempo no conjunto de ferramentas cruzadas são ligeiramente diferentes daquelas no WiringX, adicione as duas linhas de modificação a seguir:
diff --git a/src/wiringx.c b/src/wiringx.cindex 034674a..4171a75 100644--- a/src/wiringx.c+++ b/src/wiringx.c@@ -113,6 +113,9 @@ static struct spi_t spi[2] = { } while(0) #endif
+typedef time_t __time_t;
+typedef suseconds_t __suseconds_t;
+ /* Both the delayMicroseconds and the delayMicrosecondsHard are taken from wiringPi */ static void delayMicrosecondsHard(unsigned int howLong) {
A compilação no cmake criará alguns diretórios e arquivos intermediários, então criamos um novo diretório de construção e entramos neste diretório para concluir a compilação:
mkdir buildcd buildcmake ..make
Após a conclusão da compilação, o libwiringx.so
gerado no diretório build
atual é a biblioteca wiringX que precisamos.
Pontos a considerar
Se você encontrar erros de compilação, você pode tentar alterar a versão do cmake
. Por exemplo, você pode instalar manualmente a versão 3.27.6
mais recente:
wget https://github.com/Kitware/CMake/releases/download/v3.27.6/cmake-3.27.6-linux-x86_64.shchmod +x cmake-3.27.6-linux-x86_64.shsudo sh cmake-3.27.6-linux-x86_64.sh --skip-license --prefix=/usr/local/
O cmake
instalado manualmente está no formato /usr/local/bin
. Neste momento, utilize o comando cmake --version
para verificar seu número de versão, que deve ser:
cmake version 3.27.6
wiringX APIs
Geral
int wiringXSetup(char *name, ...)
int wiringXValidGPIO(int pin)
void delayMicroseconds(unsigned int ms)
int wiringXGC(void)
char *wiringXPlatform(void)
GPIO
int pinMode(int pin, pinmode_t mode)
int digitalRead(int pin)
int digitalWrite(int pin, enum digital_value_t value)
int waitForInterrupt(int pin, int ms)
int wiringXISR(int pin, enum isr_mode_t mode)
I2C
int wiringXI2CSetup(const char *dev, int addr)
int wiringXI2CRead(int fd)
int wiringXI2CReadReg8(int fd, int reg)
int wiringXI2CReadReg16(int fd, int reg)
int wiringXI2CWrite(int fd, int reg)
int wiringXI2CWriteReg8(int fd, int reg, int value8)
int wiringXI2CWriteReg16(int fd, int reg, int value16)
SPI
int wiringXSPISetup(int channel, int speed)
int wiringXSPIDataRW(int channel, unsigned char *data, int len)
int wiringXSPIGetFd(int channel)
UART
int wiringXSerialOpen(const char *dev, struct wiringXSerial_t serial)
void wiringXSerialClose(int fd)
void wiringXSerialFlush(int fd)
void wiringXSerialPutChar(int fd, unsigned char c)
void wiringXSerialPuts(int fd, const char *s)
void wiringXSerialPrintf(int fd, const char *message, ...)
int wiringXSerialDataAvail(int fd)
int wiringXSerialGetChar(int fd)
PWM
- Número do pino PWM do Duo
PWM PIN NAME Pin# Pin# PIN NAME GP0 1 40VBUS GP1 2 39VSYS GND 3 38GND 10 GP2 4 373V3_EN 11 GP3 5 363V3(OUT) 5 GP4 6 356 GP5 7 34GND 8 33GND 9 GP6 9 32GP27 8 GP7 10 31GP26 7 GP8 11 30RUN 4 GP9 12 29GP22 GND 13 28GND GP10 14 27GP21 GP11 15 26GP20 4 GP12 16 25GP19 5 GP13 17 24GP18 GND 18 23GND GP14 19 22GP17 GP15 20 21GP16 PWM
wiringXPWMSetPeriod(int pin, long period)int wiringXPWMSetDuty(int pin, long duty_cycle)int wiringXPWMSetPolarity(int pin, int polarity)int wiringXPWMEnable(int pin, int enable)
Questões: suporte@smartcore.com.brReferênciasSobre a SMARTCORE
A SMARTCORE FORNECE CHIPS E MÓDULOS PARA IOT, COMUNICAÇÃO WIRELESS, BIOMETRIA, CONECTIVIDADE, RASTREAMENTO E AUTOMAÇÃO. NOSSO PORTFÓLIO INCLUI MODEM 2G/3G/4G/NB-IOT, SATELITAL, MÓDULOS WIFI, BLUETOOTH, GPS, SIGFOX, LORA, LEITOR DE CARTÃO, LEITOR QR CCODE, MECANISMO DE IMPRESSÃO, MINI-BOARD PC, ANTENA, PIGTAIL, BATERIA, REPETIDOR GPS E SENSORES.
Nenhum comentário:
Postar um comentário