max30102 sensor with NUS Service using zephyr

Hi all,

Could anyone share a code example for sending sensor data  over BLE using the NUS Service in Zephyr RTOS? I'm new to this field and struggling to get data from the MAX30102 sensor over BLE.
If you could provide any samples, I would greatly appreciate it.

Thank you,

Fernando

  • /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Nordic UART Bridge Service (NUS) sample
     */
    #include "uart_async_adapter.h"
    
    #include <zephyr/types.h>
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/uart.h>
    #include <zephyr/usb/usb_device.h>
    
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <soc.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/hci.h>
    
    #include <bluetooth/services/nus.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <zephyr/settings/settings.h>
    
    #include <stdio.h>
    
    #include <zephyr/logging/log.h>
    #include "max.h"
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include "max.h"
    #define SLEEP_TIME_MS 1000
    
    LOG_MODULE_REGISTER(Lesson4_Exercise3, LOG_LEVEL_INF);
    
    #define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
    #define PRIORITY 7
    
    #define DEVICE_NAME CONFIG_BT_DEVICE_NAME
    #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
    
    #define RUN_STATUS_LED DK_LED1
    #define RUN_LED_BLINK_INTERVAL 1000
    
    #define CON_STATUS_LED DK_LED2
    
    #define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
    #define KEY_PASSKEY_REJECT DK_BTN2_MSK
    
    #define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
    #define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME
    
    static K_SEM_DEFINE(ble_init_ok, 0, 1);
    
    static struct bt_conn *current_conn;
    static struct bt_conn *auth_conn;
    
    static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart));
    static struct k_work_delayable uart_work;
    
    
    /* STEP 6.2 - Declare the struct of the data item of the FIFOs */
    struct uart_data_t {
    	void *fifo_reserved;
    	uint8_t data[CONFIG_BT_NUS_UART_BUFFER_SIZE];
    	uint16_t len;
    };
    
    /* STEP 6.1 - Declare the FIFOs */
    static K_FIFO_DEFINE(fifo_uart_tx_data);
    static K_FIFO_DEFINE(fifo_uart_rx_data);
    
    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
    };
    
    static const struct bt_data sd[] = {
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
    };
    
    #if CONFIG_BT_NUS_UART_ASYNC_ADAPTER
    UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
    #else
    static const struct device *const async_adapter;
    #endif
    
    static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
    {
    	ARG_UNUSED(dev);
    
    	static size_t aborted_len;
    	struct uart_data_t *buf;
    	static uint8_t *aborted_buf;
    	static bool disable_req;
    
    	switch (evt->type) {
    	case UART_TX_DONE:
    		LOG_DBG("UART_TX_DONE");
    		if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) {
    			return;
    		}
    
    		if (aborted_buf) {
    			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
    					   data[0]);
    			aborted_buf = NULL;
    			aborted_len = 0;
    		} else {
    			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
    					   data[0]);
    		}
    
    		k_free(buf);
    
    		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
    		if (!buf) {
    			return;
    		}
    
    		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
    			LOG_WRN("Failed to send data over UART");
    		}
    
    		break;
    
    	case UART_RX_RDY:
    		LOG_DBG("UART_RX_RDY");
    		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data[0]);
    		buf->len += evt->data.rx.len;
    
    		if (disable_req) {
    			return;
    		}
    
    		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
    		    (evt->data.rx.buf[buf->len - 1] == '\r')) {
    			disable_req = true;
    			uart_rx_disable(uart);
    		}
    
    		break;
    
    	case UART_RX_DISABLED:
    		LOG_DBG("UART_RX_DISABLED");
    		disable_req = false;
    
    		buf = k_malloc(sizeof(*buf));
    		if (buf) {
    			buf->len = 0;
    		} else {
    			LOG_WRN("Not able to allocate UART receive buffer");
    			k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    			return;
    		}
    
    		uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
    
    		break;
    
    	case UART_RX_BUF_REQUEST:
    		LOG_DBG("UART_RX_BUF_REQUEST");
    		buf = k_malloc(sizeof(*buf));
    		if (buf) {
    			buf->len = 0;
    			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
    		} else {
    			LOG_WRN("Not able to allocate UART receive buffer");
    		}
    
    		break;
    
    	case UART_RX_BUF_RELEASED:
    		LOG_DBG("UART_RX_BUF_RELEASED");
    		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
    				   data[0]);
    
    		if (buf->len > 0) {
    			/* STEP 9.1 -  Push the data received from the UART peripheral into the fifo_uart_rx_data FIFO */
    			k_fifo_put(&fifo_uart_rx_data, buf);
    		} else {
    			k_free(buf);
    		}
    
    		break;
    
    	case UART_TX_ABORTED:
    		LOG_DBG("UART_TX_ABORTED");
    		if (!aborted_buf) {
    			aborted_buf = (uint8_t *)evt->data.tx.buf;
    		}
    
    		aborted_len += evt->data.tx.len;
    		buf = CONTAINER_OF((void *)aborted_buf, struct uart_data_t,
    				   data);
    
    		uart_tx(uart, &buf->data[aborted_len], buf->len - aborted_len, SYS_FOREVER_MS);
    
    		break;
    
    	default:
    		break;
    	}
    }
    
    static void uart_work_handler(struct k_work *item)
    {
    	struct uart_data_t *buf;
    
    	buf = k_malloc(sizeof(*buf));
    	if (buf) {
    		buf->len = 0;
    	} else {
    		LOG_WRN("Not able to allocate UART receive buffer");
    		k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    		return;
    	}
    
    	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
    }
    
    static bool uart_test_async_api(const struct device *dev)
    {
    	const struct uart_driver_api *api = (const struct uart_driver_api *)dev->api;
    
    	return (api->callback_set != NULL);
    }
    
    static int uart_init(void)
    {
    	int err;
    	int pos;
    	struct uart_data_t *rx;
    	struct uart_data_t *tx;
    
    	if (!device_is_ready(uart)) {
    		return -ENODEV;
    	}
    
    	if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) {
    		err = usb_enable(NULL);
    		if (err && (err != -EALREADY)) {
    			LOG_ERR("Failed to enable USB");
    			return err;
    		}
    	}
    
    	rx = k_malloc(sizeof(*rx));
    	if (rx) {
    		rx->len = 0;
    	} else {
    		return -ENOMEM;
    	}
    
    	k_work_init_delayable(&uart_work, uart_work_handler);
    
    	if (IS_ENABLED(CONFIG_BT_NUS_UART_ASYNC_ADAPTER) && !uart_test_async_api(uart)) {
    		/* Implement API adapter */
    		uart_async_adapter_init(async_adapter, uart);
    		uart = async_adapter;
    	}
    
    	err = uart_callback_set(uart, uart_cb, NULL);
    	if (err) {
    		LOG_ERR("Cannot initialize UART callback");
    		return err;
    	}
    
    	if (IS_ENABLED(CONFIG_UART_LINE_CTRL)) {
    		LOG_INF("Wait for DTR");
    		while (true) {
    			uint32_t dtr = 0;
    
    			uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
    			if (dtr) {
    				break;
    			}
    			/* Give CPU resources to low priority threads. */
    			k_sleep(K_MSEC(100));
    		}
    		LOG_INF("DTR set");
    		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DCD, 1);
    		if (err) {
    			LOG_WRN("Failed to set DCD, ret code %d", err);
    		}
    		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DSR, 1);
    		if (err) {
    			LOG_WRN("Failed to set DSR, ret code %d", err);
    		}
    	}
    
    	tx = k_malloc(sizeof(*tx));
    
    	if (tx) {
    		pos = snprintf(tx->data, sizeof(tx->data),
    			       "Starting Nordic UART service example\r\n");
    
    		if ((pos < 0) || (pos >= sizeof(tx->data))) {
    			k_free(tx);
    			LOG_ERR("snprintf returned %d", pos);
    			return -ENOMEM;
    		}
    
    		tx->len = pos;
    	} else {
    		return -ENOMEM;
    	}
    	// Send a welcome message over UART
    	err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    	if (err) {
    		LOG_ERR("Cannot display welcome message (err: %d)", err);
    		return err;
    	}
    	// Enable start receiving data over UART
    	return uart_rx_enable(uart, rx->data, sizeof(rx->data), 50);
    }
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if (err) {
    		LOG_ERR("Connection failed (err %u)", err);
    		return;
    	}
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	LOG_INF("Connected %s", addr);
    
    	current_conn = bt_conn_ref(conn);
    
    	dk_set_led_on(CON_STATUS_LED);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Disconnected: %s (reason %u)", addr, reason);
    
    	if (auth_conn) {
    		bt_conn_unref(auth_conn);
    		auth_conn = NULL;
    	}
    
    	if (current_conn) {
    		bt_conn_unref(current_conn);
    		current_conn = NULL;
    		dk_set_led_off(CON_STATUS_LED);
    	}
    }
    
    #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
    static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (!err) {
    		LOG_INF("Security changed: %s level %u", addr, level);
    	} else {
    		LOG_WRN("Security failed: %s level %u err %d", addr, level, err);
    	}
    }
    #endif
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
    	.security_changed = security_changed,
    #endif
    };
    
    #if defined(CONFIG_BT_NUS_SECURITY_ENABLED)
    static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Passkey for %s: %06u", addr, passkey);
    }
    
    static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	auth_conn = bt_conn_ref(conn);
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Passkey for %s: %06u", addr, passkey);
    	LOG_INF("Press Button 1 to confirm, Button 2 to reject.");
    }
    
    static void auth_cancel(struct bt_conn *conn)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Pairing cancelled: %s", addr);
    }
    
    static void pairing_complete(struct bt_conn *conn, bool bonded)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
    }
    
    static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Pairing failed conn: %s, reason %d", addr, reason);
    }
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	.passkey_display = auth_passkey_display,
    	.passkey_confirm = auth_passkey_confirm,
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks = { .pairing_complete =
    									pairing_complete,
    								.pairing_failed = pairing_failed };
    #else
    static struct bt_conn_auth_cb conn_auth_callbacks;
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks;
    #endif
    
    static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data, uint16_t len)
    {
    	int err;
    	char addr[BT_ADDR_LE_STR_LEN] = { 0 };
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, ARRAY_SIZE(addr));
    
    	LOG_INF("Received data from: %s", addr);
    
    	for (uint16_t pos = 0; pos != len;) {
    		struct uart_data_t *tx = k_malloc(sizeof(*tx));
    
    		if (!tx) {
    			LOG_WRN("Not able to allocate UART send data buffer");
    			return;
    		}
    
    		/* Keep the last byte of TX buffer for potential LF char. */
    		size_t tx_data_size = sizeof(tx->data) - 1;
    
    		if ((len - pos) > tx_data_size) {
    			tx->len = tx_data_size;
    		} else {
    			tx->len = (len - pos);
    		}
    
    		memcpy(tx->data, &data[pos], tx->len);
    
    		pos += tx->len;
    
    		/* Append the LF character when the CR character triggered
    		 * transmission from the peer.
    		 */
    		if ((pos == len) && (data[len - 1] == '\r')) {
    			tx->data[tx->len] = '\n';
    			tx->len++;
    		}
    		/* STEP 8.3 - Forward the data received over Bluetooth LE to the UART peripheral */
    		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    		if (err) {
    			k_fifo_put(&fifo_uart_tx_data, tx);
    		}
    	}
    }
    /* STEP 8.1 - Create a variable of type bt_nus_cb and initialize it */
    static struct bt_nus_cb nus_cb = {
    	.received = bt_receive_cb,
    };
    
    void error(void)
    {
    	dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK);
    
    	while (true) {
    		/* Spin for ever */
    		k_sleep(K_MSEC(1000));
    	}
    }
    
    #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
    static void num_comp_reply(bool accept)
    {
    	if (accept) {
    		bt_conn_auth_passkey_confirm(auth_conn);
    		LOG_INF("Numeric Match, conn %p", (void *)auth_conn);
    	} else {
    		bt_conn_auth_cancel(auth_conn);
    		LOG_INF("Numeric Reject, conn %p", (void *)auth_conn);
    	}
    
    	bt_conn_unref(auth_conn);
    	auth_conn = NULL;
    }
    
    void button_changed(uint32_t button_state, uint32_t has_changed)
    {
    	uint32_t buttons = button_state & has_changed;
    
    	if (auth_conn) {
    		if (buttons & KEY_PASSKEY_ACCEPT) {
    			num_comp_reply(true);
    		}
    
    		if (buttons & KEY_PASSKEY_REJECT) {
    			num_comp_reply(false);
    		}
    	}
    }
    #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
    
    static void configure_gpio(void)
    {
    	int err;
    
    #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
    	err = dk_buttons_init(button_changed);
    	if (err) {
    		LOG_ERR("Cannot init buttons (err: %d)", err);
    	}
    #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */
    
    	err = dk_leds_init();
    	if (err) {
    		LOG_ERR("Cannot init LEDs (err: %d)", err);
    	}
    }
    static void bt_ready(int err)
    {
        if (err) {
            LOG_ERR("Bluetooth init failed (err %d)", err);
            return;
        }
        LOG_INF("Bluetooth initialized");
        err = bt_nus_init(&nus_cb);
        if (err) {
            LOG_ERR("Failed to init NUS (err: %d)", err);
            return;
        }
        err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
        if (err) {
            LOG_ERR("Advertising failed to start (err %d)", err);
            return;
        }
        LOG_INF("Advertising successfully started");
        k_sem_give(&ble_init_ok);
    }
    
    void max30102_thread(void)
    {
        // Initialize the MAX30102 sensor
        int ret = max_init();
        if (ret != 0) {
            LOG_ERR("Failed to initialize MAX30102 sensor");
            return;
        }
        
        while (1) {
            // Read data from the MAX30102 sensor
            uint32_t red, ir;
            ret = max_read_fifo(&red, &ir);
            if (ret != 0) {
                LOG_ERR("Failed to read from MAX30102 sensor");
                continue;
            }
    
            // Send the sensor data over NUS
            char sensor_data[32];
            snprintf(sensor_data, sizeof(sensor_data), "RED: %u, IR: %u\n", red, ir);
            bt_nus_send(current_conn, sensor_data, strlen(sensor_data));
            
            // Delay before the next read
            k_sleep(K_MSEC(SLEEP_TIME_MS));
        }
    }
    
    int main(void)
    {   
      
    	
    	int blink_status = 0;
    	int err = 0;
    
    	configure_gpio();
    	/* STEP 7 - Initialize the UART Peripheral  */
    	err = uart_init();
    	if (err) {
    		error();
    	}
    
    	if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
    		err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    		if (err) {
    			LOG_ERR("Failed to register authorization callbacks.\n");
    			return -1;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			LOG_ERR("Failed to register authorization info callbacks.\n");
    			return -1;
    		}
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		error();
    	}
    
    	LOG_INF("Bluetooth initialized");
    
    	k_sem_give(&ble_init_ok);
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    	/* STEP 8.2 - Pass your application callback function to the NUS service */
    	err = bt_nus_init(&nus_cb);
    	if (err) {
    		LOG_ERR("Failed to initialize UART service (err: %d)", err);
    		return -1;
    	}
    
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	if (err) {
    		LOG_ERR("Advertising failed to start (err %d)", err);
    		return -1;
    	}
    
    	for (;;) {
    		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    	}
    }
    
    
    /* STEP 9.3 - Define the thread function  */
    void ble_write_thread(void)
    {
    	/* Don't go any further until BLE is initialized */
    	k_sem_take(&ble_init_ok, K_FOREVER);
    
    	for (;;) {
    
    		
    		/* Wait indefinitely for data from the UART peripheral */
    		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data, K_FOREVER);
    		/* Send data over Bluetooth LE to remote device(s) */
    		if (bt_nus_send(NULL, buf->data, buf->len)) {
    			LOG_WRN("Failed to send data over BLE connection");
    		}
    
    		k_free(buf);
    	}
    }
    /* STEP 9.2 - Create a dedicated thread for sending the data over Bluetooth LE. */
    K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);
    

  • Hi Fernando,

    Have you checked that the sensor data you have here is good, and if bt_nus_send returns any error? I am talking about the code between line 594 and 597.

    Hieu


    Please be informed that due to a short holiday, there will be some delays in our responses in the coming days. Our apologies for the inconvenience.

  • Hi Hieu,

    Thank you for your reply

    No there is no error showing its  "Starting Nordic UART service example"  and I can connect the peripheral through the nrf connect mobile app.
    But it I could not get the sensor data here my max.c and max.h file
    Please help for get the sensor data thank you again.

    Best regards,
    Madusha Fernando

    #ifndef MAX_H
    #define MAX_H
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/sys/printk.h>
    
    /* Device-specific register addresses and settings */
    #define MAX30102_ADDRESS     0x57
    #define INT_ENABLE_1         0xC0
    #define INT_ENABLE_2         0x00
    #define FIFO_WR_PTR          0x00
    #define OVERFLOW_CTR         0x00
    #define FIFO_RD_PTR          0x00        
    #define FIFO_CONF            0x4F
    #define SPO2_CONF            0x27
    #define MODE_CONF            0x40
    #define INT_STATUS_1         0x00
    #define INT_STATUS_2         0x01
    #define MAX30102_REG_FIFO_DATA  0x07 
    #define MAX30102_REG_LED1_PA 0x0C
    #define MAX30102_REG_LED2_PA 0x0D
    #define MAX30102_REG_MODE_CONFIGURATION 0x09
    #define MAX30102_RESET 0x40
    
    /* Node identifier for the sensor */
    #define I2C_NODE DT_NODELABEL(mysensor)
    
    /* Function prototypes */
    int max30102_init(const struct device *dev);
    int max30102_read_fifo(const struct device *dev, uint32_t *red_led, uint32_t *ir_led);
    
    int ble_init(void);
    
    struct sensor_data_t {
        uint32_t red_led;
        uint32_t ir_led;
    } __packed;
    
    #endif /* MAX_H */
    



    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/sys/printk.h>
    
    #include "max.h"
    
    /* Define a variable to hold the NUS instance */
    static struct bt_nus_cb nus_cb;
    
    /* Define a variable to hold BLE data */
    static struct ble_data_t ble_data;
    
    /* Callback function to handle BLE data received event */
    static ssize_t ble_data_received(struct bt_conn *conn, const struct bt_gatt_attr *attr,
    				  const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
    {
    	/* Handle received data if needed */
    	return len;
    }
    
    /* BLE initialization function */
    int ble_init(void)
    {
    	int err;
    
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return err;
    	}
    
    	printk("Bluetooth initialized\n");
    
    	bt_nus_init(&nus_cb);
    
    	/* Register callback for data received event */
    	nus_cb.received = ble_data_received;
    
    	return 0;
    }
    
    /* Initialize the MAX30102 sensor */
    int max30102_init(const struct device *dev)
    {
        int ret;
        
        if (!device_is_ready(dev)) {
            printk("I2C bus %s is not ready!\n", dev->name);
            return -1;
        }
    
        uint8_t config[4] = {MAX30102_RESET, MAX30102_REG_MODE_CONFIGURATION, MODE_CONF, 0x40};
        ret = i2c_write(dev, config, sizeof(config), MAX30102_ADDRESS);
        if (ret != 0) {
            printk("Failed to write to I2C device address %x at Reg. %x \n", MAX30102_ADDRESS, config[0]);
            return -1;
        }
    
        k_msleep(100);
    
        uint8_t setup_registers[] = {
            INT_ENABLE_1, 0xC0,
            INT_ENABLE_2, 0x00,
            FIFO_WR_PTR, 0x00,
            OVERFLOW_CTR, 0x00,
            FIFO_RD_PTR, 0x00,
            FIFO_CONF, 0x5F,
            SPO2_CONF, 0x27,
            MAX30102_REG_LED1_PA, 0x1F,
            MAX30102_REG_LED2_PA, 0x1F,
            MAX30102_REG_MODE_CONFIGURATION, 0x03
        };
    
        ret = i2c_write(dev, setup_registers, sizeof(setup_registers), MAX30102_ADDRESS);
        if (ret != 0) {
            printk("Failed to write setup registers to MAX30102\n");
            return -1;
        }
    
        /* Initialize BLE */
        ble_init();
    
        return 0;
    }
    
    /* Read sensor data from MAX30102 sensor and transmit over BLE */
    int max30102_read_fifo(const struct device *dev, uint32_t *red_led, uint32_t *ir_led)
    {
        int ret;
        uint8_t data_array[6];
    
        ret = i2c_burst_read(dev, MAX30102_ADDRESS, MAX30102_REG_FIFO_DATA, data_array, sizeof(data_array));
        if (ret != 0) {
            printk("Failed to read FIFO data from I2C device address %x\n", MAX30102_ADDRESS);
            return -1;
        }
    
        *red_led = (data_array[0] << 16) | (data_array[1] << 8) | data_array[2];
        *ir_led = (data_array[3] << 16) | (data_array[4] << 8) | data_array[5];
    
        /* Populate BLE data */
        ble_data.red_led = *red_led;
        ble_data.ir_led = *ir_led;
    
        /* Transmit BLE data using NUS */
        bt_nus_send(NULL, &ble_data, sizeof(ble_data));
    
        return 0;
    }
    


  • Hi Fernando,

    Which sensor you are using and how you are connecting to the hardware?

    How does your overlay file look like. Also indicate about the prj.conf.

    I see in your main file you are calling "max_init()", but I don't see it in your "max.c" file.

    Can you send your minimal project, that as you have said would compile. Also indicate details about your sensor and the connections.

    Mention the NCS version and the DK / board that you are using.

    Regards,

Related