Introdução
Neste artigo vamos mostrar como fizemos para conectar um microcontrolador da linha Synergy S7 da Renesas, utilizando um kit de desenvolvimento SK-S7G2 de fácil acesso, a uma plataforma de nuvem IoT da Tago.io. Enviamos dados referentes à leitura de um conversor A/D e, para simulação de um sensor, utilizamos o potenciômetro para que, quando fosse alterado o seu valor na placa, poderíamos verificar uma mudança na plataforma. A placa vai receber, também, um comando da plataforma da nuvem para controlar um LED. Ao longo deste texto você vai percorrer o caminho que fizemos para configurar o ambiente e2Studio, verificar como foi feito o firmware e a configuração da nuvem para conexão do dispositivo IoT e recebimento das mensagens da conversão A/D feita na placa.
Sobre a placa utilizada
Para essa experiência utilizamos a placa SK-S7G2 com uma placa externa que permite conexão sem fio Wi-Fi, conectada à placa principal via conector de expansão PMOD. A placa conta com um microcontrolador S7G2, baseado no core ARM Cortex-M4, com ponto flutuante e instruções de DSP, com 4 MB de flash interna, memória SRAM de 640 KB, frequência de operação de até 240 MHz e encapsulamento LQFP de 176 pinos. Para mais informações sobre a placa acesse este link e confira o artigo detalhado sobre seus periféricos, sensores, atuadores e dispositivos presentes na placa.
Para conferir como fazer um blink LED utilizando o kit de desenvolvimento, confira o artigo publicado neste link.
Para essa experiência utilizamos o e2studio, instalado via Platform Installer versão 6.2.0.R20180102, e então foi instalado o SSP 1.4.0 e todas as versões de compilador GCC necessárias pra rodar essa aplicação.
Sobre o Firmware
O firmware, que foi feito para os microcontroladores da linha S7 da Renesas, realiza uma conexão Wi-Fi, utilizando DHCP para solicitar um endereço de IP à rede, descobre o servidor DNS e depois disso sinaliza as outras threads que elas estão prontas para serem executadas. Após a conexão, o LED verde fica piscando. Isso é feito no arquivo network_thread_entry.c.
Toda documentação utilizada para escrever esse código foi retirada do SSP User’s Manual. Estamos atualmente na versão 1.4.0 do Synergy Software Package e o documento referente a essa versão pode ser baixado aqui. Utilizamos o cliente DNS e a funcionalidade DHCP nessa aplicação. Então precisamos de documentação adicional, conforme podemos verificar na página 1214 do manual.
Para informações sobre como configurar o cliente DHCP, então, foi utilizado o manual NetX™ DHCP Client Module Guide, que pode ser acessado neste link. Para o cliente DNS, utilizamos o documento NetX™ and NetX Duo™ DNS Client Module Guide deste link.
Para conectar a placa ao Wi-Fi foi criada uma thread para DNS no projeto do Renesas Synergy, configurado conforme o manual DNS Client Module Guide, página 18, e criado um arquivo chamado network_thread_entry.c.
Neste arquivo, depois das declarações iniciais, foi invocada a função nx_ip_interface_status_check, que aguarda até que o link de rede esteja disponível.
Em seguida é chamada a função g_sf_wifi0.p_api->provisioningSet para setar o dispositivo como cliente e informar o SSID e senha da rede Wi-Fi.
Depois é chamada a função nx_dhcp_start, que faz com que o DHCP seja iniciado e o dispositivo possa receber um IP do servidor.
Em seguida, é verificado o status que diz respeito a se o servidor já atribuiu um IP, utilizando a função nx_ip_status_check.
Para verificar o IP e a máscara, foi utilizada a função nx_ip_address_get.
O servidor DNS e o servidor NTP atribuído pela rede pode ser consultado utilizando a função nx_dhcp_user_option_retrieve.
Para adicionar o servidor DNS à lista de clientes e, enfim, poder conectar e trafegar na rede, é utilizada a função nx_dns_server_add.
E assim a thread sinaliza (SYSTEM_EVENT_FLAGS_NETWORK_IS_UP) que o equipamento eletrônico está conectado à rede Wi-Fi e pode começar a monitorar os parâmetros. As outras threads que deveriam ler e enviar as mensagens apenas deveriam ter iniciado seus parâmetros e aguardar essa flag para início das atividades.
#include <stdio.h>
#include "network_thread.h"
#include "utility.h"
sf_wifi_provisioning_t prov =
{
.encryption = SF_WIFI_ENCRYPTION_TYPE_AUTO,
.mode = SF_WIFI_INTERFACE_MODE_CLIENT,
.security = SF_WIFI_SECURITY_TYPE_WPA2
};
/* Network Thread entry function */
void network_thread_entry(void)
{
ssp_err_t err;
char ip_addr_str[40];
UINT status;
ULONG actual_status;
ULONG ip_address;
ULONG ip_mask;
ULONG dns_ip[2];
ULONG dns_ip_size;
/* Turn off all LEDs */
g_ioport.p_api->pinWrite(GREEN, LED_OFF);
g_ioport.p_api->pinWrite(YELLOW, LED_OFF);
g_ioport.p_api->pinWrite(RED, LED_OFF);
/* Start network initializations, turn on yellow LED */
g_ioport.p_api->pinWrite(GREEN, LED_ON);
/* Wait until network link is up */
status = nx_ip_interface_status_check(&g_ip0, 0, NX_IP_LINK_ENABLED, &actual_status, NX_WAIT_FOREVER);
APP_ASSERT(status);
/* Set SSID and password and provision Wi-Fi */
strcpy((char *)&prov.ssid[0],"BAITA_ACELERADORA");
strcpy((char *)&prov.key[0], "agrosmart");
err = g_sf_wifi0.p_api->provisioningSet(g_sf_wifi0.p_ctrl, &prov);
APP_ASSERT(err);
/* Start DHCP client */
status = nx_dhcp_start(&g_dhcp_client0);
APP_ASSERT(status);
/* Wait until IP address is assigned by the DHCP server */
status = nx_ip_status_check(&g_ip0, NX_IP_ADDRESS_RESOLVED, &actual_status, TX_WAIT_FOREVER);
APP_ASSERT(status);
/* Retrieve IP address and mask */
status = nx_ip_address_get(&g_ip0, &ip_address, &ip_mask );
APP_ASSERT(status);
/* Print IP address to ip_addr_str */
sprintf(ip_addr_str, "IP ADDRESS: %d.%d.%d.%d \n\r", (int)((ip_address >> 24)),
(int)((ip_address >> 16) & 0x000000FFUL),
(int)((ip_address >> 8) & 0x000000FFUL),
(int)((ip_address) & 0x000000FFUL));
dns_ip_size = sizeof(dns_ip);
status = nx_dhcp_user_option_retrieve(&g_dhcp_client0, NX_DHCP_OPTION_DNS_SVR, (UCHAR *)dns_ip, (UINT *)&dns_ip_size);
APP_ASSERT(status);
status = nx_dns_server_add(&g_dns0, dns_ip[0]);
APP_ASSERT(status);
/* Indicate network initialization complete */
status = tx_event_flags_set(&g_system_event_flags, SYSTEM_EVENT_FLAGS_NETWORK_IS_UP, TX_OR);
APP_ASSERT(status);
while (1)
{
/* Blink green LED */
g_ioport.p_api->pinWrite(GREEN, LED_OFF);
tx_thread_sleep(25);
g_ioport.p_api->pinWrite(GREEN, LED_ON);
tx_thread_sleep(25);
}
}
Foi conectado um potenciômetro ao canal zero do ADC. No firmware, é iniciado o canal de conversor analógico digital com as funções g_adc0.p_api->open, g_adc0.p_api->scanCfg e g_adc0.p_api->scanStart e então deve-se aguardar até que a rede Wi-Fi esteja online, iniciada na outra thread.
É iniciado, então, o cliente mqtt, setado o endereço de IP do servidor, além de credenciais para acesso à plataforma Tago.io e feita a autenticação no servidor. Para isso foram utilizadas as funções mqtt_client_init0, nx_dns_host_by_name_get, mqtt_server_ip_address, nxd_mqtt_client_login_set, nxd_mqtt_client_connect, nxd_mqtt_client_receive_notify_set e nxd_mqtt_client_subscribe.
E então inicia-se um loop infinito onde é lido o valor do conversor A/D e, após formatado, enviado para a tago.io via mqtt.
Para publicar uma mensagem deve-se formatar a string da seguinte forma:
{
"variable":"ADC_Value",
"value": (int)ADC_value,
"unit": " "
}
E invocar a função nxd_mqtt_client_publish:
sprintf(message,"{\r\n\"variable\":\"ADC_Value\",\r\n\"value\":%d,\r\n \"unit\": \"n\"\r\n}", (int)ADC_value);
status=nxd_mqtt_client_publish(&g_mqtt_client0, topic_ADC, strlen(topic_ADC),
message, strlen(message), NX_TRUE, 0, NX_WAIT_FOREVER);
Confira o código completo a seguir.
#include <stdio.h>
#include <string.h>
#include "mqtt_thread.h"
#include "network_thread.h"
#include "utility.h"
/* Remove comment below to enable TLS configuration */
//#define USE_TLS
uint32_t tago_server_ip_address;
uint8_t tago_addr_str[40];
void receive_notify(NXD_MQTT_CLIENT *client_ptr, UINT message_count);
/* Topics to subscribe */
CHAR *topic_led = "led_s7";
/* Topic to publish */
CHAR *topic_ADC = "tago/data/post";
/* MQTT Thread entry function */
void mqtt_thread_entry(void)
{
UINT status;
ULONG actual_flags;
NXD_ADDRESS mqtt_server_ip_address;
CHAR tago_user_name[20];
CHAR tago_password[64];
uint16_t ADC_value;
CHAR message[128];
status = g_adc0.p_api->open(g_adc0.p_ctrl,g_adc0.p_cfg);
APP_ASSERT(status);
status = g_adc0.p_api->scanCfg(g_adc0.p_ctrl, g_adc0.p_channel_cfg);
APP_ASSERT(status);
status = g_adc0.p_api->scanStart(g_adc0.p_ctrl);
APP_ASSERT(status);
/* Wait until the network initialization complete */
status = tx_event_flags_get(&g_system_event_flags, SYSTEM_EVENT_FLAGS_NETWORK_IS_UP,
TX_AND_CLEAR, &actual_flags, TX_WAIT_FOREVER);
APP_ASSERT(status);
/* Start MQTT initializations, turn on yellow LED */
g_ioport.p_api->pinWrite(YELLOW, LED_ON);
/* Auto initialization is disabled to allow MQTT Client ID can be set in set_mqtt_cliend_id_cb */
mqtt_client_init0();
status = nx_dns_host_by_name_get(&g_dns0, (UCHAR *)"mqtt.tago.io", &tago_server_ip_address, TX_WAIT_FOREVER);
APP_ASSERT(status);
mqtt_server_ip_address.nxd_ip_address.v4 = (ULONG) tago_server_ip_address;
mqtt_server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
strcpy(tago_user_name, "S7G2");
strcpy(tago_password, "814eafa8-a79b-48d4-85b7-5bf60b012b38");
status = nxd_mqtt_client_login_set(&g_mqtt_client0,
tago_user_name,
strlen(tago_user_name),
tago_password,
strlen(tago_password));
APP_ASSERT(status);
/* Connect to MQTT server */
status = nxd_mqtt_client_connect(&g_mqtt_client0, /// MQTT client
&mqtt_server_ip_address, /// MQTT server IP address
NXD_MQTT_PORT, /// MQTT unsecured port number (1883)
0, /// Disable keep-alive
NX_TRUE, /// Enable clean-start
NX_WAIT_FOREVER); /// Connection wait time
APP_ASSERT(status);
/* Set MQTT message receive callback function */
status = nxd_mqtt_client_receive_notify_set(&g_mqtt_client0, receive_notify);
APP_ASSERT(status);
/* Subscribe to LED topic */
status = nxd_mqtt_client_subscribe(&g_mqtt_client0, topic_led, strlen(topic_led), 0);
APP_ASSERT(status);
while(1)
{
/* Blink yellow LED */
g_ioport.p_api->pinWrite(YELLOW, LED_OFF);
tx_thread_sleep(50);
status = g_adc0.p_api->read(g_adc0.p_ctrl, ADC_REG_CHANNEL_0, &ADC_value);
APP_ASSERT(status);
status = g_adc0.p_api->scanStart(g_adc0.p_ctrl);
APP_ASSERT(status);
/* Publish ADC topic */
sprintf(message, "{\r\n \"variable\": \"ADC_Value\",\r\n \"value\": %d,\r\n \"unit\": \"n\"\r\n}", (int)ADC_value);
status = nxd_mqtt_client_publish(&g_mqtt_client0, topic_ADC, strlen(topic_ADC),
message, strlen(message), NX_TRUE, 0, NX_WAIT_FOREVER);
APP_ASSERT(status);
/* Blink yellow LED */
g_ioport.p_api->pinWrite(YELLOW, LED_ON);
tx_thread_sleep(50);
}
}
void set_mqtt_client_id_cb(char *client_id, uint32_t *client_id_length)
{
/*
* Read unique ID and use it to create a unique client ID.
* Client ID is required by the MQTT server to uniquely identify the clients.
*/
fmi_unique_id_t uid;
g_fmi.p_api->uniqueIdGet(&uid);
sprintf(client_id, "Synergy-%0X", (unsigned int)(uid.unique_id[0] & (0x0000FFFF)));
*client_id_length = strlen(client_id);
}
void receive_notify(NXD_MQTT_CLIENT *client_ptr, UINT message_count)
{
/*
* Process MQTT message(s) received.
* This function runs on internal MQTT client thread and not in an interrupt.
* Therefore, it is OK to process received messages here. However, they should
* be processed in a separate application thread if many messages can be
* potentially received.
*/
UINT status;
UCHAR topic[NXD_MQTT_MAX_TOPIC_NAME_LENGTH]; // Topic length is configured by the module configurator
UCHAR message[NXD_MQTT_MAX_MESSAGE_LENGTH]; // Message length is configured by the module configurator
UINT actual_topic_length;
UINT actual_message_length;
while (message_count)
{
status = nxd_mqtt_client_message_get(client_ptr,
topic, sizeof(topic), &actual_topic_length,
message, sizeof(message), &actual_message_length);
if(NXD_MQTT_SUCCESS == status)
{
if(0 == strncmp((char*)topic, topic_led, actual_topic_length))
{
if('0' == message[0])
{
/* Turn off red LED */
g_ioport.p_api->pinWrite(RED, LED_OFF);
}
else if('1' == message[0])
{
/* Turn on red LED */
g_ioport.p_api->pinWrite(RED, LED_ON);
}
}
message_count--;
}
else if(NXD_MQTT_NO_MESSAGE == status)
{
/* No more message, exit the loop */
break;
}
APP_ASSERT(status);
}
return;
}
Conectando à plataforma Tago.io
Criando um device
Para criar um novo device, primeiro fazer o login na sua conta na Tago.io. Após o login, escolha a opção device -> novo device, conforme exibido na imagem a seguir:
Configure o seu novo device. Você pode inserir as mesmas informações abaixo para reproduzir o nosso exemplo:
Salve o device e em seguida clique na aba Tokens. Copie o Token do device para a área de transferência:
Esse token deve ser inserido no código para que a tago.io receba as informações da placa. Cole o token no arquivo: mqtt_thread_entry.c, no seguinte trecho de código:
strcpy(tago_user_name, "S7G2"); strcpy(tago_password, "XXXXXXX-XXXX-XXX-XXX-XXXXXXXXX");
Pronto, você pode compilar o código e gravá-lo na sua placa. Colocando para funcionar, os dados já serão enviados para a Tago.io.
Criando um Bucket
Para o armazenamento dos dados recebidos do dispositivo é necessário criar um Bucket. É recomendada a criação de um Bucket para cada um dos dispositivos para facilitar a localização e o controle dos dados. No entanto, um bucket pode estar vinculado a mais de um dispositivo.
Para criar um Bucket, acesse a opção Bucket-> Add Bucket:
Configure o novo Bucket da seguinte forma:
Após salvar, se a placa já tiver enviando as informações, você verá as variáveis:
Criando um Dashboard
Um Dashboard é onde colocamos os widgets para visualizar e interagir com os dados, tudo em tempo real.
Para adicionar um novo Dashboard, clique na opção Dashboards no menu Lateral e em seguida em Add Dashboard:
Dê um nome para o seu dashboard e em seguida salve.
Agora vamos inserir widgets para a visualização de dados. Para adicionar um widget é só clicar na opção add widget, no canto superior direito. Então será aberta uma janela com as opções de widgets disponíveis:
Como exemplo, vamos adicionar um Chart para a visualização dos valores do ADC em função do tempo. Escolha a opção Chart, e em seguida configure-o da seguinte forma:
Também vamos aproveitar e visualizar a mesma informação do ADC através de um gauge. Adicione um widget do tipo gauge e configure-o da seguinte forma:
Pronto, você já deverá ver as informações em tempo real no dashboard. Varie o potenciômetro na placa e veja se os valores são atualizados.
Criando Actions
Para enviar o comando para acionamento do LED na placa é necessário criar Actions. As Actions são recursos muito poderosos que lhe dão controle total sobre seus dispositivos com base em eventos determinados por você.
Para comandar o LED presente na placa, vamos incluir um input. Para adicionar uma Action. Selecione a opção Action no menu lateral e em seguida, Add Action:
Vamos configurar a primeira Action para apagar o LED:
E em seguida outra Action para ligar o LED:
Com as Actions criadas e configuradas, devemos voltar para o dashboard e incluir um widget de input:
Configure o widget da seguinte forma:
Finalizada a configuração, envie o comando para acender e apagar o LED2 na placa e verifique se a placa recebe o comando.
Ao final você terá um dashboard para visualização dos dados e envio de comandos para a placa:
Você pode adicionar mais widgets e compartilhar o seu dashboard com outras pessoas.
Tenho dúvidas com os microcontroladores Renesas, como faço?
O ponto principal para tirar dúvidas de hardware e firmware dos microcontroladores Renesas é o site renesasrulz.com, um fórum público que tem acompanhamento de perto dos engenheiros de aplicação da Renesas, espalhados pelo mundo.
Assista o webinar Gravado: Plataforma Renesas Synergy – Construindo sua aplicação MQTT com analytics na Tago.io
Neste webinar você irá aprender a construir uma aplicação MQTT com analytics na Tago.io utilizando a Plataforma Renesas Synergy. Clique na imagem para acessar o webinar:
Para receber o projeto completo utilizado nesse artigo, preencha esse formulario e entraremos em contato com você.
* Este post foi patrocinado pela Renesas Electronics Brasil
































Ótimo material! Lembrando que a plataforma TagoIO tem a opção de língua Portuguesa quando em modo Usuário normal (nao desenvolvedor). Mesma coisa para o aplicativo de celular que já está disponivel em Portugues.