Wireless Connectivity Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Wireless Connectivity Knowledge Base

Discussions

Sort by:
      The article will describe how to configure Access Point Based On NXP platform and WIFI chipset step by step. Users can easily make her AP based on NXP WIFI module work normally by following steps in the article. 1. Environment for the validation - Hardware Platform     i.MX8MN-EVK - Software    Kernel version: L5.4.70_2.3.0    rootfs : imx-image-multimedia -WiFi module   AW-CM358SM: NXP 88W8987 chipset 2. Diagram for Connections   For More detailed information, See attached document, please!   NXP CAS-TIC Wireless MCU team Weidong sun 04-16-2021  
View full article
CMSIS, the ARM Cortex Microcontroller Software Interface Standard, can be used to distribute software components in standard package format. CMSIS compliant software components allow: • Easy reuse of example applications or template code • Combination of SW components from multiple vendors CMSIS packages available here: https://www.keil.arm.com/packs/ NXP WiFi package available here: https://www.keil.arm.com/packs/wifi-nxp/versions/   Getting NXP WiFi/BT software   Please find the minimal setup required to download the NXP WiFi/BT software CMSIS packs: First, get cpackget binary from the Open CMSIS Pack toolbox binaries Then, install the NXP WiFi and Bluetooth packages and their dependencies using below commands cpackget add NXP::WIFI@2.0.0 cpackget add NXP::WIRELESS_WPA_SUPPLICANT@2.0.0 cpackget add NXP::EDGEFAST_BT_BLE@2.0.0   Please note that the CMSIS software packs are installed in below directory: ~/.cache/arm/packs/NXP/   Building NXP WiFi/Bluetooth software   Using combined WiFi+Bluetooth application on i.MXRT1060-revC board, as an example.   Prerequisite Follow below steps to install all the required tools to get CMSIS packages and build them . <(curl https://aka.ms/vcpkg-init.sh -L) . ~/.vcpkg/vcpkg-init vcpkg new --application vcpkg add artifact arm:cmsis-toolbox vcpkg add artifact microsoft:cmake vcpkg add artifact microsoft:ninja vcpkg add artifact arm:arm-none-eabi-gcc vcpkg activate Refer to CMSIS toolbox installation documentation    Activate required tools . ~/.vcpkg/vcpkg-init vcpkg activate Install the NXP i.MXRT1060-REVC Bluetooth examples and their dependencies cpackget add NXP::MIMXRT1060-EVKC_EDGEFAST_BLUETOOTH_Examples@1.0.0 Workaround: current NXP SW is aligned with ARM::CMSIS@5.8.0, and does not support latest ARM::CMSIS@6.0.0, so we need to use older version with below commands cpackget rm ARM::CMSIS@6.0.0 cpackget add ARM::CMSIS@5.8.0 List the installed packages cpackget list Building combined WiFi+BT example application Copy example application to local directory and provide write permissions mkdir -p ~/test cp -r ~/.cache/arm/packs/NXP/MIMXRT1060-EVKC_EDGEFAST_BLUETOOTH_Examples/1.0.0/boards/evkcmimxrt1060/edgefast_bluetooth_examples/wifi_cli_over_ble_wu/ ~/test/ cd ~/test/wifi_cli_over_ble_wu/ && chmod -R u+w .   Build the application csolution convert wifi_cli_over_ble_wu.csolution.yml cbuild wifi_cli_over_ble_wu.flexspi_nor_debug+armgcc.cprj Convert elf to bin for flashing cd armgcc/flexspi_nor_debug arm-none-eabi-objcopy wifi_cli_over_ble_wu.elf -O binary wifi_cli_over_ble_wu.bin
View full article
       The article will describe how to configure A2DP audio application Based On NXP platform and WIFI/BT chipset step by step. Users can easily make her A2DP audio based on NXP WIFI module work normally by following steps in the article. Environment for the validation Hardware Platform        i.MX8MN-EVK Software Kernel version: L5.4.70_2.3.0 rootfs : imx-image-multimedia WiFi module        AW-CM358SM: NXP 88W8987 chipset   For more detailed information, see attachment, please!   NXP CAS-TIC wireless MCU team Weidong Sun    
View full article
This article describes how to use the tcpdump tool to capture wireless network data packets. The test block diagram is as follows: For more detailed information, See attachment,please!   NXP CAS-TIC Wireless MCU team Weidong Sun
View full article
Based on i.MX8MN-EVK And Linux 5.4.70_2.3.0 BSP As an example of NXP Bluetooth Bluetooth application, this article describes how to use Bluetooth to realize file transfer between windows PC and i.MX8MN-EVK (linux), and between Android mobile phone and i.MX8MN-EVK. The test architecture used in this example is as follows: The following steps are for the application example: Step 1 Preparation  --Downloading DEMO Image For i.MX8MN-EVK  --Downloading uuu tool  --Compiling L5.4.70_2.3.0 BSP for i.MX8MN-EVK  --Copying rootfs to the DEMO Image directory  --Modifying example_kernel_emmc.uuu as uuu programming script  --Programming images to i.MX8MN-EVK board  Booting i.MX8MN-EVK board Step 2 Loading WIFI/BT driver and Enable Bluetooth Step 3 File Transter between Windows 10 PC and i.MX8MN-EVK board Step 4 File Transter between Android Mobile and i.MX8MN-EVK board [Summary] More detailed information, see attachment, please!
View full article
This article describes how to compile the Linux BSP of the i.MX platform under ubuntu 18.04, 20.04 LTS and debian-10. This is a necessary step to integrate WIFI/BT to the I.MX platform. See the attachment for detailed steps.
View full article
This article describes the detailed steps for integrating 88W8801 to i.MX6ULL-EVK and L5.4.70_2.3.0. If you are not proficient in compiling Linux BSP for I.MX platform, you can refer to this link: https://community.nxp.com/t5/Wireless-Connectivity-Knowledge/WiFi-BT-Integretion-Linux-BSP-compilation-for-iMX-platform/ta-p/1277199 For more detailed information, see attachment, please!  
View full article
[Summary]        This article demonstrates two ways to compile the driver for x86 linux kernel: Compile the driver for 4.19.35 kernel. Compile the current kernel of the driver for ubuntu 16.04.        If setting CROSS_COMPILE and ARCH, the driver can be generated with make command, but the bin_sd8978 subdirectory will not be generated. The utility needs to be compiled separately. Only for x86 arch, when compiling the driver using make build, the bin_sd8978 directory will be generated. Users need to pay attention to this.     3. For USB drivers of IW416, The usb.h in the original ubuntu 16.04 kernel has no update, struct usb_interface structure, lack of pm_usage_cnt members, so we must update the ubuntu kernel. More detaled information, see attachment, please!
View full article
The document discusses how to enable MAYA_160(IW416) bluetooth on i.MX8MM UART2. 1. Hardware connections 2. how to change device tree 3. compiling mass market driver and getting firmware 4. starting bluetooth and setting bandrate to be 3Mbps More detailed information, see attachment, please!   NXP global CAS connectivity team weidong sun 12-29-2021
View full article
The document is for 88w9098 users who is running lower version of linux kernel. just a reference for them. Driver version:      PCIE-WLAN-UART-BT-9098-U16-X86-17.68.1.p81-17.26.1.p81-MXM5X17277_V0V1-MGPL   NXP global CAS connectivity team Weidong Sun 12-29-2021
View full article
This article explains how to implement a custom profile from both server and client side using the NXP BLE stack for the RT1060.   Generic Attribute Profile To fully understand the procedure of how to implement a custom profile in this platform, we must understand the BLE basics. The GATT (Generic Attribute Profile) will help us establish in detail the way server and client exchanges data over a BLE connection. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This means that if we want to have a successful connection and data transfer in our application, we must follow all the GATT procedures successfully. GATT roles: Server: This device will store the data to be transported or send and accepts the GATT requests, commands and confirmations from the client. Client: This device will access the data on the remote GATT server with operations such as read, write, notify or indicate. Figure 1. GATT Client-Server model   GATT database defines a type of hierarchy to organize attributes. These are named as Profile, Service, Characteristic and Descriptor. The structure is shown in Figure 2. The profile is a high level definition that determines the behavior of the application as a whole. For example, a Temperature Sensor profile. This profiles are defined by at least one service. The service defines a specific functionality for the device (e.g. battery service). The next level in the structure is the characteristic. The service is defined by one or more characteristics that hold individual measurements, control points or other kind of data. Finally we find descriptors. Characteristics have descriptors that defines how characteristics have to be accessed to read or write information. Figure 2. GATT database structure   Creating a New Profile With the GATT basics understood, we can start developing the code for our custom profile. In this case we will create a potentiometer custom profile. It will read the voltage drop of the potentiometer and send that value to the client every 5 seconds. Please note that in this document we will dismiss all the ADC initialization, the voltage value will be simulated. For time saving purposes, we will use the peripheral_ht and central_ht SDK examples structure to create this project. This means that the peripheral is going to be the server, the device that has the information. And the central will be the client, the device that gets the information. In case you don’t want to start this application from a SDK example, it is highly recommended to keep the same structure as in the examples, so if you would like to add your custom profile to an existing application, you have to prepare the project environment so all the new files where your service is declared is allocated in a specific path and avoid problems in the compiling process. For the case you want to add a new service to your project, it will be needed to create two folders called services and add our service files inside it. The first folder must be in the following route: ${ProjName}/edgefast/bluetooth/include/bluetooth. Inside this folder let´s create a new header file called pot.h. Note that if you are using the examples, you already have these folders so you only need to create the files. In this file we will declare the new UUID´s for our potentiometer service and the service characteristic. In this example we are declarin one profile, one service and one characteristic. To define a 128-bit UUID we are going to be using the macros available in the uuid.h file. The declarations will look like this: #define POTENTIOMETER_SERVICE_UUID 0xAA, 0x1C, 0x12, 0x5E, 0x40, 0xEE, 0xA1, 0xF1, 0xEE, 0xF4, 0x5E, 0xBA, 0x22, 0x33, 0xFF, 0x00 #define POTENTIOMETER_CHARACTERISTIC_UUID 0xAA, 0x1C, 0x12, 0x5E, 0x40, 0xEE, 0xA1, 0xF1, 0xEE, 0xF4, 0x5E, 0xBA, 0x22, 0x33, 0xFF, 0x01 #define POTENTIOMETER_SERVICE BT_UUID_DECLARE_128(POTENTIOMETER_SERVICE_UUID) #define POTENTIOMETER_CHARACTERISTIC BT_UUID_DECLARE_128(POTENTIOMETER_CHARACTERISTIC_UUID)   In this case we are declaring a service with the 128-bit service UUID and a characteristic with its 128-bit characteristic UUID. These macros are helping us to declare a struct bt_uuid according to a specific UUID. The other service folder must be allocated in the following route: ${ProjName}/edgefast/bluetooth/source. Inside this folder we have to create a new source file called pot.c (for simplicity we will use the same #include as in hts.c). There are important configurations and declarations we need to have in this file like the read function callback and the service declaration. It will look something like this: static uint8_t pot_level = 0x01U; /* Read function */ static ssize_t read_plvl(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { uint8_t lvl = pot_level; pot_level ++; /* Voltage level simulation */ return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl, sizeof(lvl)); } /* Potentiometer Service Declaration */ BT_GATT_SERVICE_DEFINE(pot, /* Name of the service */ BT_GATT_PRIMARY_SERVICE(POTENTIOMETER_SERVICE), /* Primary sevice UUID */ BT_GATT_CHARACTERISTIC(POTENTIOMETER_CHARACTERISTIC, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, read_plvl, NULL, NULL), /* Potentiometer characteristic */ BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), /* Client Characteristic Configuration Descriptor */ );   As you can see we have this variable called pot_level. This variable is the one that has the “sensed” voltage drop of the potentiometer. In this case it is a simulated value. Every time a device requests for the voltage value, pot_level­ is increased by 1. We are also defining the potentiometer service with the macro BT_GATT_SERVICE_DEFINE. The name of our service is “pot” and we are defining the properties, permissions and the read callback for our service. We have finished with these two files and there is no need to modify them again. These files are used for both server and client. Finally we need to include the new folder´s to the project path. Once again, note that if you are using the examples, this step is not needed. To do this we have to open the project properties, and go to Settings of the C/C++ Build option. In the MCU C Compiler, we have to select the Includes folder and add the previous two paths. Figure 3. Path including We should be able the compile our service files without problem. Let’s start the server code.   Server: We already have out service declared and now we have to create two new files that are going to handle the connections. We will be basing this part in the peripheral_ht SDK example. The new files should be allocated in the following route: ${ProjName}/source. These files are potentiometer.c and potentiometer.h. In the header file we will declare our potentiometer task, that is going to be our main task: void potentiometer_task(void *pvParameters);   In the source file we will need to include the pot.h and potentiometer.h files and declare some new information. Use peripheral_ht.c as a base. We have to create and define the advertising and response packets, the connection callbacks and functions related to the connection. We are going to start declaring the connection variable: static struct bt_conn *default_conn;   The advertising packet will have the following structure: static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID128_SOME, POTENTIOMETER_SERVICE_UUID), };   We are creating an advertising packet that is general discoverable and Bluetooth basic rate/enhanced data rate is not supported, we are also including the potentiometer service UUID. The response packet will have the following structure: #define DEVICE_NAME "pot" #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) static const struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), };   The response packet only has the device name, which in this case is pot. static void connected(struct bt_conn *conn, uint8_t error) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (error) { PRINTF("Failed to connect to %s (err %u)\n\r", addr, error); } else { error = bt_conn_get_info(conn, &info); /* Getting connection info */ if(error) { PRINTF("Failed to get info\n\r"); return; } default_conn = conn; PRINTF("Connected to: %s\n\r", addr); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { PRINTF("Disconnected (reason 0x%02x/n", reason); if(default_conn) { bt_conn_unref(default_conn); default_conn = NULL; } } static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, };   Let’s keep up with the code. The connected function is going to run when a device is successfully connected to our server, and the disconnected function is going to restore the connection to NULL every time a device gets disconnected. static void bt_ready(int error) { char addr_s[BT_ADDR_LE_STR_LEN]; bt_addr_le_t addr = {0}; size_t count = 1; if (error) { PRINTF("Bluetooth init failed (error %d)\n", error); return; } PRINTF("Bluetooth initialized\n\r"); bt_conn_cb_register(&conn_callbacks); /*Start advertising*/ error = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (error) { PRINTF("Advertising failed to start (error %d)\n", error); return; } bt_id_get(&addr, &count); bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s)); PRINTF("Advertising as %s\n\r", addr_s); } void potentiometer_task(void *pvParameters) { int error, result; PRINTF("BLE POTENITOMETER [Server] Custom Profile Running...\n\r"); error = bt_enable(bt_ready); if(error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } while(1) { } }   In the main task, we are going to initialize the BLE components, and then bt_ready is going to run. If the BLE initialization was correct, the advertising will start using the previous advertising and response packets. We will use xTaskCreate to create our new potentiometer task in the main file. Notice that this is the only task created in the main file. The server is done, we can get connected to it and start to receive the potentiometer voltage. But as we want two boards connected working in each role, we will also need to modify the code for the client. In the app_config.h file there should be the following macro defined. #define CONFIG_BT_PERIPHERAL 1​   Client: To create the Client part, we will be basing on the central_ht SDK example. We need to create a new file to handle the connections and initializations like we did before in the server. This file is going to have some similar functions to potentiometer.c. I will be using the same name for simplicity purposes. We need to import the potentiometer service by adding the the pot.c and pot.h files we did on previous steps. First thing to do is create the new variables. static struct bt_conn *default_conn; static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0); static struct bt_gatt_discover_params discover_params; static struct bt_gatt_read_params read_params; static uint8_t connection_success; static uint8_t data_received;   Using central_h.c as reference, we need to modify some functions as it follows: static uint8_t read_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) { if ((data != NULL) && (err == 0)) { data_received = *(uint8_t*)data; PRINTF("Read successful - Pot voltage level: %d\n\r", data_received); } else { PRINTF("Read Failed\n\r"); } return BT_GATT_ITER_STOP; } static int bt_get_pot_lvl(void) { return bt_gatt_read(default_conn, &read_params); } static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { int32_t err; if (!attr) { PRINTF("Discover complete, No attribute found \n\r"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (bt_uuid_cmp(discover_params.uuid, POTENTIOMETER_SERVICE) == 0) { /* Potentiometer service discovered */ /* Next, Potentiometer characteristic */ PRINTF("POT service UUID found: 0x"); for(int i = 0; i<sizeof(BT_UUID_128(POTENTIOMETER_SERVICE)->val) ; i += sizeof(uint16_t)) { PRINTF("%X", uuid.val[i]); PRINTF("%X", uuid.val[i + 1]); } PRINTF("\n\r"); memcpy(&uuid, POTENTIOMETER_CHARACTERISTIC, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 1; discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; err = bt_gatt_discover(conn, &discover_params); if (err) { PRINTF("Discover failed (err %d)\n\r", err); } } else if(bt_uuid_cmp(discover_params.uuid, POTENTIOMETER_CHARACTERISTIC) == 0) { PRINTF("POT characteristic UUID found: 0x"); for(int i = 0; i<sizeof(BT_UUID_128(POTENTIOMETER_CHARACTERISTIC)->val) ; i += sizeof(uint16_t)) { PRINTF("%X", uuid.val[i]); PRINTF("%X", uuid.val[i + 1]); } PRINTF("\n\n\r"); /* Read Potentiometer */ read_params.func = read_func; read_params.handle_count = 0; /* Selects the UUID characteristic handle */ read_params.by_uuid.start_handle = 0x0001; read_params.by_uuid.end_handle = 0xffff; read_params.by_uuid.uuid = &uuid.uuid; /* Potentiometer characteristic */ err = bt_gatt_read(conn, &read_params); if(err) { PRINTF("Read failed (err %d)\n\r", err); } else { connection_success = 1; } return BT_GATT_ITER_STOP; } return BT_GATT_ITER_STOP; }   The read_func function is going to be the callback for the read parameters. The bt_get_pot_level function is going to use the read parameters to read the potentiometer value. The discover_func function is going to find every advertising device in the advertising channel. In this function we are going to force the connection to the potentiometer service, so if there is one device advertising with the potentiometer service UUID, we will verify if it has the characteristic we are interested in. In this case the potentiometer charactersic, and if this device also has this characteristic, we are going to read the data. static void connected(struct bt_conn *conn, uint8_t conn_err) { char addr[BT_ADDR_LE_STR_LEN]; int32_t err; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (conn_err) { PRINTF("Failed to connect to %s (err %u)\n\r", addr, conn_err); bt_conn_unref(default_conn); default_conn = NULL; /* Restart scanning */ scan_start(); return; } PRINTF("Connected to peer: %s\n\r", addr); if (conn == default_conn) { memcpy(&uuid, POTENTIOMETER_SERVICE, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.func = discover_func; discover_params.start_handle = 0x0001; discover_params.end_handle = 0xffff; discover_params.type = BT_GATT_DISCOVER_PRIMARY; /* Start service discovery */ err = bt_gatt_discover(default_conn, &discover_params); if (err) { PRINTF("Discover failed(err %d)\n\r", err); } else { PRINTF("Starting service discovery\n\r"); } } } ​   In the device_scanned function we are going to create a connection with the server, so we need to compare the UUID we are scanning and check if there is a device with the potentiometer service UUID. static bool device_scanned(struct bt_data *data, void *user_data) { bt_addr_le_t *addr = user_data; struct bt_uuid_128 uuid_temp; int err; int i; char dev[BT_ADDR_LE_STR_LEN]; bool continueParse = true; /* return true to continue parsing or false to stop parsing */ switch (data->type) { case BT_DATA_UUID16_SOME: break; case BT_DATA_UUID16_ALL: break; case BT_DATA_UUID128_SOME: { if (data->data_len % sizeof(uint16_t) != 0U) { PRINTF("AD malformed\n\r"); return true; } uuid_temp.uuid.type = BT_UUID_TYPE_128; for(i = 0; i < data->data_len ; i += sizeof(uint32_t)) { uuid_temp.val[i] = data->data[i]; uuid_temp.val[i + 1] = data->data[i + 1]; uuid_temp.val[i + 2] = data->data[i + 2]; uuid_temp.val[i + 3] = data->data[i + 3]; } /* Search for the Potentiometer Service in the advertising data */ if ((bt_uuid_cmp(&uuid_temp.uuid, POTENTIOMETER_SERVICE) == 0)) { /* found the Potentiometer service - stop scanning */ err = bt_le_scan_stop(); if (err) { PRINTF("Stop LE scan failed (err %d)\n", err); break; } bt_addr_le_to_str(addr, dev, sizeof(dev)); PRINTF("Found device: %s\n\r", dev); /* Send connection request */ err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn); if (err) { PRINTF("Create connection failed (err %d)\n", err); scan_start(); } continueParse = false; break; } break; } /*CASE UUDI128_SOME*/ default: { break; } } return continueParse; }   The device_found stays very similar to the example, we are just deleting the PRINTF’s functions because we don’t want to see every device found, we are just interested in our server. static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { /* We're only interested in connectable events */ if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { bt_data_parse(ad, device_scanned, (void *)addr); } } ​   The scan_start and disconnected stays the same. static int scan_start(void) { struct bt_le_scan_param scan_param = { .type = BT_LE_SCAN_TYPE_PASSIVE, .options = BT_LE_SCAN_OPT_NONE, .interval = BT_GAP_SCAN_FAST_INTERVAL, .window = BT_GAP_SCAN_FAST_WINDOW, }; return bt_le_scan_start(&scan_param, device_found); } static void disconnected(struct bt_conn *conn, uint8_t reason) { PRINTF("Disconnected reason 0x%02x\n\r", reason); int32_t err; connection_success = 0; if (default_conn != conn) { return; } bt_conn_unref(default_conn); default_conn = NULL; /* Restart scanning */ err = scan_start(); if (err) { PRINTF("Scanning failed to start (err %d)\n\r", err); } else { PRINTF("Scanning started\n\r"); } }   The bt_ready is almost the same. static void bt_ready(int error) { if (error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } PRINTF("Bluetooth initialized\n\r"); bt_conn_cb_register(&conn_callbacks); /*Scan Starting*/ error = scan_start(); if(error) { PRINTF("Scanning failed to start (error %d)\n\r", error); return; } PRINTF("Scanning started\n\r"); }   The last thing we are going to modify is the potentiometer task. We are going to read the potentiometer value every 5 seconds. void potentiometer_task(void *pvParameters) { int error, result; PRINTF("BLE POTENITOMETER [Client] Custom Profile Running...\n\r"); error = bt_enable(bt_ready); if(error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } while(1) { vTaskDelay(pdMS_TO_TICKS(5000)); if(connection_success) { error = bt_get_pot_lvl(); } } }   Finally, we need to add some macros to enable some scanning and discover functions, please confirm you do have them defined in the preprocessor or another file like app_config.h : #define CONFIG_BT_OBSERVER 1 #define CONFIG_BT_CENTRAL 1 #define CONFIG_BT_GATT_CLIENT 1   Please take in mind that if there are other BT macros defined in the app_config.h file that weren’t mentioned in this article, the example may not run as expected. Additional modifications might be needed to make it work.   Testing To test this application we are going to use the following: 2 x RT1060 EVK (Client and Server) AW-CM358-uSD (88W8987) AW-AM457-uSD (IW416)   Take in mind that to run BT and BLE applications there might be some connections or reworking needed in your board and wireless module. For more information take a look to the Hardware Rework Guide for EdgeFast BT PAL document. It is important to take in mind the version of EVK that we will be using since there might be some differences in the supported modules. In this case, the test is with the A revision of the RT1060 EVK.   Figure 4.  Server and client application running   Figure 5. Terminal output of the server (IW416)   Figure 6. Terminal output of the client (88W8987)
View full article
       The article describes how to integrate 88W8997 PCIE to Linux 5.4.24_2.1.0 based on i.MX8MM-EVK platform, and how to solve issues encountered during the integration. [Contents] Chapter 1 Connections & environments Connections Environments Hardware devices Software M.2 NGFF KEY E interface on i.MX8MM-EVK Chapter 2 Preparation For Software        2.1 Cross Compile Toolchain        2.2 Demo Image for iMX8MM-EVK        2.3 L5.4.21_2.1.0 kernel source code        2.4 88W8997 PCIe Driver source code        2.5 uuu manufacturing Tool Chapter 3 Steps For Integration        2.1 Cross compiling L5.4.21_2.1.0 kernel source code Copying Image to Demo Image directory On windows 2.2 Cross compiling 88W8997 PCIe driver Copying mlan.ko & pcie8xxx.ko to windows directory Copying Firmware to windows to windows directory 2.3 Burning Linux Images to iMX8MM-EVK board        2.4 Copying .ko and firmware files to iMX8MM-EVK board via MobaXterm        2.5 Loading 88W8997 driver Chapter 4 Troubleshooting        4.1 PCIe card can’t be found via lspci command        4.2 Errors on MSI interrupt when using PCIe Switch AW-CM276MA (88W8997 Inside)  
View full article