sexta-feira, 21 de julho de 2023

LSM110A - Programando com VISUINO E ENVIANDO DADOS SEM TTN OU CHIRPSTACK

   

O objetivo deste BLOG é demonstrar como é possível utilizar o VISUINO para programação do WISOL LSM110A. Foi utilizado o Starter Kit LSM110A para o teste. O exemplo permitirá com linhas de comando o envio de texto via LoRA (ABP, AU915) a um servidor MQTT  da U_BLOX (ThingStream), via Gateway Dragino, ou seja, não necessário ter um servidor LoRaWAN TTN ou CHIRPSTACK, ou nem mesmo acesso à Internet.

Os parâmetros de acesso ao ABP são passados pela UART e gravados na FLASH

@0000000000000099 $0080E115051FD80A #FF9F138B40180AA45D6846E0A0146954 %OTA %ABP <=== &00000000 *00000000000000000000000000000000 +00000000000000000000000000000000


LSM110A Starter KIT
Módulo

O LSM110A é um módulo de última geração que integra o STMicroelectronics STM32WL. É muito menos consumo atual para o dispositivo IoT para estender a vida útil da bateria. E, também suporta ambas as tecnologias – Sigfox e LoRa – com o próprio módulo LSM110A.

Você pode trocar Sigfox ou LoRa com ele para que você também possa reduzir o custo. É altamente otimizado para solução de IoT (Alto Consumo de Energia, Baixo Custo)

BREAKOUT para testes


Esquema Elétrico - últimas correções





PLACA MONTADA



CONEXÃO COM ST-LINK V2 E UART



VISUINO

Visuino é o mais recente software inovador da Mitov Software. Um ambiente de programação visual que permite programar suas placas Arduino.
Os componentes encontrados no software Visuino representam seus componentes de hardware e você poderá facilmente criar e projetar seus programas arrastando e soltando. Nenhum equipamento ou hardware é necessário para executar o software no modo de design. Depois de concluir o projeto, você pode conectar o upload da placa Arduino e executá-lo.
Para aquelas pessoas que não são fortes em escrever código, projetar, compilar e criar programas Arduino nunca foi tão fácil! Por que perder tempo codificando quando todo o trabalho duro é feito para você? Você tem sua placa Arduino e um ótimo design de hardware, coloque-a em funcionamento em minutos, não em horas!

Ok, o ambiente de desenvolvimento está pronto. Abra Projeto Visuino abaixo

No CustomCode, Declarations

/** * This is a an example of the asynchronous API. This sketch is not * completely asynchronous (see ScheduledAsync.ino for that) and its * flow still follows the LoRa flow, but this sketch shows how some * background work can be done while waiting for the LoRa library to * complete its work. * * Revised BSD License - https://spdx.org/licenses/BSD-3-Clause.html */ //transmit interval unsigned long last_tx = 0; //LoRa LOG char buffer[256]; HardwareSerial Serial1(PB6, PB7); STM32LoRaWAN modem; //Payload Mount uint8_t payload_size; char payload[1024]; String setAppEuiString; String setAppKeyString; String setDevEuiString; String OTA_ABP; String setDevAddrString; String setNwkSKeyString; String setAppSKeyString; /********************************************************************* * This part of the sketch defines a very simple scheduler and defines * two tasks that handle the actual work. *********************************************************************/ struct Task { unsigned long time; /* When to run, 0 == never */ void (*callback)(); }; enum Tasks { LORA_WORK_TASK, LORA_MAINTAIN_TASK, NUM_TASKS, }; void do_lora_maintain(); void do_lora_work(); void maintain_needed_callback(); Task tasks[NUM_TASKS] = { [LORA_WORK_TASK] = {0, do_lora_work}, [LORA_MAINTAIN_TASK] = {0, do_lora_maintain}, }; void run_scheduler() { // Super-simple scheduler that just checks all tasks and runs // any that are due. for (size_t i = 0; i < NUM_TASKS; ++i) { if (tasks[i].time != 0 && (int)(millis() - tasks[i].time) >= 0) { tasks[i].time = 0; tasks[i].callback(); } } } /********************************************************************* * This part of the sketch defines the lora work task, which iniates new * work and the lora_done() function that processes the results. *********************************************************************/ static const unsigned long TX_INTERVAL = 30000; /* ms */ static const unsigned long RETRY_JOIN_INTERVAL = 5000; /* ms */ enum LoraState { IDLE, JOINING, TRANSMITTING, }; LoraState lora_state; void start_join() { setAppEuiString = readStringEEPROM(0); setAppKeyString = readStringEEPROM(17); setDevEuiString = readStringEEPROM(50); OTA_ABP = readStringEEPROM(67); setDevAddrString = readStringEEPROM(71); setNwkSKeyString = readStringEEPROM(80); setAppSKeyString = readStringEEPROM(113); //Serial.println(setAppEuiString); //Serial.println(setAppKeyString); //Serial.println(setDevEuiString); //Serial.println(OTA_ABP); //Serial.println(setDevAddrString); //Serial.println(setNwkSKeyString); //Serial.println(setAppSKeyString); //found bug on STM32LoRaWAN.h (reported) //bool setAppEui(String value) { return setDevEui(value.c_str()); } //bool setAppEui(String value) { return setAppEui(value.c_str()); } //MIGUEL //@0000000000000099 //$0080E115051FD80A //#FF9F138B40180AA45D6846E0A0146954 //%OTA //%ABP //&00000000 //*00000000000000000000000000000000 //+00000000000000000000000000000000 if(OTA_ABP=="OTA") { modem.setAppEui(setAppEuiString); //@ modem.setAppKey(setAppKeyString); //# modem.setDevEui(setDevEuiString); //$ modem.joinOTAAAsync(); lora_state = JOINING; } if(OTA_ABP=="ABP") { //bool connected = modem.joinABP(/* DevAddr */ setDevAddrString, /* NwkSKey */ setNwkSKeyString, /* AppSKey */ setAppSKeyString); bool connected = modem.joinABP(/* DevAddr */ setDevAddrString, /* NwkSKey */ setNwkSKeyString, /* AppSKey */ setAppSKeyString); if (connected) { StatusLoRa("Joined"); //Serial.println("Joined"); } else StatusLoRa("Join failed"); //Serial.println("Join failed"); //while (true) /* infinite loop */; } //modem.setDevAddr("00000000"); //& //modem.setNwkSKey("00000000000000000000000000000000"); //* //modem.setAppSKey("00000000000000000000000000000000"); //+ //modem.joinABPAsync(); } void send_packet() { String s = String(payload); payload_size = s.length(); modem.setPort(10); modem.beginPacket(); modem.write(payload, payload_size); if(OTA_ABP=="OTA") { if (modem.endPacketAsync() == payload_size) { StatusLoRa("Queued packet"); //Serial.println("Queued packet"); } else { StatusLoRa("Failed to queue packet"); //Serial.println("Failed to queue packet"); } lora_state = TRANSMITTING; } if(OTA_ABP=="ABP") { if (modem.endPacket() == payload_size) { StatusLoRa("Queued packet"); //Serial.println("Queued packet"); } else { //Serial.println("Failed to queue packet"); StatusLoRa("Failed to queue packet"); } lora_state = TRANSMITTING; } } void process_rx() { if (modem.available()) { sprintf(buffer,"Received packet on port %d:",modem.getDownlinkPort()); StatusLoRa(buffer); //Serial.print("Received packet on port "); //Serial.print(modem.getDownlinkPort()); //Serial.print(":"); while (modem.available()) { uint8_t b = modem.read(); sprintf(buffer," %x%x",b >> 4,b & 0xF); StatusLoRa(buffer); //Serial.print(" "); //Serial.print(b >> 4, HEX); //Serial.print(b & 0xF, HEX); } sprintf(buffer,"%c%c",13,10); StatusLoRa(buffer); //Serial.println(); } } void do_lora_work() { // Time to start new work if (!modem.connected()) { start_join(); } else { send_packet(); } } void lora_done() { // If, after calling maintain() the library is no longer // busy, then the asynchronous operation has completed, // so check its results. if (lora_state == TRANSMITTING) { StatusLoRa("Sent packet"); //Serial.println("Sent packet"); // Done transmitting process_rx(); lora_state = IDLE; // Schedule transmission of next packet tasks[LORA_WORK_TASK].time = millis() + TX_INTERVAL; } else if (lora_state == JOINING) { if (modem.connected()) { StatusLoRa("Joined"); //Serial.println("Joined"); send_packet(); } else { StatusLoRa("Join failed"); //Serial.println("Join failed"); lora_state = IDLE; tasks[LORA_WORK_TASK].time = millis() + RETRY_JOIN_INTERVAL; } } } /********************************************************************* * This part of the sketch defines the lora maintain task, which calls * maintain() to let the lora library do any background work that it * needs to do. It is called whenever request by the callback. *********************************************************************/ void do_lora_maintain() { modem.maintain(); // If, after calling maintain() the library is no longer // busy, then the asynchronous operation has completed, // so check its results. if (!modem.busy()) { lora_done(); } } void maintain_needed_callback() { // This is called from interrupt context, so this must *not* // call maintain() directly and return as fast as possible. // So just schedule the maintain task to run ASAP. tasks[LORA_MAINTAIN_TASK].time = millis(); } /********************************************************************* * And this is the entry points of the sketch. *********************************************************************/
No CustomCode, OnInit

StatusLoRa("Starting"); //Serial.println("Starting"); modem.begin(AU915); modem.powerdB(22); modem.dataRate(10); //spread OTA_ABP = readStringEEPROM(67); if(OTA_ABP=="OTA") modem.setMaintainNeededCallback(maintain_needed_callback); do_lora_work();

No CustomCode, OnExecute

if(OTA_ABP=="OTA") { run_scheduler(); } if(OTA_ABP=="ABP") { if (!last_tx || millis() - last_tx > TX_INTERVAL) { do_lora_work(); //send_packet(); last_tx = millis(); } }

No CustomCode, Global Implementations

//https://roboticsbackend.com/arduino-write-string-in-eeprom/ //FIRST BYTE IS THE LENGHT String readStringEEPROM(int addrOffset) { int newStrLen = EEPROM.read(addrOffset); char data[newStrLen + 1]; for (int i = 0; i < newStrLen; i++) { data[i] = EEPROM.read(addrOffset + 1 + i); } data[newStrLen] = 0; //NULL return String(data); } void StatusLoRa(String Txt) { Declarations::Instances::LoRaWAN.LoRaWANStatus.Send(Txt); }














No CustomCode, Includes

#include <STM32LoRaWAN.h>

Compilando



Utilize STM32 PROGRAMMER para gravar


No Gateway da Dragino, cadastre os parâmetros ABP



Rede Privada - Direcione para um servidor MQTT

Neste caso, foi utilizado da U-BLOX





No terminal, você mandar as credenciais


%ABP &00000000 *00000000000000000000000000000000 +00000000000000000000000000000000

Pacote a ser enviado

Qualquer texto não comece com @#$%, é identificado como no novo pacote a ser enviado

Executando


Log - System Log (Dragino)


Wed Nov 30 11:11:59 2022 daemon.info lora_pkt_fwd[307]: PKT_FWD~ DATA_CONF_UP-> {"DevAddr": "00000000", "FCtrl": ["ADR": 0, "ADRACKReq": 0, "ACK": 0, "RFU" : "RFU", "FOptsLen": 0], "FCnt": 0, "FPort": 2, "MIC": "B1F93D67"}
Wed Nov 30 11:11:59 2022 daemon.info lora_pkt_fwd[307]: RXTX~ {"rxpk":[{"tmst":248124740,"time":"2022-11-30T14:11:59.008966Z","chan":1,"rfch":0,"freq":917.000000,"stat":1,"modu":"LORA","datr":"SF12BW125","codr":"4/5","lsnr":10.5,"rssi":-90,"size":18,"data":"gAAAAAAAAAACvR2eYW9nPfmx"}]}

Dados no THINGSTREAM



ffffffd70000007348656c6c6f00 




Para ver os dados, acompanhe o vídeo a partir do tempo 07:19


MONTAGEM



DÚVIDAS

suporte@smartcore.com.br

REFERÊNCIAS


ATENÇÃO: RTC BACKUP (generic_clock.c)
C:\Users\Usuario\AppData\Local\arduino15\packages\STMicroelectronics\hardware\stm32\2.6.0\variants\STM32WLxx\WL54JCI_WL55JCI_WLE4J(8-B-C)I_WLE5J(8-B-C)I

void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK |RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1 |RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } }








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