編集履歴一覧に戻る
OYのアイコン画像

OY が 2026年03月04日19時10分52秒 に編集

初版

タイトルの変更

+

STM32C011F4P6でNFCタグを読む(M5Stack Unit RFID2)

タグの変更

+

CubeIDE

+

CubeMX

+

Nucleo開発ボード

+

STM32

+

秋月電子

+

スイッチサイエンス

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

セットアップや使用方法

ライセンスの変更

+

(CC0 1+) Creative Commons Public Domain Dedication version 1.0 or later

本文の変更

+

# はじめに [前回「STM32C011F4P6のLチカ(ST-LINK/V2, Nucleo開発ボードC031C6)」](https://elchika.com/article/78beeef0-7286-48ef-b663-8d8a5b7dc1e3/) の続きです。 今回は、STM32C011F4P6とM5Stack Unit RFID2を使って NTAG215の読み取り行います。 また電子工作初心者ですので、誤ったことを記載している可能性があります。 ご了承ください。 ## ブロック図 ![キャプションを入力できます](https://camo.elchika.com/9ccd68d38ffc68bb6615569b985aa5890f014b23/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f62636463343032622d656332392d346533332d613638302d613161616335313438393863/) ## 部品, 備品類 ### 部品 AE-STM32C011F4P6-DIP(秋月電子キット) Nucleo Board STM32C031C6 ブレッドボード(BB-801を使っています) ジャンパーワイヤー オス-オス ジャンパーワイヤー オス-メス ピンヘッダ 2pcs USB A-マイクロB(2.0) (Nucleoボード接続用) M5Stack用WS1850S搭載 RFID 2ユニット, 型番:M5STACK-U031-B(スイッチサイエンス) NTAG215(AmazonのYFFSFDC NFCタグ NTAG215 30枚) ### 備品, ソフト パソコン(Windows11を使いました) はんだごて、はんだ STM32CubeMX STM32CubeIDE NFC Tools(iPhone版を使いました) # 準備 ## Nucleoボードのはんだづけ ジャンパワイヤー接続用のピンヘッダをはんだづけします。 1.(図の左上)UART通信用のTX, RXにピンヘッダをつけます。 2.(図の右上)JP2のジャンパーピンを外し、TX, RXにピンヘッダーを挿入します。 3.(図の中央左)小型のブレッドボードで固定し、基板を裏返します。 4.(図の中央右)TX, RXをはんだ付けします。 5.(図の左下)ブレッドボードを外したらはんだ付け完了です。 ![キャプションを入力できます](https://camo.elchika.com/a8e645a8d9b09fb32f67b79224905b869af8c1e6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f35633031616539392d373232622d343238332d613737322d363434613531663032663435/) 基板裏面のSB23ジャンパーチップを外していない場合、 [前回](https://elchika.com/article/78beeef0-7286-48ef-b663-8d8a5b7dc1e3/#h_Nucleo-64%E9%96%8B%E7%99%BA%E3%83%9C%E3%83%BC%E3%83%89%20ST-LINK%2FV2-1%E3%81%AE%E6%BA%96%E5%82%99) を確認して外してください。 ## NTAGの書き込み (NFC Tools) iPhoneでの操作です。 「書く」→「レコードを追加」→「テキスト」→ ![キャプションを入力できます](https://camo.elchika.com/b7c9ba1321d6e807443c4c05b7f34ef1b722c144/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f36363266373432362d316230352d346363352d393661622d306638323965323131333364/) 「001」を入力 →「✓」→「書き込み/10バイト」→「スキャンの準備ができました」 → スマートフォンにNTAG215を近づけて書き込み ![キャプションを入力できます](https://camo.elchika.com/d6d285383309f2f2dc859b1862b86261d3e239c3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f30626362633233372d643764392d346265322d623735642d353232346331326163363431/) 必須ではありませんが余裕があれば、 同様に残り2枚のNTAGへ「002」, 「003」と書き込みます。 書き込んだNTAGは、「読む」をタップしてスキャンすることで、書き込んだ数字を確認できます。 ## Eclipse Terminalのインストール (STM32CubeIDEのシリアルモニター) STM32CubeIDEを起動。 上部メニューの「help」→「Eclipse Marketplace」→「find」に下記を入力し「enter」→「install」 https://marketplace.eclipse.org/content/tm-terminal ![キャプションを入力できます](https://camo.elchika.com/d5142571f0bc82bdb734644f31045848d930a185/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f33323936343665662d653032652d346461312d393630322d373938323931343466343965/) 「confirm」→「finish」 ![キャプションを入力できます](https://camo.elchika.com/94971d8eb01f025d7d771daf879ca221f2c8a3b4/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f36656130316639652d356466612d343962322d396335632d386163356139393966626464/) 「restart now」IDEが再起動する ![キャプションを入力できます](https://camo.elchika.com/a76a694db32cd2b143ea0e4c817fb65f1d0cb390/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f39656639323538632d623963352d343666302d393338392d396430316664346532356132/) STM32CubeIDE 上部メニューの「Window」 → 「Show View」 → 「Other」 検索窓に「terminal」と入力。 →「terminal」を選択後 →「open」 ![キャプションを入力できます](https://camo.elchika.com/5651adda92443c6c96d1fde1ac92220483bee576/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f32333833636462352d656164302d346165642d616466652d613662356463323636333138/) IDE右下にTerminalが表示 ![キャプションを入力できます](https://camo.elchika.com/2774eaa05327dd7a5c64477aca4de2bb6fe480dd/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f36383531613137622d316135382d346466382d626236312d376439363461623065316138/) Terminal内のメニューより、「Open a Terminal」アイコン → 表示ウインドウの「Choose terminal:Serial Terminal」を選択。 「Serial port」よりデバッガのCOM番号を選択を選択してください。 「OK」クリックでデバッガの情報がTerminalへ表示可能となります。 ![キャプションを入力できます](https://camo.elchika.com/88dfeefc25309e00aa2b249541e52d25ef881fd9/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f30623439343161632d356337302d343264302d613266632d666664623236623133666566/) Windows11でのCOM番号の調べ方は下記です。 「Windowsスタートボタン」を右クリック → 「デバイスマネージャー」→ 「ポート」のツリーを展開、デバッガのCOM番号をチェックしてください。 今回はCOM4です。 ![キャプションを入力できます](https://camo.elchika.com/99bec4e199e0fc6458729307ccfbefd0b3832788/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f39303634383034642d393262362d346632662d623636662d393538353139346634393631/) # 初期設定とプログラムのビルド ## ピン設定等の初期設定、コード生成 STM32CubeMXを起動します。 File → New Project をクリック。 ![キャプションを入力できます](https://camo.elchika.com/49debec6d59026e3e9b51393ff5809d73d9249b8/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f30333737333531382d653631392d343363622d396235352d383734663237653266326136/) ウインドウが表示されますので使用するマイコンを「Commercial Part Number」に入力します。(今回はSTM32C011F4P6) MCUs/MCUs Listから選択 → Start Project をクリック。 ![キャプションを入力できます](https://camo.elchika.com/36a4b1379ebdef9ed745aa5d05d586ec510c8399/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f64656630313763622d633536372d343830352d623563342d303735313333316239613339/) ピンの設定画面が表示されますので、ピン設定を行います。  PB7:I2C1_SCL  PC14:I2C1_SDA  PA0:USART1_TX  PA1:USART1_RX ![キャプションを入力できます](https://camo.elchika.com/983ed50b3c3fb7d43e95e5263adbe43f281019c6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f36656365616132622d323330392d343164362d383238642d366130376531663161346662/) 左メニューの「Connectivity」→「I2C1」→Modeを「I2C」へ変更します。 ![キャプションを入力できます](https://camo.elchika.com/4a16d8881762e880646c3569d1e707626a242185/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f37386234663930662d613135312d343161312d623865302d613465646566366261663834/) 左メニューの「Connectivity」→「USART1」→Modeを「Asynchronous」へ変更します。 ![キャプションを入力できます](https://camo.elchika.com/1170d3fb9fd57ae27c5df8ed05c662ebb4a9e30b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f63623966356165632d313935362d346632342d626438302d386565353634323565636266/) 「Project Manager」タブを押し、 「Project Name」にファイル名を記入 「Project Location」にて保存場所を選択 「Toolchain /IDE」をSTM32CubeIDEを選択 「GENERATE CODE」を押し、コード生成 ※プロジェクトネームに"()"を使うと、ビルド時にエラーが発生するため使わないでください。 ※プロジェクトロケーションは「CubeMX」直下としてください。  「CubeMX\プロジェクトネーム」とした場合、CubeIDEでエラーが発生します。 ![キャプションを入力できます](https://camo.elchika.com/831d6746ff8bb89a1a581fd0860e9baebaf8ad43/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f66656331343761312d623039372d343439322d616432622d333633313732663566653764/) ※画像は前回のものです。 コード生成後のウィンドウで、「Open Project」をクリックすると 自動でSTM32CubeIDEが起動し、インポートしてくれます。 ![キャプションを入力できます](https://camo.elchika.com/a9f9c9846d94fa53d4e001d4ba2af1cb58a00b38/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f38363932363563332d303230382d346162392d383766332d356465633761643435346532/) ※画像は前回のものです。 ## コード入力、ビルド STMCubeIDEのインポートしたプロジェクト内「Core」 → 「Src」 → 「main.c」にコードを記入します。 コードは下記範囲内にコピペしてください。 /* USER CODE BEGIN Header */  コードのコピペ /* USER CODE END 3 */ ```C:NTAG215 テキスト(3桁数字) 読み取り /* USER CODE BEGIN Header */ /* * STM32 Port of M5Stack RFID2 / MFRC522_I2C functionality * * This code is released under the Creative Commons Public Domain Dedication * version 1.0 or later (CC0 1+). * To the extent possible under law, the author has waived all copyright * and related or neighboring rights to this work. * You may copy, modify, distribute and perform the work, even for commercial * purposes, all without asking permission. * * ------------------------------------------------------------------------- * Third-party components and licenses * ------------------------------------------------------------------------- * * MFRC522_I2C Library (arozcan) * - Public Domain * - https://github.com/arozcan/MFRC522-I2C-Library * * M5Unified (M5Stack) * - MIT License * - Copyright (c) M5Stack * - https://github.com/m5stack/M5Unified * * M5Stack Unit RFID / RFID2 documentation * - No explicit license noted in documentation * - Uses official M5Stack libraries (MIT License) * - https://docs.m5stack.com/ja/arduino/projects/unit/unit_rfid * * MIT License portions are used in accordance with their terms. * */ /** ****************************************************************************** * @file : main.c * @brief : NTAG215 テキスト(3桁数字) 読み取り * STM32C011F4P6 + M5Stack RFID2 Unit (WS1850S) * * 配線: * RFID2 SCL → PB7 (I2C1_SCL) * RFID2 SDA → PC14 (I2C1_SDA) * RFID2 VCC → 3.3V / GND → GND * ST-LINK → PA0(USART1_TX) / PA1(USART1_RX) ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* stdio.h / string.h 不使用 */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ typedef enum { MFRC_OK = 0, MFRC_ERROR = 1, MFRC_TIMEOUT = 2 } MFRC_Status; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* I2C アドレス (7bit=0x28 → HAL用8bit) */ #define RFID2_ADDR (0x28 << 1) /* ---- WS1850S (MFRC522互換) レジスタ ---- */ #define REG_CommandReg 0x01 #define REG_ComIrqReg 0x04 #define REG_ErrorReg 0x06 #define REG_FIFODataReg 0x09 #define REG_FIFOLevelReg 0x0A #define REG_BitFramingReg 0x0D #define REG_CollReg 0x0E #define REG_ModeReg 0x11 #define REG_TxControlReg 0x14 #define REG_TxASKReg 0x15 #define REG_RFCfgReg 0x26 #define REG_CRCResultRegH 0x21 #define REG_CRCResultRegL 0x22 #define REG_TModeReg 0x2A #define REG_TPrescalerReg 0x2B #define REG_TReloadRegH 0x2C #define REG_TReloadRegL 0x2D #define REG_VersionReg 0x37 /* ---- コマンド ---- */ #define CMD_Idle 0x00 #define CMD_CalcCRC 0x03 #define CMD_Transceive 0x0C #define CMD_SoftReset 0x0F /* ---- NFC コマンド ---- */ #define PICC_REQA 0x26 #define PICC_CT 0x88 /* Cascade Tag (7バイトUID用) */ #define PICC_SEL_CL1 0x93 /* Cascade Level 1 */ #define PICC_SEL_CL2 0x95 /* Cascade Level 2 (NTAG215必須) */ #define PICC_HLTA 0x50 #define NTAG_READ 0x30 /* ErrorReg マスク * CollErr(bit3)はAntiColl時に正常で立つため除外 * bit0=ProtocolErr / bit1=ParityErr / bit4=BufferOvfl のみ判定 */ #define ERR_MASK_STRICT 0x13 #define ERR_MASK_ANTICOLL 0x13 /* HAL_Delay 固定待機時間 (ms) * IRQポーリング廃止・待機中はI2C通信なし → WS1850SがNFCに専念 */ #define WAIT_MS_REQA 15u #define WAIT_MS_ANTICOLL 25u #define WAIT_MS_SELECT 30u #define WAIT_MS_READ 30u #define WAIT_MS_CRC 5u /* デバッグ出力切り替え * 0 = 本番モード: 結果のみ出力 (STM32C011F4P6 FLASH節約) * 1 = デバッグモード: v9相当の詳細ログ出力 */ #define RFID_DEBUG 0 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* デバッグ出力マクロ * RFID_DEBUG=0 のとき空文に展開されFLASHを消費しない */ #if RFID_DEBUG #define DBG_STR(s) uart_str(s) #define DBG_HEX8(v) uart_hex8(v) #define DBG_CRLF() uart_crlf() #else #define DBG_STR(s) ((void)0) #define DBG_HEX8(v) ((void)0) #define DBG_CRLF() ((void)0) #endif /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ I2C_HandleTypeDef hi2c1; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */ static void uart_str(const char *s); static void uart_hex8(uint8_t v); static void uart_crlf(void); static void mfrc_write(uint8_t reg, uint8_t val); static uint8_t mfrc_read(uint8_t reg); static void mfrc_read_burst(uint8_t reg, uint8_t *buf, uint8_t len); static void mfrc_set_bits(uint8_t reg, uint8_t mask); static void mfrc_clear_bits(uint8_t reg, uint8_t mask); static void mfrc_fifo_flush(void); static void mfrc_init(void); static MFRC_Status mfrc_transceive(uint8_t *tx, uint8_t txLen, uint8_t *rx, uint8_t *rxLen, uint8_t errMask, uint32_t waitMs); static MFRC_Status mfrc_calc_crc(uint8_t *data, uint8_t len, uint8_t *crcLow, uint8_t *crcHigh); static MFRC_Status ntag_request(void); static MFRC_Status ntag_select_7byte(uint8_t *uid7); static MFRC_Status ntag_read_page(uint8_t page, uint8_t *data16); static uint8_t extract_3digit(uint8_t *raw, uint8_t len, char *out3); static void rfid_task(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* ================================================================ * UARTユーティリティ (stdio.h不使用) * ================================================================ */ static void uart_str(const char *s) { while (*s) HAL_UART_Transmit(&huart1, (uint8_t *)s++, 1, 100); } static void uart_hex8(uint8_t v) { const char h[] = "0123456789ABCDEF"; uint8_t buf[2]; buf[0] = (uint8_t)h[(v >> 4) & 0x0F]; buf[1] = (uint8_t)h[v & 0x0F]; HAL_UART_Transmit(&huart1, buf, 2, 100); } static void uart_crlf(void) { uart_str("\r\n"); } /* ================================================================ * WS1850S I2Cドライバ * ================================================================ */ static void mfrc_write(uint8_t reg, uint8_t val) { uint8_t buf[2] = { reg, val }; HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, buf, 2, 100); } static uint8_t mfrc_read(uint8_t reg) { uint8_t val = 0; HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, &reg, 1, 100); HAL_I2C_Master_Receive (&hi2c1, RFID2_ADDR, &val, 1, 100); return val; } static void mfrc_read_burst(uint8_t reg, uint8_t *buf, uint8_t len) { HAL_I2C_Master_Transmit(&hi2c1, RFID2_ADDR, &reg, 1, 100); HAL_I2C_Master_Receive (&hi2c1, RFID2_ADDR, buf, len, 100); } static void mfrc_set_bits(uint8_t reg, uint8_t mask) { mfrc_write(reg, mfrc_read(reg) | mask); } static void mfrc_clear_bits(uint8_t reg, uint8_t mask) { mfrc_write(reg, mfrc_read(reg) & ~mask); } /* FIFOを確実にクリアする */ static void mfrc_fifo_flush(void) { mfrc_write(REG_FIFOLevelReg, 0x80); HAL_Delay(1); } static void mfrc_init(void) { mfrc_write(REG_CommandReg, CMD_SoftReset); HAL_Delay(100); mfrc_write(REG_TModeReg, 0x80); mfrc_write(REG_TPrescalerReg, 0xA9); mfrc_write(REG_TReloadRegH, 0x03); mfrc_write(REG_TReloadRegL, 0xE8); mfrc_write(REG_TxASKReg, 0x40); mfrc_write(REG_ModeReg, 0x3D); mfrc_set_bits(REG_RFCfgReg, 0x70); /* アンテナゲイン最大 */ mfrc_set_bits(REG_TxControlReg, 0x03); /* アンテナON */ mfrc_write(REG_BitFramingReg, 0x00); /* BitFraming初期化 */ } /* ================================================================ * mfrc_transceive() * 【重要】送信シーケンスの正しい順序 : * ① CommandReg = CMD_Transceive (先にコマンドをセット) * ② BitFramingReg = 0x80 (後からStartSendをセット) * この順序でないとWS1850SがFIFO内容を正しく送信しない * ================================================================ */ static MFRC_Status mfrc_transceive(uint8_t *tx, uint8_t txLen, uint8_t *rx, uint8_t *rxLen, uint8_t errMask, uint32_t waitMs) { uint8_t i, n, err, irq; mfrc_fifo_flush(); mfrc_write(REG_ComIrqReg, 0x7F); mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_BitFramingReg, 0x00); for (i = 0; i < txLen; i++) mfrc_write(REG_FIFODataReg, tx[i]); mfrc_write(REG_CommandReg, CMD_Transceive); /* ①コマンド先 */ mfrc_write(REG_BitFramingReg, 0x80); /* ②StartSend後 */ HAL_Delay(waitMs); mfrc_write(REG_BitFramingReg, 0x00); irq = mfrc_read(REG_ComIrqReg); err = mfrc_read(REG_ErrorReg); n = mfrc_read(REG_FIFOLevelReg); DBG_STR(" I=0x"); DBG_HEX8(irq); DBG_STR(" E=0x"); DBG_HEX8(err); DBG_STR(" F="); DBG_HEX8(n); DBG_CRLF(); if (err & errMask) return MFRC_ERROR; if (n == 0) return MFRC_TIMEOUT; if (rx && rxLen) { uint8_t lim = (*rxLen < n) ? *rxLen : n; mfrc_read_burst(REG_FIFODataReg, rx, lim); *rxLen = lim; DBG_STR(" RX["); DBG_HEX8(lim); DBG_STR("]:"); for (i = 0; i < lim; i++) { DBG_STR(" "); DBG_HEX8(rx[i]); } DBG_CRLF(); } return MFRC_OK; } /* ================================================================ * mfrc_calc_crc() : ハードウェアCRC_A計算 * ================================================================ */ static MFRC_Status mfrc_calc_crc(uint8_t *data, uint8_t len, uint8_t *crcLow, uint8_t *crcHigh) { uint8_t i; mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_ComIrqReg, 0x04); mfrc_fifo_flush(); for (i = 0; i < len; i++) mfrc_write(REG_FIFODataReg, data[i]); mfrc_write(REG_CommandReg, CMD_CalcCRC); HAL_Delay(WAIT_MS_CRC); mfrc_write(REG_CommandReg, CMD_Idle); if (!(mfrc_read(REG_ComIrqReg) & 0x04)) return MFRC_TIMEOUT; *crcLow = mfrc_read(REG_CRCResultRegL); *crcHigh = mfrc_read(REG_CRCResultRegH); return MFRC_OK; } /* ================================================================ * ntag_request() : REQA 7bit送信 (専用実装) * 【重要】送信シーケンスの正しい順序: * ① CommandReg = CMD_Transceive * ② BitFramingReg = 0x87 (StartSend=bit7 + TxLastBits=7) * 送信後 BitFramingReg を必ず 0x00 にリセットする * * NTAG215のATQA正常値: 44 00 * ================================================================ */ static MFRC_Status ntag_request(void) { uint8_t cmd = PICC_REQA; uint8_t rx[2]; uint8_t n, err; mfrc_fifo_flush(); mfrc_write(REG_ComIrqReg, 0x7F); mfrc_write(REG_CommandReg, CMD_Idle); mfrc_write(REG_BitFramingReg, 0x00); mfrc_write(REG_FIFODataReg, cmd); mfrc_write(REG_CommandReg, CMD_Transceive); /* ①コマンド先 */ mfrc_write(REG_BitFramingReg, 0x87); /* ②StartSend+7bit後 */ HAL_Delay(WAIT_MS_REQA); mfrc_write(REG_BitFramingReg, 0x00); /* 必ずリセット */ err = mfrc_read(REG_ErrorReg); n = mfrc_read(REG_FIFOLevelReg); if (err & ERR_MASK_ANTICOLL) return MFRC_ERROR; if (n == 0) return MFRC_TIMEOUT; /* ATQAを読み捨て (カード存在確認のみ) */ mfrc_read_burst(REG_FIFODataReg, rx, (n > 2) ? 2 : n); return MFRC_OK; } /* ================================================================ * ntag_select_7byte() * ISO14443A Cascade Level 1+2 でNTAG215の7バイトUIDを取得 * * Cascade Level 1: * AntiColl (93 20) → rx=[CT(0x88) uid0 uid1 uid2 BCC] * Select (93 70 CT uid0 uid1 uid2 BCC CRC_L CRC_H) → SAK=0x04 * * Cascade Level 2: * AntiColl (95 20) → rx=[uid3 uid4 uid5 uid6 BCC] * Select (95 70 uid3 uid4 uid5 uid6 BCC CRC_L CRC_H) → SAK=0x00 * ================================================================ */ static MFRC_Status ntag_select_7byte(uint8_t *uid7) { uint8_t rx[5]; uint8_t rxLen; uint8_t tx[9]; uint8_t bcc; uint8_t crcL, crcH; MFRC_Status st; /* ---- Cascade Level 1 ---- */ mfrc_clear_bits(REG_CollReg, 0x80); /* ValuesAfterColl クリア */ /* CL1 AntiColl */ DBG_STR("CL1AC"); tx[0] = PICC_SEL_CL1; tx[1] = 0x20; rxLen = sizeof(rx); st = mfrc_transceive(tx, 2, rx, &rxLen, ERR_MASK_ANTICOLL, WAIT_MS_ANTICOLL); if (st != MFRC_OK || rxLen < 5 || rx[0] != PICC_CT) return MFRC_ERROR; bcc = rx[0] ^ rx[1] ^ rx[2] ^ rx[3]; /* BCC再計算 */ /* CL1 Select */ DBG_STR("CL1SEL"); tx[0] = PICC_SEL_CL1; tx[1] = 0x70; tx[2] = rx[0]; tx[3] = rx[1]; tx[4] = rx[2]; tx[5] = rx[3]; tx[6] = bcc; if (mfrc_calc_crc(tx, 7, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[7] = crcL; tx[8] = crcH; rxLen = 3; st = mfrc_transceive(tx, 9, rx, &rxLen, ERR_MASK_STRICT, WAIT_MS_SELECT); if (st != MFRC_OK) return MFRC_ERROR; /* SAK=0x04 → Level2へ続く */ uid7[0] = tx[3]; uid7[1] = tx[4]; uid7[2] = tx[5]; /* ---- Cascade Level 2 ---- */ mfrc_clear_bits(REG_CollReg, 0x80); /* CL2 AntiColl */ DBG_STR("CL2AC"); tx[0] = PICC_SEL_CL2; tx[1] = 0x20; rxLen = sizeof(rx); st = mfrc_transceive(tx, 2, rx, &rxLen, ERR_MASK_ANTICOLL, WAIT_MS_ANTICOLL); if (st != MFRC_OK || rxLen < 5) return MFRC_ERROR; bcc = rx[0] ^ rx[1] ^ rx[2] ^ rx[3]; /* BCC再計算 */ /* CL2 Select */ DBG_STR("CL2SEL"); tx[0] = PICC_SEL_CL2; tx[1] = 0x70; tx[2] = rx[0]; tx[3] = rx[1]; tx[4] = rx[2]; tx[5] = rx[3]; tx[6] = bcc; if (mfrc_calc_crc(tx, 7, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[7] = crcL; tx[8] = crcH; rxLen = 3; st = mfrc_transceive(tx, 9, rx, &rxLen, ERR_MASK_STRICT, WAIT_MS_SELECT); if (st != MFRC_OK) return MFRC_ERROR; /* SAK=0x00 → 選択完了 */ uid7[3] = tx[2]; uid7[4] = tx[3]; uid7[5] = tx[4]; uid7[6] = tx[5]; return MFRC_OK; } /* ================================================================ * ntag_read_page() : NTAGページ読み取り (4ページ=16byte返却) * ================================================================ */ static MFRC_Status ntag_read_page(uint8_t page, uint8_t *data16) { uint8_t tx[4]; uint8_t buf[18]; /* [v10修正] 16データ + CRC2バイト = 18バイト受信 */ uint8_t rxLen = sizeof(buf); uint8_t crcL, crcH; uint8_t i; MFRC_Status st; tx[0] = NTAG_READ; tx[1] = page; if (mfrc_calc_crc(tx, 2, &crcL, &crcH) != MFRC_OK) return MFRC_ERROR; tx[2] = crcL; tx[3] = crcH; st = mfrc_transceive(tx, 4, buf, &rxLen, ERR_MASK_STRICT, WAIT_MS_READ); if (st != MFRC_OK) return st; /* 先頭16バイトのみ呼び出し側へコピー (末尾2バイトはCRC) */ for (i = 0; i < 16 && i < rxLen; i++) data16[i] = buf[i]; return MFRC_OK; } /* ================================================================ * extract_3digit() : raw[len]からASCII数字3連続を検索 * ================================================================ */ static uint8_t extract_3digit(uint8_t *raw, uint8_t len, char *out3) { uint8_t i; for (i = 0; i + 2 < len; i++) { if (raw[i] >= '0' && raw[i] <= '9' && raw[i+1] >= '0' && raw[i+1] <= '9' && raw[i+2] >= '0' && raw[i+2] <= '9') { out3[0] = (char)raw[i]; out3[1] = (char)raw[i+1]; out3[2] = (char)raw[i+2]; out3[3] = '\0'; return 1; } } return 0; } /* ================================================================ * rfid_task() : メインループから定期呼び出し * * NTAG215 メモリマップ: * page0-1: UID(7byte) * page3 : Capability Container (0xE1 0x10 0x6D 0x00) * page4〜: NDEF TLV (03 [len] D1 01 ...) ← テキストデータ * ================================================================ */ static void rfid_task(void) { uint8_t uid[7], page_data[16], raw[48]; char digit3[4]; uint8_t p, b; /* カード検出 */ if (ntag_request() != MFRC_OK) return; /* 7バイトUID取得 (Cascade Level 1+2) */ if (ntag_select_7byte(uid) != MFRC_OK) { uart_str("SEL NG\r\n"); return; } /* UID表示 */ uart_str("UID:"); for (b = 0; b < 7; b++) { uart_hex8(uid[b]); uart_str(" "); } uart_crlf(); /* page4〜6 読み取り (3ページ × 16byte = 48byte) */ for (p = 0; p < 3; p++) { if (ntag_read_page(4 + p, page_data) != MFRC_OK) { uart_str("RD NG\r\n"); goto halt_card; } for (b = 0; b < 16; b++) raw[p * 16 + b] = page_data[b]; } /* 3桁数字抽出・表示 */ if (extract_3digit(raw, 48, digit3)) { uart_str(">>>"); uart_str(digit3); uart_str("<<<\r\n"); } else { uart_str("NO 3DIGIT\r\n"); } halt_card: /* HALT送信 */ { uint8_t halt_tx[4], dummy[2]; uint8_t dLen = 2, crcL, crcH; halt_tx[0] = PICC_HLTA; halt_tx[1] = 0x00; mfrc_calc_crc(halt_tx, 2, &crcL, &crcH); halt_tx[2] = crcL; halt_tx[3] = crcH; mfrc_transceive(halt_tx, 4, dummy, &dLen, ERR_MASK_ANTICOLL, WAIT_MS_SELECT); } HAL_Delay(1000); } /* USER CODE END 0 */ /* ================================================================ * main() * ================================================================ */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(500); uart_str("RFID v10\r\n"); mfrc_init(); uart_str("Ready\r\n"); /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { rfid_task(); HAL_Delay(300); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ ``` コードはClaude Sonnet4.6に書いてもらいました。 メニューの「Project」 → 「 Build All」 を押しコンパイル&ビルドします。 ![キャプションを入力できます](https://camo.elchika.com/7dafc4b9ade52fd9e977e5467e686377170c0a75/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f30383362653037392d656561642d346436642d613435322d366433613135613536316231/) 問題がなければ、下部のコンソール画面に「0errors, 0warnings」と表示されます。 ![キャプションを入力できます](https://camo.elchika.com/582b2f8bf2cc8348155425969cffc6c1f92796b6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f61313564646336352d666236352d343066332d386137362d343230613264663066333830/) ※前回の画像です。 # 配線、NTAG読み取り動作(デバッグ) ## マイコン等の配線 ### ST-LINK - マイコン(STM32C011F4P6) CN3  pin1(VDD検知) - pin4(VDD)  pin2(SWCLK) - pin19(PA14 SWCLK)  pin3(GND) - pin5(VSS)  pin4(SWDIO) - pin18(PA13 SWDIO)  pin5(NRST) - pin6(NRST)  TX - pin8(PA1 RX)  RX - pin7(PA0 TX) CN6  3V3(3.3V給電) - pin4(VDD) ### M5StackRFID2 - マイコン(STM32C011F4P6)  GND - pin5(VSS)  SDA - pin1(PB7)  SCL - pin2(PC14) M5StackRFID2 - STLINK  5V - 5V(5V給電) 分かりづらいのですが、参考図が下記です。 TXとRXは入れ替えて接続します。(デバッガTX - マイコンRX) ![キャプションを入力できます](https://camo.elchika.com/338921ee551d6d4def2355cea74b2fce62e8355b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f31343230646530392d666365622d343962382d613135662d643930633035636533333531/) ![キャプションを入力できます](https://camo.elchika.com/8ee323734a15a15b872531675af6dc760ffa85f2/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f34343366336237322d643230332d343865332d616239622d623261363065353538626564/) ## NTAG読み取り動作(デバッグ) NucleoボードとパソコンをUSBで接続します。(接続中の場合はそのまま) 「Run」 → 「Debug」をクリック デバッグ画面に切り替えを提案されるため、 「Switch」を押して了承する。 「▶」Resumeボタンをクリック NTAGをRFID2にかざします。 ![キャプションを入力できます](https://camo.elchika.com/cc0c4dd6dbf6750c25e42d6fd021d546cbf4da6d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f38633935343534652d303361322d343832652d623830662d653466316661623539613238/) ターミナルに下図表示がでます。  NTAG:001をかざすと001  NTAG:002をかざすと002 ![キャプションを入力できます](https://camo.elchika.com/0182064391bb57a81a2beee51b66a5d670b636ac/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f35653535393663642d316666322d346463622d623235302d3661386537373964393063662f38623434316432382d353930622d343737352d626665612d616134323332633137633339/) 次回以降はUSBを刺すだけで同様の動作となります。(マイコンにプログラムが書き込まれるため) ※IDEを再起動すると、ターミナルが切断されます。  その場合は下記を実施してください。   Open a Terminal   Serial Terminalを選択   デバッガのCOM番号を選択   OK # 参考リンク ## M5StackRFID2 Arduinoコード M5STACK, Unit RFID / RFID2 Arduino 使用チュートリアル https://docs.m5stack.com/ja/arduino/projects/unit/unit_rfid GitHub, m5stack/M5Unified https://github.com/m5stack/M5Unified GitHub, MFRC522-I2C-Library/MFRC522_I2C.h https://github.com/arozcan/MFRC522-I2C-Library/blob/master/MFRC522_I2C.h