تمام مدل های متوسط و بزرگ خانواده avr حداقل دارای یک تایمر 16 بیتی به همراه تعدادی کانال adc می باشند.
این ماژول ها دارای رجیستر های 16 بیتی می باشند که هسته AVR می تونه با استفاده از دستورالعمل های اسمبلی IN , OUT به آن ها دسترسی داشته باشد. از طرفی ازآنجا که دیتا باس AVR ، 8 بیتی می باشد هسته CPU برای دسترسی به این رجیسترها به دوسیکل ماشین احتیاج دارد . توجه کنید که یک اینتراپت میتونه در بین همین دو دستور اتفاق بیوفته حال اگر تابع اینتراپت به همین منابع یعنی رجیستر های 16 بیتی تایمر یک و یا مثلا ADC باشد برای جلوگیری از ، از دست رفتن اطلاعات مورد نظر مان در این رجیسترها باید برنامه مان طوری باشد که دسترسی به این رجیسترها به صورت هسته ای باشد به عبارت دیگر باید یک عمل خواندن و نوشتن در این رجیستر ها اینتراپت ناپذیر باشد . تمام رجیسترهای I/O شانزده بیتی دارای یک رجیستر موقت برای دسترسی به 8 بیت بالای این رجیستر ها 16 بیتی می باشند توجه کنید که یک تایمر 16 بیتی مثل تایمر 1 در مگا 16 تنها دارای یک رجیستر موقت برای تمام 16 بیت رجیسترش می باشد .
معمولا یک رجیستر 16 بیتی به صورت زیر خوانده می شود :
Cycle 1: in r16, TCNT1L ;Reading low byte into r16,this triggers the high
; byte to be latched in the temporary shadow
; register.
Cycle 2: in r17, TCNT1H ;Reading high byte from the temporary register.
در مثال فوق اگر در بین دو دستور یک اینتراپپ حال به هر دلیلی رخ دهد و روتین تابع به هر کدام از بایت های رجیستر تایمر یک دسترسی داشته باشد این امکان وجود دارد که رچیستر موقت مقدار خودش را تغییر دهد که این امر باعث می شود که CPU در زمان برگشت از وقفه مقدار اشتباه را در داخل R17 بارگزاری کند.
در تصویر زیر نحوه خواندن اطلاعات در رجیستر 16 بیتی تایمر یک نشان داده شده است :
توجه کنید که اعداد نشان داده شده در دایره ها نشان دهنده شماره سیکل ماشین اجرای دستور می باشد .
عمل نوشتن در رجیستر 16 بیتی تایمر 1 نیز به ترتیب زیر انجام میشود :
;r17 contains the high byte while r16 contains
;the low byte that is to be written.
Cycle 1: out TCNT1H, r17 ;Writing the high byte to the temporary register.
Cycle 2: out TCNT1L, r16 ;Writing both the low byte and the temporary
;register into the I/O Register.
در تصویر زیر نحوه نوشتن اطلاعات در داخل رجیستر 16 بیتی تایمر1 نشان داده شده است :
توجه کنید که اعداد نشان داده شده در دایره ها نشان دهنده شماره سیکل ماشین اجرای دستور می باشد .
توجه کنید که عمل خواندن و نوشتن در رجیستر 16 بیتی تایمر 1 در شکل دسترسی به بایت بالا و پایین با هم فرق می کند که اگر این ترتیب معکوس شود اطلاعاتی که در بایت بالا نوشته و یا خوانده می شود ناصحیح خواهد بود .
راه حل :
برای اجتناب نمودن از حالات فوق می توان از ماکرو های زیر در اسمبلر AVR و کامپایلر IAR در زبان C استفاده نمود :
ماکرو ها اسمبلی برای خواندن و نوشتن در رجیستر 16 بیتی :
.macro outw
cli
out @0, @1
out @0-1, @2
sei
.endmacro
.macro inw
cli
in @1, @2-1
in @0, @2
sei
.endmacro
نحوه استفاده از ماکرو های فوق در برنامه اسمبلی :
.include “8515def.inc”
inw r17, r16, TCNT1H ; Reads the counter value (high, low, adr)
outw TCNT1H, r17, r16 ; Writes the counter value (adr, high, low)
ماکرو های زبان C برای خواندن و نوشتن در رجیستر 16 بیتی :
IAR C MACROS
#include <ina90.h>
#define outw( ADDRESS, VAL )\
{\
_CLI();
ADDRESS = VAL;\
_SEI();\
}
#define inw( ADDRESS, VAL )\
{\
_CLI();
VAL = ADDRESS;\
_SEI();\
}
نحوه استفاده از ماکرو های فوق در زبان C :
#include <io8515.h>
inw( TCNT1, i ) ;/* Reads the counter value */
outw( TCNT1, i ) ;/* Writes the counter value */
: Notes
1. The outw and the inw macros uses four instruction cycles which is the same amount
of cycles as the ret instruction uses. Doing so the macros will not increase the worst
case interrupt response time.
2. The macros will not work for setting the EEPROM address since the address can not
be changed during write operation. This will lead to corruption of the data written.
داشتن یک سیستم که مرتبا یک سری پارامتر را در داخل حافظه EEPROM بنویسه و یا اینکه از آن بخواند می تونه باعث فرسوده شدن حافظه EEPROM بشه از طرفی تعداد باری که در مورد خواندن و نوشتن به شکل صحیح داخل یک EEPROM گارانتی میشود یک چیزی حدود 100 هزار مرتبه READ/WRITE می باشد .
از آنجا که هر بایت از EEPROM قابلیت 100 هزار بار خواندن یا نوشتن صحیح را دارد نوشتن پارامتر ها به صورت یک بافر دوار در داخل EEPROM را حل خوبی برای رفع مشکل فوق باشد .اگر چه در صورتی که سیستم در مقابل شرایطی مانند خطا در تغذیه که باعث ریست شدن آن میشوند محافظت نشده باشد سیستم برای شروع دوباره نیاز دارد که این قابلیت برایش پیش بینی شده باشد تا بتواند موقعیت قبلی خودش را در داخل بافر دوار پیدا کند.
در واقع قصد این APPNOTE تشریح روشی برای ایجاد یک سیستم مطمئن برای ذخیره سازی با حداکثر پایداری پارامتره در EEPROM می باشد .
2. تئوری عملکرد سیستم :
استفاده از یک بافر دورا (O-buffer) در داخل حافظه EEPROM افزایش مدت زمان استفاده از حافظه EEPROM برای ذخیره سازی داده ها را ممکن می سازد . اگر این بافر دو سطح داشته باشد در این صورت تعداد دفعاتی که میتوان داده ها را در EEPROM ذخیره نمود دو برابر حداکثر استقامت یک سلول EEPROM یعنی 200 هزار مرتبه می باشد . با افزایش حجم "O-buffer" امکان افزایش تعداد دفعات ذخیره سازی پارامترها در داخل فضای EEPROM
میسر خواهد بود به بیان دیگر ایده این کار توزیع ذخیره سازی پارهامتر ها در سرتاسر فضای EEPROM برای دست یابی به ماکزیمم استقامت EEPROM برای ذخیره سازی داده ها می باشد .
هنگامی که از "O-buffer" استفاده می شود تعداد دفعات ذخیره سازی پایدار برابر با تعدا موقعیت های حافظه EEPROM در "O-buffer" ضرب در حداکثر دفعات قابل استفاده از یک موقعیت در حافظه EEPROM میشود.
تمام "O-buffer" ها به یک اشاره گر که به آخیر موقعیتی که در آن داده ای نوشته شده است اشاره کند که حال برای بازیابی مقدار این اشاره گر بعد از مثلا خاموش شدن و یا هرگونه خطای احتمالی که باعث ریست شدن سیستم شود می توان از یک "O-buffer" دیگر استفاده نمود که البته چیزی که داخل این بافر قرار میگیرد آدرس موجود در اشاره گر نیست بلکه فقط یک نشانه میباشد که موقعیت بافری که پارامتر در آن واقع شده را تعیین می کند .
با ایجاد دو عدد "O-buffer" که به لحاظ اندازه با هم برابر هستند و اجازه دادن به عملکرد موازی اشاره گرهای مربوط به دو "O-buffer" امکان تشخیص اینکه آخرین موقعیت پارامتر در بافر چه بوده است را میسر می سازد .
در شکل زیر یک عملکرد "O-buffer" هشت سطحی تشریح شده است :
به هنگام نوشته شدن در بافر پارامتر ، بافر موقعیت نیز پدیت می گردد به گونه ای که بافر اشاره گر "Buffer ptr" به یک قسمت یکسان در هر دو پارامتر اشاره می کند مقدار هر المنت از بافر موقعیت برابر است با المنتی از بافر پارامتر که آخرین مقدار در آن واقع شده بعلاوه 1 همچنین این قضیه در مورد چرخش معکوس نیز صادق می باشد.
به این ترتیب بعد از ریست شدن سیستم و شروع به کار دوباره سیستم با جستجو در طول بافر موقعیت و فهمیدن آن که تفاضل مقدار کدام المنت بافر موقیت با مقدار المنت بعدیش از یک بیشتر هست میتوان موقعیت آخرین المنت بافر پارامتر را که در آن یک مقدار نوشته شده یا خوانده شده است را پیدا نمود .
توجه کنید که مقدار دهی اولیه به المنت های بافر موقعیت قبل از استفاده برای اولین بار بسیار مهم می باشد . اگر این کار صورت نگیرد شاید امکان اینکه بتوان المنت مورد نظر در بافر موقعیت را پیدا نمود میسر نباشد .البته این مشکل تنها در صورتی بوجود خواهد آمد که عمل ریست شدن قبل از کامل شدن یک دور کامل از تکمیل شدن "O-buffer" یا به اصطلاح یک “tour” رخ دهد .
بهترین راه حل برای مطمئن شدن از اینکه بافر موقعیت مقدار دهی اولیه شده باشد پاک کردن و یا پراگرام کردن آن همراه با پاک کردن یا پروگرام کردن حافظه فلش می باشد.
در ابتدا باید از این موضوع گاه بود که این روش استقامت افزوده شده برای ذخیره داده در داخل فضای EEPROM مشروط به آن است که حافظه میکرو اشباع نشده باشد . همچنین از این روش می توان برای ذخیره سازی چند پارامتر نیز استفاده کرد برای این منظور از آنجا که تمام بافر ها به صورت موازی عمل می کنند تمام پارا متر ها نیز باید به صورت همزمان ذخیره شوند .
3. نمونه کد تولید شده برای اینکار :
این نمونه کد توسط کامپایلر IAR برای میکروکنترلر MEGA16 توسعه داده شده است .
این کد دارای 4 تابع به ترتیب زیر می باشد :
1) "findCurrentEepromAddr()" : این تابع برای پیدا کردن آخرین محل از بافر پارامتر برای ادامه کار "O-buffer" می باشد.
2) "EeReadBuffer()" : این تابع برای خواندن پارامترها از بافر پارامتر استفاده می شود .
3) "EeWriteBuffer()" : این تابع به منظور ذخیره سازی یا نوشتن داده در داخل بافر پارامتر استفاده می شود .
و در نهایت هم تابع اصلی که تشریح میکنه چگونه از این توابع استفاده میشود .
Features
• Simple discrete PID controller algorithm
• Supported by all AVR devices
• PID function uses 534 bytes of code memory and 877 CPU cycles (IAR - low size optimization)
دیدگاه