Indústrias William DOCSiW - ESPMI Exemplos LoRaNeste exemplo iremos explorar as capacidades do rádio LoRa encontrado na placa iW-ESPMI.
Implementação do PORT para ESP32
Primeiramente, precisamos implementar a função que faz a transmissão dos pacotes através do barramento SPI e outras funções de controle. Como podemos usar o módulo LoRa para vários tipos de microcontroladores, temos que implementar as funções especificamente para o ESP32.
Para este exemplo, iremos utilizar uma placa iW - SensorBox LoRa para enviar dados dos sensores de temperatura, umidade e dados do acelerômetro via LoRa .
Materiais necessários para o Teste
Fonte de alimentação 5V 2A;
Placa auxiliar com outro módulo LoRa
Adaptador USB host tipo C para Tipo A;
Ferramentas
ESP-IDF Framework ^= 4.4;
VSCode ou Espressif Ecplise IDE;
Ubuntu ou Windows 10, 11.
Copy // Estas funções são encontradas no arquivo ebyte_port.h
```c
#ifndef EBYTE_PORT_H_
#define EBYTE_PORT_H_
#include "stdint.h"
#include "ebyte_conf.h"
#define __weak __attribute__((weak))
void Ebyte_Port_RstIoControl( uint8_t cmd );
void Ebyte_Port_TxenIoControl( uint8_t cmd );
void Ebyte_Port_RxenIoControl( uint8_t cmd );
void Ebyte_Port_DelayMs( uint32_t time );
void Ebyte_Port_SpiCsIoControl( uint8_t cmd );
uint8_t Ebyte_Port_BusyIoRead( void );
uint8_t Ebyte_Port_SpiTransmitAndReceivce( uint8_t send );
uint8_t Ebyte_BSP_SpiTransAndRecv(uint8_t data);
void Ebyte_BSP_RfSpiUnselected( void );
void Ebyte_BSP_RfSpiSelected( void );
void Ebyte_BSP_RfResetIoHigh( void );
void Ebyte_BSP_RfResetIoLow( void );
void Ebyte_BSP_RfTxIoEnable( void );
void Ebyte_BSP_RfTxIoDisable( void );
void Ebyte_BSP_RfRxIoEnable( void );
void Ebyte_BSP_RfRxIoDisable( void );
uint8_t Ebyte_BSP_RfBusyIoRead( void );
void Ebyte_Port_DelayMs( uint32_t time );
#endif
```
Estas assinaturas de funções são marcadas como weak, e sendo assim, podem ser reimplementadas.
Implementação da função que faz a transmissão do pacote para o módulo LoRa:
Copy // Some code
```c
uint8_t Ebyte_BSP_SpiTransAndRecv(uint8_t data){
spi_transaction_t spiTrans;
const char* TAG = "E220 SPI transmitter";
memset(&spiTrans, 0, sizeof(spi_transaction_t));
spiTrans.length = 8;
spiTrans.tx_data[0] = data;
spiTrans.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
if(spi_device_polling_transmit(ESPMI_GetSPIHandle(), &spiTrans) != ESP_OK){
ESP_LOGE(TAG, "SPI transmission failed");
}
return spiTrans.rx_data[0];
}
```
Copy // Some code
```c
void Ebyte_BSP_RfSpiUnselected( void ){
gpio_set_level(ESPMI_E220_900MM22S_NSS, 1);
}
void Ebyte_BSP_RfSpiSelected( void ){
gpio_set_level(ESPMI_E220_900MM22S_NSS, 0);
}
void Ebyte_BSP_RfResetIoHigh( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RST, True);
}
void Ebyte_BSP_RfResetIoLow( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RST, False);
}
void Ebyte_BSP_RfTxIoEnable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_TXEN, True);
}
void Ebyte_BSP_RfTxIoDisable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_TXEN, False);
}
void Ebyte_BSP_RfRxIoEnable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RXEN, True);
}
void Ebyte_BSP_RfRxIoDisable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RXEN, False);
}
uint8_t Ebyte_BSP_RfBusyIoRead( void ){
Boolean state = False;
ESPMI_MCP23008_ReadLevelPin(ESPMI_E220_900MM22S_BUSY, &state);
return (uint8_t)state;
}
```
Por fim, precisamos implementar a função de callback responsável pela recepção dos pacotes.
Copy // Some code
```c
float lis3dh_from_fs16_hr_to_mg(int16_t lsb){
return ((float)lsb / 16.0f) * 12.0f;
}
void Ebyte_Port_TransmitCallback( uint16_t state ){
}
void Ebyte_Port_ReceiveCallback( uint16_t state, uint8_t *buffer, uint8_t length){
if(state == 0x0002){
sensors = (SensorBox_TypeDef*)buffer;
temperature = -45.0f + 175.0f * (float)sensors->temperature/65535.0f;
humidity = 100 * ((float)sensors->humidity/65535.0f);
accX = lis3dh_from_fs16_hr_to_mg(sensors->accX)/100.0f;
accY = lis3dh_from_fs16_hr_to_mg(sensors->accY)/100.0f;
accZ = lis3dh_from_fs16_hr_to_mg(sensors->accZ)/100.0f;
packetsReceived++;
rx_done = 1;
printf("%.1f, %.1f, %.1f, %.1f, %.1f\r\n", temperature, humidity, accX, accY, accZ);
}
}
```
O inteiro "state" é responsável por sinalizar o estado da recepção do pacote.
Copy // Some code
```c
/* !
* @brief Ebyte_Port_ReceiveCallback
*
* @param state
*
* @note E220-900MM22S
* IRQ_TX_DONE = 0x0001,
* IRQ_RX_DONE = 0x0002,
* IRQ_PREAMBLE_DETECTED = 0x0004,
* IRQ_SYNCWORD_VALID = 0x0008,
* IRQ_HEADER_VALID = 0x0010,
* IRQ_HEADER_ERROR = 0x0020,
* IRQ_CRC_ERROR = 0x0040,
* IRQ_CAD_DONE = 0x0080,
* IRQ_CAD_ACTIVITY_DETECTED = 0x0100,
* IRQ_RX_TX_TIMEOUT = 0x0200,
*/
```
Código completo
Copy // Some code
```c
#include <stdio.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <freertos/queue.h>
#include <esp_lcd_types.h>
#include <driver/gpio.h>
#include <esp_err.h>
#include <esp_log.h>
#include "ESPMI.h"
#include <usb/hid_host.h>
#include <usb/usb_host.h>
#include "HDMI.h"
#include "lvgl.h"
#include "ebyte_core.h"
#include "ebyte_port.h"
#include "ebyte_callback.h"
static const char TAG [] = "Main";
typedef struct {
uint16_t temperature;
uint16_t humidity;
int16_t accX;
int16_t accY;
int16_t accZ;
}SensorBox_TypeDef;
SensorBox_TypeDef* sensors;
uint32_t packetsReceived = 0;
volatile static float temperature;
volatile static float humidity;
static float accX;
static float accY;
static float accZ;
extern int8_t Ebyte_E220x_GetRssiInst( void );
float lis3dh_from_fs16_hr_to_mg(int16_t lsb){
return ((float)lsb / 16.0f) * 12.0f;
}
void Ebyte_Port_TransmitCallback( uint16_t state ){
}
void Ebyte_Port_ReceiveCallback( uint16_t state, uint8_t *buffer, uint8_t length){
static ESPMI_MCPGpioLevel level;
if(state == 0x0002){
sensors = (SensorBox_TypeDef*)buffer;
temperature = -45.0f + 175.0f * (float)sensors->temperature/65535.0f;
humidity = 100 * ((float)sensors->humidity/65535.0f);
accX = lis3dh_from_fs16_hr_to_mg(sensors->accX)/100.0f;
accY = lis3dh_from_fs16_hr_to_mg(sensors->accY)/100.0f;
accZ = lis3dh_from_fs16_hr_to_mg(sensors->accZ)/100.0f;
packetsReceived++;
ESP_LOGI(TAG, "%.1f, %.1f, %.1f, %.1f, %.1f, %i\r\n", temperature, humidity, accX, accY, accZ, Ebyte_E220x_GetRssiInst());
level = !level;
ESPMI_MCP23008_SetLevelGpioPin(GPIO_NUM_7, level);
}
}
uint8_t Ebyte_BSP_SpiTransAndRecv(uint8_t data){
spi_transaction_t spiTrans;
const char* TAG = "E220 SPI transmitter";
memset(&spiTrans, 0, sizeof(spi_transaction_t));
spiTrans.length = 8;
spiTrans.tx_data[0] = data;
spiTrans.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
if(spi_device_polling_transmit(ESPMI_GetSPIHandle(), &spiTrans) != ESP_OK){
ESP_LOGE(TAG, "SPI transmission failed");
}
return spiTrans.rx_data[0];
}
void Ebyte_BSP_RfSpiUnselected( void ){
gpio_set_level(ESPMI_E220_900MM22S_NSS, 1);
}
void Ebyte_BSP_RfSpiSelected( void ){
gpio_set_level(ESPMI_E220_900MM22S_NSS, 0);
}
void Ebyte_BSP_RfResetIoHigh( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RST, True);
}
void Ebyte_BSP_RfResetIoLow( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RST, False);
}
void Ebyte_BSP_RfTxIoEnable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_TXEN, True);
}
void Ebyte_BSP_RfTxIoDisable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_TXEN, False);
}
void Ebyte_BSP_RfRxIoEnable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RXEN, True);
}
void Ebyte_BSP_RfRxIoDisable( void ){
ESPMI_MCP23008_SetLevelGpioPin(ESPMI_E220_900MM22S_RXEN, False);
}
uint8_t Ebyte_BSP_RfBusyIoRead( void ){
Boolean state = False;
ESPMI_MCP23008_ReadLevelPin(ESPMI_E220_900MM22S_BUSY, &state);
return (uint8_t)state;
}
void app_main(void){
ESPMI_ConfigI2C(ESPMI_I2C_MASTER_NUM);
ESPMI_ConfigSPI(SPI2_HOST);
ESPMI_ConfigGPIO();
ESPMI_MCP23008_ConfigGpioDir(0x71);
Ebyte_RF.Init();
Ebyte_RF.EnterReceiveMode(0);
while (1) {
Ebyte_RF.StartPollTask();
vTaskDelay(1/portTICK_PERIOD_MS);
}
}
```