بررسی
در فصل قبل یکی از دو استاندارد ارتباطی رایج در مارکت سیستم های ارتباطی intra-boards ، پروتکل I²C، را تجزیه و تحلیل کردیم. اکنون زمان آن است که پروتکل SPI را تجزیه و تحلیل کنیم.
همه میکروکنترلرهای STM32 حداقل یک رابط SPI که امکان توسعه هر دو کاربرد master و slave را فراهم می کند، ارائه می دهند. CubeHAL تمام موارد لازم برای برنامهریزی آسان چنین ابزار جانبی را پیادهسازی میکند. این فصل طبق معمول، یک نمای کلی و سریع از ماژول HAL_SPI پس از معرفی مختصر از ویژگی های SPI، ارائه می دهد.
Introduction to the SPI Specification
Serial Peripheral Interface (SPI) یک پروتکل در حوزه ارتباطات سریال، همزمان و دو طرفه بین کنترل کننده master (که معمولاً با یک MCU یا چیزی با قابلیت برنامه ریزی اجرا می شود) و چندین دستگاه Slave است. همانطور که در ادامه خواهیم دید، ماهیت رابط SPI اجازه می دهد تا ارتباطات full duplex و half duplex را از طریق یک گذرگاه انجام دهید. پروتکل SPI یک استاندارد واقعی است و در اواخر دهه 70 توسط Motorola معرفی شد که هنوز هم تا حد زیادی به عنوان پروتکل ارتباطی برای بسیاری از آی سی های دیجیتال استفاده می شود. برخلاف پروتکل I²C، SPI پروتکل پیام معینی را روی گذرگاه خود اعمال نمی کند، اما محدود به سیگنال دهی گذرگاه است که به دستگاه های Slave در ساختار پیام های مبادله شده آزادی کامل می دهد.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)
همانطور که در شکل 1 نشان داده شده است، گذرگاه SPI معمولا از چهار سیگنال تشکیل می شود، حتی ممکن است برخی از دستگاه های SPI بتوانند تنها با سه I/O کار کنند (در این جا ما از 3-wire SPI صحبت می کنیم):
- SCK: این سیگنال I/O برای تولید کلاک جهت همگام سازی انتقال داده از طریق گذرگاه SPI ، توسط دستگاه master تولید می شود . یعنی در یک گذرگاه SPI، هر انتقال همیشه توسط Master شروع می شود. برخلاف I²C، SPI ذاتا سریعتر و سرعت کلاک آن معمولاً چندین مگاهرتز است. امروزه یافتن دستگاه های SPI که قادر به تبادل داده تا نرخ 100 مگاهرتز هستند بسیار رایج است. علاوه بر این، پروتکل SPI به دستگاههای دارای سرعت ارتباطی متفاوت اجازه میدهد تا روی یک گذرگاه با یکدیگر تبادل داده داشته باشند.
- MOSI: نام این سیگنال I/O مخفف Master Output Slave Input است و برای ارسال داده ها از دستگاه Master به Slave استفاده می شود. برخلاف گذرگاه I²C، که در آن فقط یک سیم برای تبادل داده در هر دو جهت استفاده می شود، پروتکل SPI دو لاین مجزا برای تبادل داده بین master و slave تعریف می کند.
- MISO: مخفف Master Input Slave Output است و در واقع I/O ایست که برای ارسال داده از یک دستگاه Slave به Master استفاده می شود.
- SSn: مخفف Slave Select است و در یک گذرگاه SPI معمولی که ‘n’ خط مجزا وجود دارد ، برای آدرس دادن به دستگاه های SPI مورد نظر در تراکنش استفاده می شود. بر خلاف پروتکل I²C، SPI از آدرسهای Slave برای انتخاب دستگاهها استفاده نمیکند، این کار را با استفاده از یک خط فیزیکی با LOW کردن ان ، دستگاه مورد نظر را انتخاب می کند. در یک گذرگاه SPI ، تنها یک دستگاه Slave می تواند با پایین آوردن خط SS خود فعال باشد. به همین دلیل است که دستگاههایی با سرعت ارتباطی متفاوت میتوانند در یک باس وجود داشته باشند.
SPI با داشتن دو خط ارتباطی جدا از هم، MOSI و MISO، امکان ارتباطات فول دوبلکس را فراهم می کند، زیرا دستگاه Slave قادر است در حالی که داده های جدیدی را از آن دریافت می کند، داده ها را به Master ارسال کند. در یک گذرگاه SPI یک به یک (فقط یک Master و یک Slave)، سیگنال SS را می توان حذف کرد (I/O Slave مربوطه به زمین متصل می شود) و خطوط MISO/MOSI در یک خط واحد به نام Slave In/Slave Out (SISO) ادغام می شوند . در این مورد می توانیم در مورد SPI 2 سیم صحبت کنیم، حتی اگر اساساً باس 3 سیم باشد.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)
هر تراکنش روی گذرگاه با فعال کردن خط SCK با توجه به حداکثر فرکانس slave شروع می شود. هنگامی که خط کلاک شروع به تولید سیگنال می کند، master خط SS را LOW می کند و انتقال داده آغاز شود. انتقال معمولاً شامل دو رجیستر (یکی در master و دیگری در slave) با اندازه معین است. دادهها معمولاً ابتدا با مهمترین بیتها به خارج منتقل میشوند، در حالی که یک بیت جدید کم ارزش به همان رجیستر منتقل میشود. در همان زمان، داده های slave به رجیستر بیت کم اهمیت منتقل می شود. پس از اینکه بیت های رجیستر به خارج و داخل منتقل شدند، master و slave داده ها را رد و بدل می کنند. اگر نیاز به مبادله داده های بیشتری باشد، shift رجیسترها مجددا بارگذاری می شوند و فرآیند تکرار می شود. انتقال ممکن است برای هر تعداد چرخه از کلاک ادامه یابد. پس از تکمیل، Master از تغییر دادن toggling سیگنال کلاک دست میکشد و معمولاً Slave را از حالت انتخاب خارج میکند.
شکل 2 نحوه انتقال داده ها را در یک انتقال full-duplex نشان می دهد، در حالی که شکل 3 روشی را نشان می دهد که معمولاً در یک اتصال half-duplex مبادله می شود.
تنظیمات Clock Polarity and Phase
علاوه بر تنظیم فرکانس کلاک باس، master و slave باید در مورد قطبیت و فاز کلاک با توجه به داده های مبادله شده روی خطوط MOSI و MISO نیز توافق کنند. SPI Motorola این دو تنظیمات را به ترتیب CPOL و CPHA نامگذاری میکند و اکثر silicon vendors آن قرارداد را پذیرفتهاند.
ترکیبات قطبیت و فاز اغلب به عنوان SPI bus modes نامیده شده که معمولاً مطابق جدول 1 شماره گذاری می شوند. رایج ترین حالت ها ، حالت 0 و حالت 3 هستند، اما اکثر دستگاه های slave حداقل از چندین حالت باس پشتیبانی می کنند.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)
دیاگرام زمان بندی در شکل 4 نشان و در زیر بیشتر توضیح داده شده است:
- در CPOL=0 مقدار اولیه کلاک صفر است، یعنی حالت فعال 1 و حالت بیکار 0 است.
– برای CPHA=0، داده ها در لبه بالارونده SCK (انتقال LOW → HIGH) کپچر می شوند و در لبه پایین رونده (HIGH → LOW Clock Transition) خارج می شوند.
– برای CPHA=1، داده ها در لبه پایین رونده SCK کپچر می شوند و در لبه بالارونده خارج می شوند.
- در CPOL=1 مقدار اولیه کلاک یک است (برعکس CPOL=0)، یعنی حالت فعال 0 و حالت بیکار 1 است.
– برای CPHA=0، داده ها در لبه پایین رونده SCK گرفته می شوند و در لبه بالارونده خارج می شوند.
– برای CPHA=1، داده ها در لبه بالارونده SCK گرفته می شوند و در لبه پایین رونده خارج می شوند.
یعنی CPHA=0 به معنای نمونه برداری در اولین لبه کلاک است، در حالی که CPHA=1 به معنای نمونه برداری از دومین لبه کلاک است، صرف نظر از اینکه آن لبه کلاک در حال بالا یا پایین رفتن می باشد. توجه داشته باشید که با CPHA=0، داده ها باید در نیم چرخه قبل از اولین چرخه کلاک پایدار باشند.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)
Slave Select Signal Management
همانطور که قبلاً گفته شد، دستگاه های SPI Slave آدرسی ندارند که آنها را در گذرگاه شناسایی کند، اما تا زمانی که سیگنال Slave Select (SS) LOW باشد، شروع به تبادل داده با master می کنند. میکروکنترلرهای STM32 دو حالت مجزا برای کنترل سیگنال SS ارائه می دهند که در مستندات ST NSS نامیده می شود. بیایید آنها را تحلیل کنیم.
- حالت نرم افزار NSS: سیگنال SS توسط فریمور هدایت می شود و هر GPIO آزاد را می توان برای راه اندازی یک آی سی زمانی که MCU در حالت master کار می کند، یا برای تشخیص شروع انتقال داده توسط Master ، زمانی که MCU در حالت Slave کار می کند، استفاده کرد.
- حالت سخت افزار NSS: یک I/O خاص از میکروکنترلر برای هدایت سیگنال SS استفاده و به صورت داخلی توسط ابزار جانبی SPI مدیریت می شود. بسته به تنظیمات خروجی NSS دو نوع پیکربندی ممکن است:
– خروجی NSS فعال است: این پیکربندی فقط زمانی استفاده می شود که دستگاه در حالت Master کار می کند. سیگنال NSS هنگامی که Master ارتباط را شروع می کند، LOW شده و تا زمانی که SPI غیرفعال شود، LOW نگه داشته می شود. ذکر این نکته ضروری است که این حالت زمانی مناسب است که فقط یک دستگاه SPI Slave در گذرگاه وجود داشته باشد و SS آن به سیگنال NSS متصل باشد. این پیکربندی اجازه حالت مولتی مستر را نمی دهد.
– خروجی NSS غیرفعال است: این پیکربندی قابلیت چند مستر multi-master را برای دستگاههایی که در حالت master کار میکنند ، فراهم می کند. برای دستگاههایی که بهعنوان Slave تنظیم شدهاند، پین NSS بهعنوان ورودی کلاسیک NSS عمل میکند: زمانی که NSS LOW است، Slave انتخاب میشود و زمانی که NSS HIGH است انتخاب نمیشود.
SPI TI Mode
ابزار جانبی SPI در میکروکنترلرهای STM32 هنگام کار در حالت master و هنگامی که سیگنال NSS برای کار در حالت سخت افزاری پیکربندی شده است، از حالت TI پشتیبانی می کند. در حالت TI، قطبیت کلاک و فاز مجبور به انطباق با الزامات پروتکل Texas Instruments هر مقدار که تنظیم شده باشد، می شود. مدیریت NSS نیز مختص پروتکل TI است که پیکربندی مدیریت NSS را برای کاربر شفاف می کند. در حالت TI، در واقع، سیگنال NSS در انتهای هر بایت ارسالی “پالس” می زند (در ابتدای بیت LSB از LOW به HIGH و در شروع بیت MSB از HIGH به LOW می رود و بایت انتقالی بعدی را تشکیل می دهد.). برای اطلاعات بیشتر در مورد این حالت ارتباطی، به دیتاشیت MCU مورد نظر خود مراجعه کنید.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)
Availability of SPI Peripherals in STM32 MCUs
بسته به نوع خانواده و پکیج مورد استفاده، میکروکنترلرهای STM32 می توانند تا شش واحد جانبی مستقل SPI را ارائه دهند. جدول 2 در دسترس بودن تجهیزات جانبی SPI در MCU های STM32 در تمام شانزده برد Nucleo ، خلاصه می کند.
برای هر ابزار جانبی SPI و یک MCU STM32 داده شده، جدول 2 پین های مربوط به خطوط MOSI، MISO و SCK را نشان می دهد. علاوه بر این، ردیفهای تیرهتر، پینهای جایگزینی را نشان میدهند که میتوان از آنها در طراحی آسانتر بردها استفاده کرد. به عنوان مثال، با توجه به STM32F401RE MCU، می ببینیم که پریفرال SPI1 به PA7، PA6 و PA5 نگاشت شده است، اما PB5، PB5 و PB3 نیز میتوانند به عنوان پایههای جایگزین استفاده شوند. توجه داشته باشید که واحد جانبی SPI1 از پین های I/O مشابه در تمام MCU های STM32 با پکیج LQFP-64 استفاده می کند. این مثال واضح دیگری از سازگاری پین به پین pin-to-pin ارائه شده توسط میکروکنترلرهای STM32 است.
اکنون آمادهایم تا نحوه استفاده از CubeHAL API برای برنامهنویسی این ابزار جانبی را ببینیم.
HAL_SPI Module
برای برنامه ریزی ابزار جانبی SPI، HAL ساختار SPI_HandleTypeDef به صورت زیر تعریف می شود:
typedef struct __SPI_HandleTypeDef {
SPI_TypeDef *Instance; /* SPI registers base address */
SPI_InitTypeDef Init; /* SPI communication parameters */
uint8_t *pTxBuffPtr; /* Pointer to SPI Tx transfer Buffer */
uint16_t TxXferSize; /* SPI Tx Transfer size */
__IO uint16_t TxXferCount; /* SPI Tx Transfer Counter */
uint8_t *pRxBuffPtr; /* Pointer to SPI Rx transfer Buffer */
uint16_t RxXferSize; /* SPI Rx Transfer size */
__IO uint16_t RxXferCount; /* SPI Rx Transfer Counter */
DMA_HandleTypeDef *hdmatx; /* SPI Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /* SPI Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /* Locking object */
__IO HAL_SPI_StateTypeDef State; /* SPI communication state */
__IO uint32_t ErrorCode; /* SPI Error code */
} SPI_HandleTypeDef;
- Instance: اشاره گر به توصیفگر SPI ایست که قرار است از آن استفاده کنیم. به عنوان مثال، SPI1 توصیف کننده اولین ابزار جانبی SPI است.
- Init: نمونه ای از ساختار SPI_InitTypeDef است که برای پیکربندی دستگاه جانبی استفاده می شود. تا مدتی دیگر آن را عمیق تر بررسی خواهیم کرد.
- pTxBuffPtr، pRxBuffPtr: اشاره گر به بافرهای داخلی مورد استفاده برای ذخیره موقت داده های منتقل شده به و از دستگاه جانبی SPI است. این ایتم زمانی استفاده می شود که SPI در حالت وقفه کار می کند و نباید در کد کاربر تغییر یابد.
- hdmatx، hdmarx: اشارهگر به نمونههایی از ساختار DMA_HandleTypeDef که وقتی ابزار جانبی SPI در حالت DMA کار میکند استفاده میشود.
راه اندازی ابزار جانبی SPI با استفاده از ساختار SPI_InitTypeDef انجام می شود که به صورت زیر تعریف شده است:
typedef struct {
uint32_t Mode; /* Specifies the SPI operating mode. */
uint32_t Direction; /* Specifies the SPI bidirectional mode state. */
uint32_t DataSize; /* Specifies the SPI data size. */
uint32_t CLKPolarity; /* Specifies the serial clock steady state. */
uint32_t CLKPhase; /* Specifies the clock active edge for the bit capture. */
uint32_t NSS; /* Specifies whether the NSS signal is managed by hardware (NSS pin) or by software */
uint32_t BaudRatePrescaler; /* Specifies the Baud Rate prescaler value which will be used to configure the SCK clock. */ uint32_t FirstBit; /* Specifies whether data transfers start from MSB or LSB bit. */
uint32_t TIMode; /* Specifies if the TI mode is enabled or not. */
uint32_t CRCCalculation; /* Specifies if the CRC calculation is enabled or not. */
uint32_t CRCPolynomial; /* Specifies the polynomial used for the CRC calculation. */ } SPI_InitTypeDef;
- Mode: این پارامتر ، SPI را در حالت master یا slave قرار می دهد. می تواند مقادیر SPI_MODE_MASTER و SPI_MODE_SLAVE را در بر گیرد.
- Direction: مشخص می کند که دستگاه جانبی slave به صورت 4 سیم (دو خط مجزا برای ورودی/خروجی) یا 3 سیم (فقط یک خط برای I/O) کار کند. می تواند مقدار SPI_DIRECTION_2LINES را برای پیکربندی حالت 4 سیمی full-duplex.، مقدار SPI_DIRECTION_2LINES_RXONLY برای راه اندازی حالت half-duplex 4 سیم و مقدار SPI_DIRECTION_1LINE برای پیکربندی حالت 3 سیم half-duplex ، در بر گیرد.
- DataSize: اندازه داده های انتقالی روی گذرگاه SPI را پیکربندی می کند و می تواند مقادیر SPI_DATASIZE_8BIT و SPI_DATASIZE_16BIT را در بر گیرد.
- CLKPolarity: تنظیمات SCK CPOL را پیکربندی می کند و می تواند مقادیر SPI_POLARITY_LOW (که مربوط به CPOL=0) و SPI_POLARITY_HIGH (که مطابق با CPOL=1 است) را در بر گیرد.
- :CLKPhase این فیلد فاز کلاک را تنظیم می کند، و می تواند مقادیر SPI_PHASE_1EDGE (که مربوط به CPHA=0) و SPI_PHASE_2EDGE (که مطابق با CPHA=1 است) را در بر گیرد.
- NSS: این فیلد رفتار I/O NSS را کنترل می کند. می تواند مقدار SPI_NSS_SOFT را برای پیکربندی سیگنال NSS در حالت نرم افزاری و مقادیر SPI_NSS_HARD_INPUT و SPI_NSS_HARD_OUTPUT را برای پیکربندی سیگنال NSS در حالت سخت افزاری ورودی و خروجی ، در بر گیرد.
- BaudRatePrescaler: مقدار prescaler کلاک APB را تنظیم و حداکثر سرعت کلاک SCK را تعیین می کند. میتواند مقادیر SPI_BAUDRATEPRESCALER_2، SPI_BAUDRATEPRESCALER_4، …، SPI_BAUDRATEPRESCALER_256 را در بر گیرد (همه دو به توان از 2¹ تا 28).
- FirstBit: ترتیب انتقال داده را مشخص می کند و می تواند مقادیر SPI_FIRSTBIT_MSB و SPI_FIRSTBIT_LSB را در بر گیرد.
- TIMode: برای فعال/غیرفعال کردن حالت TI استفاده می شود و می تواند مقادیر SPI_TIMODE_DISABLE و SPI_TIMODE_ENABLE را در بر گیرد.
- CRCCcalculation و CRCPolynomial: ابزار جانبی SPI در همه میکروکنترلرهای STM32 از تولید CRC در سخت افزار پشتیبانی می کند. مقدار CRC را می توان به عنوان آخرین بایت در حالت Tx منتقل کرد، یا بررسی خطای CRC را می توان برای آخرین بایت دریافتی به طور خودکار انجام داد. مقدار CRC با استفاده از یک چند جملهای فرد قابل برنامهریزی در هر بیت محاسبه میشود. محاسبه در لبه کلاک نمونهبرداری که توسط CPHA و CPOL تعریف شده است، پردازش میشود. مقدار CRC محاسبه شده به طور خودکار در انتهای بلوک داده و همچنین برای انتقال مدیریت شده توسط CPU یا DMA بررسی می شود. هنگامی که یک عدم تطابق بین CRC محاسبه شده داخلی بر روی داده های دریافتی و CRC ارسال شده توسط فرستنده تشخیص داده شود، یک شرط خطا ست می شود. وقتی SPI در حالت دایره ای DMA درایو می شود، ویژگی CRC در دسترس نیست. برای اطلاعات بیشتر در مورد این موضوع، به دیتاشیت STM32 MCU مورد نظر خود مراجعه کنید.
طبق معمول، برای پیکربندی ابزار جانبی SPI از تابع زیر استفاده می کنیم:
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);
که یک اشاره گر به نمونه ای از ساختار SPI_HandleTypeDef که قبلا دیده شده است را می پذیرد.
Exchanging Messages Using SPI Peripheral
هنگامی که ابزار جانبی SPI پیکربندی شد، میتوانیم تبادل داده را با دستگاههای slave شروع کنیم. از آنجایی که SPI یک پروتکل ارتباطی معین را تحمیل نمیکند، هیچ تفاوتی بین توابع CubeHAL هنگام استفاده از ابزار جانبی SPI در حالت Slave یا Master وجود ندارد. تنها تفاوت در پیکربندی پریفرال است که پارامتر Mode ساختار SPI_InitTypeDef را بر این اساس تنظیم می کند.
طبق معمول، CubeHAL سه راه برای برقراری ارتباط از طریق گذرگاه SPI ارائه می دهد: polling interrupt و DMA.
برای ارسال مقداری بایت به یک دستگاه Slave در حالت polling ، از تابع زیر استفاده می کنیم:
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
رفتار تابع تقریباً مشابه سایر توابع ارتباطی است که تاکنون دیده شد (به عنوان مثال، مواردی که برای UART استفاده می شود)، بنابراین ما در اینجا پارامترهای آن را شرح نمی دهیم. اگر واحد جانبی SPI به گونهای پیکربندی شده باشد که در حالت SPI_DIRECTION_1LINE یا SPI_DIRECTION_2LINES کار کند، میتوان از این تابع استفاده کرد.
برای دریافت مقداری بایت در حالت polling ، از تابع زیر استفاده می کنیم:
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);
این تابع در هر سه حالت Direction قابل استفاده است.
Maximum Transmission Frequency Reachable using the CubeHAL
فرکانس SCK از فرکانس PCLK با استفاده از یک prescaler قابل برنامه ریزی مشتق شده است. این prescaler از 2¹ تا 2⁸ متغیر است. با این حال، همانطور که چندین بار قبلاً گفته شد، CubeHAL در هنگام درایو واحدهای جانبی هزینههای غیرقابل اجتنابی را اضافه میکند. و این در مورد SPI نیز صدق می کند. در واقع، با استفاده از CubeHAL نمی توان به تمام فرکانس های SPI پشتیبانی شده با حالت های مختلف SPI دست یافت.
مهندسان ST به وضوح این را در CubeHAL مستند کرده اند. اگر فایل stm32XXxx_hal_spi.c را باز کنید، می توانید (حدوداً در خط 60) دو جدول را مشاهده کنید که حداکثر فرکانس انتقال قابل دسترسی را با توجه به حالت جهت (half-duplex or full-duplex) و نحوه برنامه ریزی و استفاده از پریفرال (polling, interrupt and DMA) گزارش می دهد.
به عنوان مثال، در STM32F4 اگر واحد جانبی SPI در حالت Slave کار کند و آن را با استفاده از CubeHAL در حالت وقفه برنامه ریزی کنیم ، می توانیم به فرکانس SCK برابر با fPCLK/8 برسیم .
CubeHALUsing CubeMX to Configure SPI Peripheral
برای استفاده از CubeMX به منظور فعال کردن ابزار جانبی SPI مورد نظر، باید به ترتیب زیر عمل کنیم. ابتدا باید حالت ارتباط مورد نظر را از نمای IP tree انتخاب کنیم، همانطور که در شکل 5 نشان داده شده است. سپس، رفتار سیگنال NSS را در نمای پیکربندی مشابه مشخص کنیم. پس از تنظیم این دو پارامتر، میتوانیم با پیکربندی سایر تنظیمات SPI در نمای CubeMX Configuration ادامه دهیم.
![](https://gebrabit.com/wp-content/themes/woodmart/images/lazy.png)