1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

micro:bit v1にてnRF Connect SDKでBLE Peripheral

Last updated at Posted at 2024-09-21

micro:bit v1にてnRF Connect SDKでBLE Peripheral

概要

nRF Connect SDKのBoard taget:bbc_microbitのサンプルのpongで、片方がCentalもう一方がPeripheralになるBLE通信してるっぽいので、それを参考に、Peripheralを簡単実装して、スマホからnRF Connect for Mobileアプリで、キャラクタリスティクスの読み書きをしてみる。

動機

  • たしか、v1.5がうちに4つ、v2.2が1つあったハズ...

    • nRF Connect SDKにボード設定(bbc_microbit)がある
      • hello_worldサンプルが実行・デバッグできる。
      • bbc_microbit用のサンプルがある
      • pongで、2台のmicrobitで対戦ゲームができるらしい => 実際できた
  • センサーでも読みだして、お知らせするようなBLEデバイス(Peripheral)でも、できるんでは?

環境

  • micro:bit V1.5

    • nRF51822 (FLASH 256KB/RAM16KB) ... メモリがきつい。。 nrf51822はRAM32KBのもあるのだが、micro:bit v1では、16KB
  • nRF Connect SDK v2.4.3

    • 最新v2.7.0でビルドしたら、RAMに はまらなかったような。
    • ただのBLE使うんだったら、v2.4.xあたりで大丈夫なはず。
  • VSCode

    • Serial Monitorを入れて、接続して、printkの出力を確認
    • cortex-debugで、pyocdで、デバッグもできるぞ (nRF Connect SDKは通常jlinkを使用)
  • スマホアプリ nRF Connect for Mobile

    • 動作確認用 Connectして、READ↓ / WRITE↑ する

動作

  • 1秒ごとにカウンターが+1され、printk で出力される
  • セントラルと接続時
    • セントラルからREADされると、カウンターの値を返す。
    • セントラルからWRITEされると、カウンターの値を更新する

コード

  • prog.confは、pongからそのまま流用

    • ※ちなみにCONFIG_BT_CENTRAL=nにすれば、FLASHもRAMもうちょっと空きができます。
    prj.conf
    CONFIG_ISR_STACK_SIZE=1024
    CONFIG_BT=y
    CONFIG_BT_CENTRAL=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_DEVICE_NAME="MICROBITv1"
    CONFIG_GPIO=y
    CONFIG_DISPLAY=y
    CONFIG_MICROBIT_DISPLAY=y
    CONFIG_PWM=y
    CONFIG_PWM_NRF5_SW=y
    
    # This feature isn't needed as this sample is intended to be used
    # between zephyr devices only.
    CONFIG_BT_GATT_CACHING=n
    

  • src/main.c

    src/main.c
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/device.h>
    #include <string.h>
    #include <zephyr/drivers/pwm.h>
    #include <zephyr/debug/stack.h>
    
    #include <zephyr/display/mb_display.h>
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/hci.h>
    
    /*
      - 動作
    	- 1秒ごとにカウンターが+1され、printk で出力される
        - セントラルと接続時
    		- セントラルからREADされると、カウンターの値を返す。
    		- セントラルからWRITEされると、カウンターの値を更新する
    */
    uint32_t count = 0;
    
    //----------------------------------------------------------------------
    //サービスとキャラクタリスティクスのUUID
    /** @brief Service UUID of Example Custom Service **/
    // 1605b267-ca22-4f4e-b7ea-0955ad54ca00
    #define BT_UUID_EXAMPLE_SERVICE_VAL \
    	BT_UUID_128_ENCODE(0x1605b267, 0xca22, 0x4f4e, 0xb7ea, 0x0955ad54ca00)
    
    /** @brief Characteristic UUID of EXAMPLE - Read/Write **/
    // ebbff71b-8a65-4596-be37-d845e2e7667e
    #define BT_UUID_EXAMPLE_CHAR_VAL \
    	BT_UUID_128_ENCODE(0xebbff71b, 0x8a65, 0x4596, 0xbe37, 0xd845e2e7667e)
    
    #define BT_UUID_EXAMPLE_SERVICE	BT_UUID_DECLARE_128(BT_UUID_EXAMPLE_SERVICE_VAL)
    #define BT_UUID_EXAMPLE_CHAR	BT_UUID_DECLARE_128(BT_UUID_EXAMPLE_CHAR_VAL)
    #define EXAMPLE_CHAR_NAME	"ExampleChar"
    //セントラルからREADされたときに呼ばれる関数
    static ssize_t read_EXAMPLE(struct bt_conn* conn,
    	const struct bt_gatt_attr* attr,
    	void* buf,
    	uint16_t len,
    	uint16_t offset)
    {
    	uint8_t buffer[4];
    	uint16_t buffer_len;
    	printk("%s\n", __FUNCTION__);
    
    	buffer_len = 4;
    	buffer[0] = (uint8_t)(count >> 24);
    	buffer[1] = (uint8_t)(count >> 16);
    	buffer[2] = (uint8_t)(count >> 8);
    	buffer[3] = (uint8_t)count;
    	return bt_gatt_attr_read(conn, attr, buf, len, offset,
    		buffer,
    		buffer_len);
    }
    //セントラルからWRITEされたときに呼ばれる関数
    static ssize_t write_EXAMPLE(struct bt_conn* conn,
    	const struct bt_gatt_attr* attr,
    	const void* buf,
    	uint16_t len,
    	uint16_t offset,
    	uint8_t flags)
    {
    	const char* const buffer = buf;
    	ARG_UNUSED(conn);	//avoid warning
    	printk("%s\n", __FUNCTION__);
    	uint32_t value = 0;
    	for (int i = 0; i < len; i++)
    	{
    		value = (value << 8) + buffer[i];
    		printk("%02x ", buffer[i]);
    	}
    	printk("\n");
    	count = value;
    
    	return len;
    }
    
    //こんな感じで定義する
    /* EXAMPLE BLE Service Declaration */
    BT_GATT_SERVICE_DEFINE(EXAMPLE_svc,
    	BT_GATT_PRIMARY_SERVICE(BT_UUID_EXAMPLE_SERVICE),
    	// Read/Write
    	BT_GATT_CHARACTERISTIC(BT_UUID_EXAMPLE_CHAR,
    		BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
    		BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
    		read_EXAMPLE, write_EXAMPLE, NULL),
    	BT_GATT_CUD(EXAMPLE_CHAR_NAME, BT_GATT_PERM_READ),
    );
    
    //----------------------------------------------------------------------
    //セントラルと接続したら呼ばれる関数
    static void connected(struct bt_conn* conn, uint8_t err)
    {
    	if (err) {
    		printk("Connection failed (err %u)\n", err);
    		return;
    	}
    	printk("Connected\n");
    }
    //セントラルから切断したら呼ばれる関数
    static void disconnected(struct bt_conn* conn, uint8_t reason)
    {
    	printk("Disconnected (reason %u)\n", reason);
    }
    //こんな感じで設定する
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    };
    
    //----------------------------------------------------------------------
    // アドバタイズ
    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_ALL, BT_UUID_EXAMPLE_SERVICE_VAL),
    };
    static const struct bt_data sd[] = {
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_EXAMPLE_SERVICE_VAL),
    };
    
    //----------------------------------------------------------------------
    int main(void)
    {
    	int err;
    	err = bt_enable(NULL);
    	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    	while (1)
    	{
    		printk("%08x\n", count++);
    		k_msleep(1000);
    	}
    	return 0;
    }
    

その他

  • UUID


  • 使用メモリ

    • -Os にてビルド => RAM: 16044 / 16384
      [246/246] Linking C executable zephyr\zephyr.elf
      Memory region         Used Size  Region Size  %age Used
                 FLASH:      127492 B       256 KB     48.63%
                   RAM:       16044 B        16 KB     97.92%
              IDT_LIST:          0 GB         2 KB      0.00%
      
    • -O2 にてビルド => RAM: 16068 / 16384
      [246/246] Linking C executable zephyr\zephyr.elf
      Memory region         Used Size  Region Size  %age Used
                 FLASH:      138968 B       256 KB     53.01%
                   RAM:       16068 B        16 KB     98.07%
              IDT_LIST:          0 GB         2 KB      0.00%
      
    • -Og にてビルド => RAM: 16356 / 16384
      [247/247] Linking C executable zephyr\zephyr.elf
      Memory region         Used Size  Region Size  %age Used
                 FLASH:      140080 B       256 KB     53.44%
                   RAM:       16356 B        16 KB     99.83%
              IDT_LIST:          0 GB         2 KB      0.00%
      

  • cortex-debugでの設定

    • launch.json - デバッグから、Create launch.jsonで。
      launch.json
       {
       	// Use IntelliSense to learn about possible attributes.
       	// Hover to view descriptions of existing attributes.
       	// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
       	"version": "0.2.0",
       	"configurations": [
       		{
       			"name": "Cortex Debug",
       			"cwd": "${workspaceFolder}",
       			"executable": "./build/zephyr/zephyr.elf", //実行ファイルを指定
       			"request": "launch",
       			"type": "cortex-debug",
       			"runToEntryPoint": "main",
       			"servertype": "pyocd",   //pyocd
       		}
       	]
       }
      

    • settings.json - CTRL+,で設定開く. ツールのパスと、プリフィックスを指定
      settings.json
      {
          ...
      	"cortex-debug.armToolchainPath": "C:/ncs/toolchains/31f4403e35/opt/zephyr-sdk/arm-zephyr-eabi/bin",
      	"cortex-debug.armToolchainPrefix": "arm-zephyr-eabi",
      	"cortex-debug.pyocdPath": "C:/ncs/toolchains/31f4403e35/opt/bin/Scripts/pyocd"
      }
      
      
  • あとで電力測定してみたいのだが、Interfaceチップ(KL26)で電気食ってる気がする..

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?