segunda-feira, 24 de outubro de 2022

Mbed-OS LoRaWAN no LSM110A

LSM110A Starter KIT
Módulo

O objetivo deste BLOG é mostrar outra opção para desenvolver código personalizado para o STM32WL55, ou seja, via Mbed-OS. É um sistema operacional de código aberto e fácil de usar para a Internet das Coisas (IoT), desenvolvido pela ARM.

BETA - EM TESTES - APENAS PARA PROGRAMADORES COM Mbed-OS

Mbed-OS

O Mbed oferece um sistema operacional IoT de código aberto gratuito com conectividade, segurança, armazenamento, gerenciamento de dispositivos e aprendizado de máquina. Construa seu próximo produto com ferramentas de desenvolvimento gratuitas, milhares de exemplos de código e suporte para centenas de placas de desenvolvimento de microcontroladores.

APP

Este é um aplicativo de exemplo baseado nas APIs de protocolo Mbed-OS LoRaWAN. A implementação da pilha Mbed-OS LoRaWAN está em conformidade com a especificação LoRaWAN v1.0.2. Este aplicativo pode funcionar com qualquer Servidor de Rede se você tiver credenciais corretas para o referido Servidor de Rede.

Compilar e atualizar o firmware

Você pode compilar e atualizar a placa com excelente framework mbed-os. A maneira mais fácil é com a IDE do Mbed Studio

Basicamente adicionaremos a placa com STM32WL55 em stm32customtargets e finalmente, o programa principal do firmware mbed-os-example-lorawan.

Instalando a IDE do Mbed Studio

Mbed Studio | Mbed (ou Keil Studio Cloud)

  • use file/import program e importe o exemplo com URL https://github.com/ARMmbed/mbed-os-example-lorawan

  • clique com o botão direito no nome do projeto e selecione Adicionar Biblioteca e digite https://github.com/ARMmbed/stm32customtargets


Mantenha as LIBS atualizadas
  • abra o arquivo custom_targets.json da pasta stm32customtargets e copie todo o conteúdo

  • cole o conteúdo copiado no arquivo da pasta raiz principal custom_targets.json (sim, substitua o arquivo inteiro)

Altere os parâmetros LoRaWAN, como plano de frequência, OTAA, Duty Cycle, ...


  • substitua as chaves pelas que você obteve, lora.device-eui, lora.application-eui e lora.application-key
Em seguida, no IDE, selecione o alvo "NUCLEO-WL55JC", build e faça o flash com seu programador favorito (estou usando STLink) com GND/SWDIO/SWDCLK/RESET conectado.

Escolha Target NUCLEO-WL55JC


Compilação (Build) e Gravação

A partir do IDE você pode pode dar um Build no exemplo. 

Configuração e seleção do Rádio

Para módulos LoRa suportados pelo Mbed-OS, o conjunto de pinos já está fornecido target-overrides do arquivo mbed_app.json

Sub-band
  "lora.fsb-mask""{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}"

   "target_overrides": {
        "*": {
            "platform.stdio-convert-newlines": true,
            "platform.stdio-baud-rate": 115200,
            "platform.default-serial-baud-rate": 115200,
            "mbed-trace.enable": false,
            "mbed-trace.max-level": "TRACE_LEVEL_DEBUG",
            "lora.over-the-air-activation": true,
            "lora.duty-cycle-on": true,
            "lora.phy": "AU915",
            "lora.device-eui": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }",
            "lora.application-eui": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }",
            "lora.application-key": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }"
            "lora.fsb-mask""{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}"
        },

Adicionando credenciais de Rede

Abra o arquivo mbed_app.json no diretório raiz do seu aplicativo. Este arquivo contém todas as configurações específicas do usuário que o aplicativo e a pilha Mbed OS LoRaWAN precisam. As credenciais de rede são normalmente fornecidas pelo provedor de rede LoRa.

Para OTAA

Por favor, adicione o Dispositivo EUI, o aplicativo EUI e a chave de aplicação necessária para ativação over-the-air(OTAA). Por exemplo:

"lora.device-eui": "{ YOUR_DEVICE_EUI }",
"lora.application-eui": "{ YOUR_APPLICATION_EUI }",
"lora.application-key": "{ YOUR_APPLICATION_KEY }"
"lora.over-the-air-activation": true,

Para ABP

Para o método de conexão ABP (Activation-By-Personalization, conexão ativação por personalização), modifique o mbed_app.json para habilitar a ABP. Você pode fazê-lo simplesmente desligando OTAA. Por exemplo:

"lora.over-the-air-activation": false,

Além disso, você precisa fornecer chave de sessão de aplicativos, chave de sessão de rede e endereço do dispositivo. Por exemplo:

"lora.appskey": "{ YOUR_APPLICATION_SESSION_KEY }",
"lora.nwkskey": "{ YOUR_NETWORK_SESSION_KEY }",
"lora.device-address": " YOUR_DEVICE_ADDRESS_IN_HEX " 


Mudar para Regional 1.0.2

Configuração do aplicativo

A pilha Mbed OS LoRaWAN fornece muitos controles de configuração para o aplicativo através do sistema de configuração Mbed OS configuration system. Esta seção destaca alguns recursos úteis que você pode configurar.

Selecionando um PHY

O protocolo LoRaWAN está sujeito a regulamentos específicos de vários países relativos às emissões de rádio. É por isso que a pilha Mbed OS LoRaWAN fornece uma classe LoRaPHY que você pode usar para implementar qualquer camada PHY específica da região. Atualmente, a pilha Mbed OS LoRaWAN fornece 10 implementações específicas de países diferentes da classe LoRaPHY. A seleção de uma camada PHY específica acontece no momento da compilação. Por padrão, a pilha Mbed OS LoRaWAN usa PHY EU 868MHz. 

   "lora.phy": "AU915",

Duty Cycle

A especificação LoRaWAN v1.0.2 é exclusivamente baseada em Duty Cycle. Este aplicativo vem com Duty Cycle. Em outras palavras, a pilha Mbed OS LoRaWAN impõe o Duty Cycle. A pilha mantém o controle das transmissões nos canais em uso e programa transmissões em canais que ficam disponíveis no menor tempo possível. Recomendamos que você mantenha o ciclo de serviço ligado para o cumprimento das regulamentações específicas do seu país.

"target_overrides": {
    "*": {
        "lora.duty-cycle-on": false
    }
}

Ficando então assim mbed_app.json

{
    "config": {
        "main_stack_size":     { "value"4096 }
    },
    "target_overrides": {
        "*": {
            "lora.tx-max-size"242,
            "platform.stdio-convert-newlines"true,
            "platform.stdio-baud-rate"115200,
            "platform.default-serial-baud-rate"115200,
            "mbed-trace.enable"false,
            "mbed-trace.max-level""TRACE_LEVEL_DEBUG",
            "lora.over-the-air-activation"true,
            "lora.duty-cycle-on"true,
            "lora.phy""AU915",
            "lora.device-eui""{ 0x00,0x2c,0x00,0xff,0x00,0x00,0x59,0x9e}",
            "lora.application-eui""{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99 }",
            "lora.application-key""{ 0x83, 0x12, 0x41, 0x00, 0xf1, 0x04, 0x00, 0x5f, 0x9c, 0xc3, 0x9f, 0x9c, 0x05, 0x66, 0x3f, 0x16 }",
            "lora.fsb-mask""{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}"
        },

        "NUCLEO_WL55JC": {
            "stm32wl-lora-driver.debug_rx""LED1",
            "stm32wl-lora-driver.debug_tx""LED2"
        },

        "MTB_MURATA_ABZ": {
            "main_stack_size":      1024,
            "target.components_add":            ["SX1276"],
            "sx1276-lora-driver.spi-mosi":       "PA_7",
            "sx1276-lora-driver.spi-miso":       "PA_6",
            "sx1276-lora-driver.spi-sclk":       "PA_5",
            "sx1276-lora-driver.spi-cs":         "PA_4",
            "sx1276-lora-driver.reset":          "PA_8",
            "sx1276-lora-driver.dio0":           "PA_12",
            "sx1276-lora-driver.dio1":           "PB_2",
            "sx1276-lora-driver.dio2":           "PB_5",
            "sx1276-lora-driver.dio3":           "PB_0",
            "sx1276-lora-driver.txctl":          "PC_2",
            "sx1276-lora-driver.rxctl":          "PA_15",
            "sx1276-lora-driver.pwr-amp-ctl":    "PC_1",
            "sx1276-lora-driver.tcxo":           "PB_1"
        }
    },
    "macros": ["MBEDTLS_USER_CONFIG_FILE=\"mbedtls_lora_config.h\""]
}


e ficando assim o main.cpp

/**
 * Copyright (c) 2017, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed 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 <stdio.h>

#include "lorawan/LoRaWANInterface.h"
#include "lorawan/system/lorawan_data_structures.h"
#include "events/EventQueue.h"

// Application helpers
#include "trace_helper.h"
#include "lora_radio_helper.h"
#include "mbed-os/platform/mbed-trace/include/mbed-trace/mbed_trace.h"

using namespace events;

// Max payload size can be LORAMAC_PHY_MAXPAYLOAD.
// This example only communicates with much shorter messages (<30 bytes).
// If longer messages are used, these buffers must be changed accordingly.
uint8_t tx_buffer[500];
uint8_t rx_buffer[500];

/*
 * Sets up an application dependent transmission timer in ms. Used only when Duty Cycling is off for testing
 */
#define TX_TIMER                        10000

/**
 * Maximum number of events for the event queue.
 * 10 is the safe number for the stack events, however, if application
 * also uses the queue for whatever purposes, this number should be increased.
 */
#define MAX_NUMBER_OF_EVENTS            10

/**
 * Maximum number of retries for CONFIRMED messages before giving up
 */
#define CONFIRMED_MSG_RETRY_COUNTER     3

/**
* This event queue is the global event queue for both the
* application and stack. To conserve memory, the stack is designed to run
* in the same thread as the application and the application is responsible for
* providing an event queue to the stack that will be used for ISR deferment as
* well as application information event queuing.
*/
static EventQueue ev_queue(MAX_NUMBER_OF_EVENTS *EVENTS_EVENT_SIZE);

/**
 * Event handler.
 *
 * This will be passed to the LoRaWAN stack to queue events for the
 * application which in turn drive the application.
 */
static void lora_event_handler(lorawan_event_t event);

/**
 * Constructing Mbed LoRaWANInterface and passing it the radio object from lora_radio_helper.
 */
static LoRaWANInterface lorawan(radio);

/**
 * Application specific callbacks
 */
static lorawan_app_callbacks_t callbacks;

//APB:
// static uint32_t DEV_ADDR = 0x;
// static uint8_t NWK_SKEY[] = {};
// static uint8_t APP_SKEY[] = {};
//OTAA: 
static uint8_t DEV_EUI[] = { 0x100x000x1f0xff0x000x530x000x9e };
static uint8_t APP_EUI[] = { 0x000x000x000x000x000x000x000x00 };
static uint8_t APP_KEY[] = { 0x330x110x410x110xf10x040x520x510x9d0xd30x9f0x9c0x050x660x3f0x16 };

/**
 * Entry point for application
 */
int main(void)
{
    // stores the status of a call to LoRaWAN protocol
    lorawan_status_t retcode;

    // Initialize LoRaWAN stack
    if (lorawan.initialize(&ev_queue) != LORAWAN_STATUS_OK) {
        printf("\r\n LoRa initialization failed! \r\n");
        return -1;
    }

    printf("\r\n Mbed LoRaWANStack initialized \r\n");

    // prepare application callbacks
    callbacks.events = mbed::callback(lora_event_handler);
    lorawan.add_app_callbacks(&callbacks);

    // Set number of retries in case of CONFIRMED messages
    if (lorawan.set_confirmed_msg_retries(CONFIRMED_MSG_RETRY_COUNTER)
            != LORAWAN_STATUS_OK) {
        printf("\r\n set_confirmed_msg_retries failed! \r\n\r\n");
        return -1;
    }

    printf("\r\n CONFIRMED message retries : %d \r\n",
           CONFIRMED_MSG_RETRY_COUNTER);

    // Enable adaptive data rate
    if (lorawan.disable_adaptive_datarate() != LORAWAN_STATUS_OK) {
        printf("\r\n disable_adaptive_datarate failed! \r\n");
        return -1;
    }

    printf("\r\n Adaptive data  rate (ADR) - Disabled \r\n");

    lorawan_connect_t connect_params;

        //OTAA:
    connect_params.connect_type = LORAWAN_CONNECTION_OTAA;
    connect_params.connection_u.otaa.dev_eui = DEV_EUI;
    connect_params.connection_u.otaa.app_eui = APP_EUI;
    connect_params.connection_u.otaa.app_key = APP_KEY;
    connect_params.connection_u.otaa.nb_trials = 3;

    //ABP:
    // connect_params.connect_type = LORAWAN_CONNECTION_ABP;
    // connect_params.connection_u.abp.dev_addr = DEV_ADDR;
    // connect_params.connection_u.abp.nwk_skey = NWK_SKEY;
    // connect_params.connection_u.abp.app_skey = APP_SKEY;

    retcode = lorawan.connect(connect_params);

    if (retcode == LORAWAN_STATUS_OK ||
            retcode == LORAWAN_STATUS_CONNECT_IN_PROGRESS) {
    } else {
        printf("\r\n Connection error, code = %d \r\n", retcode);
        return -1;
    }

    printf("\r\n Connection - In Progress ...\r\n");

    // make your event queue dispatching events forever
    ev_queue.dispatch_forever();

    return 0;
}

/**
 * Sends a message to the Network Server
 */
static void send_message()
{
    static uint8_t packet_toggle = 0;
    uint16_t packet_len;
    int16_t retcode;


    float temperature_bme = 0;
    float pressure_bme = 0;
    float humidity_bme = 0;
    float gas_res_bme = 0;
    float co2_eq_bme = 0;
    float breath_voc_eq_bme = 0;
    float iaq_score_bme = 0;
    uint8_t iaq_acc_bme = 0;
    uint32_t humidity_si = 0;
    uint32_t temp_si = 0;
    float x_accel = 0;
    float y_accel = 0;
    float z_accel = 0;
    float x_mag = 0;
    float y_mag  = 0;
    float z_mag = 0;
    float x_gyro = 0;
    float y_gyro = 0;
    float z_gyro = 0;
    uint32_t distance = 0;
    float vbat = 0;


    if(!packet_toggle)
    packet_len = sprintf((char *) tx_buffer, "{\"Data_Msg_0\":{\"temp_bme\":%3.3f,\"pres_bme\":%3.3f,\"hum_bme\":%3.3f,\"gas_res_bme\":%3.3f,\"co2_eq_bme\":%3.3f,\"breath_voc_eq_bme\":%3.3f,"
                                                "\"iaq_score_bme\":%3.3f,\"iaq_acc_bme\":%d}}",temperature_bme, pressure_bme, humidity_bme, gas_res_bme, co2_eq_bme, breath_voc_eq_bme, iaq_score_bme,
                                                iaq_acc_bme);
    if(packet_toggle)
    packet_len = sprintf((char *) tx_buffer, "{\"Data_Msg_1\":{\"hum_si\":%lu,\"temp_si\":%lu,\"x_accel\":%3.3f,\"y_accel\":%3.3f,"
                                                "\"z_accel\":%3.3f,\"x_mag\":%3.3f,\"y_mag\":%3.3f,\"z_mag\":%3.3f,\"x_gyro\":%3.3f,\"y_gyro\":%3.3f,\"z_gyro\":%3.3f,"
                                                "\"dist\":%lu,\"vbat\":%3.3f}}",humidity_si, temp_si, x_accel, y_accel, z_accel, 
                                                x_mag, y_mag, z_mag,x_gyro, y_gyro, z_gyro,distance, vbat);

    packet_toggle ^= 1;

    retcode = lorawan.send(MBED_CONF_LORA_APP_PORT, tx_buffer, packet_len,
                           MSG_UNCONFIRMED_FLAG);

    if (retcode < 0) {
        retcode == LORAWAN_STATUS_WOULD_BLOCK ? printf("send - WOULD BLOCK\r\n")
        : printf("\r\n send() - Error code %d \r\n", retcode);

        if (retcode == LORAWAN_STATUS_WOULD_BLOCK) {
            //retry in 3 seconds
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                ev_queue.call_in(3000, send_message);
            }
        }
        return;
    }

    printf("\r\n %d bytes scheduled for transmission \r\n", retcode);
    memset(tx_buffer, 0sizeof(tx_buffer));
}

/**
 * Receive a message from the Network Server
 */
static void receive_message()
{
    uint8_t port;
    int flags;
    int16_t retcode = lorawan.receive(rx_buffer, sizeof(rx_buffer), port, flags);

    if (retcode < 0) {
        printf("\r\n receive() - Error code %d \r\n", retcode);
        return;
    }

    printf(" RX Data on port %u (%d bytes): ", port, retcode);
    for (uint8_t i = 0; i < retcode; i++) {
        printf("%02x "rx_buffer[i]);
    }
    printf("\r\n");
    
    memset(rx_buffer, 0sizeof(rx_buffer));
}

/**
 * Event handler
 */
static void lora_event_handler(lorawan_event_t event)
{
    switch (event) {
        case CONNECTED:
            printf("\r\n Connection - Successful \r\n");
            lorawan.set_datarate(4);
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                send_message();
            } else {
                ev_queue.call_every(TX_TIMER, send_message);
            }

            break;
        case DISCONNECTED:
            ev_queue.break_dispatch();
            printf("\r\n Disconnected Successfully \r\n");
            break;
        case TX_DONE:
            printf("\r\n Message Sent to Network Server \r\n");
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                send_message();
            }
            break;
        case TX_TIMEOUT:
        case TX_ERROR:
        case TX_CRYPTO_ERROR:
        case TX_SCHEDULING_ERROR:
            printf("\r\n Transmission Error - EventCode = %d \r\n", event);
            // try again
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                send_message();
            }
            break;
        case RX_DONE:
            printf("\r\n Received message from Network Server \r\n");
            receive_message();
            break;
        case RX_TIMEOUT:
        case RX_ERROR:
            printf("\r\n Error in reception - Code = %d \r\n", event);
            break;
        case JOIN_FAILURE:
            printf("\r\n OTAA Failed - Check Keys \r\n");
            break;
        case UPLINK_REQUIRED:
            printf("\r\n Uplink required by NS \r\n");
            if (MBED_CONF_LORA_DUTY_CYCLE_ON) {
                send_message();
            }
            break;
        default:
            MBED_ASSERT("Unknown Event");
    }
}

// EOF


UART

PA2 e PA3

mbed_lib.json
C:\Users\Usuario\Mbed Programs\mbed-os-example-lorawan\mbed-os\connectivity\lorawan


Máscaras

Você pode configurar a pilha Mbed LoRaWAN para usar uma sub-banda de frequência específica (FSB), o que significa que você não precisa sondar todos os conjuntos de canais. "fsb-mask" em lorawan/mbed_lib.json é o parâmetro que você pode usar para dizer ao sistema qual FSB ou conjunto de FSBs usar. 

Por default, o "fsb-mask" é configurado para "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00FF}". 

Isso significa que todos os canais estão ativos. Em outras palavras, 64 canais de 125 kHz e 8 canais de 500 kHz estão ativos. Se você deseja usar um FSB personalizado, você precisa definir uma máscara apropriada como o valor de "fsb-mask". Por exemplo, se você deseja usar o primeiro FSB, ou seja, os primeiros canais de 8 125 kHz (0-7) e o primeiro canal de 500 kHz:

    "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0x0000, 0x0001}" 

Da mesma forma, se você deseja usar o segundo FSB, ou seja, o segundo conjunto de canais de 8 125 kHz (8-15) e o 2º canal de 500 kHz:

    "fsb-mask" = "{0xFF00, 0x0000, 0x0000, 0x0000, 0x0002}"

Você também pode combinar FSBs se sua estação base suportar mais de 8 canais. Por exemplo:
    "fsb-mask" = "{0x00FF, 0x0000, 0x0000, 0xFF00, 0x0081}"
 
significa usar canais 0-7 (125 kHz) + canal 64 (500 KHz) e canais 56-63 (125 kHz) + canal 71 (500 kHz), significa usar canais 0-7 (125 kHz) + canal 64 (500 KHz) e canais 56-63 (125 kHz) + canal 71 (500 kHz).
 
Build

Será gerado um BIN na pasta

C:\Users\Usuario\Mbed Programs\mbed-os-example-lorawan\BUILD\NUCLEO_WL55JC\ARMC6

chamado

mbed-os-example-lorawan.bin

Utilize STM32 PROGRAMMER para gravar


Resultados

O terminal serial mostra uma saída semelhante a:

Pela USB Serial do KIT - após "conexão" à rede, perde Baud Rate

Problemas com versão ONLINE do MBED (Keill Studio)


  • Remova o diretório mbed-os do seu projeto
  • Importe versão recente da biblioteca mbed-os (Add Mbed Library… →

    URL: https://github.com/ARMmbed/mbed-os → click Next >>)
  • Configure a versão para mais recente (mbed-os-6.16.0 → click Finish)
  • Aguarde finalizar

Agora, você pode definir NUCLEO_WJ55JC ou STM32WL55C-DK.

Questões: Fórum Mbed-OS


Fontes: 


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