এমবেডেড সিস্টেম ডিবাগিং — JTAG/SWD ও লজিক অ্যানালাইজার
এই পাঠে যা শিখবেন
- এমবেডেড ডিবাগিং সাধারণ সফটওয়্যার ডিবাগিং থেকে কেন ও কীভাবে আলাদা
- JTAG ও SWD হার্ডওয়্যার ডিবাগ ইন্টারফেস ঠিক কী সুবিধা দেয়
- লজিক অ্যানালাইজার ও অসিলোস্কোপ কখন ও কেন ব্যবহার করা হয়
- একটি সত্যিকারের সিমুলেশন — ব্রেকপয়েন্ট হিট হয়ে রেজিস্টার-ফাইল ডাম্প দেখানো
১ · এমবেডেড ডিবাগিং কেন ভিন্ন
একটি সাধারণ ডেস্কটপ/ওয়েব অ্যাপ্লিকেশন ডিবাগ করার সময় প্রায় সবসময় একটি কনসোল থাকে যেখানে
print/লগ স্টেটমেন্ট দিয়ে দ্রুত অবস্থা দেখা যায়, এবং প্রোগ্রামটি নিজের PC-তেই চলে বলে একটি
সফটওয়্যার ডিবাগার সহজেই তার মেমরি/থ্রেড নিয়ন্ত্রণ করতে পারে। এমবেডেড ফার্মওয়্যারে এই দুটোই সহজ নয় — অনেক
বেয়ার-মেটাল সিস্টেমে কোনো কনসোল/অপারেটিং সিস্টেমই থাকে না (একটি UART থাকলে তবেই একটি সরলীকৃত "প্রিন্ট"
সম্ভব, নাহলে নয়), আর প্রোগ্রামটি চলছে একটি সম্পূর্ণ ভিন্ন, বাহ্যিক চিপে (L12-এর
ক্রস-কম্পাইলেশন মনে করুন) — তাই ডেভেলপারের PC থেকে সরাসরি সেই চিপের ভেতরের অবস্থা দেখার জন্য একটি বিশেষ
হার্ডওয়্যার-লেভেল সংযোগ দরকার হয়।
২ · JTAG ও SWD — হার্ডওয়্যার ডিবাগ ইন্টারফেস
JTAG (Joint Test Action Group) মূলত একটি চিপ-টেস্টিং স্ট্যান্ডার্ড হিসেবে শুরু হলেও, আজ এটি ব্যাপকভাবে ডিবাগিং-এর জন্যও ব্যবহৃত হয় — একটি একাধিক-তার (সাধারণত ৪-৫ পিন) সিরিয়াল ইন্টারফেস যা একটি ডিবাগ প্রোব (হোস্ট PC ও চিপের মাঝে একটি ছোট হার্ডওয়্যার অ্যাডাপ্টার) দিয়ে চিপের একটি বিশেষ "ডিবাগ পোর্ট"-এ সংযুক্ত হয়। এই সংযোগের মাধ্যমে ডেভেলপার সরাসরি ব্রেকপয়েন্ট বসাতে পারেন (নির্দিষ্ট ইনস্ট্রাকশনে প্রোগ্রাম থামিয়ে দেওয়া), সিঙ্গল-স্টেপ চালাতে পারেন (একটি একটি করে ইনস্ট্রাকশন এক্সিকিউট করা), এবং যেকোনো মুহূর্তে চিপের রেজিস্টার ও মেমরির বর্তমান অবস্থা লাইভ পড়তে পারেন — এমনকি প্রোগ্রামের নিজের কোডে কোনো ডিবাগ-স্পেসিফিক লাইন না লিখেই।
SWD (Serial Wire Debug) হলো ARM-এর নিজস্ব, সরলীকৃত ২-তারের বিকল্প — একই কাজ করে (ব্রেকপয়েন্ট, সিঙ্গল-স্টেপ, রেজিস্টার/মেমরি অ্যাক্সেস) কিন্তু কম পিন ব্যবহার করে, যা ছোট, পিন-সীমিত মাইক্রোকন্ট্রোলার প্যাকেজের জন্য সুবিধাজনক — আজকাল বেশিরভাগ ARM Cortex-M-ভিত্তিক বোর্ডে (L04-এর পরিচিত পরিবার) SWD-ই প্রধান ডিবাগ ইন্টারফেস হিসেবে ব্যবহৃত হয়।
৩ · লজিক অ্যানালাইজার ও অসিলোস্কোপ
JTAG/SWD প্রোগ্রামের যুক্তিগত অবস্থা (রেজিস্টার, মেমরি, ইনস্ট্রাকশন) দেখায় — কিন্তু কখনো কখনো সমস্যা থাকে ইলেকট্রিক্যাল স্তরে, যেমন একটি GPIO পিনের প্রকৃত টাইমিং প্রত্যাশিত মতো হচ্ছে কিনা, বা একটি UART লাইনে (M6-এ বিস্তারিত আসবে) সঠিক বিট-প্যাটার্ন পাঠানো হচ্ছে কিনা। এখানেই একটি লজিক অ্যানালাইজার (একাধিক ডিজিটাল পিনের HIGH/LOW অবস্থা সময়ের সাথে রেকর্ড করে) বা অসিলোস্কোপ (একটি পিনের প্রকৃত অ্যানালগ ভোল্টেজ ওয়েভফর্ম দেখায়, ডিজিটাল সিগন্যালের রাইজ/ফল টাইম বা নয়েজ ধরার জন্য উপযোগী) কাজে আসে — এরা কোডের ভেতরে কোনো "রেজিস্টার" ধারণা ছাড়াই সরাসরি তারে কী ভোল্টেজ যাচ্ছে তা দেখায়।
৪ · সত্যিকারের সিমুলেশন — ব্রেকপয়েন্ট হিট ও রেজিস্টার ডাম্প
নিচের কোড সেলে L05-এর ধাঁচের একটি ছোট রেজিস্টার-ফাইল সিমুলেশন ব্যবহার করে দেখানো হয়েছে — একটি সরলীকৃত "প্রোগ্রাম" ধাপে ধাপে চলে, এবং একটি নির্দিষ্ট ইনস্ট্রাকশনে (যেন একটি JTAG/SWD ব্রেকপয়েন্ট হিট হলো) থেমে গিয়ে সেই মুহূর্তের রেজিস্টার অবস্থা ডাম্প করে দেখানো হয় — ঠিক যেমন একটি বাস্তব ডিবাগার JTAG/SWD দিয়ে চিপ থামিয়ে রেজিস্টার উইন্ডো দেখায়।
class RegisterFile:
"""একটি ছোট মাইক্রোকন্ট্রোলারের CPU রেজিস্টার-ফাইলের সরলীকৃত সিমুলেশন (L05-এর ধাঁচে)।"""
def __init__(self):
self.regs = {f"R{i}": 0 for i in range(8)}
self.regs["SP"] = 0x20010000 # স্ট্যাক পয়েন্টার -- SRAM-এর উপরের দিকে শুরু (L06/L12-এর মেমরি ম্যাপের ধাঁচে)
self.regs["PC"] = 0 # প্রোগ্রাম কাউন্টার
def dump(self, label):
print(f"--- {label} ---")
for name in ["R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "SP", "PC"]:
print(f" {name:3s} = 0x{self.regs[name]:08X}")
# একটি সরলীকৃত "প্রোগ্রাম" -- প্রতিটি এন্ট্রি একটি (রেজিস্টার, নতুন মান) পরিবর্তন প্রতিনিধিত্ব করে
program = [
("R0", 5),
("R1", 10),
("R2", 15), # <- এই ইনস্ট্রাকশনের ঠিক পরে একটি ব্রেকপয়েন্ট বসানো হয়েছে
("R0", 20),
("R3", 99),
]
BREAKPOINT_INDEX = 2 # ডিবাগারে ইনস্ট্রাকশন #2 ("R2 = 15") এক্সিকিউট হওয়ার পরে থামার জন্য সেট করা
rf = RegisterFile()
print("প্রোগ্রাম রান শুরু (হোস্ট PC থেকে JTAG/SWD-এর মাধ্যমে চিপ নিয়ন্ত্রণ করা হচ্ছে)...")
for i, (reg, value) in enumerate(program):
rf.regs[reg] = value
rf.regs["PC"] += 4 # প্রতিটি ইনস্ট্রাকশন ৪ বাইট ধরে PC এগিয়ে যায় (সরলীকৃত)
if i == BREAKPOINT_INDEX:
print(f"\n>>> ব্রেকপয়েন্ট হিট! ইনস্ট্রাকশন #{i} ('{reg} = {value}') চালানোর পরে থামলো <<<")
rf.dump("ব্রেকপয়েন্টে রেজিস্টার ডাম্প (ডিবাগার এই মুহূর্তে যা দেখাবে)")
break
else:
print("ব্রেকপয়েন্ট কখনো হিট হয়নি")
print()
print("(ব্রেকপয়েন্ট রিলিজ করলে বাকি ইনস্ট্রাকশনগুলো চলতে থাকবে...)")
for reg, value in program[BREAKPOINT_INDEX + 1:]:
rf.regs[reg] = value
rf.regs["PC"] += 4
rf.dump("প্রোগ্রাম শেষে চূড়ান্ত রেজিস্টার অবস্থা")
R3 এখনও 0 (কারণ ইনস্ট্রাকশন #৪ তখনও
চলেনি), কিন্তু প্রোগ্রাম শেষে ডাম্পে R3 = 0x00000063 (দশমিক ৯৯) দেখা যায় এবং R0
বদলে গিয়ে 20 হয়েছে। ঠিক এভাবেই একটি বাস্তব ডিবাগার ব্রেকপয়েন্টে থামার সময়ের "স্ন্যাপশট" ও
প্রোগ্রাম চলতে দেওয়ার পরের চূড়ান্ত অবস্থা — দুটোই আলাদাভাবে দেখাতে পারে।
JTAG/SWD প্রোগ্রামের যুক্তিগত (রেজিস্টার/মেমরি) অবস্থা লাইভ দেখার সুযোগ দেয়, যখন সাধারণ
print-নির্ভর ডিবাগিং সহজলভ্য নয়। লজিক অ্যানালাইজার/অসিলোস্কোপ এর পরিপূরক — যখন সমস্যা কোডের
যুক্তিতে নয় বরং প্রকৃত ইলেকট্রিক্যাল সিগন্যালে থাকে। বাস্তব এমবেডেড ডেভেলপমেন্টে এই দুই ধরনের টুলই একসাথে
ব্যবহৃত হয় — একটি "কী ভুল হচ্ছে তা কোডে দেখায়", আরেকটি "তারে সত্যিই কী ঘটছে তা দেখায়"। এই মডিউল (M3) এখানেই
শেষ — পরের মডিউলে (M4, শুরু L14 থেকে) আমরা এই সব ধারণা প্রয়োগ করে সরাসরি GPIO নিয়ন্ত্রণে যাচ্ছি।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
কোড সেলে ব্রেকপয়েন্টে থামার মুহূর্তে PC-এর মান কত, এবং কেন এটি ঠিক সেই মানই?
ব্রেকপয়েন্টে থামার সময় PC = 0x0000000C (দশমিক ১২)। কারণ, প্রতিটি ইনস্ট্রাকশন এক্সিকিউট
হওয়ার সাথে সাথে PC ৪ বাইট করে বাড়ে, আর ব্রেকপয়েন্ট ইনস্ট্রাকশন #২ (তিন নম্বর, ইনডেক্স
০-থেকে-গোনা) চালানোর পরে
প্র ০২ একটি বাস্তব ডিবাগ সেশনে, ব্রেকপয়েন্টে থামার পর ডেভেলপার যদি একটি রেজিস্টারের মান ম্যানুয়ালি বদলে দেন (যেমন একটি ভুল ভ্যারিয়েবল ঠিক করতে), এটি কি সম্ভব — এবং কীভাবে?
হ্যাঁ, সম্ভব — এটাই JTAG/SWD-ভিত্তিক ডিবাগিং-এর একটি শক্তিশালী দিক। যেহেতু ডিবাগ প্রোব সরাসরি চিপের রেজিস্টার/মেমরিতে রিড এবং রাইট উভয়ই করতে পারে (শুধু রিড নয়), ডেভেলপার ডিবাগারের "watch/registers" উইন্ডোতে নতুন মান লিখে চিপের প্রকৃত রেজিস্টার সেই মুহূর্তেই আপডেট করে দিতে পারেন — পরীক্ষামূলকভাবে একটি "যদি এই ভ্যারিয়েবলের মান অন্যরকম হতো" পরিস্থিতি লাইভ চিপে যাচাই করার জন্য এটি খুবই কার্যকর একটি কৌশল।
প্র ০৩ একটি টাইমিং-সংবেদনশীল বাগ (যেমন একটি সিগন্যাল খুব দ্রুত বদলাচ্ছে বলে মিস হয়ে যাচ্ছে) ডিবাগ করার জন্য JTAG/SWD-এর বদলে লজিক অ্যানালাইজার বেশি উপযোগী কেন হতে পারে?
কারণ JTAG/SWD দিয়ে ব্রেকপয়েন্টে থামালে প্রোগ্রামের প্রকৃত সময়-নির্ভরতা নষ্ট হয়ে যায় — চিপ থেমে থাকা অবস্থায় বাহ্যিক সিগন্যাল/টাইমিং স্বাভাবিকভাবে চলতে থাকে না, তাই একটি দ্রুত, ক্ষণস্থায়ী টাইমিং সমস্যা ব্রেকপয়েন্টে ধরা পড়ে না ("Heisenbug"-এর মতো আচরণ)। একটি লজিক অ্যানালাইজার প্রোগ্রামকে থামায় না — এটি নিরবিচ্ছিন্নভাবে প্রকৃত সময়ে পিনের অবস্থা রেকর্ড করে, তাই আসল টাইমিং সম্পর্ক অক্ষত থাকে এবং পরে বিশ্লেষণ করা যায়।
অনুশীলন
-
চিন্তা করুন: যদি
BREAKPOINT_INDEX-এর মান4(শেষ ইনস্ট্রাকশন) করা হয়, ব্রেকপয়েন্টে থামার মুহূর্তের ডাম্পেR3-এর মান কত দেখাবে বলে আপনার ধারণা?ইনস্ট্রাকশন #৪ হলো
("R3", 99)—BREAKPOINT_INDEX=4মানে এই ইনস্ট্রাকশন চালানোর পরে থামবে, তাই ব্রেকপয়েন্ট ডাম্পেইR3 = 0x00000063(৯৯) দেখাবে — অর্থাৎ ব্রেকপয়েন্টের স্ন্যাপশট আর "প্রোগ্রাম শেষে" ডাম্প এক্ষেত্রে অভিন্ন হবে, কারণ এটিই শেষ ইনস্ট্রাকশন। -
পরীক্ষা করুন: কোড সেলে
programলিস্টে একটি নতুন এন্ট্রি("R4", 7)ব্রেকপয়েন্টের আগে (ইনডেক্স ২-এর আগে) যোগ করে Run চেপে দেখুন ব্রেকপয়েন্ট হিট হওয়ার সময়PC-এর মান কীভাবে বদলায়।একটি নতুন ইনস্ট্রাকশন যোগ করলে
BREAKPOINT_INDEX=2-এ পৌঁছানোর আগে এখন চারটি (আগে তিনটি ছিল) ইনস্ট্রাকশন চলবে (নতুনটিসহ, ব্রেকপয়েন্ট-ইনস্ট্রাকশন পর্যন্ত), তাইPC$4 \times 4 = 16$ বাইট (0x00000010) হবে, আগের0x0000000C-এর বদলে — দেখাচ্ছেPCসবসময় "এতগুলো ইনস্ট্রাকশন চলেছে × ৪" এই সম্পর্ক মেনে চলে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ মাইক্রোপ্রসেসর আর্কিটেকচার, এমবেডেড C, GPIO, টাইমার/PWM/ADC, সিরিয়াল প্রোটোকল, RTOS, সেন্সর/অ্যাকচুয়েটর, IoT আর্কিটেকচার, ওয়্যারলেস প্রোটোকল, MQTT/CoAP ও IoT সিকিউরিটি — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
- Computer Architecture & Digital Logic কোর্স সহোদর কোর্স রেজিস্টার ও ইনস্ট্রাকশন এক্সিকিউশনের সাধারণ ভিত্তি সেই কোর্সেই তৈরি হয়েছে — এই কোর্স হার্ডওয়্যার-লেভেল ডিবাগিং টুলের প্র্যাকটিক্যাল দিকে গভীরে যায়।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Design and Analysis of Algorithms ও আরও অনেক কোর্স — সব এক জায়গায়।