2025年8月16日土曜日

NFCアンテナ(7)

 

ループコイルアンテナの等価回路定数を算出して考察してみる。


インダクタの等価回路はいくつか考案されているけど、まぁこれでやってみる。
で、どういう特性をもってこれらの素子の値を推定するかというと、ここ(https://sunday-engineer.jimdofree.com/2022/10/09/%E3%82%B3%E3%82%A4%E3%83%AB-1/)に書いてある。が、再度書くと、
1)Lは自己共振周波数より十分低い周波数でX/omegaとして推定。
2)CpはLと並列共振を作るので、共振周波数から推定。
3)Rpは共振周波数でのインピーダンスの上限を与えるもので、インピーダンスの上限(=共振時のインピーダンス)から推定。
4)Rsは線材による抵抗なので、低周波でのレジスタンスから推定。
今回、自己共振周波数までデータを採ってないから、2)3)については、並列にキャパシタを追加して共振周波数を下げた状態で推定する。
TXアンテナについて
んで、
L=1544nH
Cp=13.2pF(89.2-76)
Rs=1.46ohm
Rp=3741ohm
(76pF追加したときに共振周波数13.56MHzであり、Lは1544nHであることから算出) となる。
ちなみにシミュレーターをQucsatorにしないと、数式が面倒だったり、1ポートでなぜか計算してくれなかったりする。
RXアンテナも同様にして
L=678nH
Cp=12.2pF(203.2-191)
Rs=0.689ohm
Rp=1239ohm
となる。
で、こんな回路を組んで、、、ちなみにコイルの極性と結合係数を何となくいじって、
こうなる
実測データはこうなので、
まぁまぁ再現できている。
こっからどういじっていくかを考えないといけないけど、、、なんかこっからがしんどい

NFCアンテナ(6)というかOpenEMS

 

NFCアンテナのシミュレーションをしてみたくなったのでOpenEMSでやってみた。


NFCで主流のISO14443Aってproximity card(近接カード)とかcontactless card(非接触カード)であって、タッチすることが前提の規格だと思うんだけど、なぜか通信距離を求められることが多い。だったらvicinity card(近傍カード=ISO15693)にすればいいのにってのは許されない。いろんなしがらみがあるんだと思う。ほんと大人の世界はいやらしい。は、さておき、こういうのなかなか実験できない場合にシミュレーションで何とかしたくなることもある(実験の方が早いことも多々あるので決断は慎重に)。
では、OpenEMSでシミュレーションしてみよう。OpenEMSの環境構築はまぁあっちこっち検索すればわかるっしょ。Octaveをインストールして、、、云々。
例によって唐突にソースコードはこちら。

gen_small_loop_coil.m
  1. function [CSX port]=gen_small_loop_coil(
  2.   CSX,
  3.   loop_name,
  4.   coil_width,coil_height,coil_nturn,
  5.   metal_width,metal_pitch,metal_thickness,
  6.   sub_thickness,
  7.   series_cap_value,parallel_cap_value,port_n,port_excite,
  8.   x_origin,y_origin,z_origin
  9. )
  10.  
  11. metal_name=[loop_name '_metal'];
  12. CSX=AddMetal(CSX,metal_name);
  13. parallel_cap_name=[loop_name '_pcap_z'];
  14. CSX=AddLumpedElement(CSX,parallel_cap_name,'z','C',parallel_cap_value);
  15. series_cap_name=[loop_name '_scap_z'];
  16. CSX=AddLumpedElement(CSX,series_cap_name,'z','C',series_cap_value);
  17. x_start=coil_width/2-metal_width/2;
  18. x_end=x_start-(coil_nturn)*metal_pitch;
  19. x=x_start:-metal_pitch:x_end;
  20. y_start=coil_height/2-metal_width/2;
  21. y_end=y_start-(coil_nturn)*metal_pitch;
  22. y=y_start:-metal_pitch:y_end;
  23.  
  24. z0=-sub_thickness/2;
  25. z1=sub_thickness/2;
  26.  
  27. start_stop_vector=[metal_width/2 metal_width/2 metal_thickness/2];
  28. origins=[x_origin y_origin z_origin];
  29.  
  30. for i=1:coil_nturn
  31.   if i>1
  32.     point1=[-x(i-1) -y(i) z1]+origins-start_stop_vector;
  33.     point2=[x(i) -y(i) z1]+origins+start_stop_vector;
  34.   else
  35.     point1=[-x(coil_nturn) -y(i) z1]+origins-start_stop_vector;
  36.     point2=[x(i) -y(i) z1]+origins+start_stop_vector;
  37.   endif
  38.   CSX=AddBox(CSX,metal_name,1,point1,point2);
  39.  
  40.   point1=[x(i) -y(i) z1]+origins-start_stop_vector;
  41.   point2=[x(i) y(i) z1]+origins+start_stop_vector;
  42.   CSX=AddBox(CSX,metal_name,1,point1,point2);
  43.  
  44.   point1=[-x(i) y(i) z1]+origins-start_stop_vector;
  45.   point2=[x(i) y(i) z1]+origins+start_stop_vector;
  46.   CSX=AddBox(CSX,metal_name,1,point1,point2);
  47.  
  48.   point1=[-x(i) -y(i+1) z1]+origins-start_stop_vector;
  49.   point2=[-x(i) y(i) z1]+origins+start_stop_vector;
  50.   CSX=AddBox(CSX,metal_name,1,point1,point2);
  51. endfor
  52.  
  53. point1=[-x(coil_nturn) -y(1) z0]+origins-start_stop_vector;
  54. point2=[-x(coil_nturn) -y(coil_nturn+1) z0]+origins+start_stop_vector;
  55. CSX=AddBox(CSX,metal_name,1,point1,point2);
  56.  
  57. point1=[-x(coil_nturn) -y(coil_nturn+1) z0]+origins-start_stop_vector;
  58. point2=[-x(coil_nturn) -y(coil_nturn+1) z1]+origins+start_stop_vector;
  59. CSX=AddBox(CSX,series_cap_name,10,point1,point2);
  60.  
  61. point1=[-x(coil_nturn) -y(1) z0]+origins+start_stop_vector.*[-1 1 1];
  62. point2=[-x(coil_nturn) -y(1) z1]+origins+start_stop_vector.*[1 1 -1];
  63. CSX=AddBox(CSX,parallel_cap_name,10,point1,point2);
  64.  
  65. point1=[-x(coil_nturn) -y(1) z0]+origins+start_stop_vector.*[-1 -1 1];
  66. point2=[-x(coil_nturn) -y(1) z1]+origins+start_stop_vector.*[1 -1 -1];
  67. [CSX port]=AddLumpedPort(CSX,100,port_n,50,point1,point2,[0 0 1],port_excite);
  68.  
  69.  
  70. endfunction

nfc_trx_analysis_main.m
  1. function [freq s11 s21 s12 s22]=nfc_trx_analysis_main(
  2.   port_direction,
  3.   tx_coil_width,tx_coil_height,tx_coil_nturn,
  4.   rx_coil_width,rx_coil_height,rx_coil_nturn,
  5.   trx_distance,
  6.   disgeomplot
  7. )
  8.  
  9. physical_constants;
  10. unit=1e-3;
  11.  
  12. FDTD=InitFDTD('NrTS',4e6,'EndCriteria',1e-3);
  13. f0=14e6;
  14. fc=12e6;
  15. FDTD=SetGaussExcite(FDTD,f0,fc);
  16. BC={'MUR','MUR','MUR','MUR','MUR','MUR'};
  17. FDTD=SetBoundaryCond(FDTD,BC);
  18.  
  19. CSX=InitCSX();
  20. if port_direction>0
  21.   txport_excite=false;
  22.   rxport_excite=true;
  23. else
  24.   txport_excite=true;
  25.   rxport_excite=false;
  26. endif
  27. [CSX port1]=gen_small_loop_coil(
  28.   CSX,
  29.   'tx',
  30.   tx_coil_width,tx_coil_height,tx_coil_nturn,
  31.   0.2,0.4,0,
  32.   0.2,
  33.   1,1e-18,1,txport_excite,
  34.   0,0,trx_distance/2
  35. );
  36. [CSX port2]=gen_small_loop_coil(
  37.   CSX,
  38.   'rx',
  39.   rx_coil_width,rx_coil_height,rx_coil_nturn,
  40.   0.2,0.4,0,
  41.   0.2,
  42.   1,1e-18,2,rxport_excite,
  43.   0,0,-trx_distance/2
  44. );
  45.  
  46. ## magnetic material
  47. ##CSX = AddMaterial(CSX, 'mag_material');
  48. ##CSX = SetMaterialProperty(CSX, 'mag_material', 'Mue',45);
  49. ##x_mag=rx_coil_width/2-(rx_coil_nturn-1)*0.4-0.2-1;
  50. ##y_mag=rx_coil_height/2-(rx_coil_nturn-1)*0.4-0.2-1;
  51. ##z_mag=0.2/2;
  52. ##mag_origins=[0 0 -trx_distance/2];
  53. ##CSX=AddBox(CSX,'mag_material',1,[-x_mag -y_mag z_mag]+mag_origins,[x_mag y_mag z_mag]+mag_origins);
  54. ##
  55.  
  56. air_box=16;
  57. mesh_box_size=[20 20 16];
  58. mesh_box_resolution=16;
  59. mesh=DetectEdges(CSX);
  60. mesh.x=[-mesh_box_size(1) mesh.x +mesh_box_size(1)];
  61. mesh.y=[-mesh_box_size(2) mesh.y +mesh_box_size(2)];
  62. mesh.z=[-mesh_box_size(3) mesh.z +mesh_box_size(3)];
  63.  
  64. mesh=SmoothMesh(mesh,mesh_box_resolution);
  65.  
  66. mesh.x=[-air_box+mesh.x(1) mesh.x mesh.x(end)+air_box];
  67. mesh.y=[-air_box+mesh.y(1) mesh.y mesh.y(end)+air_box];
  68. mesh.z=[-air_box+mesh.z(1) mesh.z mesh.z(end)+air_box];
  69.  
  70. mesh=SmoothMesh(mesh,c0/(f0+fc)/unit/10,1.5,'algorithm',1);
  71.  
  72. mesh=AddPML(mesh,4);
  73.  
  74. disp(['number of cells: ' num2str(1e-6*numel(mesh.x)*numel(mesh.y)*numel(mesh.z)) 'Mcells'])
  75.  
  76. CSX=DefineRectGrid(CSX,unit,mesh);
  77.  
  78. Sim_Path=['tmp_' mfilename];
  79. Sim_CSX=[mfilename '.xml'];
  80. confirm_recursive_rmdir(0);
  81. [status,message,messageid]=rmdir(Sim_Path,'s');
  82. [status,message,messageid]=mkdir(Sim_Path);
  83. WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX);
  84. if disgeomplot==0
  85.   CSXGeomPlot( [Sim_Path '/' Sim_CSX],['--export-polydata-vtk=' Sim_Path ' --RenderDiscMaterial -v']);
  86. endif
  87. RunOpenEMS(Sim_Path,Sim_CSX);
  88.  
  89. port={port1 port2};
  90.  
  91. freq=linspace(f0-fc,f0+fc,10001);
  92. port_calc=calcPort(port,Sim_Path,freq,'RefImpedance',50);
  93.  
  94. s11=port_calc{1}.uf.ref./port_calc{1}.uf.inc;
  95. s21=port_calc{2}.uf.ref./port_calc{1}.uf.inc;
  96. s12=port_calc{1}.uf.ref./port_calc{2}.uf.inc;
  97. s22=port_calc{2}.uf.ref./port_calc{2}.uf.inc;
  98.  
  99. ##[fid,msg]=fopen('out.s2p','w');
  100. ##wdata=[freq' real(s11)' imag(s11)' real(s21)' imag(s21)' real(s12)' imag(s12)' real(s22)' imag(s22)'];
  101. ##dlmwrite(fid,wdata,'delimiter','\t');
  102. ##fclose(fid);
  103.  
  104. endfunction

nfc_trx_analysis.m
  1. close all
  2. clear all
  3. clc
  4.  
  5. distance=[96 20 16 12 8 4 2 1];
  6.  
  7. for i=1:length(distance)
  8.   [freq_1 s11_1 s21_1 s12_1 s22_1]=nfc_trx_analysis_main(0,36,32,4,26,12,4,distance(i),1);
  9.   [freq_2 s11_2 s21_2 s12_2 s22_2]=nfc_trx_analysis_main(1,36,32,4,26,12,4,distance(i),1);
  10.  
  11.   fn=['out_' num2str(distance(i)) '.s2p']
  12.   #fn=['out_m45_' num2str(distance(i)) '.s2p']
  13.   [fid,msg]=fopen(fn,'w');
  14.   fprintf(fid,"# Hz S RI R 50\n");
  15.   wdata=[freq_1' real(s11_1)' imag(s11_1)' real(s21_1)' imag(s21_1)' real(s12_2)' imag(s12_2)' real(s22_2)' imag(s22_2)'];
  16.   dlmwrite(fid,wdata,'delimiter','\t');
  17.   fclose(fid);
  18. endfor

コードの構成がまぁまぁいびつなんだけど、しゃーない。OpenEMSで集中定数も含めてシミュレーションできるので、そのようなコードにしているけど、今回は無効になるような値を入れて無効化している。OpenEMSで2portのシミュレーションをするには、port1をexcite=trueにしたケースとport2をexcite=trueにしたケースの2回のシミュレーションが必要になる。んで、コイル間距離を8パタンやってしまおうという上記のコードを我が家のCorei5 Ubuntu24.02マシンで実行すると6.5時間くらいで完了。まぁ思ったより短い。てか短くするためにいろいろごまかしている。メタルはperfect electric conductor(PEC)で、厚さを0としている。誘電体は入れてないので真空にメタルのコイルが浮かんでるモデル。
で、結果を見てみる。
コイル間距離96mm(まぁ十分遠いのでほぼ結合していないと見ていい状態)のSパラファイルをQucs-sで見てみて、で、同調も取ってみる。
ってなるので、TXコイルは1548nH、RXコイルは686nHってことになる。あってるかどうか、、、例のサイトによると、TXコイルは1530nH、RXコイルは670nHってなるっぽい。まぁまぁあってるすごい。ちなみに、同調とってインダクタンスを推定するのはシミュレーションデータだからこそたぶんやっても大丈夫なやつで、実測データには寄生容量が含まれているので、このやり方ではなく、過去、日曜技術者がやったように低周波で \[ L=\frac{X}{\omega} \] をインダクタンス値とすべきである(はず)。

で、実際のものはどんな感じなのかって思う、、、完全に同じものは無理だけど、こんな感じで大体で作っちゃう。
んで、
TXアンテナは
ってことで1540nH。
RXアンテナは
ってことで690nH。
すごいね、よくあってる。むしろ工作が正確なのにびっくり。
では、2つのコイルを結合させてみる。とりあえず、20mm。
こんなかんじ。スペーサーボルトを駆使してちょうどコイル間が20mmになっている。
これを我が家のNanoVNA H4で測定するにはport1とport2を入れ替えて2回測定する必要がある。、、、やっぱまともなネットアナが欲しいなって思っちゃうけど、がまんも大事。
んで、見てみるわけだが、まずはOpenEMSのシミュレーション結果がこちら(注:Qucs-s回路図内の同調Cは無効化している)。
んで、実測結果はこちら。
いや、これがまた、よくあってるんよ。OpenEMSがまぁまぁ使えるってのと日曜技術者の器用さがまだまだ損なわれていないことに超びっくり。

んで、実測データに対してQucs-sで狙いの共振周波数を13.56MHzとして同調をとってみる。
送信側は76pF、受信側は191pFでそれぞれ直列共振周波数が13.56MHz、並列共振周波数が13.56MHzあたりになる。
で、この状態でACシミュレーションをしてみる。
これって入力している電圧源が1Vrmsに対して、出力が7.5Vrmsでるってことだと思うんだけど、ほんとかな?と思いながら今回をクローズする。これの実測はやらんといかんのはわかるけど、やる気が出るかどうか、、、

いやーさぼりにさぼった、、、このブログを購読している人はレアだろうから、まいっか。

2025年6月11日水曜日

NFCアンテナ(5)

 


実験用のNFCアンテナを作って、、、性能を見てたつもりなんだけど、性能確認に使っていたPN5180ってDPC(Dynamic Power Control)ってのが有効になっていて、アンテナそのものの性能が比較できない状態だったので、これを無効にする。クソッ

PN5180のデータシートはこちら(https://www.nxp.jp/docs/en/data-sheet/PN5180A0XX_C3_C4.pdf)
で、NXPが提供しているライブラリとかを参照できればEEPROMとかレジスタとかのアドレスとか書いてあるんだろうけど、NXPってこういうのをホビーユーザーに公開してないんよね。ホビーユーザー?知らんがなって態度がマジむかつく。が、NFCってなるとNXPがメジャーだから使うしかない。で、データシートからがんばってEEPROMのアドレスとサイズを抽出して、
  1. #include <PN5180.h>
  2. #include <PN5180ISO14443.h>
  3. #define PN5180_NSS 1
  4. #define PN5180_BUSY 2
  5. #define PN5180_RST 3
  6.  
  7. #define EEADDR_Die_identifier (0x00)
  8. #define EEADDR_Product_Version (0x10)
  9. #define EEADDR_Firmware_Version (0x12)
  10. #define EEADDR_EEPROM_Version (0x14)
  11. #define EEADDR_IDLE_IRQ_AFTER_BOOT (0x16)
  12. #define EEADDR_TESTBUS_ENABLE (0x17)
  13. #define EEADDR_XTAL_BOOT_TIME (0x18)
  14. #define EEADDR_IRQ_PIN_CONFIG (0x1A)
  15. #define EEADDR_MISO_PULLUP_ENABLE (0x1B)
  16. #define EEADDR_PLL_DEFAULT_SETTING (0x1C)
  17. #define EEADDR_PLL_DEFAULT_SETTING_ALM (0x24)
  18. #define EEADDR_PLL_LOCK_SETTING (0x2C)
  19. #define EEADDR_CLOCK_CONFIG (0x30)
  20. #define EEADDR_MFC_AUTH_TIMEOUT (0x32)
  21. #define EEADDR_LPCD_REFERENCE_VALUE (0x34)
  22. #define EEADDR_LPCD_FIELD_ON_TIME (0x36)
  23. #define EEADDR_LPCD_THRESHOLD (0x37)
  24. #define EEADDR_LPCD_REFVAL_GPO_CONTROL (0x38)
  25. #define EEADDR_LPCD_GPO_TOGGLE_BEFORE_FIELD_ON (0x39)
  26. #define EEADDR_LPCD_GPO_TOGGLE_AFTER_FIELD_OFF (0x3A)
  27. #define EEADDR_NFCLD_SENSITIVITY_VAL (0x3B)
  28. #define EEADDR_FIELD_ON_CP_SETTLE_TIME (0x3C)
  29. #define EEADDR_RF_DEBOUNCE_TIMEOUT (0x3F)
  30. #define EEADDR_SENS_RES (0x40)
  31. #define EEADDR_NFCID1 (0x42)
  32. #define EEADDR_SEL_RES (0x45)
  33. #define EEADDR_FELICA_POLLING_RESPONSE (0x46)
  34. #define EEADDR_RANDOM_UID_ENABLE (0x58)
  35. #define EEADDR_DPC_CONTROL (0x59)
  36. #define EEADDR_DPC_TIME (0x5A)
  37. #define EEADDR_DPC_XI (0x5C)
  38. #define EEADDR_AGC_CONTROL (0x5D)
  39. #define EEADDR_DPC_THRSH_HIGH (0x5F)
  40. #define EEADDR_DPC_THRSH_LOW (0x7D)
  41. #define EEADDR_DPC_DEBUG (0x7F)
  42. #define EEADDR_DPC_AGC_SHIFT_VALUE (0x80)
  43. #define EEADDR_DPC_AGC_GEAR_LUT__SIZE (0x81)
  44. #define EEADDR_DPC_AGC_GEAR_LUT (0x82)
  45. #define EEADDR_DPC_GUARD_FAST__MODE (0x91)
  46. #define EEADDR_DPC_GUARD_SOF__DETECTED (0x93)
  47. #define EEADDR_DPC_GUARD_FIELD_ON (0x95)
  48. #define EEADDR_PCD_AWC_DRC_LUT_SIZE (0x97)
  49. #define EEADDR_PCD_AWC_DRC_LUT (0x98)
  50. #define EEADDR_Misc_Config (0xE8)
  51. #define EEADDR_DigiDelay_A_848_RW (0xE9)
  52. #define EEADDR_DigiDelay_B_848_RW (0xEA)
  53. #define EEADDR_DigiDelay_F_424_RW (0xEB)
  54. #define EEADDR_DigiDelay_15693_RW_FastHigh (0xEC)
  55. #define EEADDR_DigiDelay_18000_2_848 (0xED)
  56. #define EEADDR_DigiDelay_18000_4_848 (0xEE)
  57. #define EEADDR_TestbusMode (0xF0)
  58. #define EEADDR_TbSelect (0xF1)
  59. #define EEADDR_MapTb1_to_Tb0 (0xF2)
  60. #define EEADDR_NumPadSignalMaps (0xF3)
  61. #define EEADDR_PadSignalMap (0xF4)
  62. #define EEADDR_TbDac1 (0xF8)
  63. #define EEADDR_TbDac2 (0xF9)
  64. #define EEADDR_Legacy_typeB_handling_enable (0xFA)
  65. #define EEADDR_Legacy_typeB_handling_interval (0xFB)
  66. #define EEADDR_DPC_Config (0xFC)
  67.  
  68. #define EELEN_Die_identifier (16)
  69. #define EELEN_Product_Version (2)
  70. #define EELEN_Firmware_Version (2)
  71. #define EELEN_EEPROM_Version (2)
  72. #define EELEN_IDLE_IRQ_AFTER_BOOT (1)
  73. #define EELEN_TESTBUS_ENABLE (1)
  74. #define EELEN_XTAL_BOOT_TIME (2)
  75. #define EELEN_IRQ_PIN_CONFIG (1)
  76. #define EELEN_MISO_PULLUP_ENABLE (1)
  77. #define EELEN_PLL_DEFAULT_SETTING (8)
  78. #define EELEN_PLL_DEFAULT_SETTING_ALM (8)
  79. #define EELEN_PLL_LOCK_SETTING (4)
  80. #define EELEN_CLOCK_CONFIG (1)
  81. #define EELEN_MFC_AUTH_TIMEOUT (2)
  82. #define EELEN_LPCD_REFERENCE_VALUE (1)
  83. #define EELEN_LPCD_FIELD_ON_TIME (1)
  84. #define EELEN_LPCD_THRESHOLD (1)
  85. #define EELEN_LPCD_REFVAL_GPO_CONTROL (1)
  86. #define EELEN_LPCD_GPO_TOGGLE_BEFORE_FIELD_ON (1)
  87. #define EELEN_LPCD_GPO_TOGGLE_AFTER_FIELD_OFF (1)
  88. #define EELEN_NFCLD_SENSITIVITY_VAL (1)
  89. #define EELEN_FIELD_ON_CP_SETTLE_TIME (1)
  90. #define EELEN_RF_DEBOUNCE_TIMEOUT (1)
  91. #define EELEN_SENS_RES (2)
  92. #define EELEN_NFCID1 (3)
  93. #define EELEN_SEL_RES (1)
  94. #define EELEN_FELICA_POLLING_RESPONSE (18)
  95. #define EELEN_RANDOM_UID_ENABLE (1)
  96. #define EELEN_DPC_CONTROL (1)
  97. #define EELEN_DPC_TIME (2)
  98. #define EELEN_DPC_XI (1)
  99. #define EELEN_AGC_CONTROL (2)
  100. #define EELEN_DPC_THRSH_HIGH (30)
  101. #define EELEN_DPC_THRSH_LOW (2)
  102. #define EELEN_DPC_DEBUG (1)
  103. #define EELEN_DPC_AGC_SHIFT_VALUE (1)
  104. #define EELEN_DPC_AGC_GEAR_LUT__SIZE (1)
  105. #define EELEN_DPC_AGC_GEAR_LUT (15)
  106. #define EELEN_DPC_GUARD_FAST__MODE (2)
  107. #define EELEN_DPC_GUARD_SOF__DETECTED (2)
  108. #define EELEN_DPC_GUARD_FIELD_ON (2)
  109. #define EELEN_PCD_AWC_DRC_LUT_SIZE (1)
  110. #define EELEN_PCD_AWC_DRC_LUT (80)
  111. #define EELEN_Misc_Config (1)
  112. #define EELEN_DigiDelay_A_848_RW (1)
  113. #define EELEN_DigiDelay_B_848_RW (1)
  114. #define EELEN_DigiDelay_F_424_RW (1)
  115. #define EELEN_DigiDelay_15693_RW_FastHigh (1)
  116. #define EELEN_DigiDelay_18000_2_848 (1)
  117. #define EELEN_DigiDelay_18000_4_848 (1)
  118. #define EELEN_TestbusMode (1)
  119. #define EELEN_TbSelect (1)
  120. #define EELEN_MapTb1_to_Tb0 (1)
  121. #define EELEN_NumPadSignalMaps (1)
  122. #define EELEN_PadSignalMap (1)
  123. #define EELEN_TbDac1 (1)
  124. #define EELEN_TbDac2 (1)
  125. #define EELEN_Legacy_typeB_handling_enable (1)
  126. #define EELEN_Legacy_typeB_handling_interval (1)
  127. #define EELEN_DPC_Config (1)
  128.  
  129. #define EESETUP_SIZE (60)
  130.  
  131. typedef struct {
  132.     uint8_t EEADR;
  133.     uint8_t EELEN;
  134. }EESETUP_T;
  135. EESETUP_T EESETUP[]={
  136. {EEADDR_Die_identifier,EELEN_Die_identifier},
  137. {EEADDR_Product_Version,EELEN_Product_Version},
  138. {EEADDR_Firmware_Version,EELEN_Firmware_Version},
  139. {EEADDR_EEPROM_Version,EELEN_EEPROM_Version},
  140. {EEADDR_IDLE_IRQ_AFTER_BOOT,EELEN_IDLE_IRQ_AFTER_BOOT},
  141. {EEADDR_TESTBUS_ENABLE,EELEN_TESTBUS_ENABLE},
  142. {EEADDR_XTAL_BOOT_TIME,EELEN_XTAL_BOOT_TIME},
  143. {EEADDR_IRQ_PIN_CONFIG,EELEN_IRQ_PIN_CONFIG},
  144. {EEADDR_MISO_PULLUP_ENABLE,EELEN_MISO_PULLUP_ENABLE},
  145. {EEADDR_PLL_DEFAULT_SETTING,EELEN_PLL_DEFAULT_SETTING},
  146. {EEADDR_PLL_DEFAULT_SETTING_ALM,EELEN_PLL_DEFAULT_SETTING_ALM},
  147. {EEADDR_PLL_LOCK_SETTING,EELEN_PLL_LOCK_SETTING},
  148. {EEADDR_CLOCK_CONFIG,EELEN_CLOCK_CONFIG},
  149. {EEADDR_MFC_AUTH_TIMEOUT,EELEN_MFC_AUTH_TIMEOUT},
  150. {EEADDR_LPCD_REFERENCE_VALUE,EELEN_LPCD_REFERENCE_VALUE},
  151. {EEADDR_LPCD_FIELD_ON_TIME,EELEN_LPCD_FIELD_ON_TIME},
  152. {EEADDR_LPCD_THRESHOLD,EELEN_LPCD_THRESHOLD},
  153. {EEADDR_LPCD_REFVAL_GPO_CONTROL,EELEN_LPCD_REFVAL_GPO_CONTROL},
  154. {EEADDR_LPCD_GPO_TOGGLE_BEFORE_FIELD_ON,EELEN_LPCD_GPO_TOGGLE_BEFORE_FIELD_ON},
  155. {EEADDR_LPCD_GPO_TOGGLE_AFTER_FIELD_OFF,EELEN_LPCD_GPO_TOGGLE_AFTER_FIELD_OFF},
  156. {EEADDR_NFCLD_SENSITIVITY_VAL,EELEN_NFCLD_SENSITIVITY_VAL},
  157. {EEADDR_FIELD_ON_CP_SETTLE_TIME,EELEN_FIELD_ON_CP_SETTLE_TIME},
  158. {EEADDR_RF_DEBOUNCE_TIMEOUT,EELEN_RF_DEBOUNCE_TIMEOUT},
  159. {EEADDR_SENS_RES,EELEN_SENS_RES},
  160. {EEADDR_NFCID1,EELEN_NFCID1},
  161. {EEADDR_SEL_RES,EELEN_SEL_RES},
  162. {EEADDR_FELICA_POLLING_RESPONSE,EELEN_FELICA_POLLING_RESPONSE},
  163. {EEADDR_RANDOM_UID_ENABLE,EELEN_RANDOM_UID_ENABLE},
  164. {EEADDR_DPC_CONTROL,EELEN_DPC_CONTROL},
  165. {EEADDR_DPC_TIME,EELEN_DPC_TIME},
  166. {EEADDR_DPC_XI,EELEN_DPC_XI},
  167. {EEADDR_AGC_CONTROL,EELEN_AGC_CONTROL},
  168. {EEADDR_DPC_THRSH_HIGH,EELEN_DPC_THRSH_HIGH},
  169. {EEADDR_DPC_THRSH_LOW,EELEN_DPC_THRSH_LOW},
  170. {EEADDR_DPC_DEBUG,EELEN_DPC_DEBUG},
  171. {EEADDR_DPC_AGC_SHIFT_VALUE,EELEN_DPC_AGC_SHIFT_VALUE},
  172. {EEADDR_DPC_AGC_GEAR_LUT__SIZE,EELEN_DPC_AGC_GEAR_LUT__SIZE},
  173. {EEADDR_DPC_AGC_GEAR_LUT,EELEN_DPC_AGC_GEAR_LUT},
  174. {EEADDR_DPC_GUARD_FAST__MODE,EELEN_DPC_GUARD_FAST__MODE},
  175. {EEADDR_DPC_GUARD_SOF__DETECTED,EELEN_DPC_GUARD_SOF__DETECTED},
  176. {EEADDR_DPC_GUARD_FIELD_ON,EELEN_DPC_GUARD_FIELD_ON},
  177. {EEADDR_PCD_AWC_DRC_LUT_SIZE,EELEN_PCD_AWC_DRC_LUT_SIZE},
  178. {EEADDR_PCD_AWC_DRC_LUT,EELEN_PCD_AWC_DRC_LUT},
  179. {EEADDR_Misc_Config,EELEN_Misc_Config},
  180. {EEADDR_DigiDelay_A_848_RW,EELEN_DigiDelay_A_848_RW},
  181. {EEADDR_DigiDelay_B_848_RW,EELEN_DigiDelay_B_848_RW},
  182. {EEADDR_DigiDelay_F_424_RW,EELEN_DigiDelay_F_424_RW},
  183. {EEADDR_DigiDelay_15693_RW_FastHigh,EELEN_DigiDelay_15693_RW_FastHigh},
  184. {EEADDR_DigiDelay_18000_2_848,EELEN_DigiDelay_18000_2_848},
  185. {EEADDR_DigiDelay_18000_4_848,EELEN_DigiDelay_18000_4_848},
  186. {EEADDR_TestbusMode,EELEN_TestbusMode},
  187. {EEADDR_TbSelect,EELEN_TbSelect},
  188. {EEADDR_MapTb1_to_Tb0,EELEN_MapTb1_to_Tb0},
  189. {EEADDR_NumPadSignalMaps,EELEN_NumPadSignalMaps},
  190. {EEADDR_PadSignalMap,EELEN_PadSignalMap},
  191. {EEADDR_TbDac1,EELEN_TbDac1},
  192. {EEADDR_TbDac2,EELEN_TbDac2},
  193. {EEADDR_Legacy_typeB_handling_enable,EELEN_Legacy_typeB_handling_enable},
  194. {EEADDR_Legacy_typeB_handling_interval,EELEN_Legacy_typeB_handling_interval},
  195. {EEADDR_DPC_Config,EELEN_DPC_Config}
  196. };
  197.  
  198. PN5180ISO14443 nfc(PN5180_NSS, PN5180_BUSY, PN5180_RST);
  199.  
  200. void setup()
  201. {
  202.     delay(3000);
  203.     pinMode(LED_BUILTIN, OUTPUT);
  204.     digitalWrite(LED_BUILTIN, HIGH);
  205.     Serial.begin(115200);
  206.     Serial.println(F("=================================="));
  207.     Serial.println(F("Uploaded: " __DATE__ " " __TIME__));
  208.     Serial.println(F("PN5180 ISO14443 Test Sketch"));
  209.     nfc.begin();
  210.     Serial.println(F("----------------------------------"));
  211.     Serial.println(F("PN5180 Hard-Reset..."));
  212.     nfc.reset();
  213.     Serial.println(F("----------------------------------"));
  214.     Serial.println(F("Reading product version..."));
  215.     uint8_t productVersion[2];
  216.     nfc.readEEprom(PRODUCT_VERSION, productVersion, sizeof(productVersion));
  217.     Serial.print(F("Product version="));
  218.     Serial.print(productVersion[1]);
  219.     Serial.print(".");
  220.     Serial.println(productVersion[0]);
  221.     if (0xff == productVersion[1])
  222.     { // if product version 255, the initialization failed
  223.         Serial.println(F("Initialization failed!?"));
  224.         Serial.println(F("Press reset to restart..."));
  225.         Serial.flush();
  226.         exit(-1); // halt
  227.     }
  228.  
  229.     Serial.println(F("----------------------------------"));
  230.     Serial.println(F("Reading firmware version..."));
  231.     uint8_t firmwareVersion[2];
  232.     nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
  233.     Serial.print(F("Firmware version="));
  234.     Serial.print(firmwareVersion[1]);
  235.     Serial.print(".");
  236.     Serial.println(firmwareVersion[0]);
  237.     Serial.println(F("----------------------------------"));
  238.     Serial.println(F("Reading EEPROM version..."));
  239.     uint8_t eepromVersion[2];
  240.     nfc.readEEprom(EEPROM_VERSION, eepromVersion, sizeof(eepromVersion));
  241.     Serial.print(F("EEPROM version="));
  242.     Serial.print(eepromVersion[1]);
  243.     Serial.print(".");
  244.     Serial.println(eepromVersion[0]);
  245.     Serial.println(F("----------------------------------"));
  246.     uint8_t eereadbuf[80];
  247.     char prnbuf[256];
  248.     for(uint8_t i=0;i<EESETUP_SIZE;i++){
  249.         nfc.readEEprom(EESETUP[i].EEADR, eereadbuf, EESETUP[i].EELEN);
  250.         sprintf(prnbuf,"%02X=",EESETUP[i].EEADR);
  251.         Serial.print(prnbuf);
  252.         for(uint8_t j=0;j<EESETUP[i].EELEN;j++){
  253.             sprintf(prnbuf," %02X",eereadbuf[j]);
  254.             Serial.print(prnbuf);
  255.         }
  256.         Serial.println("");
  257.     }
  258.     Serial.println(F("----------------------------------"));
  259.     nfc.readEEprom(EEADDR_DPC_CONTROL, eereadbuf, EELEN_DPC_CONTROL);
  260.     sprintf(prnbuf,"DPC_CONTROL=%02X",eereadbuf[0]);Serial.println(prnbuf);
  261.     eereadbuf[0]&=0xFE;
  262.     nfc.writeEEPROM(EEADDR_DPC_CONTROL, eereadbuf, EELEN_DPC_CONTROL);
  263.     nfc.readEEprom(EEADDR_DPC_CONTROL, eereadbuf, EELEN_DPC_CONTROL);
  264.     sprintf(prnbuf,"DPC_CONTROL=%02X",eereadbuf[0]);Serial.println(prnbuf);
  265.  
  266.     Serial.println(F("----------------------------------"));
  267.     Serial.println(F("Enable RF field..."));
  268.     nfc.setupRF();
  269.     digitalWrite(LED_BUILTIN, LOW);
  270. }
  271. uint32_t loopCnt = 0;
  272. bool errorFlag = false;
  273. void loop()
  274. {
  275.     digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
  276.     Serial.println(F("----------------------------------"));
  277.     Serial.print(F("Loop #"));
  278.     Serial.println(loopCnt++);
  279.     uint8_t uid[20];
  280.     // check for ISO14443 card
  281.     nfc.reset();
  282.     nfc.setupRF();
  283.     uint8_t uidLength = nfc.readCardSerial(uid);
  284.     if (uidLength > 0)
  285.     {
  286.         Serial.print(F("ISO14443 card found, UID="));
  287.         for (int i = 0; i < uidLength; i++)
  288.         {
  289.             Serial.print(uid[i] < 0x10 ? " 0" : " ");
  290.             Serial.print(uid[i], HEX);
  291.         }
  292.         Serial.println();
  293.         Serial.println(F("----------------------------------"));
  294.         delay(1000);
  295.         return;
  296.     }
  297.  
  298.     // no card detected
  299.     Serial.println(F("*** No card detected!"));
  300.     digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
  301.     delay(100); // wait for a second
  302. }
って感じ。DPCをDisableにするのも実装した。↓これ参照
ちなみに、データシートにめっちゃ間違いがあるんよ。まじクソ。
で、実行すると、こんな感じで書き換えてくれる。
----------------------------------
DPC_CONTROL=73
DPC_CONTROL=72
----------------------------------
EEPROMを書き替えるので、一度だけ書き換えてしまえばいい。

なお、「NFCアンテナ(4)」の記事は諸事情により非公開です。たぶん、この後もかなり非公開。非公開だとモチベーションないんだけど、諸事情により、、、

2025年5月3日土曜日

ペルチェ温度制御(1)

普通は冷却に使うケースが多いペルチェ素子で昇温してみる。

普通は冷却に使うケースが多いペルチェ素子で昇温してみる。色んな評価の時に簡単に温度を制御できないかって

使用部材
ペルチェ素子 : TEC1-03103-T100-SS-TF01-ALO
サーミスタ : 103AT-2-34119
アルミブロック : 30x30x20mm
熱伝導テープ : DY.2ten 熱伝導テープ 幅20mm×長さ25m

アルミブロックにはM3でタッピングする。2.5mmドリルで穴をあけた後、ハンドタップでねじを切る。
で、ここにサーミスタをねじ止めして、で、別の面に熱伝導テープでペルチェを貼り付ける。で、配線する。今回は安定化電源から1.5Aで供給し、サーミスタはHIOKIのテスター(DT4261)で計測する。
こんなかんじ
で、抵抗をロギングする。DT4261はスマホにデータを飛ばせるので自分でメモ取る必要がないのでこういう時便利。
でもって、抵抗値を温度に換算するんだが、サーミスタのデータシートは
ってなってて、秋月のHPによると、
ってことらしい。で、データをまとめてみると
ってなる。80℃に到達するのに69分かかる。アルミブロックがでかいからってのもあるけど、まぁいいっちゃーいい。
2.5Aでやってみると
ってなる。80℃に到達するのに9分、、、めっちゃ劇的に早くなる!温度制御しようと思うと、2.5Aの制御、、、PMOSだとPMOSの発熱も気にしないといけない、、、メカリレーかなー、、、

ちょっと脱線するけど、その後自然放熱するとこうなる
ちなみにこれを計算してくれるサイトがあった(白光)。
で、こうなる
これがよく合ってるんよねーよくできてる!脱線おわり

で、ペルチェを熱源としてその電源2.5Aを制御すればまぁまぁ実用に耐えられそうな温度制御装置ができそうな気がしてきている。

2025年4月30日水曜日

コッククロフト・ウォルトン回路

人生にしびれるような刺激が欲しくなったのでコッククロフト・ウォルトン回路を試してみる。
 


人生にしびれるような刺激が欲しくなったのでコッククロフト・ウォルトン回路を試してみる。ダイオードとコンデンサと交流電源だけの簡単な回路で高電圧を生成することができるらしい。
ダイオードはうちに腐るほどある1N4148を使う。コンデンサはなけなしの4.7uF(1608)を使う。
まずはシミュレーションしてみる。copilotによると1N4148は
.model D1N4148 D (IS=2.52E-9 N=1.752 RS=0.568 CJO=2.9E-12 VJ=0.7 M=0.5)
らしい、、、諸説あるかも;
まずはダイオードの特性を見てみる。
1n4148_test.cir
  1. * 1n4148_test.cir
  2. .title 1n4148_test
  3. .model D1N4148 D (IS=2.52E-9 N=1.752 RS=0.568 CJO=2.9E-12 VJ=0.7 M=0.5)
  4.  
  5. V1 N001 0 DC 0
  6. R1 N001 N002 1000
  7. D1 N002 0 D1N4148
  8.  
  9. .control
  10. dc V1 -5 5 0.01
  11. plot (v(N001)-v(N002))/1000 vs v(N002)
  12. .endc
でngspiceを起動して、
source 1n4148_test.cir
とりあえず、ダイオードである;
で、回路を作って、、、こんなかんじ、
ccw_1.subckt
  1. * ccw single stage
  2. .subckt ccw_1 p1 p2 p3 p4
  3. .model D1N4148 D (IS=2.52E-9 N=1.752 RS=0.568 CJO=2.9E-12 VJ=0.7 M=0.5)
  4.  
  5. C1 p1 p3 4.7e-6
  6. C2 p2 p4 4.7e-6
  7. D1 p2 p3 D1N4148
  8. D3 p3 p4 D1N4148
  9.  
  10. .ends ccw_1
ccw1.cir
  1. * ccw1.cir
  2. .title ccw1
  3. .include "ccw_1.subckt"
  4.  
  5. V01 N001 0 PULSE ( 0 3 0 0 0 10us 20us)
  6. X01 N001 0 N003 N004 ccw_1
  7. X02 N003 N004 N005 N006 ccw_1
  8. X03 N005 N006 N007 N008 ccw_1
  9. X04 N007 N008 N009 N010 ccw_1
  10.  
  11. C98 N009 0 1e-15
  12. C99 N010 0 100e-6
  13.  
  14. .control
  15. tran 1us 1000ms
  16. plot v(N010) v(N001)
  17. .endc
サブサーキット1回路当たりダイオード2個なので、回路全体としてダイオード8個(4段型コッククロフト・ウォルトン回路)で、3V, 50kHzのパルスを入力するってこと。で、こうなる。
理論的な説明は(いつも通り)ほかのサイトに任せることとして、つくってみるヽ(‘ ∇‘ )ノ
久しぶりにユニバーサル基板に実装するってことでこんな感じでって計画
で、作ったのがこれ
で、裏はこんな感じ
チップコンデンサメーカーが見たら「やめーいヽ(`Д´)ノ」って言いそう
で、実際に動かしてみる

1s後に6.64V...やっぱりシミュレーション通りではない、、、が、昇圧はしている。しばらくすると8.7Vくらいで安定する。1N4148は順方向電圧1V@10mAなので、そのまま考えると、8Vまで昇圧するはずなんだけど、電流をひっぱってないので順方向電圧がちょっと下がるので、最終的には8Vより高くなるのかなって勝手に思う、、、昇圧時間は、、、FGがそんなに低インピーダンスじゃないってのとコンデンサの漏れ電流とかかな、、、この辺の考察はほかのサイトがやってるやろ(`▽´)
簡単な回路で昇圧できるこの回路だけど、人生をしびれさせる電圧に達するには数十個レベルのダイオードが必要orzそんなに簡単にしびれるような回路は作れない( ;ㅿ; )