পাঠ ২৩ · ৫৭-এর মধ্যে · মডিউল ৬
Home / Courses / Microprocessors, Embedded Systems & IoT / SPI প্রোটোকল

SPI প্রোটোকল

SPI protocol
৯ মিনিট পড়া মধ্যম · Intermediate Python সিমুলেশনসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • SPI-এর চারটি সিগন্যাল লাইন এবং কেন এটি সিঙ্ক্রোনাস
  • শিফট-রেজিস্টার মডেল -- মাস্টার ও স্লেভ কীভাবে একটি বড় সার্কুলার রেজিস্টারের মতো আচরণ করে
  • ফুল-ডুপ্লেক্স মানে ঠিক কী -- একই সময়ে দুই দিকেই ডেটা চলাচল
  • একটি সত্যিকারের, ধাপে-ধাপে যাচাইযোগ্য সিমুলেশন -- ৮টি ক্লক পালসের পর রেজিস্টার এক্সচেঞ্জ

১ · SPI কেন "সিঙ্ক্রোনাস"

আগের পাঠে UART দেখা গেছে, যেখানে দুই পাশ শুধু একটি বড রেট নিয়ে "একমত" থাকে, কোনো ভাগাভাগি করা ক্লক তার নেই। SPISPISerial Peripheral Interface -- একটি সিঙ্ক্রোনাস, ফুল-ডুপ্লেক্স সিরিয়াল প্রোটোকল যেখানে মাস্টার নিজেই ক্লক লাইন চালায়। এর বিপরীত -- এখানে মাস্টার নিজেই একটি ক্লক লাইন (SCLK) চালায়, আর স্লেভ প্রতিটি ক্লক পালসে ঠিক এক বিট করে ডেটা শিফট করে। যেহেতু ক্লক ভাগাভাগি করা হয়, বড রেট অনুমান করার কোনো প্রশ্নই ওঠে না -- উভয় পাশ ঠিক একই ক্লক এজ-এ কাজ করে।

SPI-তে চারটি সিগন্যাল লাগে:

  • MOSI (Master Out, Slave In) -- মাস্টার থেকে স্লেভে ডেটা
  • MISO (Master In, Slave Out) -- স্লেভ থেকে মাস্টারে ডেটা
  • SCLK (Serial Clock) -- মাস্টার এই ক্লক চালায়, প্রতিটি পালসে ১ বিট শিফট হয়
  • CS/SS (Chip Select / Slave Select) -- মাস্টার কোন স্লেভের সাথে কথা বলছে তা নির্বাচন করে (একাধিক স্লেভ থাকলে প্রতিটির জন্য আলাদা CS লাইন লাগে)
মাস্টার (৮-বিট শিফট রেজিস্টার) স্লেভ (৮-বিট শিফট রেজিস্টার) MOSI SCLK (ক্লক, মাস্টার চালায়) MISO
প্রতিটি SCLK পালসে মাস্টার ও স্লেভ দুজনেই একসাথে এক বিট করে পাঠায় (MOSI/MISO) -- এটাই ফুল-ডুপ্লেক্স।

২ · শিফট-রেজিস্টার মডেল -- কেন এটি কাজ করে

SPI-এর আসল কৌশলটা বোঝা সহজ যদি মাস্টার ও স্লেভের ৮-বিট রেজিস্টারকে একটি একক ১৬-বিট সার্কুলার রেজিস্টার হিসেবে কল্পনা করা যায় -- মাস্টারের ৮ বিট উপরে, স্লেভের ৮ বিট নিচে। প্রতিটি ক্লক পালসে:

  • মাস্টারের সবচেয়ে গুরুত্বপূর্ণ বিট (MSB) MOSI দিয়ে বেরিয়ে স্লেভের সবচেয়ে কম গুরুত্বপূর্ণ বিটের জায়গায় ঢোকে
  • স্লেভের MSB MISO দিয়ে বেরিয়ে মাস্টারের সবচেয়ে কম গুরুত্বপূর্ণ বিটের জায়গায় ঢোকে

এটি ঠিক এই ১৬-বিট রেজিস্টারকে ১ বিট বাম দিকে সার্কুলার শিফট করার সমান। তাই ৮ বার শিফট করলে (৮টি ক্লক পালস) পুরো ১৬-বিট রেজিস্টার ঠিক অর্ধেক (৮ বিট) ঘুরে যায় -- যা মাস্টারের আসল ৮ বিট আর স্লেভের আসল ৮ বিটকে সম্পূর্ণভাবে অদল-বদল করে দেয়। এটাই নিচের কোড সেল সত্যিই চালিয়ে যাচাই করে দেখাচ্ছে।

Python
def to_bin(v):
    return format(v, '08b')


def spi_transfer(master_reg, slave_reg, num_bits=8):
    print(f"শুরুতে       : master_reg={to_bin(master_reg)} (0x{master_reg:02X})  "
          f"slave_reg={to_bin(slave_reg)} (0x{slave_reg:02X})")
    for pulse in range(1, num_bits + 1):
        master_out = (master_reg >> 7) & 1   # MOSI দিয়ে মাস্টারের MSB বের হচ্ছে
        slave_out = (slave_reg >> 7) & 1      # MISO দিয়ে স্লেভের MSB বের হচ্ছে
        master_reg = ((master_reg << 1) | slave_out) & 0xFF
        slave_reg = ((slave_reg << 1) | master_out) & 0xFF
        print(f"ক্লক পালস {pulse}  : MOSI={master_out} MISO={slave_out}  ->  "
              f"master_reg={to_bin(master_reg)}  slave_reg={to_bin(slave_reg)}")
    return master_reg, slave_reg


original_master = 0xA5   # 1010 0101 -- মাস্টার যা পাঠাতে চায় (যেমন একটি কমান্ড বাইট)
original_slave = 0x3C    # 0011 1100 -- স্লেভ যা পাঠাতে চায় (যেমন একটি সেন্সর রিডিং)

print("=== SPI ফুল-ডুপ্লেক্স শিফট-রেজিস্টার এক্সচেঞ্জ (৮ ক্লক পালস) ===\n")
final_master, final_slave = spi_transfer(original_master, original_slave)

print(f"\n৮ পালসের পর  : master_reg={to_bin(final_master)} (0x{final_master:02X})  "
      f"slave_reg={to_bin(final_slave)} (0x{final_slave:02X})")

assert final_master == original_slave, "এক্সচেঞ্জ ব্যর্থ -- মাস্টার স্লেভের আসল মান পায়নি!"
assert final_slave == original_master, "এক্সচেঞ্জ ব্যর্থ -- স্লেভ মাস্টারের আসল মান পায়নি!"
print("\nযাচাই সফল: মাস্টারের রেজিস্টারে এখন স্লেভের আসল মান (0x3C), "
      "আর স্লেভের রেজিস্টারে এখন মাস্টারের আসল মান (0xA5) -- ফুল-ডুপ্লেক্স এক্সচেঞ্জ সম্পন্ন।")

    

৩ · SPI-এর গতি -- কেন এটি UART-এর চেয়ে দ্রুত

যেহেতু SPI-তে মাস্টার নিজেই ক্লক চালায় (কোনো বড রেট-ম্যাচিং লাগে না), এটি সাধারণত UART-এর চেয়ে অনেক বেশি ক্লক ফ্রিকোয়েন্সিতে চালানো যায়। একটি নির্দিষ্ট ক্লক ফ্রিকোয়েন্সিতে ৮ বিট (১ বাইট) পাঠাতে কত সময় লাগে তা সরাসরি গণনাযোগ্য:

$$transfer\_time_{\mu s} = \frac{num\_bits}{f_{clock}} \times 10^6$$

Python
def spi_byte_transfer_time_us(clock_hz, num_bits=8):
    return (num_bits / clock_hz) * 1e6


for clock_hz in [1_000_000, 10_000_000, 50_000_000]:
    t_us = spi_byte_transfer_time_us(clock_hz)
    print(f"SCLK = {clock_hz:>11,} Hz  ->  ১ বাইট (৮ বিট) পাঠাতে সময় = {t_us:.4f} µs")

    
বাস্তব SPI ডিভাইসে সাধারণত ১ থেকে ৫০ MHz (বা তারও বেশি) ক্লক ফ্রিকোয়েন্সি ব্যবহৃত হয় -- এগুলো এই কোর্সের প্রসঙ্গে সাধারণভাবে গৃহীত ইলাস্ট্রেটিভ পরিসীমা, কোনো একক নির্দিষ্ট চিপের নিশ্চিত স্পেসিফিকেশন নয়। প্রতিটি ডিভাইসের নিজস্ব সর্বোচ্চ SPI ক্লক ফ্রিকোয়েন্সি তার ডেটাশিটে উল্লেখ থাকে।
মূল কথা · Key takeaway

SPI = মাস্টার-চালিত ক্লক + MOSI/MISO/CS + ফুল-ডুপ্লেক্স শিফট-রেজিস্টার এক্সচেঞ্জ। এটি UART-এর চেয়ে দ্রুত ও একাধিক স্লেভ সমর্থন করে (প্রতিটির জন্য আলাদা CS), কিন্তু প্রতিটি স্লেভের জন্য আলাদা তার লাগায় পিন সংখ্যা বেড়ে যায় -- পরের পাঠে I2C দেখাবে কীভাবে মাত্র দুটো শেয়ার্ড তারে একাধিক ডিভাইস চালানো যায়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন -- তারপর "→ উত্তর" চাপুন।

প্র ০১ যদি মাত্র ৪টি ক্লক পালস চালানো হয় (৮টির বদলে), master_reg এবং slave_reg-এ কী থাকবে বলে আপনার মনে হয়?

পুরো এক্সচেঞ্জ হবে না -- মাস্টারের উপরের ৪ বিট আর স্লেভের নিচের ৪ বিট মিশে থাকবে (আংশিক শিফট)। সম্পূর্ণ অদল-বদল ঘটতে ঠিক ৮টি পালস লাগে, কারণ প্রতিটি রেজিস্টার ৮ বিট চওড়া -- এটাই ১৬-বিট সার্কুলার রেজিস্টার মডেলের সরাসরি ফল।

প্র ০২ SPI-তে একাধিক স্লেভ যুক্ত করতে হলে সাধারণত প্রতিটির জন্য আলাদা CS লাইন লাগে। ৫টি স্লেভের জন্য মোট কতগুলো পিন লাগবে (MOSI/MISO/SCLK শেয়ার্ড ধরে)?

MOSI, MISO, SCLK -- এই তিনটি সব স্লেভ শেয়ার করে, কিন্তু প্রতিটি স্লেভের নিজস্ব CS লাইন লাগে। তাই মোট $3 + 5 = 8$টি পিন লাগবে। এই CS-স্কেলিং সমস্যাটাই I2C-এর (পরের পাঠ) একটি বড় সুবিধার জায়গা -- I2C-তে ডিভাইস সংখ্যা বাড়লেও পিন সংখ্যা সবসময় ২-ই থাকে।

প্র ০৩ কোড সেলে original_master = 0xA5 ও original_slave = 0x3C-এর বদলে দুটোই একই মান (যেমন 0x55) হলে ফলাফলে কী পার্থক্য হবে?

কোনো দৃশ্যমান পার্থক্য হবে না -- ৮ পালসের পর দুটো রেজিস্টারই আবার 0x55-এই থাকবে, কারণ দুজনের আসল মান একই ছিল। এক্সচেঞ্জ লজিক ঠিকই কাজ করবে, শুধু ইনপুট-আউটপুট একরকম দেখাবে বলে চোখে বদল ধরা পড়বে না -- এটি নিজে রান করিয়ে যাচাই করাই সবচেয়ে ভালো উপায়।

অনুশীলন

  1. চিন্তা করুন: spi_byte_transfer_time_us ফাংশনে ক্লক ফ্রিকোয়েন্সি 20_000_000 Hz দিলে ১ বাইট পাঠাতে কত সময় লাগবে বলে আপনার হিসাব বলে?

    $transfer\_time = (8 / 20{,}000{,}000) \times 10^6 = 0.4\,\mu s$ -- অর্থাৎ ১ MHz-এর তুলনায় ২০ গুণ দ্রুত, ঠিক যেমন ক্লক ফ্রিকোয়েন্সি ২০ গুণ বেড়েছে।

  2. পরীক্ষা করুন: কোড সেলে spi_transfer ফাংশনকে num_bits=16 দিয়ে (দুটো ১৬-বিট মান পাঠিয়ে) কল করুন -- Run চেপে দেখুন কতগুলো ক্লক পালস লাগে সম্পূর্ণ এক্সচেঞ্জ হতে।

    ১৬টি ক্লক পালস লাগবে -- কারণ সার্কুলার-শিফট মডেল অনুযায়ী সম্পূর্ণ এক্সচেঞ্জ ঘটতে রেজিস্টারের প্রস্থ যত বিট, ঠিক ততগুলো পালস লাগে। রেজিস্টার প্রস্থ দ্বিগুণ হলে প্রয়োজনীয় পালসও দ্বিগুণ হয়।

আরও পড়ুন · 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 ও আরও অনেক কোর্স -- সব এক জায়গায়।
আগের পাঠ
UART সিরিয়াল কমিউনিকেশন