--- 直接在下面更新 --- The Wio WM1110 Dev Kit is an open source platform for building IoT projects. It provides low-power loRa network connection and a full range of location coverage services. This kit also includes a range of sensors and peripherals, making it a versatile platform for building IoT projects. In this tutorial, we will introduce the hardware overview and how to develop your own application! # Hardware Overview The Wio-WM1110 Dev Kit is based on [Wio-WM1110 Module](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html),integrates Semtech's LoRa® transceiver and a multi-purpose radio front-end for geolocation, the board has a built-in TH sensor and a 3-axis Accelerometer, also providing connectivity options for a variety of peripherals. <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/hardware_overview1.png" alt="pir" width={800} height="auto" /></p> # Pinout <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/PIN.png" alt="pir" width={800} height="auto" /></p> ## LoRaWAN® Communication ### Define the keys Define the JoinEUI/DevEUI/APPEUI in config file. ```cpp ...\Seeed_Wio_WM1110_Dev_Board\apps\common\lorawan_key_config.h ``` <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/keys.png" alt="pir" width={800} height="auto" /></p> **LoRa Basics Modem LoRaWAN® Class A/C example** The application will automatically starts a procedure to join a LoRaWAN network see **lorawan_key_config.h** Once a network is joined (i.e. when the corresponding event is triggered), uplinks are sent periodically. This periodic action is based on the LoRa Basics Modem alarm functionality. Each time the alarm-related event is triggered, the application requests an uplink. The content of the uplink is the value read out from the charge counter by calling `smtc_modem_get_charge()`. The application is also capable of displaying data and meta-data of a received downlink. **Configuration** Several parameters can be updated in `main_lorawan.h` header file: | Constant | Description | | -------------------------- | ----------------------------------------------------------------------------- | | `LORAWAN_APP_PORT` | LoRaWAN® FPort used for the uplink messages | | `LORAWAN_CONFIRMED_MSG_ON` | Request a confirmation from the LNS that the uplink message has been received | | `APP_TX_DUTYCYCLE` | Delay in second between two uplinks | ## Positioning ### GNSS By capturing a short portion of the signal broadcast by the GNSS satellites, and extracting the information required to calculate the device position - the pseudo-ranges. This information is aggregated into a NAV message which can be sent to a back-end system to compute the device position. <p style={{textAlign: 'center'}}><img src="https://wdcdn.qpic.cn/MTY4ODg1NTkyNTI4NTI1MQ_47857_JbH8r_MU_X1uz1V7_1687329215?w=1265&h=592&type=image/jpeg" alt="pir" width={800} height="auto" /></p> The GNSS scanner of the Wio-WM1110 has two modes of operations: autonomous and assisted. **GNSS autonomous mode:** Does not require any assistance location or almanac data, and aims to detect strong satellite signals. Therefore it is suitable for outdoor conditions with good sky visibility. **GNSS assisted mode**:It allows the most efficient GNSS geolocation. Assistance information can build a list of the satellites in view at the current time and location, in order to reduce the GNSS satellites search space, and therefore optimize the time and energy spent geolocating. The assistance information is tailored to an LPWAN network, limiting the data sent, especially the downlink size and frequency. It consists of: * LR1110 approximate position * Current time * Up-to-date reduced size Almanac information (less than 3 months old) #### Geolocation GNSS Example This example illustrates the GNSS scan procedure: - configuration of the LoRa Basics Modem library; and - execution of GNSS *scan & send* feature using the *GNSS geolocation middleware*. **GNSS demonstration related configuration** The `main_geolocation_gnss.h` header file defines several constants to configure geolocation parameters. | Constant | Comments | Possible values | Default Value | | ---------------------------------------- | --------------------------------------------------------------------------------------- | ---------------- | ------------- | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_AUTO` | If set to `true`: configures the application to autonomously get an assistance position | {`true`,`false`} | `true` | If manual mode is selected for assistance position, the following constants define the position to be used. | Constant | Comments | Possible values | Default Value | | ---------------------------------------- | ------------------------------------------------------------------------------- | -------------------------- | ------------------ | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_LAT` | The latitude to use for GNSS Assisted scan (decimal degree) | Any `float` in [-90, 90] | 45.181454 | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_LONG` | The longitude to use for GNSS Assisted scan (decimal degree) | Any `float` in [-180, 180] | 5.720893 | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_TEXT` | A text representation of the assistance position, for information printing only | Any constant c-string | "Grenoble, FRANCE" | ***Note***: The pre-defined assistance position must be within a 150 km range of the actual location. | Constant | Comments | Possible values | Default Value | | ------------------------ | --------------------------------------------------------------------------------------------- | ------------------------- | --------------------- | | `GNSS_SCAN_GROUP_PERIOD` | Defines the duration between the end of a scan & send sequence and the start of next sequence | `uint32_t` | 30 | | `GNSS_SCAN_MODE` | Defines the GNSS scan mode (static or mobile) to be used for scan & send sequences. | Value in `gnss_mw_mode_t` | `GNSS_MW_MODE_STATIC` | The GNSS scan mode selected by default is `GNSS_MW_MODE_STATIC`, meaning that this application example targets non-mobile objects. ### Wi-Fi By discovering the Wi-Fi b/g/n access points available in the vicinity of the device, and extract MAC addresses allowing to geolocate the device. The objective is to obtain at least 2 MAC addresses, which can be used to position the device, after they have been sent to an online Wi-Fi lookup service <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/Schematic02.png" alt="pir" width={800} height="auto" /></p> #### Geolocation Wi-Fi Example This application demonstrates the usage of the Wi-Fi geolocation middleware and how the LoRa Basics Modem should be configured to meet the prerequisites for This example illustrates the Wi-Fi scan procedure: - configuration of the LoRa Basics Modem library; and - execution of Wi-Fi *scan & send* feature using the *Wi-Fi geolocation middleware*. **Wi-Fi demonstration related configuration** The `main_geolocation_wifi.h` header file defines several constants which can be set to define the configurable parameters of the application. | Constant | Comments | Possible values | Default Value | | ------------------ | --------------------------------------------------------------------------------------------- | --------------- | ------------- | | `WIFI_SCAN_PERIOD` | Defines the duration between the end of a scan & send sequence and the start of next sequence | `uint32_t` | 30 | ### GNSS and Wi-Fi #### Geolocation GNSS and Wi-Fi example This example illustrates the combination of GNSS and Wi-Fi scan procedures: - configuration of the LoRa Basics Modem library; and - concurrent execution of GNSS and Wi-Fi *scan & send* features using the *GNSS geolocation middleware* and the *Wi-Fi geolocation middleware*. **Geolocation demonstration related configuration** The `main_geolocation_gnss_wifi.h` header file defines several constants to configure geolocation parameters. | Constant | Comments | Possible values | Default Value | | ---------------------------------------- | --------------------------------------------------------------------------------------- | ---------------- | ------------- | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_AUTO` | If set to `true`: configures the application to autonomously get an assistance position | {`true`,`false`} | `false` | If manual mode is selected for assistance position, the following constants define the position to be used. | Constant | Comments | Possible values | Default Value | | ---------------------------------------- | ------------------------------------------------------------------------------- | -------------------------- | ------------------ | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_LAT` | The latitude to use for GNSS Assisted scan (decimal degree) | Any `float` in [-90, 90] | 45.181454 | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_LONG` | The longitude to use for GNSS Assisted scan (decimal degree) | Any `float` in [-180, 180] | 5.720893 | | `MODEM_EXAMPLE_ASSISTANCE_POSITION_TEXT` | A text representation of the assistance position, for information printing only | Any constant c-string | "Grenoble, FRANCE" | ***Note***: The pre-defined assistance position must be within a 150 km range of the actual location. | Constant | Comments | Possible values | Default Value | | ------------------------ | --------------------------------------------------------------------------------------------- | ------------------------- | --------------------- | | `GNSS_SCAN_GROUP_PERIOD` | Defines the duration between the end of a scan & send sequence and the start of next sequence | `uint32_t` | 30 | | `GNSS_SCAN_MODE` | Defines the GNSS scan mode (static or mobile) to be used for scan & send sequences. | Value in `gnss_mw_mode_t` | `GNSS_MW_MODE_MOBILE` | The GNSS scan mode selected by default is `GNSS_MW_MODE_MOBILE`, meaning that this application example targets mobile objects. ## Low Energy Bluetooth(BLE) ### Introduction Low Energy Bluetooth (BLE), also known as Bluetooth Low Energy, is a wireless communication technology designed to provide a low-power and low-complexity communication method for devices that require long-term power supply, low data transfer rates, and short communication distances. Optimized based on Bluetooth technology, BLE has lower power consumption and a simpler protocol stack, making it suitable for low-power and Internet of Things (IoT) applications. BLE uses short-range, low-power wireless communication, making it more energy-efficient than traditional Bluetooth protocols, which is important for devices that need to operate for long periods of time, such as sensors, health tracking devices, and smart home control devices. The main application scenarios of BLE include the following: - Health tracking devices: smartwatches, health bands, and other devices used to track health data such as steps, heart rate, and sleep. - Smart home control devices: used to control smart lighting, bathroom equipment, home entertainment systems, etc. - Sensor devices: used to monitor environmental parameters such as temperature, humidity, and air pressure. The low power consumption, low cost, and small size of BLE make it an important communication standard for IoT devices, suitable for various scenarios that require long-term power supply, low power consumption, and short-distance wireless communication. The Wio-WM1110 has a Low Energy Bluetooth based on the nRF52840 chip. ### Starting a Bluetooth routine Open the Bluetooth demo located at `nRF5_SDK_17.1.0_ddde560/examples/ble_peripheral/ble_app_uart/pca10056/s140/ses/` Firstly, burn the Bluetooth protocol stack firmware located at `nRF5_SDK_17.1.0_ddde560/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex` Burn the .hex file onto the development board using SES. Once complete, burn the Bluetooth project firmware. <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/SES_Burn_hex.png" alt="pir" width={800} height="auto" /></p> Download [nRF Connect]( https://github.com/NordicSemiconductor/Android-nRF-Connect/releases) Connect the development board's serial port to the PC and set the baud rate to `115200`. Open the nRF Connect app and search for Bluetooth devices. Find the Bluetooth device named "Nordic_UART." <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/nRF_connect1.jpg" alt="pir" width={500} height="auto" /></p> Open the Nordic UART Service and click RX Characteristic to send data. <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/nRF_connect2.jpg" alt="pir" width={500} height="auto" /></p> The serial port will forward the received Bluetooth data to the PC. <p style={{textAlign: 'center'}}><img src="https://files.seeedstudio.com/wiki/SenseCAP/Wio-WM1110%20Dev%20Kit/nRF_connect3.jpg" alt="pir" width={500} height="auto" /></p> ### Bluetooth Demo Analysis This section mainly analyzes the ble_app_uart example. The working mode of the Bluetooth slave serial port is: the host sends data to the slave via Bluetooth, and the slave forwards it through the serial port after receiving the Bluetooth data. The slave receives data from the serial port and sends the data to the host via Bluetooth. The Bluetooth serial port mainly has three parts of work: the first part is to establish the serial port, the second part is to establish BLE, and the third part is to establish a bidirectional data channel between Bluetooth and the serial port. The initialization part of the main function is mainly divided into three parts:   1. Initialization of peripheral devices such as timers, keys, LED lights, serial ports, and power management.   2. Protocol layer initialization, such as protocol stack initialization, GAP, GATT initialization, broadcast initialization, connection parameter initialization, etc.   3. Application layer initialization, such as service initialization and Bluetooth service initialization. ```c= /**@brief Application main function. */ int main(void) { bool erase_bonds; // Initialize. uart_init(); log_init(); timers_init(); buttons_leds_init(&erase_bonds); power_management_init(); ble_stack_init(); gap_params_init(); gatt_init(); services_init(); advertising_init(); conn_params_init(); // Start execution. printf("\r\nUART started.\r\n"); NRF_LOG_INFO("Debug logging for UART over RTT started."); advertising_start(); // Enter main loop. for (;;) { idle_state_handle(); } } ``` Ignoring the Bluetooth protocol stack for now, the focus is on how a Bluetooth service is implemented. Find the `services_init` function, where the Bluetooth service is registered. First, initialize a callback: `nus_init.data_handler = nus_data_handler` This callback is used to upload data from the lower layers to the main file for processing. The Bluetooth serial port service is registered through the ble_nus_init function. ```c= /**@brief Function for initializing services that will be used by the application. */ static void services_init(void) { uint32_t err_code; ble_nus_init_t nus_init; nrf_ble_qwr_init_t qwr_init = {0}; // Initialize Queued Write Module. qwr_init.error_handler = nrf_qwr_error_handler; err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init); APP_ERROR_CHECK(err_code); // Initialize NUS. memset(&nus_init, 0, sizeof(nus_init)); nus_init.data_handler = nus_data_handler; err_code = ble_nus_init(&m_nus, &nus_init); APP_ERROR_CHECK(err_code); } ``` Inside the `ble_nus_init` function, the `sd_ble_uuid_vs_add` function is called to add the UUID of the service. Then, the `sd_ble_gatts_service_add` function is called to register this service. The service handle is allocated by the protocol stack and is stored in `p_led->service_handle`. After registering the service, the characteristics of the service are added. Usually, a Bluetooth device contains one profile, which includes multiple services. Each service contains multiple characteristics, and characteristics are the basic units for transmitting data through Bluetooth. Each characteristic has a different value. The `characteristic_add` function is called to add the characteristics, with the first characteristic being the Bluetooth Serial RX characteristic, which is enabled for writing through `add_char_params.char_props.write`. The second characteristic is the Bluetooth Serial TX characteristic, which has its notification property enabled through `add_char_params.char_props.notify`. ```c= uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init) { ret_code_t err_code; ble_uuid_t ble_uuid; ble_uuid128_t nus_base_uuid = NUS_BASE_UUID; ble_add_char_params_t add_char_params; VERIFY_PARAM_NOT_NULL(p_nus); VERIFY_PARAM_NOT_NULL(p_nus_init); // Initialize the service structure. p_nus->data_handler = p_nus_init->data_handler; /**@snippet [Adding proprietary Service to the SoftDevice] */ // Add a custom base UUID. err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type); VERIFY_SUCCESS(err_code); ble_uuid.type = p_nus->uuid_type; ble_uuid.uuid = BLE_UUID_NUS_SERVICE; // Add the service. err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_nus->service_handle); /**@snippet [Adding proprietary Service to the SoftDevice] */ VERIFY_SUCCESS(err_code); // Add the RX Characteristic. memset(&add_char_params, 0, sizeof(add_char_params)); add_char_params.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC; add_char_params.uuid_type = p_nus->uuid_type; add_char_params.max_len = BLE_NUS_MAX_RX_CHAR_LEN; add_char_params.init_len = sizeof(uint8_t); add_char_params.is_var_len = true; add_char_params.char_props.write = 1; add_char_params.char_props.write_wo_resp = 1; add_char_params.read_access = SEC_OPEN; add_char_params.write_access = SEC_OPEN; err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles); if (err_code != NRF_SUCCESS) { return err_code; } // Add the TX Characteristic. /**@snippet [Adding proprietary characteristic to the SoftDevice] */ memset(&add_char_params, 0, sizeof(add_char_params)); add_char_params.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC; add_char_params.uuid_type = p_nus->uuid_type; add_char_params.max_len = BLE_NUS_MAX_TX_CHAR_LEN; add_char_params.init_len = sizeof(uint8_t); add_char_params.is_var_len = true; add_char_params.char_props.notify = 1; add_char_params.read_access = SEC_OPEN; add_char_params.write_access = SEC_OPEN; add_char_params.cccd_write_access = SEC_OPEN; return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles); /**@snippet [Adding proprietary characteristic to the SoftDevice] */ } ``` In the `ble_nus_init` function, there is a parameter m_nus. The `BLE_NUS_DEF(m_nus, NRF_SDH_BLE_TOTAL_LINK_COUNT)` function is used to instantiate the Bluetooth serial port and obtain the m_nus instance. The `BLE_NUS_DEF` function calls `NRF_SDH_BLE_OBSERVER` to register the m_nus instance as an observer, which means that when there are relevant messages in the GAP and GATT layers, the `ble_nus_on_ble_evt` function will be called to handle them. ```c= /**@brief Macro for defining a ble_nus instance. * * @param _name Name of the instance. * @param[in] _nus_max_clients Maximum number of NUS clients connected at a time. * @hideinitializer */ #define BLE_NUS_DEF(_name, _nus_max_clients) \ BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage), \ (_nus_max_clients), \ sizeof(ble_nus_client_context_t)); \ static ble_nus_t _name = \ { \ .p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage) \ }; \ NRF_SDH_BLE_OBSERVER(_name ## _obs, \ BLE_NUS_BLE_OBSERVER_PRIO, \ ble_nus_on_ble_evt, \ &_name) ``` In the `ble_nus_on_ble_evt` function, a total of three types of messages are processed: `BLE_GAP_EVT_CONNECTED`, `BLE_GATTS_EVT_WRITE`, and `BLE_GATTS_EVT_HVN_TX_COMPLETE`. For the `BLE_GATTS_EVT_WRITE` event, the on_write function is called to process the received Bluetooth data. In the `on_write` function, the `p_nus->data_handler(&evt)` callback function is also called, which is the `nus_data_handler`function. Finally, the data is passed back to the `nus_data_handler` function in the main file for processing. ```c= void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context) { if ((p_context == NULL) || (p_ble_evt == NULL)) { return; } ble_nus_t * p_nus = (ble_nus_t *)p_context; switch (p_ble_evt->header.evt_id) { case BLE_GAP_EVT_CONNECTED: on_connect(p_nus, p_ble_evt); break; case BLE_GATTS_EVT_WRITE: on_write(p_nus, p_ble_evt); break; case BLE_GATTS_EVT_HVN_TX_COMPLETE: on_hvx_tx_complete(p_nus, p_ble_evt); break; default: // No implementation needed. break; } } ``` Finally, the nus_data_handler function forwards the data received over Bluetooth to the UART by calling the `app_uart_put(p_evt->params.rx_data.p_data[i])` function. ```c= /**@brief Function for handling the data from the Nordic UART Service. * * @details This function will process the data received from the Nordic UART BLE Service and send * it to the UART module. * * @param[in] p_evt Nordic UART Service event. */ /**@snippet [Handling the data received over BLE] */ static void nus_data_handler(ble_nus_evt_t * p_evt) { if (p_evt->type == BLE_NUS_EVT_RX_DATA) { uint32_t err_code; NRF_LOG_DEBUG("Received data from BLE NUS. Writing data on UART."); NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length); for (uint32_t i = 0; i < p_evt->params.rx_data.length; i++) { do { err_code = app_uart_put(p_evt->params.rx_data.p_data[i]); if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) { NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code); APP_ERROR_CHECK(err_code); } } while (err_code == NRF_ERROR_BUSY); } if (p_evt->params.rx_data.p_data[p_evt->params.rx_data.length - 1] == '\r') { while (app_uart_put('\n') == NRF_ERROR_BUSY); } } } ``` This is the complete process for implementing a Bluetooth service. If you want to add your own service, you can follow this process. ## Built-in Sensors ### TH Sensor(SHT41) SHT41 is a digital humidity and temperature sensor, it communicates with a microcontroller or other digital device through an I2C interface. The SHT41 sensor is commonly used in a wide range of applications, including HVAC systems, weather stations, indoor air quality monitoring, and industrial process control. Its small size, low power consumption, and high accuracy make it a popular choice for many different types of projects. | | Range | Accuracy | | -------- | -------- | -------- | |Temperature | -40~125°C |0.2°C| | Humidity | 0~100%RH |1.8%RH| **Code:** This example provides functions for initializing the sensor, reading temperature and humidity values, and setting the temperature unit. Here's a brief summary of the functions defined in this code: **SHT41Init**: a function that initializes the sensor by resetting it and waiting for 1ms before proceeding. **SHT41GetTemperature, SHT41GetHumidity, and SHT41GetTempAndHumi**: functions for reading temperature and/or humidity values from the sensor. These functions convert the raw sensor values to a float value in degrees Celsius or Fahrenheit, depending on the current temperature unit setting. **SHT41SetTemperatureUnit and SHT41GetTemperatureUnit**: functions for setting and getting the temperature unit. crc8: an internal function that calculates the CRC-8 checksum of a byte array. ### 3-axis Accelerometer(LIS3DHTR) The LIS3DHTR is a high-performance sensor that measures acceleration in three dimensions and provides accurate and reliable readings. The LIS3DHTR sensor communicates with a microcontroller or other digital device through an I2C or SPI interface. It also includes advanced features such as programmable interrupts and a wide range of power-saving modes to help minimize power consumption. | Range | Bandwidth | Sensitivity(LSB/g) | | -------- | -------- | -------- | | ±2g, 4g, 8g, 16g | 0.5Hz ~ 625Hz |1000 (±2g) ~ 83 (±16g) ## Grove ### Grove I2C The Wio-WM1110 has a Grove IIC port with `SCL` on pin 26 and `SDL` on pin 27. Before using it, define the following: ```c= #define IIC_POWER 7 ``` To use the Grove IIC, you need to enable and set the `I2C_PWR` (pin 7) on the Wio-WM1110 development board. This pin controls the pull-up voltage on the IIC signal line. If this pin is not set, the IIC signal line will not be able to communicate due to a lack of pull-up voltage. TWI needs to be enabled in the `sdk_config.h` file before usage. ```C= // <e> TWI_ENABLED - nrf_drv_twi - TWI/TWIM peripheral driver - legacy layer //========================================================== #ifndef TWI_ENABLED #define TWI_ENABLED 1 #endif // <e> TWI0_ENABLED - Enable TWI0 instance //========================================================== #ifndef TWI0_ENABLED #define TWI0_ENABLED 1 #endif // <q> TWI0_USE_EASY_DMA - Use EasyDMA (if present) #ifndef TWI0_USE_EASY_DMA #define TWI0_USE_EASY_DMA 1 #endif // </e> // <e> TWI1_ENABLED - Enable TWI1 instance //========================================================== #ifndef TWI1_ENABLED #define TWI1_ENABLED 1 #endif // <q> TWI1_USE_EASY_DMA - Use EasyDMA (if present) #ifndef TWI1_USE_EASY_DMA #define TWI1_USE_EASY_DMA 1 #endif ``` This sample code is based on the Grove [SHT41](https://wiki.seeedstudio.com/Grove-SHT4x/) digital sensor. ```c= #include "nrf_gpio.h" #include "nrf_gpiote.h" #include "nrf_drv_gpiote.h" #include "nrf_delay.h" #include "app_error.h" #include "sht41.h" #include "nrf_drv_twi.h" int main(void) { float temp = 0; float humi = 0; hal_i2c_master_init( ); hal_gpio_init_out( SENSOR_POWER, HAL_GPIO_SET ); nrf_delay_ms(10); SHT41Init(); while(1){ SHT41GetTempAndHumi(&temp,&humi); nrf_delay_ms(1000); printf("temperature:%.3f humidity:%.3f\n",temp,humi); } } ``` ### Grove UART The Wio-WM1110 has two UART peripherals, namely `uart0` and `uart1`. Among them, `uart0` pins are connected to the CH340C for debugging purposes, while `uart1` serves as a Grove UART Port. Before using the UART, the TXD and RXD pins need to be defined. Referring to the schematic, TXD is located on pin 8 and RXD is on pin 6. >(Note: Except for analog interfaces like ADC, the nRF52840 chip has fixed pins for other digital peripherals. However, other digital peripherals can be remapped to any pin. For example, the RXD and TXD pin configurations can be swapped.) ```c= #define LED1 13 #define LED2 14 #define TXD 8 #define RXD 6 #define UART_TX_RX_BUF_SIZE 256 ``` UART needs to be enabled in the `sdk_config.h` file before usage. ```C= //<e>UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver - legacy layer //========================================================== #ifndef UART_ENABLED #define UART_ENABLED 1 #endif // <e> UART0_ENABLED - Enable UART0 instance //========================================================== #ifndef UART0_ENABLED #define UART0_ENABLED 1 #endif // <e> UART1_ENABLED - Enable UART1 instance //========================================================== #ifndef UART1_ENABLED #define UART1_ENABLED 1 #endif // <q> UART_LEGACY_SUPPORT - Driver supporting Legacy mode #ifndef UART_LEGACY_SUPPORT #define UART_LEGACY_SUPPORT 1 #endif ``` The following is an example code for UART, which implements the functions of serial transmission and reception with feedback. ```c= #include "nrf_gpio.h" #include "nrf_gpiote.h" #include "nrf_drv_gpiote.h" #include "nrf_delay.h" #include "smtc_hal.h" #include "app_uart.h" #include "app_error.h" #include "nrf_uart.h" #include "nrf_drv_uart.h" static void uart_handleEvent( app_uart_evt_t *pEvent ); APP_UART_DEF( uart, 0, UART_TX_RX_BUF_SIZE, uart_handleEvent ); static app_uart_comm_params_t const commParams = { .rx_pin_no = RXD, .tx_pin_no = TXD, .rts_pin_no = NRF_UART_PSEL_DISCONNECTED, .cts_pin_no = NRF_UART_PSEL_DISCONNECTED, .flow_control = APP_UART_FLOW_CONTROL_DISABLED, .use_parity = false, .baud_rate = NRF_UART_BAUDRATE_115200 }; void uart_tx( uint8_t* buff, uint16_t len ) { for( uint16_t i = 0; i < len; i++ ) { app_uart_put( &uart, buff[i] ); } } int main(void) { uint32_t err_code; uart.comm_params = &commParams; uint8_t arr[] = "hello world\n"; nrf_gpio_cfg_output(LED1); nrf_gpio_cfg_output(LED2); nrf_gpio_pin_clear(LED1); nrf_gpio_pin_clear(LED2); app_uart_init( &uart, &uart_buffers, APP_IRQ_PRIORITY_LOWEST ); while( 1 ) { nrf_delay_ms(1000); nrf_gpio_pin_toggle(LED2); uart_tx(arr,strlen(arr)); } } void uart_handleEvent(app_uart_evt_t * p_event) { uint8_t dat; if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) { APP_ERROR_HANDLER(p_event->data.error_communication); } else if (p_event->evt_type == APP_UART_FIFO_ERROR) { APP_ERROR_HANDLER(p_event->data.error_code); } else if (p_event->evt_type == APP_UART_DATA_READY) { app_uart_get(&uart,&dat); app_uart_put(&uart,dat); } else if (p_event->evt_type == APP_UART_TX_EMPTY) { nrf_gpio_pin_toggle(LED1); } } ``` ### Grove ADC The Wio-WM1110 has a total of eight ADC peripherals (0~7), among which `ADC6` and `ADC7` are used as the Grove ADCT Port. >(Note: ADC pins are fixed and cannot be remapped.) The corresponding relationships for ADC pins are shown in the table below: |ADCx|pin| |:-------:|:------:| |ADC0|2| |ADC1|3| |ADC2|4| |ADC3|5| |ADC4|28| |ADC5|29| |ADC6|30| |ADC7|31| SAADC needs to be enabled in the `sdk_config.h` file before usage. ```C= //<e> SAADC_ENABLED - nrf_drv_saadc - SAADC peripheral driver legacy layer //========================================================== #ifndef SAADC_ENABLED #define SAADC_ENABLED 1 #endif // <o> SAADC_CONFIG_RESOLUTION - Resolution // <0=> 8 bit // <1=> 10 bit // <2=> 12 bit // <3=> 14 bit #ifndef SAADC_CONFIG_RESOLUTION #define SAADC_CONFIG_RESOLUTION 2 #endif ``` This is an example program for ADC6, which implements the function of reading the analog input value of a single channel of the ADC6 pin and outputting the measured ADC value through the UART: ```c= #include "nrf_gpio.h" #include "nrf_gpiote.h" #include "nrf_drv_gpiote.h" #include "nrf_delay.h" #include "app_uart.h" #include "app_error.h" #include "nrf_uart.h" #include "nrf_drv_uart.h" #include "nrf_drv_saadc.h" #define LED1 13 #define LED2 14 #define TXD 8 #define RXD 6 #define UART_TX_RX_BUF_SIZE 256 static void uart_handleEvent( app_uart_evt_t *pEvent ); APP_UART_DEF( uart, 0, UART_TX_RX_BUF_SIZE, uart_handleEvent ); static app_uart_comm_params_t const commParams = { .rx_pin_no = RXD, .tx_pin_no = TXD, .rts_pin_no = NRF_UART_PSEL_DISCONNECTED, .cts_pin_no = NRF_UART_PSEL_DISCONNECTED, .flow_control = APP_UART_FLOW_CONTROL_DISABLED, .use_parity = false, .baud_rate = NRF_UART_BAUDRATE_115200 }; void uart_tx( uint8_t* buff, uint16_t len ) { for( uint16_t i = 0; i < len; i++ ) { app_uart_put( &uart, buff[i] ); } } void ADC_Interrupt(nrfx_saadc_evt_t const *p_event){ } void uart_handleEvent(app_uart_evt_t * p_event) { uint8_t dat; if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR) { APP_ERROR_HANDLER(p_event->data.error_communication); } else if (p_event->evt_type == APP_UART_FIFO_ERROR) { APP_ERROR_HANDLER(p_event->data.error_code); } else if (p_event->evt_type == APP_UART_DATA_READY) { app_uart_get(&uart,&dat); //app_uart_put(&uart,dat); } else if (p_event->evt_type == APP_UART_TX_EMPTY) { //nrf_gpio_pin_toggle(LED1); } } int main(void) { nrf_saadc_value_t saadc_val = 0; uint8_t arr[32]; nrf_saadc_channel_config_t channel_config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, .gain = NRF_SAADC_GAIN1_6, .reference = NRF_SAADC_REFERENCE_INTERNAL, .acq_time = NRF_SAADC_ACQTIME_10US, .mode = NRF_SAADC_MODE_SINGLE_ENDED, .burst = NRF_SAADC_BURST_DISABLED, .pin_p = NRF_SAADC_INPUT_AIN6, .pin_n = NRF_SAADC_INPUT_DISABLED }; nrf_drv_saadc_init(NULL, ADC_Interrupt); nrf_drv_saadc_channel_init(0, &channel_config); uart.comm_params = &commParams; app_uart_init( &uart, &uart_buffers, APP_IRQ_PRIORITY_LOWEST ); nrf_gpio_cfg_output(LED2); while( 1 ) { nrf_drv_saadc_sample_convert (0,&saadc_val); sprintf(arr,"value:%d\n",saadc_val); uart_tx(arr,strlen(arr)); nrf_delay_ms(1000); nrf_gpio_pin_toggle(LED2); } } ``` # Resources [Seeed_Wio_WM1110_Dev_Board](https://github.com/Seeed-Studio/Seeed_Wio_WM1110_Dev_Board) [nRF5-SDK](https://www.nordicsemi.com/Products/Development-software/nRF5-SDK/Download#infotabs) # Tech Support **Need help with your Wio-WM1110 Dev Kit? We're here to assist you!** <div class="button_tech_support_container"> <a href="https://discord.gg/sensecap" class="button_tech_support_sensecap"></a> <a href="https://support.sensecapmx.com/portal/en/home" class="button_tech_support_sensecap3"></a> </div> <div class="button_tech_support_container"> <a href="mailto:support@sensecapmx.com" class="button_tech_support_sensecap2"></a> <a href="https://github.com/Seeed-Solution/SenseCAP_Indicator_ESP32/discussions" class="button_discussion"></a> </div>