terça-feira, 30 de novembro de 2021

NuttX em Detalhes no U-BLOX NINA W106 - Habilitando GPIOS

O objetivo deste BLOG é demonstrar como é possível utilizar o NuttX para programação do U-BLOX NINA W106. Foi utilizado o EVK U-BLOX NINA W106.

Adaptação e Tradução do Blog da embetronicx

Testado no Ubuntu 20
EVK U-BLOX NINA W106


NuttX: O sistema operacional para a Internet das Coisas.

NuttX é um sistema operacional em tempo real (RTOS) com ênfase na conformidade de padrões e pequeno footprint. Escaláveis de ambientes microcontroladores de 8 bits a 64 bits, os principais padrões de governo em NuttX são os padrões Posix e ANSI. ApIs padrão adicionais do Unix e de outros RTOS comuns (como o VxWorks) são adotadas para funcionalidades não disponíveis sob esses padrões, ou para funcionalidades que não são apropriadas para ambientes profundamente incorporados (como fork()).

Apache NuttX é um esforço em incubação na Apache Software Foundation (ASF), patrocinada pela Incubadora. A incubação é necessária de todos os projetos recém-aceitos até que uma nova revisão indique que o processo de infraestrutura, comunicação e tomada de decisão se estabilizou de forma consistente com outros projetos ASF bem-sucedidos. Embora o status de incubação não seja necessariamente um reflexo da completude ou estabilidade do código, ele indica que o projeto ainda não foi totalmente endossado pela ASF.

NuttX é um sistema operacional incorporado em tempo real (RTOS). Seus objetivos são:

Rich Feature OS Set
O objetivo é fornecer implementações da maioria das interfaces padrão do SISTEMA OPERACIONAL POSIX para oferecer suporte a um ambiente de desenvolvimento rico e multi-threaded para processadores profundamente incorporados.

Não é um objetivo fornecer o nível de recursos do SO como os fornecidos pelo Linux. Para trabalhar com MCUs menores, a pequena footprint deve ser mais importante do que um conjunto de recursos extenso. Mas a conformidade padrão é mais importante do que uma pequena footprint. Certamente um RTOS menor poderia ser produzido ignorando padrões. Pense no NuttX é um pequeno trabalho linux com um conjunto de recursos muito reduzido.

Altamente escalável
Totalmente escalável de minúsculo (8 bits) a moderado incorporado (64 bits). A escalabilidade com conjunto de recursos ricos é realizada com: Muitos arquivos de origem minúsculos, link de bibliotecas estáticas, altamente configurável, uso de símbolos fracos quando disponíveis.

Conformidade de padrões
A NuttX se esforça para alcançar um alto grau de conformidade de padrões. As principais normas de governo são as normas POSIX e ANSI. ApIs padrão adicionais do Unix e de outros RTOS comuns são adotadas para funcionalidades não disponíveis sob esses padrões ou para funcionalidades que não são apropriadas para os RTOS profundamente incorporados (como fork()).

Devido a essa conformidade de padrões, o software desenvolvido sob outros OSs padrão (como o Linux) deve ser portado facilmente para NuttX.

Tempo Real Totalmente preventivo; prioridade fixa, round-robin, e agendamento "esporádico".

Licença Apache não restritiva totalmente aberta.

GNU Toolchains Compatíveis com as cadeias de ferramentas GNU baseadas no buildroot disponível para download para fornecer um ambiente completo de desenvolvimento para muitas arquiteturas.

Colocando Nuttx no U-BLOX NINA W106

O link abaixo, é roteiro Básico para que você possa preparar o ambiente para programar o U-BLOX NINA W106 com o NuttX


    Dependências
$sudo apt install \
bison flex gettext texinfo libncurses5-dev libncursesw5-dev \
gperf automake libtool pkg-config build-essential gperf genromfs \
libgmp-dev libmpc-dev libmpfr-dev libisl-dev binutils-dev libelf-dev \
libexpat-dev gcc-multilib g++-multilib picocom u-boot-tools util-linux
Nota 1: O NuttX utiliza um sistema de build semelhante ao do Kernel do Linux (https://www.kernel.org/doc/html/latest/kbuild/index.html). Ele utiliza o kconfig-frontends como seu sistema de configuração. O repositório tools.git é utilizado para instalar este pacote. Porém se você estiver usando o Ubuntu 19.10 ou mais recente, estas distribuições já contém o pacote, mas de qualquer forma, instale.

$ sudo apt-get install kconfig-frontends


Nota 2: Outra dependência para o processo do NuttX com o ESP32 é o ESP-IDF (Espressif IoT Development Framework). Este framework é nativo do ESP e mantido pela Espressif. Ele compreende um conjunto de códigos como drivers, APIs, scripts, ferramental para compilar e fazer upload do firmware e o FreeRTOS customizado. Neste ponto, uma observação conceitual é muito importante, o NuttX não usa o FreeRTOS em nenhuma camada interna, apenas algumas ferramentas auxiliares que compõem o IDF serão utilizadas para geração do binário e gravação.
Download do NuttX
$ mkdir nuttx
$ cd nuttx
$ git clone https://github.com/apache/incubator-nuttx.git nuttx
$ git clone https://github.com/apache/incubator-nuttx-apps apps
O Ubuntu e o Debian ainda fornecem o Python 2.7 como o interpretador padrão, mas alguns 
pacotes necessários podem estar faltando para distribuições mais recentes. Python 3 é
recomendado e pode ser instalado da seguinte maneira:
 
$ sudo apt-get install python3 python3-pip python3-setuptool sudo update-alternatives --install /usr/bin/python python /usr/bin/python3
 Instale agora o ESP-IDF (ESP32 TOOLS, LIBS, ETC) manualmente
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-setup.html
(ESP-IDF) extrair
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git

osboxes@osboxes:~$ cd esp/
osboxes@osboxes:~/esp$ cd esp-idf/
osboxes@osboxes:~/esp/esp-idf$ ./install.sh
Detecting the Python interpreter
Checking "python" ...
/home/osboxes/esp/esp-idf/tools/detect_python.sh: line 16: python: command not found
Checking "python3" ...
Python 3.8.5
"python3" has been detected
Installing ESP-IDF tools
Installing tools: xtensa-esp32-elf, xtensa-esp32s2-elf, xtensa-esp32s3-elf, riscv32-esp-elf, esp32ulp-elf, esp32s2ulp-elf, openocd-esp32
Installing xtensa-esp32-elf@esp-2020r3-8.4.0
Downloading xtensa-esp32-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz to /home/osboxes/.espressif/dist/xtensa-esp32-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz.tmp
Done
Extracting /home/osboxes/.espressif/dist/xtensa-esp32-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz to /home/osboxes/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0
Installing xtensa-esp32s2-elf@esp-2020r3-8.4.0
Downloading xtensa-esp32s2-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz to /home/osboxes/.espressif/dist/xtensa-esp32s2-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz.tmp
Done
.
.
.
 $ cd nuttx
$ make -C tools/esp32/ ${HOME}/esp/esp-idf
Após a instalação do IDF, ou caso já possua o IDF instalado, execute o
seguinte comando para ativar o ambiente virtual que foi configurado na
instalação. Sempre que for realizar o build do NuttX, será necessário
ativar este ambiente.
$. ${HOME}/esp/esp-idf/export.sh
No presente momento, o NuttX utiliza 2 binários gerados através do
IDF: o bootloader e a tabela de partição. Ainda dentro do diretório
/nutxtx/nuttx/, faça o download destes binários pré configurados:
$ wget -O bootloader.bin https://github.com/saramonteiro/esp32_binaries_nuttx/blob/main/bootloader.bin?raw=true
$ wget -O partitions.bin https://github.com/saramonteiro/esp32_binaries_nuttx/blob/main/partitions.bin?raw=true

Mantenha-se no diretório do NuttX e execute o script de configuração para criar um arquivo de configuração para o
U-BLOX NINA W106. 

$ make distclean
uttX has not been configured!
To configure the project:
  tools/configure.sh <config>
For a list of available configurations:
  tools/configure.sh -L
$ ./tools/configure.sh esp32-devkitc:nsh 
 

Finalmente, faça o build e confirme em seguida que o firmware binário foi gerado:
$ make
osboxes@osboxes:~/nuttx/nuttx$ make
Create .version
Create version.h
LN: include/arch/board to /home/osboxes/nuttx/nuttx/boards/xtensa/esp32/esp32-devkitc/include
make[1]: Entering directory '/home/osboxes/nuttx/nuttx/libs/libxx'
make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/libs/libxx'
make[1]: Nothing to be done for 'dirlinks'. make[1]: Entering directory '/home/osboxes/nuttx/nuttx/boards'
make[1]: Entering directory '/home/osboxes/nuttx/nuttx/openamp'
make[1]: Nothing to be done for 'dirlinks'. make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/boards' make[1]: Nothing to be done for 'dirlinks'.
make[2]: Entering directory '/home/osboxes/nuttx/apps/platform'
make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/openamp' make[1]: Entering directory '/home/osboxes/nuttx/apps' LN: platform/board to /home/osboxes/nuttx/apps/platform/dummy
make[2]: Entering directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common'
make[2]: Leaving directory '/home/osboxes/nuttx/apps/platform' make[1]: Leaving directory '/home/osboxes/nuttx/apps' make[1]: Entering directory '/home/osboxes/nuttx/nuttx/boards' make[2]: Nothing to be done for 'context'.
make[1]: Nothing to be done for 'context'.
make[2]: Leaving directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common' make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/boards' make[1]: Entering directory '/home/osboxes/nuttx/nuttx/fs' make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/fs'
make[2]: Entering directory '/home/osboxes/nuttx/apps'
make[1]: Entering directory '/home/osboxes/nuttx/apps'
.
.
.
make[3]: Leaving directory '/home/osboxes/nuttx/apps/system/readline'
make[2]: Leaving directory '/home/osboxes/nuttx/apps'
IN: /home/osboxes/nuttx/apps/libapps.a -> staging/libapps.a
make[1]: Leaving directory '/home/osboxes/nuttx/apps'
make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/fs'
make[1]: Entering directory '/home/osboxes/nuttx/nuttx/fs' make[1]: 'libfs.a' is up to date.
make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/binfmt'
make[1]: Entering directory '/home/osboxes/nuttx/nuttx/binfmt' make[1]: 'libbinfmt.a' is up to date.
make[2]: 'libboard.a' is up to date.
make[1]: Entering directory '/home/osboxes/nuttx/nuttx/arch/xtensa/src' make[2]: Entering directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common'
CP: nuttx.hex
make[2]: Leaving directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common' LD: nuttx make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/arch/xtensa/src' CP: nuttx.bin
osboxes@osboxes:~/nuttx/nuttx$

**Este binário não tem os cabeçalhos com as informações que o bootloader do ESP32 espera encontrar, então ele deve ser removido:

$ rm nuttx.bin

E um novo binário deverá ser gerado a partir do arquivo ELF chamado “nuttx”. Para isso, é necessário usar o script esptool.py para gerar este arquivo:

esptool.py --chip esp32 elf2image --flash_mode dio --flash_size 4MB -o ./nuttx.bin nuttx

$ make menuconfig
.config - NuttX/x86_64 Configuration
────────────────────────────────────────────────────────────────────────────────────
┌───────────────────────── NuttX/x86_64 Configuration ──────────────────────────
Arrow keys navigate the menu. <Enter> selects submenus ---> (or empty │
submenus ----). Highlighted letters are hotkeys. Pressing <Y> includes, │
<N> excludes, <M> modularizes features. Press <Esc><Esc> to exit, <?> for │
Help, </> for Search. Legend: [*] built-in [ ] excluded <M> module < > │
┌───────────────────────────────────────────────────────────────────────────
Build Setup --->
System Type --->
Board Selection --->
RTOS Features --->
Device Drivers --->
│ Networking Support --->
Crypto API --->
File Systems --->
Graphics Support --->
│ Memory Management --->
Audio Support --->
Video Support --->
Wireless Support --->
Binary Loader --->
Library Routines --->
Open Asymmetric Multi Processing --->
Application Configuration --->
───────────────────────────────────────────────────────────────────────────┘
├───────────────────────────────────────────────────────────────────────────────
<Select> < Exit > < Help > < Save > < Load > │
───────────────────────────────────────────────────────────────────────────────┘
make menuconfig customiza o que deseja adicionar/retirar na placa. Por exemplo, permite adicionar os drivers de um determinado periférico, adicionar mensagens de debug, etc.

Anote endereços de Gravação

Controlando LEDs

Vamos escrever um código para controlar os LEDs. Basicamente, o NuttX é um sistema operacional compatível com POSIX e gosta de usar a mesma convenção de nomenclatura de muitas das funções e arquivos que você encontraria em seu sistema UNIX / Linux padrão. E está operando como um sistema Linux. Em um sistema Linux, temos que escrever um driver de kernel para conversar com o hardware. Este driver do kernel residirá no espaço do kernel. E o aplicativo precisa estar lá para falar com o driver do kernel. Esse aplicativo residirá no espaço do usuário.

Portanto, vamos desenvolver um driver de LED e uma aplicação de LED. Se você já está familiarizado com o driver do kernel Linux e um aplicativo de espaço do usuário, prometo que será muito fácil entender o NuttX RTOS. Se você não estiver familiarizado também está bem. Você aproveita a chance e aprende o NuttX RTOS. Tenho certeza que você vai começar a adorar trabalhar com drivers do kernel Linux e também em um aplicativo.

Vamos começar. Estamos dividindo o tutorial em duas partes.

  • Escrevendo um driver de LED
  • Escrevendo um aplicativo

Escrevendo um driver de LED

No Linux / POSIX, todas as coisas são consideradas como um arquivo. Então, vamos criar um arquivo em /dev/. Em nosso exemplo, nosso driver criará o arquivo /dev/etx_led.

Primeiro, vamos ver o código abaixo.

esp32_etx_led.c

Eu adicionei este arquivo ao nuttx/boards/xtensa/esp32/common/src/.

sp32_etx_led.h

/****************************************************************************
* boards/xtensa/esp32/common/src/esp32_etx_led.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <assert.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
#include <nuttx/arch.h>
#include "esp32-devkitc.h"
#include "esp32_gpio.h"
#include "esp32_etx_led.h"
#ifdef CONFIG_ESP32_ETX_LED
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Character driver methods */
static int etx_led_open(FAR struct file *filep);
static int etx_led_close(FAR struct file *filep);
static ssize_t etx_led_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations etx_led_fops =
{
etx_led_open, /* open */
etx_led_close, /* close */
NULL, /* read */
etx_led_write, /* write */
NULL, /* seek */
NULL, /* ioctl */
NULL, /* poll */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
NULL /* unlink */
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: etx_led_open
*
* Description:
* This function will be getting called when the application
* opens the "/dev/etx_led" file.
****************************************************************************/
static int etx_led_open(FAR struct file *filep)
{
int ret = 0;
return ( ret );
}
/****************************************************************************
* Name: etx_led_close
*
* Description:
* This function will be getting called when the application
* closess the "/dev/etx_led" file.
****************************************************************************/
static int etx_led_close(FAR struct file *filep)
{
int ret = 0;
return ( ret );
}
/****************************************************************************
* Name: etx_led_write
*
* Description:
* This function will be getting called when the application
* writes data the "/dev/etx_led" file.
****************************************************************************/
static ssize_t etx_led_write(FAR struct file *filep, FAR const char *buffer,
size_t len)
{
DEBUGASSERT(buffer != NULL);
//buffer[0] contains the value (ON/OFF)
//buffer[1] contains the GPIO Number
int32_t value = buffer[0];
int32_t gpio_pin = buffer[1];
if( gpio_pin < 0 || gpio_pin > ESP32_NGPIOS )
{
syslog(LOG_ERR, "Invalid GPIO Number - %d\n", gpio_pin);
return (-1);
}
// Configure the GPIO as Output
esp32_configgpio( gpio_pin, OUTPUT );
//syslog(LOG_ERR, "GPIO Number - %d\n", gpio_pin);
//syslog(LOG_ERR, "value - %d\n", value);
// Write to the GPIO
esp32_gpiowrite(gpio_pin, value);
return ( len );
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: etx_led_driver_init
*
* Description:
* Initialize the EmbeTronicX LED device Driver.
* This will create the device file as "/dev/etx_led"
*
* return negative number on failure.
* return 0 on success.
*
****************************************************************************/
int etx_led_driver_init( void )
{
int ret = 0;
ret = register_driver("/dev/etx_led", &etx_led_fops, 0666, NULL);
if (ret < 0)
{
_err("ERROR: register_driver failed : /dev/etx_led : %d\n", ret);
ret = -1;;
}
return ( ret );
}
#endif /* CONFIG_ESP32_ETX_LED */

esp32_etx_led.h

Eu adicionei este arquivo ao caminho nuttx/boards/xtensa/esp32/common/include/.

/****************************************************************************
* boards/xtensa/esp32/common/include/esp32_etx_led.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ETX_LED_H
#define __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ETX_LED_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: etx_led_driver_init
*
* Description:
* Initialize the EmbeTronicX LED device Driver.
* This will create the device file as "/dev/etx_led"
*
* return negative number on failure.
* return 0 on success.
*
****************************************************************************/
#ifdef CONFIG_ESP32_ETX_LED
int etx_led_driver_init( void );
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif #endif /* __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ETX_LED_H */


Explicação do código

Vou apenas explicar a você o código que foi fornecido acima.

Existe uma função chamada etx_led_driver_init(), que é um ponto de partida do driver e registra o driver e cria o arquivo do dispositivo chamado /dev/etx_led.

Existe uma estrutura chamada 

struct file_operations etx_led_fops. Utilizando esta estrutura  file_operations, estamos registrando nossos funções open(), close() e write().

open()

A função será chamada sempre que o aplicativo abrir o arquivo /dev/etx_led.

close()

A função será chamada sempre que o aplicativo fechar o arquivo /dev/etx_led

write()

A função é chamada quando o aplicativo grava algo no arquivo /dev/etx_led

Na função write(), estamos configurando o GPIO como uma saída usando o esp32_configgpio(). E defina o valor para esse GPIO usando o esp32_gpiowrite(). Portanto, sempre que um aplicativo quiser ligar ou desligar os LEDs, ele deve escrever o número GPIO e o valor neste driver.

Como já te disse, etx_led_driver_init() é o ponto de partida do driver. Mas alguém tem que ligar para isso. Estamos chamando essa função de esp32_bringup.c.  Estou adicionando o código abaixo na  função  esp32_bringup() do  nuttx/boards/xtensa/esp32/esp32-devkitc/src/esp32_bringup.c

#ifdef CONFIG_ESP32_ETX_GPIO
#include "esp32_etx_gpio.h"
#endif
#ifdef CONFIG_ESP32_ETX_GPIO
/* Register the EmbeTronicX GPIO Driver */
ret = etx_gpio_driver_init();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: etx_gpio_driver_init() failed: %d\n", ret);
}
#endif


int esp32_bringup(void)
{
  int ret;

#ifdef CONFIG_ESP32_ETX_GPIO
#include "esp32_etx_gpio.h"
#endif
#ifdef CONFIG_ESP32_ETX_GPIO
  /* Register the EmbeTronicX GPIO Driver */
  ret = etx_gpio_driver_init();
  if (ret < 0)
    {
      syslog(LOG_ERR, "ERROR: etx_gpio_driver_init() failed: %d\n", ret);
    }
#endif

Makefile

Agora temos que construir este driver. Então, temos que adicionar as linhas abaixo dentro do nuttx/boards/xtensa/esp32/common/src/Make.defs

ifeq ($(CONFIG_ESP32_ETX_GPIO),y)
CSRCS += esp32_etx_gpio.c

endif


# License for the specific language governing permissions and limitations # under the License. # ############################################################################# ifeq ($(CONFIG_ESP32_ETX_GPIO),y)   CSRCS += esp32_etx_gpio.c endif ifeq ($(CONFIG_WATCHDOG),y)   CSRCS += esp32_board_wdt.c endif


Kconfig

Até agora, estamos prontos com o driver LED. Mas se adicionarmos uma opção para habilitar / desabilitar este driver durante a compilação, seria muito bom. Então, para fazer isso, estou adicionando as linhas abaixo ao arquivo nuttx/boards/xtensa/esp32/common/Kconfig.

comment "Drivers added by EmbeTronicX (www.embetronicx.com)"
menu "EmbeTronicX Drivers"
config ESP32_ETX_LED
bool "EmbeTronicX LED driver"
default n
---help---
Enables the GPIOs to control the LEDs (ESP32).
This is added by the EmbeTroincX to demonstrate the
LED control using the ESP32 Dev board with NuttX.
This includes the EmbeTronicX LED driver which controls
the output.
endmenu # EmbeTronicX Drivers

# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
comment "Drivers added by EmbeTronicX (www.embetronicx.com)"
menu "EmbeTronicX Drivers"
config ESP32_ETX_LED
  bool "EmbeTronicX LED driver"
  default n
  ---help---
    Enables the GPIOs to control the LEDs (ESP32).

    This is added by the EmbeTroincX to demonstrate the
    LED control using the ESP32 Dev board with NuttX.

    This includes the EmbeTronicX LED driver which controls
    the output. 

endmenu # EmbeTronicX Drivers

Isso é tudo sobre o driver. Vamos escrever nosso aplicativo para acessar este driver. Você pode consultar este commit no GitHub para as alterações acima. Se você quiser o código-fonte completo, pegue o código do GitHub .

Escrevendo um aplicativo

No aplicativo, vou criar uma tarefa chamada ETX_LED usando a  função task_create(). Nessa tarefa, estou escrevendo o número GPIO e seu valor para o driver /dev/etx_led. Olhe o código abaixo.

etx_led_app.c

Estou criando um novo diretório chamado etx_led abaixo de  apps/examples

/****************************************************************************
* examples/etx_led/etx_led_app.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sched.h>
#include <errno.h>
#ifdef CONFIG_EXAMPLES_ETX_LED
#define ETX_LED_DRIVER_PATH "/dev/etx_led" // LED Driver path
/****************************************************************************
* Private Data
****************************************************************************/
struct gpio
{
uint8_t gpio_val;
uint8_t gpio_num;
};
static struct gpio etx_gpio;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: etx_led_task
****************************************************************************/
static int etx_led_task(int argc, char *argv[])
{
int ret = 0;
printf("ETX_LED: Task Starting\n");
int fd = open( ETX_LED_DRIVER_PATH, O_WRONLY);
if (fd < 0)
{
printf("ETX_LED:ERROR - Failed to open %s: %d\n", ETX_LED_DRIVER_PATH, errno);
ret = -1;
}
while( ret >= 0 )
{
printf("ETX_LED: GPIO = %d Value %d\n", etx_gpio.gpio_num, etx_gpio.gpio_val);
ret = write( fd, (const void*)&etx_gpio, sizeof(etx_gpio) );
//toggle the gpio val
etx_gpio.gpio_val = !etx_gpio.gpio_val;
usleep(500*1000L);
}
printf("ETX_LED: ERROR - Task finishing\n");
return EXIT_FAILURE;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
int ret;
printf("ETX_LED: Starting the Application\n");
if( argc < 2 )
{
printf("Usage : etx_led needs one argument which is GPIO number to toggle\n");
printf("Example : To toggle the GPIO 2, please enter \"etx_led 2\"\n");
return EXIT_FAILURE;
}
etx_gpio.gpio_val = 1; //Initialy turn ON the LED
etx_gpio.gpio_num = atoi(argv[1]); //Get the GPIO Number from user
ret = task_create( "ETX_LED", // Task Name
CONFIG_EXAMPLES_ETX_LED_PRIORITY, // Task priority
CONFIG_EXAMPLES_ETX_LED_STACKSIZE, // Task Stack size
etx_led_task, // Task function
NULL
);
if (ret < 0)
{
int errcode = errno;
printf("ETX_LED: ERROR: Failed to start ETX LED task: %d\n", errcode);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#endif //#ifdef CONFIG_EXAMPLES_ETX_LED

Junto com etx_led_app.c, estou criando mais três arquivos chamados Makefile, Make.defs e Kconfig no diretório apps/examples/etx_led.

Makefile

############################################################################
# apps/examples/etx_led/Makefile
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
# ETX LED built-in application info
PROGNAME = $(CONFIG_EXAMPLES_ETX_LED_PROGNAME)
PRIORITY = $(CONFIG_EXAMPLES_ETX_LED_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_ETX_LED_STACKSIZE)
MODULE = $(CONFIG_EXAMPLES_ETX_LED)
# ETX LED Example
MAINSRC = etx_led_app.c
include $(APPDIR)/Application.mk

Make.defs

############################################################################
# apps/examples/etx_led/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_EXAMPLES_ETX_LED),)
CONFIGURED_APPS += $(APPDIR)/examples/etx_led
endif

Kconfig

#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
comment "Applications added by EmbeTronicX (www.embetronicx.com)"
config EXAMPLES_ETX_LED
tristate "EmbeTronicX LED app example"
default n
depends on ESP32_ETX_LED
---help---
Enable the EmbeTronicX LED app example
if EXAMPLES_ETX_LED
config EXAMPLES_ETX_LED_PROGNAME
string "Program name"
default "etx_led"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config EXAMPLES_ETX_LED_PRIORITY
int "etx_led task priority"
default 100
config EXAMPLES_ETX_LED_STACKSIZE
int "etx_led stack size"
default DEFAULT_TASK_STACKSIZE
endif
canard        fboverlay    igmp             mld             nxdemo         pppd           smps           unionfs
osboxes@osboxes:~/nuttx/apps/examples$ mkdir etx_led 
osboxes@osboxes:~/nuttx/apps/examples$ cd etx_led/
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ 
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ ls
etx_led_app.c
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ nano Makefile
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ nano Make.defs
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ nano Kconfig
osboxes@osboxes:~/nuttx/apps/examples/etx_led$ ls -l
total 16
-rw-rw-r-- 1 osboxes osboxes 4023 Nov 30 09:49 etx_led_app.c
-rw-rw-r-- 1 osboxes osboxes  750 Nov 30 09:50 Kconfig
-rw-rw-r-- 1 osboxes osboxes 1062 Nov 30 09:50 Make.defs
-rw-rw-r-- 1 osboxes osboxes 1301 Nov 30 09:50 Makefile 
osboxes@osboxes:~/nuttx/apps/examples/etx_led$

Se você quiser ver as mudanças em relação ao aplicativo, você pode olhar este commit . Você também pode obter o código completo do GitHub .

Construindo o driver e o aplicativo

Tudo indo bem. Vamos construir nosso aplicativo e o driver juntos. Eu criei o script de shell build.sh para combinar todas as etapas necessárias em um arquivo.

build.sh
Foi adicionado ao diretório o nuttx/ . Você pode obter o build.sh no GitHub .

# !/bin/bash
# A simple bash script to build the NuttX RTOS
#export ESP32 env
. $HOME/esp/esp-idf/export.sh
if [ $1 -eq 1 ]
then
#distclean
echo "Dist clean"
make distclean
#ESP32 configure
echo "configuring ESP32 with NuttX RTOS"
./tools/configure.sh esp32-devkitc:nsh
fi
#menuconfig
make menuconfig
#make and flash
make download ESPTOOL_PORT=/dev/ttyUSB0

O script acima tem um argumento. Se você passar 1, ele faz distclean e inicializa as configurações da placa . Se você passar diferente de 1, ele fará apenas o make menuconfig e make.

build.sh
osboxes@osboxes:~/nuttx/nuttx$ sudo chmod +x build.sh 
osboxes@osboxes:~/nuttx/nuttx$ ./build.sh 
Detecting the Python interpreter
Checking "python" ...
Python 3.8.10
"python" has been detected
Adding ESP-IDF tools to PATH...
Using Python interpreter in /home/osboxes/.espressif/python_env/idf4.4_py3.8_env/bin/python
Checking if Python packages are up to date...
Python requirements from /home/osboxes/esp/esp-idf/requirements.txt are satisfied.
Added the following directories to PATH:
.
.
.
Vamos fazer distclean e build. Execute o comando abaixo no diretório nuttx/nuttx.

Ao executar o comando acima, você deverá obter a janela menuconfig. Nesse menu, temos que habilitar o driver etx_led  e o aplicativo etx_led_app .

Basta navegar para Seleção de placa -> Drivers EmbeTronicX -> e verificar o driver LED EmbeTroincX como na imagem abaixo.


Depois de habilitado isso, pressione Exit e vá para Home . Agora é hora de habilitar o aplicativo. Para fazer isso, navegue até Home ->Application Configuration -> Examples -> e verifique o exemplo do aplicativo EmbeTronicX LED como a imagem abaixo .


Isso é tudo. Salve e saia do menu e deixe-o fazer o Build. 

AS:  common/xtensa_vectors.S
AS:  common/xtensa_window_vector.S
AS:  common/xtensa_windowspill.S
AS:  common/xtensa_int_handlers.S
AS:  common/xtensa_user_handler.S
CC:  chip/esp32_start.c
CC:  chip/esp32_wdt.c
make[2]: Entering directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common'
CC:  board/esp32_boot.c
CC:  board/esp32_bringup.c
CC:  board/esp32_appinit.c
CC:  src/esp32_etx_led.c
AR (create): libboard.a   esp32_boot.o esp32_bringup.o esp32_appinit.o esp32_etx_led.o 
make[2]: Leaving directory '/home/osboxes/nuttx/nuttx/boards/xtensa/esp32/common'
LD: nuttx
make[1]: Leaving directory '/home/osboxes/nuttx/nuttx/arch/xtensa/src'
CP: nuttx.hex
CP: nuttx.bin
MKIMAGE: ESP32 binary
esptool.py -c esp32 elf2image -fs 4MB -fm dio -ff 40m -o nuttx.bin nuttx
esptool.py v3.2-dev
Merged 1 ELF section 
Generated: nuttx.bin (ESP32 compatible)

Assim que estiver tentando se conectar, segure o botão BOOT . Em seguida, ele começará a piscar.

Depois o build e gravação, você conecta o dispositivo usando o picocom  usando o comando 
picocom -b 115200 /dev/ttyUSB0

Agora você obterá o NuttShell (nsh) . Digite o comando help . Você obterá a saída como a imagem abaixo.


Nosso aplicativo etx_led  foi adicionado em Builtin Apps . Vamos executar o aplicativo.

Exemplo de LED piscando ESP32 - Saída

app etx_led  tem um argumento que é o número GPIO. Você pode fornecer qualquer número GPIO válido. Neste exemplo, estou fornecendo o número GPIO do LED integrado 2. Execute o comando abaixo.

etx_led 2

Se você não quiser usar o aplicativo, pode usar o comando printf  abaixo . Mas certifique-se de ter habilitado o comando printf  no menuconfig.

Para ligar o LED GPIO 2, tente inserir o comando abaixo em nsh .

printf \x0201 > /dev/etx_led
Aqui, 02 é o número GPIO e 01 é o valor a ser definido.

Para desligar o LED GPIO 2, tente inserir o comando abaixo em nsh.

printf \x0200 > /dev/etx_led
Aqui, 02 é o número GPIO e 00 é o valor a ser definido.






RODANDO EM BACKGROUND

nsh> etx_led 15 &

DÚVIDAS

suporte@smartcore.com.br

AGRADECIMENTOS

Alan Carvalho de Assis
Mestre em Engenharia Elétrica pela UFRGS; Formado em Computação
Sistemas de Informação pela UnilesteMG

REFERÊNCIAS
 

Sobre a SMARTCORE

A SmartCore fornece módulos para comunicação wireless, biometria, conectividade, rastreamento e automação.
Nosso portfólio inclui modem 2G/3G/4G/NB-IoT/Cat.M, satelital, módulos WiFi, Bluetooth, GNSS / GPS, Sigfox, LoRa, leitor de cartão, leitor QR code, mecanismo de impressão, mini-board PC, antena, pigtail, LCD, bateria, repetidor GPS e sensores.
Mais detalhes em www.smartcore.com.br

Nenhum comentário:

Postar um comentário