فهرست مطالب
Toggleآموزش ESP32-IDF قسمت چهارم-پورت I2C
I2C (Inter-Integrated Circuit) یک پروتکل ارتباطی سریال است که به چندین دستگاه اجازه می دهد تا به یک گذرگاه واحد متصل شوند. معمولاً در سیستمهای تعبیهشده و سایر برنامههایی که تعداد کمی از دستگاهها نیاز به ارتباط با یکدیگر دارند، استفاده میشود.
انتقال داده بین دستگاه های دیجیتال عمدتاً به دو صورت موازی یا سریال از طریق یک رسانه سیمی انجام می شود. میکروکنترلرها از پروتکل های سریال زیادی برای ارتباط با دستگاه های خارجی مانند سنسورها و نمایشگرها استفاده می کنند که ارتباط I2C یکی از آنهاست. زبانی که در آن یک حالت ارتباطی بین دستگاه ها و یک سیستم تعریف شده است به عنوان پروتکل شناخته می شود. جنبه های الکتریکی، سرعت انتقال، ترتیب بیت و معنای الگوی بیت را مشخص می کند. برای ارتباط سریال داده ها از پروتکل های مختلفی مانند TWI، USB، SPI یا UART و … استفاده می شود که کاربردهای زیادی در پروژه های میکروکنترلر دارد.
ارتباط I2C :
I2C (مدار یکپارچه ای که به عنوان “آی تو سی” تلفظ می شود) پروتکلی است که به تراشه ها یا مدارهای اسلیو مختلف اجازه می دهد با تراشه های اصلی مختلف ارتباط برقرار کنند. فقط برای ارتباطاتمسر کوتاه استفاده می شود. از نظر استفاده از سیم به صرفه است، زیرا تنها به 2 سیم نیاز دارد اما 1008 دستگاه را می توان تنها با این 2 سیم پشتیبانی کرد.
پروتکل I2C توسط شرکت فیلیپس در دهه 1980 اختراع شد تا ارتباطات آسان روی پردازنده بین CPU و تراشه های مختلف محیطی را فراهم کند. I²C مخفف Inter-Integrated Circuit است. این ارتباط یک رابط سریال فاصله کوتاه است که تنها به دو خط باس برای انتقال داده دو طرفه نیاز دارد. برای اتصال آی سی های محیطی با سرعت پایین تر به میکروکنترلرها در فاصله کم استفاده می شود. تجهیزات جانبی کم سرعت شامل EEPROM های خارجی، سنسورهای دیجیتال، I2C LCD و سنسورهای دما از جمله مواردی هستند که معمولا دارای پورت I2C هستند.
I2C از ارتباط مولتی مستر پشتیبانی می کند، به این معنی که چندین مستر می توانند به گذرگاه متصل شوند و می توانند با یکدیگر و با Slave ارتباط برقرار کنند. همچنین از کشش ساعت پشتیبانی می کند و به یک اسلیو اجازه می دهد تا خط ساعت را پایین نگه دارد تا نشان دهد که برای پردازش یک فرمان یا داده به زمان بیشتری نیاز دارد.
پینهای ارتباط I2C :
I2C یک پروتکل ساده و کارآمد است که تنها به دو سیم برای ارتباط نیاز دارد: یک خط ساعت و یک خط داده. اغلب در برنامه هایی که به ارتباطات کم هزینه و کم مصرف نیاز است، مانند سنسورها، نمایشگرها و سایر لوازم جانبی استفاده می شود. هر تعداد Slave و هر تعداد Master را می توان به این 2 سیگنال متصل کرد. برخلاف UART Communication، این پروتکل به سیگنال ساعت نیاز دارد زیرا این ارتباط همزمان است. با استفاده از سیگنال ساعت، سرعت انتقال داده با سرعت بالا را نیز میتواند به دست می آورد.
باس مستر سیگنال ساعت را تولید می کند. در برخی موارد، اسلیوها کند می شوند. که ممکن است به این دلیل باشد که داده های داده شده به آنها بسیار طولانی هستند یا بازه زمانی هر چرخه ساعت بسیار کوتاه است، بنابراین اسلیوها خط ساعت را پایین می آورند تا بتوانند به راحتی داده ها را قبل از شروع چرخه بعدی آماده کنند. این پدیده به “کشش ساعت” (clock stretching) معروف است.
درایورهای باس I2C “اپن درین” هستند، به این معنی که آنها می توانند یک خط سیگنال را low کنند، اما نمی توانند آن را بالا ببرند. فرض کنید اگر یک دستگاه سعی کند خط را به پایین بکشد در حالی که دستگاه دیگری سعی می کند خط را به سمت بالا هدایت کند، در این صورت بحث باس وجود نخواهد داشت. این مکانیزم درایورها را از آسیب دیدن محافظت می کند . در شکل زیر میتوانید سخت افزار بخش درایور I2C را ببینید:
مقاومت های pull-up متصل شده روی خط، خط را به سطح بالا هدایت می کند، زمانی که هیچ سیگنال دیگری آن را پایین نمی آورد. مقاومتها میتوانند مقادیر متفاوتی داشته باشند، اما معمولاً ما با مقاومت 4.7k شروع میکنیم و سپس در صورت نیاز، مقدار را با توجه به نیاز خود کاهش میدهیم.
سطوح سیگنال باس I2C :
برخی مواقع، ماژول ها و قطعات متصل به یک سیستم دارای سطوح ولتاژ متفاوتی هستند، یعنی ولتاژ یک دستگاه در مقایسه با دستگاه دیگر بیشتر است. اما امکان اتصال هر دو دستگاه بدون استفاده از مدار تغییر سطح وجود دارد. این کار با اتصال یک مقاومت Pull up به دستگاهی که سطح ولتاژ کمتری دارد انجام می شود. مطمئناً این روش در همه موارد کار نمی کند، اما در برخی موارد که ولتاژ پایین تر از سطح ورودی سیستم ولتاژ بالاتر است، به خوبی کار می کند. یک مثال خوب از این روش می توانداتصال شتاب سنج 3.3 ولت و به یک میکرو 5 ولت باشد.
قالب بسته پیام I2C :
داده ها در هر دو جهت در خط داده سریال (SDA) توسط master یا slave ارسال می شوند. فقط یک Master می تواند انتقال داده را شروع کند و Slaves به Master پاسخ می دهد. امکان داشتن چندین Master در یک باس مشترک وجود دارد، اما تنها یکی می تواند در یک زمان فعال باشد. خط کلاک SCL همیشه توسط Master هدایت می شود.
هر دو خط SCL و SDA درایورهای اپن درین هستند و از طریق مقاومت های pull-up به ولتاژ تغذیه مثبت متصل می شوند. دستگاه های I²C فقط می توانند خط را پایین بکشند و نمی توانند آن را بالا ببرند. هنگامی که هیچ وسیله ای روی خط فعال نیست ، از طریق مقاومت pull up خط شناور می شود. به همین دلیل است که مقاومت های pull up در I²C مهم هستند.
ارتباط از طریق I2C تقریبا پیچیده است. برای برقراری ارتباط معتبر، سیگنالهای دستگاههای موجود در باس باید به یک پروتکل خاص پایبند باشند. اما خوشبختانه، بیشتر پردازنده ها به تنهایی جزئیات را مدیریت میکنند و ما میتوانیم فقط روی دادههایی که میخواهیم انتقال دهیم تمرکز کنیم.
همه پیام ها در دو فریم تقسیم می شوند:
یک فریم آدرس
و فریم های داده
در فیلد آدرس، master آدرس برده ای را که قرار است داده ها به آن منتقل شود، می گوید. و فریم های داده شامل پیام های 8 بیتی است که از master به slave یا از slave به master ارسال می شود. وقتی خط SCL پایین می آید، داده ها روی خط SDA قرار می گیرند. و هنگامی که خط SCL بالا رفت، داده ها نمونه برداری می شوند.
شرایط شروع/توقف :
هر دستور I²C که توسط یک دستگاه master با یک شرط START شروع می شود و با یک شرط STOP پایان می یابد. برای هر دو شرایط، SCL باید بالا باشد. پس از شرط Start، گذرگاه مشغول در نظر گرفته می شود و تنها پس از شناسایی شرط Stop توسط مستر دیگری می تواند استفاده شود.
دستگاه مستر SDA (دادههای سریال) را پایین میکشد و SCL (ساعت سریال) را بالا میگذارد تا فیلد آدرس را ارسال کند. به همه دستگاههای اسلیو هشدار میدهد که یک انتقال قرار است شروع شود. اگر دو یا چند دستگاه مستر وجود داشته باشد، هر دستگاه مستر که ابتدا SDA را پایین بیاورد، مالکیت باس را در اختیار خواهد گرفت.
- Start condition: A high to low transition of SDA.
- Stop condition: A low to high transition of SDA.
فریم آدرس I2C:
فریم آدرس همیشه اول است، زیرا بدون آدرس، دستگاه نمیداند دادهها به کدام اسلیو منتقل میشود. اگر آدرس 7 بیتی باشد، ابتدا MSB (مهمترین بیت) خوانده می شود و سپس یک بیت R/W نشان می دهد که عملیات مورد نظر خواندن یا نوشتن است.
پس از شرط شروع، ما باید آدرس اسلیو را مشخص کنیم زیرا یک دستگاه مستر می تواند داده ها را به چندین Slave ارسال کند. هر اسلیو یک آدرس منحصر به فرد خواهد داشت. هر slave متصل به گذرگاه دارای یک آدرس منحصر به فرد 7 بیتی یا 10 بیتی میباشد.
آدرس دهی دستگاه 7 بیتی:
پس از شرط Start، اولین بایت ارسال شده به عنوان بایت کنترل شناخته می شود. هفت بیت اول بایت کنترل آدرس اسلیو را تشکیل می دهد.
چهار بیت اول ثابت هستند.
سه بیت بعدی توسط پین های آدرس سخت افزاری (A0، A1 و A2) تنظیم می شوند که به کاربر اجازه می دهد آدرس I²C را تغییر دهد. این روش اجازه می دهد تا هشت دستگاه در باس I²C کار کنند.
بیت هشتم (LSB) بیت تعیین جهت داده (R/W) است.
“0” در LSB نشان می دهد که Master اطلاعات را در یک Slave انتخاب شده می نویسد.
“1” در LSB نشان می دهد که Master داده ها را از Slave می خواند.
هنگامی که گیرنده آدرس خود را دریافت می کند، باید سیگنال Acknowledge را تولید کند. در این حالت فرستنده باید گذرگاه SDA را آزاد کند تا گیرنده بتواند آن را کنترل کند. هنگامی که گیرنده خط SDA را پایین می آورد، تصدیق می کند که بایت آدرس دریافت شده است. اگر گیرنده SDA را پایین نیاورد، شرایط یک عدم تایید (NACK) است و عملیات متوقف می شود.
Acknowledge = 0 volts No Acknowledge = High volts.
هنگامی که یک بایت کنترل ارسال می شود، هر دستگاه/برد در سیستم آدرس دهی هفت بیتی، هفت بیت اول دریافت شده را با آدرس خود مقایسه می کند. اگر آدرس با هم مطابقت داشته باشد، دستگاه خود را آدرسدهی شده توسط مستر میداند. اکنون بسته به مقدار بیت R/W بهعنوان گیرنده داده اسلیو یا فرستنده داده اسلیو عمل میکند.
آدرس دهی دستگاه 10 بیتی:
هر دستگاه I2C باید یک آدرس داخلی ۷ بیتی داشته باشد. بنابراین بر ، تنها 128 نوع دستگاه I2C مختلف وجود خواهد داشت. اما دستگاه های I2C مختلف بسیار بیشتری وجود دارد و احتمال زیادی وجود دارد که 2 دستگاه دارای آدرس یکسان در گذرگاه I2C باشند. برای غلبه بر این مشکل، دستگاه ها اغلب دارای چندین آدرس داخلی هستند که می توانیم از طریق پین های پیکربندی خارجی روی دستگاه انتخاب کنیم. برای گسترش دامنه آدرس دستگاه های موجود، یک طرح آدرس دهی 10 بیتی نیز ارائه شده است.
به جای یک، از دو کلمه آدرس برای آدرس دهی دستگاه استفاده می شود.
اولین کلمه آدرس حاوی کد ثابت به عنوان “11110” در بیتهای پرارزش تر برای آگاهی از بردهای موجود در گذرگاه آدرس دستگاه 10 بیتی است. پس از آن، شامل دو بیت پر ارزشتر از آدرس 10 بیتی و بیت R/W است.
کلمه آدرس دوم شامل 8 بیت کم ارزش (LSB) از آدرس 10 بیتی است. بنابراین با این روش افزودن بیت ها، سازگاری با مدل آدرس دهی 7 بیتی تضمین می شود.
فریم داده I2C:
اکنون انتقال داده ها می تواند انجام شود. پالس های ساعت توسط مستر به طور منظم تولید می شود. بیت R/W نشان میدهد که دادهها توسط مستر خوانده یا نوشته میشوند. اگر قرار باشد داده ها خوانده شوند، Slave داده ها را روی SDA قرار می دهد و اگر قرار است داده ها نوشته شوند، Master داده ها را روی SDA قرار می دهد. رجیستر داخلی در اکثر موارد بر اساس تعداد خواندن یا نوشتن به صورت خودکار افزایش می یابد.
وضعیت توقف :
پس از انتقال متوالی تمام داده ها، یک شرط توقف توسط Master ایجاد می شود. SCL باید از وضعیت پایین به بالا منتقل شود و سپس باید بالا بماند، در حالی که SDA از پایین به بالا تغییر وضعیت می دهد تا شرایط توقف را تعریف کند. در شکل بالا این حالت نشان داده شده است.
مراحل انتقال داده I2C :
خب حالا وقتشه که انتقال داده ها از طریق پروتکل I2C را به صورت گام به گام با هم بررسی کنیم.
برای شروع ارتباط در گذرگاه I2C، مستر ابتدا باید یک شرط شروع ارسال کند. شرط شروع، الگوی خاصی از سیگنالها در کلاک و خطوط داده است که به همه دستگاههای موجود در باس نشان میدهد که یک ارتباط جدید در شرف شروع است.
پس از ارسال شرط شروع، master آدرس اسلیوی را که می خواهد با آن ارتباط برقرار کند ارسال می کند. همانطور که قبلا ذکر شد، هر دستگاه Slave دارای یک آدرس 7 بیتی منحصر به فرد است و Master مشخص می کند که آیا می خواهد از Slave بخواند یا در آن بنویسد که این کار با تنظیم LSB آدرس انجام میشود.
دستگاه Slave به آدرس خود در باس گوش می دهد و اگر آدرس خود را دریافت کند با یک سیگنال تایید پاسخ می دهد. سیگنال تایید یک پالس در خط داده است که توسط اسلیو برای یک سیکل ساعت پایین کشیده می شود. این سیگنال به master نشان می دهد که Slave آدرس خود را دریافت کرده و آماده برقراری ارتباط است.
اگر Slave آدرس خودش را دریافت نکند، یا اگر مشغول باشد و قادر به برقراری ارتباط نباشد، سیگنال تایید ارسال نمی کند و ارتباط قطع می شود. سپس Master می تواند در زمان دیگری ارتباط را دوباره امتحان کند یا با یک Slave دیگر ارتباط برقرار کند.
اگر سیگنال تایید دریافت شود، Master می تواند سپس دستور یا داده ای را برای Slave ارسال کند. Slave با یک سیگنال تایید پاسخ می دهد تا نشان دهد که داده را دریافت کرده است. این فرآیند می تواند چندین بار برای ارسال و دریافت چندین بایت داده تکرار شود.
توجه به این نکته مهم است که سیگنال تایید در برخی موارد اختیاری است. اگر برخی از بردها قادر به دریافت یا پردازش داده نباشند، یا اگر برای کار در حالت عدم تأیید پیکربندی شده باشند، ممکن است سیگنال تأیید ارسال نکنند. در این موارد، مستر ممکن است نیاز به استفاده از روشهای دیگری برای تشخیص دریافت داده یا بررسی خطا داشته باشد.
پس از اینکه Slave با یک سیگنال تایید پاسخ داد تا نشان دهد که آماده برقراری ارتباط است، master می تواند دستور یا داده ای را برای Slave ارسال کند. دستور یا داده به صورت یک سری بیت در خط داده ارسال می شود که هر بیت توسط سیگنال ساعت مستر کلاک می شود.
علاوه بر ارسال و دریافت داده، Master همچنین می تواند دستورات خاصی را برای Slave ارسال کند تا رفتار آن را کنترل کند یا اطلاعات خاصی را درخواست کند. به عنوان مثال، Master می تواند دستوری برای خواندن یک رجیستر در Slave یا نوشتن داده ها در یک مکان حافظه خاص ارسال کند. Slave با داده های مناسب یا یک سیگنال تایید به این دستورات پاسخ می دهد تا نشان دهد که دستور دریافت و اجرا شده است.
در ارتباط I2C، مستر و اسلیو می توانند چندین بایت داده را به یکدیگر ارسال و دریافت کنند. این در کاربردهایی هایی مفید است که لازمه حجم زیادی از داده بین دستگاه ها منتقل شود.
پس از اینکه master ارتباط خود را با Slave کامل کرد، یک شرط توقف برای پایان دادن به انتقال ارسال می کند. شرط توقف، الگوی خاصی از سیگنالها روی ساعت و خطوط داده است که به تمام دستگاههای موجود در باس نشان میدهد که ارتباط کامل شده است.
شرط توقف به Slave می گوید که می تواند گوش دادن به داده ها را متوقف کند و می تواند به حالت کم مصرف برگردد. همچنین باس را آزاد می کند تا دیگر مسترها یا اسلیوها بتوانند ارتباط را آغاز کنند.
پس از ارسال شرط توقف، Master می تواند با ارسال یک شرط شروع و آدرس یک Slave دیگر، ارتباط جدیدی را آغاز کند، یا می تواند برای صرفه جویی در انرژی وارد حالت کم مصرف شود.
توجه به این نکته ضروری است که شرط توقف در برخی موارد اختیاری است. اگر برخی از دستگاهها به گونهای پیکربندی شده باشند که در حالت پیوسته کار کنند، جایی که ارتباط در جریان است و دادهها به طور مداوم بدون وقفه منتقل میشوند، ممکن است وضعیت توقف ارسال نکنند. در این موارد، ممکن است استاد یا برده نیاز به استفاده از روشهای دیگری برای تشخیص پایان انتقال یا پایان دادن به ارتباط داشته باشند.
کاربردهای I2C:
I2C یک پروتکل پرکاربرد در مصارف مختلف است، از جمله:
سیستم های تعبیه شده: I2C معمولاً در سیستم های تعبیه شده برای ارتباط با سنسورها، نمایشگرها و سایر تجهیزات جانبی استفاده می شود. سادگی و مصرف انرژی کم آن را به گزینه ای ایده آل برای این نوع کاربردها تبدیل کرده است.
اتوماسیون صنعتی: I2C در سیستم های اتوماسیون صنعتی برای اتصال حسگرها، محرک ها و سایر دستگاه ها برای کنترل و نظارت بر فرآیندها استفاده می شود.
لوازم الکترونیکی مصرفی: I2C در طیف وسیعی از دستگاه های الکترونیکی مصرفی مانند گوشی های هوشمند، تبلت ها و لپ تاپ ها برای برقراری ارتباط با سنسورها، نمایشگرها و سایر لوازم جانبی استفاده می شود.
دستگاه های پزشکی: I2C در دستگاه های پزشکی مانند سیستم های مانیتورینگ، گلوکز متر و کنسانتره های اکسیژن قابل حمل برای برقراری ارتباط با حسگرها و سایر وسایل جانبی استفاده می شود.
خودرو: I2C در سیستمهای خودرویی برای برقراری ارتباط با سنسورها، نمایشگرها و سایر تجهیزات جانبی مانند سیستمهای کنترل موتور، سیستمهای اطلاعات سرگرمی و سیستمهای ایمنی استفاده میشود.
هوافضا: I2C در کاربردهای هوافضا برای برقراری ارتباط با حسگرها، نمایشگرها و سایر لوازم جانبی مانند سیستم های اویونیک هواپیما و سیستم های ارتباطی ماهواره ای استفاده می شود.
پورت I2C در ESP32 :
پردازنده ESP32-S3 دارای دو رابط گذرگاه I2C است که برای حالت مستر I2C یا حالت Slave استفاده می شود، بسته به نوع پیکربندی کاربر رابط های I2C از ویژگیهای زیر پشتیبانی می کنند:
- حالت استاندارد (100 کیلوبیت بر ثانیه)
- حالت سریع (400 کیلوبیت بر ثانیه)
- تا 800 کیلوبیت بر ثانیه (محدود شده توسط مقاومت پول آپ خطوط SCL و SDA)
- حالت آدرس دهی 7 بیتی و 10 بیتی
- حالت آدرس دهی دوگانه (آدرس سازی اسلیو و آدرس دهی رجیستر اسلیو)
- انتقال مداوم داده با پایین کشیدن خط SCL
- فیلتر نویز دیجیتال قابل برنامه ریزی
ساختار سخت افزاری I2C:
در شکل زیر سخت افزار داخلی واحد I2C را در پردازنده ESP32-S3 مشاهده میکنید.
کنترلر واحد I2C دارای بخشهای مهم زیر است:
- (transmit and receive memory (TX/RX RAM
- command controller (CMD_Controller)
- SCL clock controller (SCL_FSM)
- SDA data controller (SCL_MAIN_FSM)
- serial/parallel data converter (DATA_Shifter)
- filter for SCL (SCL_Filter)
- filter for SDA (SDA_Filter)
علاوه بر این، کنترلر I2C دارای یک ماژول کلاک است که کلاک های I2C را تولید می کند و یک ماژول همگام سازی که گذرگاه APB و کنترلر I2C را همگام می کند.
ماژول کلاک برای انتخاب منابع کلاک ، روشن و خاموش کردن و تقسیم کلاک ها استفاده می شود.
SCL_Filter و SDA_Filter به ترتیب نویزهای سیگنال های ورودی SCL و سیگنال های ورودی SDA را حذف می کنند. ماژول همگام سازی انتقال سیگنال بین حوزه های کلاک مختلف را همگام می کند.
SCL_MAIN_FSM اجرای دستورات I2C و توالی خط SDA را کنترل می کند. CMD_Controller در حالت مستر I2C برای تولید دستورات (R)START، STOP، WRITE، READ و END استفاده می شود. رم TX و RX به ترتیب داده های ارسالی و دریافتی را ذخیره می کنند. DATA_Shifter داده ها را بین فرم سریال و موازی تبدیل می کند.
برای کار و کد نویسی واحد I2C اما ما فقط قسمتهایی که با رنگ نارنجی در کد بالا مشخص شده است را نیاز داریم در واقع این قسمتها با کد ما قابل کنترل هستند.
اما فرایند کار به چه صورت است:
به عکس زیر دقت کنید.
نوشتن در حالت مستر با I2C:
با توجه به تصویر بالا برای نوشتن در حالت مستر باید 7 گام را طی کنیم:
گام اول: ایجاد یک لینک به بخش Command هستش.وظیفه بخش کامند نگه داری دستوراتی هست که بایستی به اسلیو ارسال گردد.
گام دوم: ایجاد شرایط start.
گام سوم: ارسال آدرس به همراه بیت نوشتن.
گام چهارم:ارسال داده مورد نظر.
گام پنجم: ارسال بیت توقف.
گام ششم:شروع اجرای دستورات گامهای دو تا 5 توسط واحد CMD. در واقع ما دستورات را نوشته در واحد کامند قرار داده ایم و در گام ششم به واحد کامند اعلام میکنیم دستورات را ارسال نماید.
برخلاف سایر پردازنده های دیگر که اجرا و زمانبندی دستورات بالا بر عهده کاربر است در ESP32 سخت افزار این وظیفه را بر عهده دارد و ما دستورات را تعیین میکنیم و سخت افزار خود آنهارا اجرا میکند.
گام هفتم: و در انتها لینک ایجاد شده را حذف میکنیم.
خواندن در حالت مستر با I2C:
برای خواندن دیتا از اسلیو با توجه به عکس بالا تمامی مراحل مانند حالت نوشتن میباشد به جز دو مورد.
مورد اول در گام سوم به همراه ارسال آدرس اسلیو بایستی بیت خواندن همراه آدرس ارسال گردد.
مورد دوم بعد از خواندن هربایت داده طبق شکل بایستی سیگنال ACK توسط مستر ایجاد شود به جز هنگام خواندن بایت آخر که بعد از آن بایستی سیگنال NACK فرستاده شود.
حالت اسیلو I2C:
اگر واحد I2C را در مد اسلیو کانفیگ کرده باشیم درایور I2C آماده استفاده میباشد و تنها کار لازم استفاده از دو تابع زیر است:
i2c_slave_read_buffer()
هر زمان که master داده ها را برای Slave بنویسد، Slave به طور خودکار آن را در بافر دریافت ذخیره می کند. این کار به برنامه Slave اجازه می دهد تا تابع ()i2c_slave_read_buffer را بنا به صلاحدید خود فراخوانی کند. این تابع همچنین دارای پارامتری برای تعیین زمان بلاک در صورت عدم وجود داده در بافر دریافت است. که به برنامه اسلیو اجازه می دهد تا با یک بازه زمانی مشخص منتظر بماند تا داده ها به بافر برسد.
i2c_slave_write_buffer()
بافر ارسال برای ذخیره تمام داده هایی که Slave می خواهد به ترتیب FIFO برای master ارسال کند استفاده می شود. داده ها در آنجا باقی می مانند تا زمانی که مستر آن را درخواست کند. تابع ()i2c_slave_write_buffer دارای پارامتری برای تعیین زمان بلاک در صورت پر بودن بافر ارسال است. این کار به برنامه Slave این امکان را می دهد تا با یک بازه زمانی مشخص منتظر بماند فضای کافی در بافر ارسال در دسترس قرار گیرد.
بررسی API های I2C:
خب حالا که تا اندازه ای با واحد I2C و مکانیزم عملکرد آن اشنا شدید به بررسی API های پر کاربرد آن خواهیم پرداخت.
برای راه اندازی کامل درایور I2C و استفاده از تمامی امکانات 7 قدم نیاز میباشد.اما بسته به کاربرد و استراتژی برنامه شما میتوان تعدادی از آنها را حذف نمود.این هفت گام به صورت زیر میباشد:
گام اول :تنظیم پارامترهای اولیه مانند مد ارتباط،اختصاص پایه ها سرعت ارتباط و…
گام دوم :نصب درایور.
گام سوم :نوشتن توابع موردنظر برای ارسال و دریافت داده بر اساس مد ارتباط.(اسلیو/مستر)
گام چهارم :تنظیمات وقفه ها.
گام پنجم : شخصی سازی تنظیمات پارامترهای I2C مانند زمانبندی،ترتیب بیتها و…
گام ششم : هندل کردن خطاها.
گام هفتم :حذف درایور در صورت عدم نیاز به I2C.
برای برقراری ارتباط I2C، با پیکربندی درایور شروع کنید. این کار با تنظیم پارامترهای ساختار i2c_config_t انجام می شود:
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_5, // select SDA GPIO specific to your project
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = GPIO_NUM_6, // select SCL GPIO specific to your project
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000, // select frequency specific to your project
.clk_flags = 0, // optional; you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here
}
تنظیمات در حالت اسلیو:
i2c_config_t conf_slave = {
.sda_io_num = GPIO_NUM_5, // select SDA GPIO specific to your project
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = GPIO_NUM_6, // select SCL GPIO specific to your project
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.mode = I2C_MODE_SLAVE,
.slave.addr_10bit_en = 0,
.slave.slave_addr = ESP_SLAVE_ADDR, // slave address of your project
.slave.maximum_speed = 100000 // expected maximum clock speed
.clk_flags = 0, // optional; you can use I2C_SCLK_SRC_FLAG_* flags to choose I2C source clock here
}
بعد از قرار دادن تنظیمات موردنظر در ساختار i2c_config_t ادرس متغیر را به همراه شماره پورت در تایع ()i2c_param_config وارد میکنیم.
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
در گام دوم باید درایور I2C را نصب نماییم تا منابع لازم برای آن در نظر گرفته شود برای این منظور تابع زیر را فراخوانی میکنیم.
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_buf_len, size_t
slv_tx_buf_len, int intr_alloc_flags)
این تابع دارای چندین پارامتر است.
پارامتر اول شماره پورت I2C موردنظر.
پارامتر دوم مد عملکر (اسلیو/مستر).
پارامتر سوم و چهارم طول بافر ارسال و دریافت در مد اسلیو.
پارامتر پنجم پرچم وقفه های مورد نظر برای استفاده.
در گام سوم بایستی دستورات و به عبارتی کامندهای مورد نظر را برای برقراری ارتباط تنظیم نماییم.
برای این منظور
ما با ایجاد و مقداردهی اولیه لینک فرمان I2C با استفاده از تابع ()i2c_cmd_link_create شروع می کنیم. این تابع یک کنترل کننده لینک فرمان I2C را برمی گرداند.
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
پس از ایجاد لینک فرمان، ()i2c_master_start را فراخوانی می کنیم و لینک فرمان را به عنوان پارامتر داخل آن ارسال می کنیم. با این کار I2C Master قادر به تولید یک سیگنال شروع می شود. و تمام دستورات در صف را ارسال می کند.
i2c_master_start(cmd);
i2c_master_write_byte(cmd, SLAVE_ADDRESS << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write(cmd, message, len, ACK_CHECK_EN);
پس از ارسال دیتای مورد نظر با ارسال دستور () i2c_master_stop و ایجاد شرایط توقف ارتباط I2C را خاتمه میدهیم.
i2c_master_stop(cmd);
سپس تابع ()i2c_master_cmd_begin را فراخوانی می کنیم که به I2C master اجازه می دهد تا دستورات در صف را ارسال کند. این تابع دارای سه پارامتر است. پارامتر اول شماره پورت I2C، پارامتر دوم کنترل کننده فرمان I2C و پارامتر سوم حداکثر تیک های انتظار است که در این حالت روی 1 ثانیه تنظیم می شود.
ret = i2c_master_cmd_begin(i2c_master_port, cmd, 1000 / portTICK_PERIOD_MS);
پس از اتمام ارسال دستورات، لینک فرمان را آزاد می کنیم. این امر با فراخوانی تابع ()i2c_cmd_link_delete و ارسال فرمان I2C به عنوان پارامتر در داخل آن انجام میشود.
i2c_cmd_link_delete(cmd);
خب گامهای بعدی به دلیل آنکه استفاده خیلی زیادی ندارند و در مواقع خاص مورد استفاده قرار میگیرند به جهت طولانی نشدن آموزش مورد بررسی قرار نمیگیرند و در صورت نیاز میتوانید به داکیومنتهای شرکت esspresif مراجعه نمایید.
سایر نکات مهم و مثالهای عملی در ویدیو این قسمت مورد بحث و بررسی قرار گرفته است.