راه اندازی SPI رزبری پای پیکو – Raspberry Pi Pico SPI

SPI رزبری پای پیکو بیشتر از آنچه به فکرتان برسد در کار با این میکروکنترلر جذاب و قدرتمند به شما کمک خواهد کرد. بسیاری از سنسورها، ADCها، LCDها، چیپهای حافظه، چیپهای کنترلی و … از درگاه SPI برای انتقال اطلاعات خود استفاده میکنند. سرعت بالای انتقال اطلاعات، تعداد پایههای کم و هزینه پیادهسازی پایین از مهمترین دلایل استفاده گسترده از SPI است. در این مقاله ابتدا به توضیح مفاهیم SPI میپردازیم و پس از آن واحد SPI رزبری پای پیکو با زبان میکروپایتون برای خواندن اطلاعات شتاب از سنسور MPU-9250 راهاندازی میشود.
SPI چیست؟
SPI (یا Serial Peripheral Interface) یک درگاه ارتباط سریال سنکرون برای انتقال اطلاعات است. پشتیبانی از ارتباط Full Duplex (ارسال و دریافت همزمان)، سرعت کلاک بالا (معمولا چند ده مگاهرتز) و هزینه پیادهسازی پایین، مهمترین ویژگیهای SPI هستند. ساختار SPI به صورت Master-Slave است و با دارا بودن قابلیت باس امکان ارتباط چند Slave با یک Master وجود دارد. این درگاه در دهه 1980 توسط شرکت موتورلا برای ایجاد ارتباط در سیستمهای embedded طراحی و ساخته شد.
اگر با درگاه SPI آشنایی کامل ندارید پیشنهاد میکنیم قبل از مطالعه این مقاله به مقاله SPI چیست مراجعه کنید.
واحد SPI رزبری پای پیکو
برد رزبری پای پیکو دارای دو واحد SPI با نامهای SPI0 و SPI1 است که کاملا مستقل از یکدیگر هستند. SPI رزبری پای پیکو هم قابلیت Master شدن و هم قابلیت Slave شدن را دارد. برای ایجاد انعطافپذیری، پایههای مختلفی از میکروکنترلر قابلیت اتصال به این دو SPI را دارند. در ادامه تصویری از این پایهها آورده شده است.

دقت داشته باشید برای پایه SS یا همان CS میتوانید از هر کدام از GPIOهای میکروکنترلر استفاده کنید و محدود به پایههای معرفی شده در تصویر فوق نیستید.
مهمترین ویژگیهای SPI رزبری پای پیکو عبارتند از:
- دو واحد SPI مستقل
- قابلیت تنظیم به صورت Master و Slave
- دارا بودن بافر برای ارسال و دریافت داده
- قابلیت تنظیم Data Size بین 4 تا 16 بیت
- قابلیت اتصال به DMA
- اتصال به Interrupt
- حداکثر نرخ کلاک 62.5MHz در حالت Master و 11MHz در حالت Slave
شاید برایتان جالب باشد بدانید توسط کتابخانههای نرم افزاری هم میتوان یک SPI نرم افزاری ایجاد کرد. به این معنی که CPU با اجرای کدهای نوشته شده دقیقا همان عملکرد واحد سخت افزاری SPI را روی پایهها ایجاد میکند. در این صورت محدود به استفاده از پایههای خاص نیستید و میتوانید تعداد واحدهای SPI رزبری پای پیکو را به بیش از دو عدد برسانید اما توجه داشته باشید لود زیادی روی CPU وارد خواهید کرد. بنابراین توصیه میکنیم تا حد امکان از ساخت Pripheralهای میکروکنترلر به صورت نرم افزاری خودداری کنید.
برای کسب اطلاعات بیشتر در مورد واحد SPI رزبری پای پیکو میتوانید به سند دیتاشیت میکروکنترلر RP2040 مراجعه کنید.
راه اندازی SPI رزبری پای پیکو – اتصال به ماژول MPU-9250
در این بخش استفاده از SPI رزبری پای پیکو را با یک پروژه عملی به شما نشان میدهیم. در این پروژه قصد داریم مقادیر زاویه در راستای محور X، محور Y و محور Z را با استفاده از شتاب سنج موجود در چیپ MPU-9250 بدست آوریم. چیپ MPU-9250 هم دارای درگاه SPI و هم دارای درگاه I2C است که در این نوشته از درگاه SPI آن استفاده شده است.
دقت داشته باشید در اینجا هدف ما ذکر قابلیتهای این چیپ یا نحوه عملکرد آن نیست بلکه تمرکز بر راه اندازی SPI رزبری پای پیکو با زبان میکرو پایتون است. بنابراین در رابطه با چیپ MPU-9250 تنها به ذکر اطلاعات مورد نیاز میپردازیم.

تنظیمات سنسور است که میتوانید با نوشتن درون آنها تنظیمات سنسور را تغییر دهید و برخی نیز شامل اطلاعات خواندنی است از جمله اطلاعات اندازه گیری شده توسط سنسور که با خواندن آنها به اطلاعات مورد نظرتان دسترسی پیدا میکنید. برای انجام یک عملیات در این سنسورها ابتدا باید مشخص کنید با کدام رجیستر میخواهید ارتباط برقرار کنید و قصد شما خواندن اطلاعات آن رجیستر است یا نوشتن اطلاعات در آن رجیستر و سپس اقدام به خواندن یا نوشتن اطلاعات کنید.
با این توضیحات مشخص میشود که ما به سه دسته اطلاعات در مورد کار با سنسور MPU-9250 احتیاج داریم
- اطلاعات مربوط به تنظیمات SPI، مانند نرخ کلاک و مد SPI
- اطلاعات مربوط به نحوه آدرسدهی رجیسترها و فهماندن به سنسور که قصد خواندن داریم یا نوشتن
- اطلاعات مربوط به آدرس رجیسترها، یعنی اینکه هر رجیستری در چه آدرسی قرار گرفته است.
به این منظور بخشهای کوچکی از دیتاشیت سنسور را در اینجا آوردهایم. اگر علاقهمند به مطالعه کامل دیتاشیت هستید به سند MPU-9250 Datasheet مراجعه کنید.

از تصویر فوق اطلاعات زیر نتیجهگیری میشود:
- تنظیم بیت ابتدای SPI به صورت MSB first باشد
- دیتا در لبه بالارنده کلاک نمونهبرداری میشود بنابراین یا باید در مد 0 باشیم و یا در مد 2
- فرکانس SPI حداکثر روی 1MHz تنظیم شود.
- ابتدا باید یک بایت ارسال شود که 7 بیت کم ارزش آن آدرس رجیستر مورد نظر باشد. اگر قصد خواندن رجیستر باشد بیت پرارزش باید 1 باشد و اگر بخواهیم درون رجیستر بنویسیم بیت پرارزش باید 0 باشد.
- بایت(های) بعدی شامل اطلاعاتی است که میخواهیم بخوانیم یا بنویسیم
در مورد آدرس رجیسترها به تصویر زیر توجه کنید

از سمت چپ ستون اول آدرس رجیسترها به صورت هگزادسیمال و ستون دوم آدرس رجیستارها به صورت دسیمال است. مطابق این جدول برای بدست آوردن مقادیر شتاب در سه جهت X, Y, Z کافی است از آدرس 3B شروع کنیم و 6 بایت بخوانیم. برای اطلاعات بیشتر درمورد لیت رجیسترهای MPU-9250 میتوانید به سند MPU-9250 Register Map مراجعه کنید.
حالا که اطلاعات مورد نظر برای خواندن اطلاعات شتاب سنج موجود در چیپ MPU-9250 از طریق درگاه SPI را بدست آوردهایم وقت آن است که SPI رزبری پای پیکو را در زبان میکروپایتون راهاندازی کنیم.
در اولین قدم کلاسهای SPI و Pin را از ماژول machine ایمپورت میکنیم. همچنین توابع sleep_us و sleep_ms از ماژول utime را ایمپورت میکنیم تا در جاهایی از برنامه که نیازمند تاخیر هستیم از آنها استفاده کنیم.
from machine import Pin, SPI from utime import sleep_us, sleep_ms
در قدم بعدی یک نمونه (instance) از کلاس SPI با نام spi0 میسازیم (این نام اختیاری است) و واحد SPI0 را به آن اختصاص میدهیم. همچنین تنظیمات SPI در همین مرحله قابل اعمال است.
spi0 = SPI( 0, baudrate=1_000_000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(18), mosi=Pin(19), miso=Pin(16) )
اولین پارامتر مربوط به انتخاب SPI0 یا SPI1 است که به ترتیب با عدد 0 یا 1 مشخص میشود. مطابق اطلاعات ارائه شده شده در بخش قبل، حداکثر کلاک پشتیبانی شده در چیپ MPU-9250 مقدار 1MHz است که همین عدد را برای کلاک SPI رزبری پای پیکو قرار دادهایم. با قرار دادن عدد 0 برای polarity و phase به مد 0 برای SPI میرویم که نمونهبرداری در لبه بالارونده کلاک باشد. (از مد 3 هم میتوان استفاده کرد)
مطابق اطلاعات دیتاشیت mpu-9250، سایز داده را 8 بیتی در نظر میگیریم و جهت ارسال داده را MSB first قرار میدهیم. ما در اینجا از پایههای GP16, GP18 و GP19 استفاده کردهایم اما استفاده از هرکدام از پایههایی که رزبری پای پیکو برای SPI0 قرار داده بلامانع است.
یک پایه از میکروکنترلر را برای استفاده به عنوان SS نیاز داریم. ما از پایه GP17 استفاده کردایم اما شما میتوانید از هر GPIO دلخواه برای این مورد استفاده کنید. اگر در مورد GPIO، کلاس Pin و یا نحوه import کردن ماژولها در پایتون به اطلاعات بیشتری نباز دارید میتوانید مقاله راه اندازی پایه های رزبری پای پیکو را مطالعه کنید.
ss = Pin(17)
حالا که کار تنظیمات SPI رزبری پای پیکو به پایان رسیده است کد مربوط به ارسال آدرس رجیستر(همراه با بیت read) و دریافت داده را مینویسیم. در این کد برای ارسال داده از Master به Slave از متد write استفاده خواهیم کرد. ورودی این متد دیتایی است که باید ارسال شود و جنس آن باید bytearray باشد. همچنین برای خواندن اطلاعات Slave توسط Master از متد read استفاده خواهیم کرد. ورودی این متد تعداد بایتهایی است که باید خوانده شود و خروجی آن اطلاعات خوانده شده به فرمت bytearray است.
transmit_data = bytearray([0x3B | 0x80]) ss.low() sleep_us(100) spi0.write(transmit_data) recive_data = spi0.read(6) ss.high()
به توضیحات کد توجه کنید:
- خط 1: از آنجا که متد write به ورودی از جنس bytearray نیاز دارد متغیری از جنس bytearray میسازیم. این متغیر باید 8بیت باشد که 7 بیت کم ارزش آدرس رجیستری است کخ قصد خواندن اطلاعات آن را داریم و بیت پر ارزش باید 1 باشد. (1 نشان دهنده خواندن و 0 نشان دهنده نوشتن است). خود آدرسها 7 بیتی هستند و برای اضافه کردن 1 به عنوان بیت پرارزش کافی است آدرس را با عدد باینری 10000000 به صورت منطقی OR کنیم. معادل هگزادسیمال این عدد 0x8B است.
- خط 2: برای آنکه Slave یا همان چیپ MPU-9250 فعال شود پایه SS را در حالت low قرار میدهیم. (Slaveها در SPI به صورت Active Low هستند)
- خط 3: پس از فعال کردن Slave، مدت کوتاهی به آن فرصت میدهیم تا فعال شود. در بسیاری از موارد نیاز به این فرصتدهی نیست. اما توصیه میکنیم برای آنکه دچار ایراد نشوید همیشه این فرصت کوتاه را به Slave بدهید.
- خط 4: با ارسال محتویات transmit_data به MPU-9250 میفهمانیم که قصد خواندن (چون بیت پر ارزش بایت ارسالی 1 است) از آدرس 0X8B (چون مقدار 7 بیت کم ارزش بایت ارسالی 0X7B است)را داریم.
- خط 5: مطابق با تصویری که از آدرس رجیسترهای MPU-9250 قرار دادهایم، دادههای مربوط به شتاب در راستای X, Y, Z پشت سر هم قرار گرفتهاند و هرکدام 2 بایت هستند. بنابراین 6 بایت داده را از Slave توسط متد read میخوانیم. خروجی این متد همان اطلاعات مورد نظر ماست که در متغیر recive_data ریختهایم.
- خط 6: مجددا SS را در حالت high قرار میدهیم تا Slave برای ارتباط بعدی آماده شود.
اطلاعات خوانده شده در متغیر recive_data به صورت bytearray است. برای آنکه بتوانیم در محاسبات ریاضی از آنها استفاده کنیم ابتدا باید آنها را به فرمت عددی درآوریم. این کار در قطعه کد زیر انجام شده است.
data_x = int.from_bytes(recive_data[0:2], 'big') data_y = int.from_bytes(recive_data[2:4], 'big') data_z = int.from_bytes(recive_data[4:6], 'big')
تا اینجا اطلاعات مربوط به شتاب در راستای X (متغیر data_x)، شتاب در راستای Y (متغیر data_y) و شتاب در راستای Z (متغیر data_z) را داریم. برای بدست آوردن زاویه خطی از این شتابها یک رابطه ریاضی وجود دارد.

بر اساس روابط فوق قطعه کد زیر عمل تبدیل شتاب خطی به زاویه خطی را انجام میدهد. دقت داشته باشید برای استفاده از توابع ریاضی مانند atan و sqrt ابتدا باید آنها را از ماژول math ایمپورت کرده باشید.
angle_x_radian = atan(data_x/sqrt(data_y**2 + data_z**2)) angle_y_radian = atan(data_y/sqrt(data_x**2 + data_z**2)) angle_z_radian = atan(data_z/sqrt(data_x**2 + data_y**2))
زوایای بدست آمده از این رابطه بر حسب رادیان هستند. در ادامه برای درک بهتر، آنها را به درجه تبدیل میکنیم.
angle_x_degree = (angle_x_radian/3.14)*180 angle_y_degree = (angle_y_radian/3.14)*180 angle_z_degree = (angle_z_radian/3.14)*180
در نهایت دادهها را چاپ میکنیم.
print('angle x is : ', angle_x_degree) print('angle y is : ', angle_y_degree) print('angle z is : ', angle_z_degree)
کد کامل این بخش به صورت زیر است:
from machine import Pin, SPI from utime import sleep_us, sleep_ms from math import sqrt, atan spi0 = SPI( 0, baudrate=1_000_000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=Pin(18), mosi=Pin(19), miso=Pin(16) ) ss = Pin(17, Pin.OUT) transmit_data = bytearray([0x3B | 0x80]) ss.low() sleep_us(100) spi0.write(transmit_data) recive_data = spi0.read(6) ss.high() data_x = int.from_bytes(recive_data[0:2], 'big') data_y = int.from_bytes(recive_data[2:4], 'big') data_z = int.from_bytes(recive_data[4:6], 'big') angle_x_radian = atan(data_x/sqrt(data_y**2 + data_z**2)) angle_y_radian = atan(data_y/sqrt(data_x**2 + data_z**2)) angle_z_radian = atan(data_z/sqrt(data_x**2 + data_y**2)) angle_x_degree = (angle_x_radian/3.14)*180 angle_y_degree = (angle_y_radian/3.14)*180 angle_z_degree = (angle_z_radian/3.14)*180 print('angle x is : ', angle_x_degree) print('angle y is : ', angle_y_degree) print('angle z is : ', angle_z_degree)
در انتهای این مقاله از شما دعوت میکنم تا تجربیات ارزشمند خود در مورد SPI رزبری پای پیکو را در بخش دیدگاهها با ما و دیگر دوستانتان به اشتراک بگذارید.
دیدگاهتان را بنویسید