ファームウェアの書き込み後にシリアル通信が応答しなくなった場合、まずアプリケーション通信、ダウンロードエントリポイント、またはハードウェアデバッグアクセスのいずれが失われたかを判断する必要があります。これらは依存関係が異なります。アプリケーションがクラッシュしている場合でも、ROMダウンロードは依然として実行可能である可能性があります。また、デバッグポートは電源、配線、またはセキュリティ設定によりアクセス不可となることもあります。「JTAG/SWDなら必ずブランク化を回避できる」や「USBで書き込めればデバッグも可能」といった一般論は当てはまりません。
| 能力 | 機能 | 依存関係 |
| コアデバッグ | 一時停止、ステップ実行、ブレークポイント、レジスタ/メモリアクセス | チップのデバッグモジュール、権限、プローブおよびサービスサポート |
| ファームウェアプログラミング | イメージの消去、書き込み、検証 | プログラミングインターフェース/アルゴリズム、ストレージ設定および動作条件 |
| バウンダリスキャン | カバー対象のピン/配線に対してテストステートを印加および取得 | バウンダリユニット、BSDL、テストベクトルおよび基板レベルの連携 |
| ROM/ブートローダーダウンロード | ブート段階でイメージを受信 | 指定されたエントリポイント、転送プロトコルおよびイメージ形式 |
| オンラインアップグレード | 実行中に受信し、ファームウェアを切り替え | サービス、検証、電源断からの復旧およびバージョンポリシー |
JTAG:伝送インターフェースはすべてのテスト能力を保証しない
JTAGの一般的な信号はTCK、TMS、TDI、TDOであり、TRSTの有無は実装に依存します。TMSはTCKの立上がり/立下がりエッジでTAP状態機械を駆動し、TDI/TDOは選択されたレジスタへのシリアル入力/出力を行います。デバッグモジュールとバウンダリスキャンは、関連する構造の上に構築された異なる用途です。JTAG端子を持つチップすべてが、必要なコアデバッグまたは完全なバウンダリスキャンをサポートしているわけではありません。
ドミノ接続(菊花連鎖)では、通常、1つのデバイスのTDOが次のデバイスのTDIに接続されます。ホストはチェーンの順序や各デバイスの命令レジスタ長などの設定を知る必要があります。他のデバイスはBYPASSを使用してシフトオーバーヘッドを削減できますが、物理チェーンから自動的に消えるわけではありません。混合電圧ドメインも一致させる必要があり、すべてのJTAGターゲットが5Vを受け入れると仮定してはいけません。
バウンダリスキャンは、アプリケーションファームウェアを実行せずに一部のデジタル相互接続をチェックできますが、「各ピンを直接制御できる」わけではありません。アナログ、電源、高速専用ピン、およびバウンダリユニットを持たないネットワークはカバーされない可能性があります。また、テスト時には基板の他のドライバとの競合を避ける必要があります。BSDLはデバイスのバウンダリ構造を記述しており、基板レベルのネットリストおよびベクトルと組み合わせて初めて実際のカバレッジを定義できます。OpenOCD:バウンダリスキャンの概要およびツールサポート
Microchip:TAP 状態機械
シフトしたビットはいつ有効になる?
リセットから TMS=0,1,0,0 で取り込みを終え Shift-DR に達する。以後は Shift-DR を離れる TMS=1 の周期も含め、TCK ごとにシフトする。Pause-DR に留まっても更新値は変わらず、Update-DR で確定する。入力は自由に選べ、寄り道、停止、再同期も試せる。TMS=1 を 5 回続けると TAP がリセットに戻るが、CPU リセットやチップ内データの消去とは異なる。
図を準備しています
シフトしたビットはいつ有効になる?シフトと更新は別の TAP 状態。Shift-DR は一時ビットを変え、Update-DR で更新レジスタへ転送する。
{"id":"jtag-tap-update","title":"シフトしたビットはいつ有効になる?","summary":"シフトと更新は別の TAP 状態。Shift-DR は一時ビットを変え、Update-DR で更新レジスタへ転送する。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><label class=\"check\"><input type=\"checkbox\" id=\"tdi\"><span data-i18n=\"tdi\"></span></label><div class=\"actions\"><button id=\"tms0\" data-i18n=\"tms0\"></button><button id=\"tms1\" data-i18n=\"tms1\"></button><button id=\"reset5\" data-i18n=\"reset5\"></button><button id=\"reset\" data-i18n=\"reset\"></button></div><div class=\"metrics\"><div><span data-i18n=\"state\"></span><strong id=\"state\"></strong></div></div><section class=\"panel\"><h3 data-i18n=\"next\"></h3><div id=\"next\"></div></section><div class=\"track-row\"><span data-i18n=\"shift\"></span><div id=\"bits\" class=\"track\"></div></div><div class=\"track-row\"><span data-i18n=\"updated\"></span><div id=\"committed\" class=\"track\"></div></div><div class=\"metrics\"><div><span data-i18n=\"tdo\"></span><strong id=\"tdo\"></strong></div></div><section class=\"panel\"><h3 data-i18n=\"history\"></h3><div id=\"history\"></div></section><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:550;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:550 20px ui-monospace,monospace}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px ui-monospace,monospace;background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n/* Action labels must remain readable across locales and narrow embeds. */\n.actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}\n.actions button{overflow-wrap:anywhere;white-space:normal;min-height:58px;padding:8px}\nbutton{overflow-wrap:anywhere}\n@media(min-width:640px){.actions{grid-template-columns:repeat(3,minmax(0,1fr))}}\n\n.metrics span{overflow-wrap:anywhere}\n.panel{border:1px solid var(--rule);border-radius:9px;padding:12px;margin:14px 0;min-width:0}.panel h3{font-size:13px;margin:0 0 10px;color:var(--muted)}.source{font:13px/1.8 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;margin:12px 0}.source mark{background:var(--accent-soft);color:var(--ink);border-bottom:2px solid var(--accent)}.source .fault{background:var(--second-soft);border-color:var(--second)}.diagram{display:block;width:100%;height:auto;max-height:320px;margin:14px 0;overflow:visible}.diagram text{fill:var(--ink);font:12px ui-monospace,monospace}.diagram .edge{stroke:var(--muted);stroke-width:1.5;fill:none}.diagram .edge.on{stroke:var(--accent);stroke-width:3}.diagram .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.5}.diagram .node.on{fill:var(--accent-soft);stroke:var(--accent)}.diagram .node.gold{fill:var(--second-soft);stroke:var(--second)}.log{font:12px/1.8 ui-monospace,monospace;white-space:pre-line;overflow-wrap:anywhere;min-height:7.2em}.table{display:grid;gap:5px;margin:14px 0}.table .tr{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:5px}.table .tr>*{padding:8px 5px;background:var(--surface);border-radius:4px;min-width:0;overflow-wrap:anywhere;font-size:12px}.table .tr .on{background:var(--accent-soft)}.table .tr .gold{background:var(--second-soft)}.choices button{min-height:44px}.metrics strong{min-height:1.6em}.code-line{display:block}.code-line.on{background:var(--accent-soft);border-left:2px solid var(--accent);padding-left:6px}.status-badge{font-size:12px;color:var(--accent)}.tile-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.tile-grid .cell{min-height:40px}.actions button{min-height:48px}.form-field{display:grid;gap:8px;margin:14px 0;font-size:13px}.form-field input{width:100%;font-family:ui-monospace,monospace}.metrics.three{grid-template-columns:repeat(3,minmax(0,1fr))}.formula{min-height:3.2em}.presets{flex-wrap:wrap}.presets button{flex-basis:25%;min-height:44px}\n\n.budget{display:flex;height:28px;margin:16px 0;background:var(--surface);border-radius:5px;overflow:hidden}.budget i{display:block;background:var(--accent);transition:width .2s}.budget i.gold{background:var(--second)}.intervals{margin:16px 0}.interval{position:relative;height:36px;background:var(--surface);margin:6px 0;border-radius:4px;overflow:hidden}.interval i{position:absolute;height:100%;background:var(--accent-soft);border-left:2px solid var(--accent)}.interval i.gold{background:var(--second-soft);border-color:var(--second)}.interval span{position:relative;z-index:1;font:12px/36px ui-monospace,monospace;padding-left:7px}.table .tr>*{min-height:4.8em}.formula{white-space:pre-line;min-height:7.2em}.actions:has(>button:only-child){grid-template-columns:1fr}.metrics strong{min-height:3.2em}.rangegrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:3px;margin:14px 0}.rangegrid .cell{min-height:30px;padding:3px 1px;font-size:10px}.message{min-height:7.2em;white-space:pre-line;font:13px/1.8 ui-monospace,monospace;overflow-wrap:anywhere}\n/* Allow CJK hanging punctuation without overflowing a metric's border box. */\n.metrics>div{padding-right:4px}.metrics span{line-break:anywhere}\n\n.chart-wrap{margin:18px 0}.chart-label{font-size:12px;color:var(--muted);min-height:3.2em}.curve{display:block;width:100%;height:auto;max-height:320px;overflow:visible}.curve text{font:11px ui-monospace,monospace;fill:var(--muted)}.gridline{stroke:var(--rule);stroke-width:1}.metrics strong{font-size:20px;min-height:3.2em}.formula{font:12px/1.8 ui-monospace,monospace;min-height:9em}.readout{min-height:8em}.presets button{flex-basis:30%}.scope p{overflow-wrap:anywhere} .unit-note{font-size:12px;color:var(--muted);margin:10px 0}\n\n.metrics span{word-break:break-all;line-break:strict}.metrics>div{padding-right:6px}\n\n#state{min-height:3.2em}.tr{grid-template-columns:1fr 2fr}.track .cell{flex:1}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}const esc=s=>String(s).replace(/[&<>\"']/g,c=>({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));const fmt=s=>'{'+[...s].sort().join(', ')+'}';function graph(id,nodes,edges){const el=$('#'+id);el.setAttribute('viewBox','0 0 360 200');el.innerHTML='<defs><marker id=\"arrow-'+id+'\" viewBox=\"0 0 10 10\" refX=\"8\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto-start-reverse\"><path d=\"M 0 0 L 10 5 L 0 10 z\" fill=\"var(--muted)\"/></marker></defs>'+edges.map(e=>{const a=nodes[e[0]],b=nodes[e[1]],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1;if(edges.some(r=>r[0]===e[1]&&r[1]===e[0])){const nx=-dy/d,ny=dx/d;return '<path class=\"edge '+(e[2]?'on':'')+'\" d=\"M '+(a.x+dx/d*22+nx*12)+' '+(a.y+dy/d*22+ny*12)+' Q '+((a.x+b.x)/2+nx*38)+' '+((a.y+b.y)/2+ny*38)+' '+(b.x-dx/d*25+nx*12)+' '+(b.y-dy/d*25+ny*12)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}return '<line class=\"edge '+(e[2]?'on':'')+'\" x1=\"'+(a.x+dx/d*25)+'\" y1=\"'+(a.y+dy/d*25)+'\" x2=\"'+(b.x-dx/d*28)+'\" y2=\"'+(b.y-dy/d*28)+'\" marker-end=\"url(#arrow-'+id+')\"/>';}).join('')+nodes.map(n=>'<g><circle class=\"node '+(n.cls||'')+'\" cx=\"'+n.x+'\" cy=\"'+n.y+'\" r=\"25\"/><text x=\"'+n.x+'\" y=\"'+(n.y+4)+'\" text-anchor=\"middle\">'+esc(n.name)+'</text>'+(n.sub?'<text x=\"'+n.x+'\" y=\"'+(n.y+43)+'\" text-anchor=\"middle\">'+esc(n.sub)+'</text>':'')+'</g>').join('');}function table(id,rows){$('#'+id).classList.add('table');$('#'+id).replaceChildren(...rows.map(r=>{const row=document.createElement('div');row.className='tr';row.style.gridTemplateColumns='repeat('+r.length+',minmax(0,1fr))';r.forEach(x=>{const c=document.createElement('div');if(typeof x==='object'){c.textContent=x.text;c.className=x.cls||'';}else c.textContent=x;row.append(c)});return row;}));}function band(id,parts,total){$('#'+id).replaceChildren(...parts.map((p,i)=>{const e=document.createElement('i');e.style.width=(100*p.value/total)+'%';e.className=i%2?'gold':'on';e.title=p.name+': '+p.value;return e}));}function intervals(id,items,total){$('#'+id).replaceChildren(...items.map(p=>{const row=document.createElement('div');row.className='interval';const bar=document.createElement('i');bar.style.left=(100*p.start/total)+'%';bar.style.width=(100*(p.end-p.start)/total)+'%';bar.className=p.cls||'';const label=document.createElement('span');label.textContent=p.label;row.append(bar,label);return row;}));}function plot(id,series,xr,yr,opts={}){const e=$('#'+id),X=x=>42+(x-xr[0])/(xr[1]-xr[0])*298,Y=y=>175-(y-yr[0])/(yr[1]-yr[0])*148;let out='<defs><clipPath id=\"clip-'+id+'\"><rect x=\"42\" y=\"27\" width=\"298\" height=\"148\"/></clipPath></defs>';for(let i=0;i<3;i++){let x=xr[0]+i*(xr[1]-xr[0])/2,y=yr[0]+i*(yr[1]-yr[0])/2;out+='<path class=\"gridline\" d=\"M '+X(x)+' 27V175M42 '+Y(y)+'H340\"/><text x=\"'+X(x)+'\" y=\"194\" text-anchor=\"middle\">'+esc(opts.xfmt?opts.xfmt(x):Number(x.toFixed(2)))+'</text><text x=\"36\" y=\"'+(Y(y)+4)+'\" text-anchor=\"end\">'+esc(opts.yfmt?opts.yfmt(y):Number(y.toFixed(2)))+'</text>';}out+='<g clip-path=\"url(#clip-'+id+')\">';for(const s of series){out+='<path fill=\"none\" stroke=\"'+(s.color||'var(--accent)')+'\" stroke-width=\"2.5\" '+(s.dash?'stroke-dasharray=\"5 4\"':'')+' d=\"'+s.pts.map((p,i)=>(i?'L':'M')+X(p[0]).toFixed(2)+','+Y(p[1]).toFixed(2)).join(' ')+'\"/>';}for(const p of opts.points||[])out+='<circle cx=\"'+X(p[0])+'\" cy=\"'+Y(p[1])+'\" r=\"4\" fill=\"var(--second)\" stroke=\"var(--paper)\" stroke-width=\"1.5\"/>';if(opts.cursor!==undefined)out+='<path d=\"M'+X(opts.cursor)+' 27V175\" stroke=\"var(--muted)\" stroke-dasharray=\"3 3\"/>';e.innerHTML=out+'</g>';e.dataset.curves=JSON.stringify(series.map(s=>s.pts));}const curve=(fn,lo,hi,n=120)=>Array.from({length:n+1},(_,i)=>{const x=lo+(hi-lo)*i/n;return[x,fn(x)]});function inputs(draw){document.querySelectorAll('input,select').forEach(e=>{e.addEventListener('input',draw);e.addEventListener('change',draw)});draw()}const n=id=>+$('#'+id).value;const show=(id,v,d=3)=>set(id,Number(v.toFixed(d)));const transitions={'Test-Logic-Reset':['Run-Test/Idle','Test-Logic-Reset'],'Run-Test/Idle':['Run-Test/Idle','Select-DR-Scan'],'Select-DR-Scan':['Capture-DR','Select-IR-Scan'],'Capture-DR':['Shift-DR','Exit1-DR'],'Shift-DR':['Shift-DR','Exit1-DR'],'Exit1-DR':['Pause-DR','Update-DR'],'Pause-DR':['Pause-DR','Exit2-DR'],'Exit2-DR':['Shift-DR','Update-DR'],'Update-DR':['Run-Test/Idle','Select-DR-Scan'],'Select-IR-Scan':['Capture-IR','Test-Logic-Reset'],'Capture-IR':['Shift-IR','Exit1-IR'],'Shift-IR':['Shift-IR','Exit1-IR'],'Exit1-IR':['Pause-IR','Update-IR'],'Pause-IR':['Pause-IR','Exit2-IR'],'Exit2-IR':['Shift-IR','Update-IR'],'Update-IR':['Run-Test/Idle','Select-DR-Scan']};let state='Test-Logic-Reset',bits=0,updated=0,tdo=null,hist=[state];function pulse(tms){if(state==='Capture-DR')bits=10;if(state==='Shift-DR'){tdo=bits&1;bits=(bits>>1)|($('#tdi').checked?8:0)}state=transitions[state][tms];if(state==='Update-DR')updated=bits;hist.push(state);hist=hist.slice(-5);draw()}function draw(){set('state',state);table('next',[['TMS=0',transitions[state][0]],['TMS=1',transitions[state][1]]]);cells('bits',bits.toString(2).padStart(4,'0').split('').map(text=>({text,cls:'on'})));cells('committed',updated.toString(2).padStart(4,'0').split('').map(text=>({text,cls:'gold'})));set('tdo',tdo===null?t('none'):tdo);table('history',Array.from({length:5},(_,i)=>[String(i+1),hist[i]||'—']));$('#state').dataset.values=JSON.stringify({state,bits,updated,tdo});}$('#tms0').onclick=()=>pulse(0);$('#tms1').onclick=()=>pulse(1);$('#reset5').onclick=()=>{for(let i=0;i<5;i++)pulse(1)};$('#reset').onclick=()=>{state='Test-Logic-Reset';bits=updated=0;tdo=null;hist=[state];draw()};draw();","audio":false,"strings":{"heading":"シフトしたビットはいつ有効になる?","history":"最近の状態(古 → 新)","intro":"TMS を選んで TCK エッジを与え、シフトレジスタと更新値を比較。","next":"次周期の状態","none":"まだシフトなし","reset":"リセット","reset5":"TMS=1 を 5 周期","scope":"16 状態の TAP。選択済みの 4 bit 学習用データレジスタを仮定し、Capture-DR は固定 1010 を取り込む。ボタンは適用エッジの処理を含む TCK 一周期。IR ビット、実命令、ピン駆動は省略。","scopeLabel":"モデルの範囲と前提","shift":"シフトレジスタ","state":"現在の TAP 状態","tdi":"TDI=1(未選択は 0)","tdo":"最後にシフト出力した TDO","tms0":"TMS=0 · TCK","tms1":"TMS=1 · TCK","updated":"更新済み値"}}
SWD:2本のプロトコル信号以外に電気的条件がある
SWDIOは双方向データ線、SWCLKはクロックです。要求にはアクセス方向やDP/APなどの情報が含まれ、リンクには応答、データ、パリティ、および双方向切替フェーズが必要です。Armデバッグアーキテクチャを例にとると、DPは外部デバッグエントリを提供し、APは対応する内部リソースにアクセスします。具体的なコア、マルチコア、およびバス能力は実装によって決定されます。Arm Debug Interface アーキテクチャ
「2本線だけでよい」というのはプロトコル信号のみをカウントしたものであり、基板レベルでは通常、GND、目標電圧参照が必要であり、信頼性の高いリセット/リカバリのためにnRESETを確保する価値がよくあります。SWOはオプションのトレース出力であり、SWD通常の通信に必要な第3のデータ線ではありません。また、SWDはJTAGのバウンダリスキャン機能を一般的に代替できるわけではありません。
VTrefは通常、プローブがターゲットI/Oのレベリングを検知できるようにするためのものであり、ターゲットに電力を供給する出力ではありません。プローブが別途給電機能を提供する場合でも、インターフェース定義に従って使用し、基板電源との競合を避ける必要があります。短い配線と適切なリターンパスは信号品質に役立ちます。SWDIOは双方向駆動を許可する必要があり、単方向バッファを安易に追加してはいけません。SEGGER VTref 定義
GDBからFlashへ:中間にはどのような責任があるか
GDBは一致するELFを使用してアドレスとデバッグ情報を取得し、リモートプロトコルを介してOpenOCDなどのサービスにリクエストを送信します。サービスはプローブとターゲット設定を組み合わせてチップにアクセスします。プローブがSWDをサポートしていても、それがソフトウェア的に新しいMCUのFlashコントローラ、セキュリティモード、またはマルチコアトポロジをサポートしていることを意味するわけではありません。
Flashへの書き込みには、デバイスアルゴリズムが必要になることが多く、場合によっては小さなプログラムをターゲットRAMに配置して実行します。RAMの利用可能性、Flashのサイズとバンク、クロックの初期化、およびアドレスマッピングのエラーは、「IDは読み込めるが書き込めない」という状況を引き起こす可能性があります。J-Link、CMSIS-DAP、ST-Linkなども、ブランドだけで機能が同じではありません。具体的なプローブモデル、ファームウェア、ホストソフトウェア、およびターゲットサポートを一緒に照合する必要があります。「無制限のFlashブレークポイント」も条件付きのソフトウェア機能であり、すべてのプローブの一般的なハードウェアコンパレータが無制限にあるわけではありません。
以下に、OpenOCDのST-Linkインターフェース設定とSTM32F4ターゲット設定の例を示します。これは、照合済みのハードウェアおよびツールバージョンにのみ適用されます。コマンドはデバッグセッションを確立します。ここで、リセットと一時停止はターゲットの実行状態を変更するため、現場の障害を調査する際はまず必要な情報を保存してください。
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg
別のターミナルでターゲットアーキテクチャをサポートするGDBを起動し、ターゲットファームウェアに対応するELFをロードします。
arm-none-eabi-gdb firmware.elf
target extended-remote localhost:3333
monitor reset halt
info registers
x/8i $pc
ここでは自動消去やアンロックコマンドは提供されていません。reset halt の実際の効果はターゲットのリセット設定に依存し、ポートも設定可能です。ローカルのOpenOCDドキュメントとターゲット設定に合わせて照合してください。OpenOCD:GDB接続とデバッグ、リセット設定
ハードウェアブレークポイント/ウォッチポイントの数は限られています。ソフトウェアブレークポイントは命令の修正が必要になることがあり、Flashでの実装はツールのサポートによって決定されます。CPUを一時停止した後、周辺デバイス、DMA、ウォッチドッグタイマ、または別のコアが一緒に一時停止されるとは限りません。ステップ実行による観察自体がタイミングを変更するため、これに基づいてリアルタイム実行に競合がないと直接証明することはできません。
ROM、USB DFU、UF2、UART は異なる分類次元に属する
ROMはコードの配置場所を指し、DFUはファームウェアアップグレードプロトコルの名称であり、UART/USBは伝送関連のインターフェース、UF2はイメージブロック形式および一般的なロード方法を指します。USB DFUはROMまたは更新可能なブートローダーによって実装できます。USB端子を持つチップすべてに、工場出荷時にDFUが備わっているわけではありません。
| プラットフォーム例 | 照合可能な実際の動作 | 一般化できない結論 |
| STM32 システムメモリダウンロード | 具体的なモデルの起動モード、インターフェース、およびピンはAN2606を参照 | BOOT0をすべてハイにすればUSART1 + USB DFUが有効になるわけではない |
| RP2040 Pico BOOTSEL | ROMエントリは仮想USB大容量ストレージとして表示され、UF2を受信可能 | UF2のドラッグ&ドロップはUSB DFUクラスプロトコルではない |
| nRF52 ソフトウェアDFU | 一般的なソリューションは、書き込まれた対応ブートローダーに依存 | 全シリーズにUSB ROM DFUが工場出荷時に搭載されているわけではない |
| AVR / PIC プログラミング | インターフェースはデバイスとツールに応じて選択 | ISP、ICSP、UPDI はすべてAVRの6ピンで同じプロトコルではない |
STM32のエントリポイントは、オプションバイト、チップのリビジョン、およびセキュリティ設定の影響を受ける可能性があり、正確な品番で表を参照する必要があります。ST AN2606
PicoのBOOTSELコードはROMに位置しており、アプリケーションFlashが破損しても、このROMが上書きされることは通常ありません。ただし、正常な電源供給、USB接続、およびデバイスの状態に依存します。Raspberry Pi Pico ドキュメント
NordicのnRF5 SDK DFUツールは、対応するソフトウェアブートローダーを要求します。新しいソフトウェアプラットフォームでも、使用するアップグレードソリューションに合わせて設定する必要があります。特定の開発ボードにプリインストールされている機能を、すべてのブートチップに帰属させてはいけません。Nordic nRF Device Firmware Update
Microchipのいくつかの新しいAVRは、プログラミングとデバッグにUPDIを使用し、PICのICSPには独自のデバイスプロトコルと進入条件があります。Microchip AVR インターフェース
ダウンロード時間には、消去、検証、および伝送を分けて考慮する
UART 115200ボー、8N1の場合、1バイトあたり10ビットが必要であり、理想的な純粋バイト率は11520 B/sです。256 KiBのイメージの場合、データ伝送だけでも少なくとも約22.76秒かかり、プロトコルヘッダ、応答、再試行、Flashの消去/書き込み、および検証が加わります。シリアルボーレートを上げても、内部消去/書き込みに支配される時間は比例して短縮されず、USB接続だからといってUSBの公称バス帯域幅で書き込みが完了するわけではありません。
イメージアドレス、ベクタテーブル/エントリ、リンクレイアウト、ブートローダーパーティション、および署名要件は一致している必要があります。ツールが書き込み完了を報告した後でも、バイト検証の通過、起動検証の通過、およびアプリケーション機能の通過を区別する必要があります。これら3つは同じ結果ではありません。
接続できない場合、依存関係が最も少ない層から段階的に確認する
まず、ターゲット電源、VTref、GND、インターフェース方向、リセット状態、およびホストによるプローブの認識を照合し、次に伝送選択、ターゲット設定、およびクロックを照合します。デバッグレートを下げると接続品質の判断に役立ちますが、誤った電圧やセキュリティロックは修復できません。
アプリケーションが起動後にデバッグピンを無効にするか、低消費電力モードに入った場合、チップのサポートに応じてリセット時に接続を試みることができます。これにはリセット線と正しいツール設定が必要であり、すべてのデバイスが同じフローをサポートしているわけではありません。読み込み保護、認証、および永続的なセキュリティ状態は、ベンダーの定義に従って処理する必要があります。一部のリカバリはデータを消去し、一部の状態は不可逆的であるため、「アンロック/チップ全体消去」を障害証拠を保存する前のデフォルトアクションとして扱ってはいけません。
一時停止できるようになったら、まずELFが実行中のイメージと一致していることを確認し、次にリセット原因、PC、スタック、および例外コンテキストを確認します。ソースファイルが同じであるだけでは不十分で、最適化、リンクアドレス、ライブラリ、または生成設定が異なると、変数や行番号が誤った判断を招くことがあります。
バストラブルシューティングでは、ロジックアナライザとオシロスコープを組み合わせます。1回のACKは、あるバイトが受信されたことを示すだけで、データが新鮮であること、後続のトランザクション、または電気的マージンが常に正しいことを証明するものではありません。プロトコルデコードが正常であっても、必要に応じて電圧、立ち上がりエッジ、および電源をチェックする必要があります。ロジックアナライザだけでは、すべての物理層の問題を排除できません。
開発、生産ライン、および現場はターゲットに応じてプロセスを整理する
開発段階では、観測可能性とリカバリエントリポイントが必要です。生産ラインでは、追跡可能なイメージ、検証、シリアライズ、および機能テストが必要です。現場でのアップグレードでは、検証、互換性、および電源断からの復旧が必要です。量産では、専用のプログラマを使用してバッチ書き込みを行うことも、確立されたダウンロードサービスを使用することもでき、「まずSWDでブートローダーを書き込み、次にDFU」と固定する必要はありません。
OTAは、イメージが無線またはネットワークを介して到達したことを示すだけで、真正性と信頼性の高い切り替えを自動的に提供するものではありません。受信、検証、候補領域への書き込み、起動確認、および失敗時のリカバリは、明確な状態機械を形成する必要があります。読み込み保護、署名、およびデバッグ権限は異なるメカニズムであり、最終的な設定は製品の保守ポリシーと一致している必要があります。
伝送の下限を再計算する
from math import isclose
baud, bits_per_byte, image_bytes = 115200, 10, 256*1024
payload_rate = baud/bits_per_byte
assert payload_rate == 11520
assert isclose(image_bytes/payload_rate, 22.755555555555556)
assert isclose(image_bytes*8/1e6, 2.097152)
print('UART 8N1 の有効バイト率およびイメージ純粋伝送時間の下限チェック通過')
伝送時間は書込み経路の下限にすぎません。書込み内容、起動、実際の機能の検証結果はそれぞれ記録します。
続きの参照