در قسمت قبلی درباره استفاده از DMA برای ارسال اطلاعات از حافظه توسط واحد USART صحبت کردیم. قبل از هرچیز، باید به توضیح پروتکل ارتباطی SPI و مودهای کاری مختلف آن بپردازیم. SPI مخفف Serial Peripheral Interface است که به معنی رابط سریال برای دستگاههای جانبی است. SPI یک پروتکل پراستفاده برای ارتباط بین میکروکنترلر و ICهای وسایل جانبی مانند سنسورها، ADC، DAC، SRAM، شیفت رجیستر و … است. این پروتکل برای ارسال اطلاعات به صورت سنکرون استفاده میشود و به همین دلیل همراه با داده، یک سیگنال کلاک نیز فرستاده میشود. همچنین این ارتباط میتواند به صورت full duplex باشد، بدین معنی که همزمان از هر دو سمت اطلاعات فرستاده و دریافت شود. برای ارتباط SPI همواره یک دستگاه به عنوان Master، و یک یا چند دستگاه به عنوان Slave تنظیم میشوند و کلاک این ارتباط توسط دستگاه Master ارسال میشود. ارتباط SPI میتواند با 3 یا 4 سیم انجام شود.
4 سیگنالی که در ارتباط SPI استفاده میشوند، عبارتند از:
- سیگنال کلاک (SPI CLK یا SCLK)
- انتخاب کننده چیپ Slave (Chip select یا )
- خروجی Master، ورودی Slave (MOSI)
- ورودی Master، خروجی Slave (MISO)
همانطور که گفته شد، ارتباط SPI یک ارتباط سنکرون است و ارسال اطلاعات با سیگنال کلاکی که توسط Master تولید میشود، همزمان میباشد. برای اطمینان از استفاده صحیح از این پروتکل باید، در دیتاشیت دستگاهی که با آن کار میکنیم، در بخش مربوط به رابط SPI مشخصات کلاک و فرکانس آن را بررسی کنیم.
سیگنال انتخاب چیپ از سوی دستگاه Master برای انتخاب Slave استفاده میشود و معمولا به صورت active low است. بنابراین Master برای انتخاب یک Slave باید منطق ‘0’ بفرستد. در کاربردهایی که از چند دستگاه Slave استفاده میشود، دستگاه Master باید برای انتخاب هر کدام از آنها یک سیگنال CS تولید کند.
توسط سیگنالهای MOSI و MISO نیز اطلاعات به ترتیب توسط Master به Slave و برعکس فرستاده میشود.
ارسال اطلاعات
برای شروع ارتباط، دستگاه Master سیگنال کلاک را تولید میکند و میفرستد، همچنین Slave مورد نظر را توسط سیگنال CS انتخاب میکند. در طول این ارتباط به طور همزمان اطلاعات فرستاده (و به صورت سریال در باس MOSI/SDO شیفت داده میشوند) و دریافت (و به صورت سریال در باس MISO/SDI شیف) میشوند. شیفت و نمونهگیری اطلاعات با لبه سیگنال کلاک انجام میشود، و آزادی انتخاب لبه بالا رونده یا پایین رونده برای این منظور وجود دارد. برای اطلاع از تعداد بیتهایی که میتوان منتقل کرد نیز باید به دیتاشیت مراجعه کنیم.
قطبیت و فاز کلاک
در واحد SPI، دستگاه Master میتواند تعیین کند که قطبیت و فاز کلاک به چه صورت باشد. بیت CPOL قطبیت کلاک را در حالت بیکاری () در سطح 0 باشد یا 1. حالت بیکاری به وقتی گفته میشود که قبل و بعد از ارتباط، سیگنال در سطح بالا (منطق 1) باشد. همچنین بیت CPHA برای انتخاب فاز کلاک استفاده میشود. همانطور که گفته شد، امکان انتخاب لبه کلاک که شیف و نمونه برداری را تنظیم میکند، وجود دارد. این انتخاب توسط بیت CPHA انجام میشود. بسته به وضعیت دو بیت CPOL و CPHA، چهار حالت یا مود کاری برای SPI تعریف میشود که در جدول زیر شرح داده شدهاند.
واحد SPI در STM32
در بورد Blue Pill دو واحد SPI وجود دارد که میتوان به صورت مستقل آنها را راهاندازی و استفاده کرد. اکنون میخواهیم یک پروژه ایجاد کنیم و به صورت ساده از واحد SPI1 برای ارسال اطلاعات روی یک شیفت رجیستر استفاده کنیم. برای شیف رجیستر از M74HC595 استفاده شده است.
برای شروع کار، مانند گذشته، در محیط Cube MX یک پروژه جدید ایجاد میکنیم و تنظیمات کلاک و دیباگ را انجام میدهیم. برای تنظیم واحد SPI، از منوی Connectivity، SPI1 را انتخاب میکنیم و از منوی باز شده، حالت Transmit Only Master را برمیگزینیم. مورد کاری SPI را در حالت 0 تنظیم میکنیم و سایر تنظیمات را در همان حالت اولیه رها میکنیم.
همچنین، برای تحریک پایهی RCK در HC595 (دیتاشیت آی سی را در اینترنت ببینید)، به یک پایه دیگر نیاز داریم که ما در اینجا با کلیک روی پایه PA4 آن را به عنوان پین خروجی تنظیم میکنیم.
تنظیمات کلاک و ایجاد پروژه را نیز مانند قبل انجام میدهیم، کد پروژه را تولید میکنیم و وارد محیط برنامهنویسی میشویم.
نوشتن کد پروژه
در ابتدا برنامه و قبل از main یک تابع برای فرستادن داده توسط SPI تعریف میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* USER CODE BEGIN 0 */ void send_SPI(uint8_t data) { LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4); while(!LL_SPI_IsActiveFlag_TXE(SPI1)); LL_SPI_TransmitData8(SPI1, data); if(LL_SPI_IsActiveFlag_RXNE(SPI1)) {} __NOP(); LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4); } /* USER CODE END 0 */ |
نکته: با اینکه در این برنامه نیازی به دریافت اطلاعات نداریم، اما همچنان علاوه بر پرچم مربوط به خالی بودن بافر ارسال اطلاعات، پرچم دریافت اطلاعات را نیز چک کردیم. زیرا رجیستر SPI به صورت چرخشی عمل میکند و برای کاربرد صحیح خواندن و نوشتن همزمان باید این پرچم چک شود. با این حال در این برنامه اگر این قسمت کد وجود نداشت نیز، عمل مورد نظر ما به درستی انجام میشد.
همانطور که قبلتر توضیح داده شد، از پایه PA4 برای ایجاد کلاک تحریک استفاده کردهایم، تابع __NOP() نیز برای ایجاد یک تاخیر قبل از فعال کردن سیگنال استفاده شده است.
سپس درون main و قبل از حلقه while(1) واحد SPI را فعال میکنیم:
1 | LL_SPI_Enable(SPI1); |
حالا میتوانیم با استفاده از تابعی که تعریف کردیم، داده دلخواهمان را توسط SPI ارسال کنیم. بدین منظور میتوانیم توسط کد زیر عدد هگز 66 را به شیف رجیستر بفرستیم:
1 | send_SPI(0x66); |
اکنون نوشتن کد به اتمام رسیده است، میتوانیم از پروژه خروجی بگیریم و روی میکرو دانلود کنیم. توجه کنید که حتما با توجه به دیتا شیت HC595، همهی پایهها (به جز پایه9 یعنی QH’ که نیازی به آن نداریم) را به درستی وصل کنید. ما برای نمایش اطلاعات دریافت شده از 8 LED که به پایههای QA تا QH متصل میشوند، استفاده کردیم. پایههای GND و به زمین، و پایههای VDD، به 5v یا 3.3v میکرو وصل میشوند.
RCK را به PA4، SI را به PA7 (همان پایه SPI1_MOSI) و SCK را به PA5 (پایه کلاک SPI) وصل میکنیم.
اگر همهی پایهها به درستی وصل شده باشند، عدد 66 توسط LEDها نمایش داده میشود.
در این بخش با ساز و کار واحد SPI آشنا شدیم. در بخش بعدی در مورد راهاندازی LCD Nokia و نمایش اطلاعات روی آن به کمک SPI صحبت خواهیم کرد.