اطلاعیه

Collapse
No announcement yet.

آموزش winavr و avrlib

Collapse
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    #16
    پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

    سلام
    به درخواست یکی از دوستان، می خوام تو این تاپیک به کتابخونه ارتباط سریال uart رو معرفی کنم. این کتابخونه جدا از کتابخونه های avrlib و چون راحتر بود دیگه بیخیال کتابخونه uart Avrlib شدم. این فایل رو می تونین از اینجا دانلود کنید : (چرا سایت امکان پلود نداره؟؟!)
    http://beaststwo.org/avr-uart/Updated%20_UART_Library.zip
    کار کردن باهاش خیلی ساده. (البته یه باگ داشت که در راه پیدا کردنش، دست دوتا mega16 هام از این دنیا کوتاه شد و البته یه mega16 دیگه رو هم فلج کردم!! بهرحال در راه علم ...)
    uart.h رو باز کنید. خیلی سریع بررسی می کنیم. یه ماکرو به شکل زیر تعریف کرده :

    #define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1)

    این ماکرو برای معرفی کردن نرخ ارتباط سریال (یا همون سرعت خودمون!!) استفاده میشه. پارامتر هاش هم که مشخص، اولی baud و دومی فرکانس کلاک. بعد از این یه ماکرو دیگه یه نام UART_BAUD_SELECT_DOUBLE_SPEED برای استفاده از سرعت دو برابر تعریف شده.
    ادامه:

    /** Size of the circular receive buffer, must be power of 2 */
    #ifndef UART_RX_BUFFER_SIZE
    #define UART_RX_BUFFER_SIZE 32
    #endif
    /** Size of the circular transmit buffer, must be power of 2 */
    #ifndef UART_TX_BUFFER_SIZE
    #define UART_TX_BUFFER_SIZE 32
    #endif

    اینجا اندازه بافر برای نگهداری داده های دریافت شده یا داده هایی که باید ارسال بشن تعریف شده. اگه بخواین تغییرش بدین، دقت کنید که گفته باید توانی از 2 باشه. فعلا تغییرش نمیدیم...
    بریم به قسمت توابع

    extern void uart_init(unsigned int baudrate);

    این تابع uart رو فعال میکنه و مقداردهی های اولیه رو انجام میده. پارامتر تابع باید با ماکرو تعیین baud باشه. مثلا این دستور برای تعیین باوود 9600 برای کلاک 1 مگاهرتز :

    uart_init(UART_BAUD_SELECT(9600, 1000000L));

    بقیه توابع هم مشخص دیگه! من فقط با uart_puts کار میکنم. برای ارسال رشته. بقیه توابع بکار نمیان!!!
    uart.c رو باز کنید. اینجا دو تا متغیر مهم داریم.
    UART_RxBuf
    این رشته، همون بافر برای نگه داری اطلاعات دریافتیه. هر بایت اطلاعاتی که بیاد تو این متغیر ذخیره میشه.
    UART_RxHead
    این متغیر نشون میده چند بایت تو بافر UART_RxBuf اطلاعات دریافتی ذخیره شده.
    وقفه دربافت رو ببینید ...

    ISR(UART0_RECEIVE_INTERRUPT)
    /************************************************** ***********************
    Function: UART Receive Complete interrupt
    Purpose: called when the UART has received a character
    ************************************************** ************************/
    { …

    این خط رو آخر وقفه می بینیم :

    UART_RxBuf[tmphead] = data;

    بایت دریافتی رو تو بافر مینویسه. اما یه مشکل داره! اونم اینه که از اندیس شماره 1 شروع به نوشتن میکنه نه صفر!! چراش رو دیگه خودتون تو چند خط بالاتر ببینین. خوب برای رفع این مشکل اینطوری تغییرش بدین:

    UART_RxBuf[tmphead-1] = data;

    خوب فعلا دیگه مشکلی نیست. این برنامه برای میکرو اول که اطلاعات می فرسته:

    #include <avr/io.h>
    #include <util/delay.h>
    #include "uart.c"
    char *str="test serial";
    int main()
    {
    sei();
    uart_init(UART_BAUD_SELECT(9600, 1000000L));
    _delay_ms(2000);
    uart_puts(str);
    _delay_ms(2000);
    uart_puts("ok"
    return 0;
    }

    اینم برنامه میکرو دوم که اطلاعات ارسال شده رو دریافت میکنه و رو ال سی دی نمایش میده:

    #include <avr/io.h>
    #include <util/delay.h>
    #include "lcd.c"
    #include "uart.c"
    int main()
    {
    sei();
    lcdInit();
    uart_init(UART_BAUD_SELECT(9600, 1000000L));

    while(1)
    {
    lcdClear();
    if (UART_RxHead != 0)
    lcdPrintData(UART_RxBuf, UART_RxHead);
    _delay_ms(20);
    }
    }

    دستور sei یادتون نره! وقفه ها باید فعال بشن.
    ضمنا فریم ارسال اطلاعات هم تو تابع uart_init تعیین شده. پیش فرض همون 8 بیت داده بدون parity و یک بیت داده. معمولا همینه دیگه. مگه اینکه یه پروژه مخوف سری داشته باشین ... !!
    موفق باشید.
    https://www.linkedin.com/in/mohammadhosseini69

    http://zakhar.blog.ir

    دیدگاه


      #17
      پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

      من یک سری به winavr عزیزتون زدم. روتین _delay_ms باگ نداره فقط دو تا مشکل اساسی داره.

      اول اینکه از محاسبات اعشاری برای delay استفاده میکنه که کار درستی نیست. چون avr عملیات اعشاری رو با نرم افزار انجام میده که کداش کند و حجیم هست. دوم اینکه اغلب موارد این تیپ delay دادن کار درستی نیست. بهتره از idle استفاده بشه.

      از طرف دیگه بنظر میاد روتینهای avrlib با اینکه توابع خوشگلی هستن ولی الزاما برای تمام موارد بهینه نیستن. مثلا میدونین ارسال اطلاعات بصورت خیلی سریع روی lcd های کاراکتری فقط وقت برنامه رو هدر میده. شاید بهتر باشه در اینگونه موارد اطلاعات ارسالی روی lcd بافر بشه و در زمانهای خاصی روی lcd ریخته بشه.

      دیدگاه


        #18
        پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

        در مورد محاسبات اعشاری چیزی نمی دونم! فقط بگم توابع ایجاد تاخیر تو هدر تایمر هم هست. حتما اونا اصولی تر هستن ...

        احتمالا کدویژن کار می کنی دیگه... شما مگه کد توابع کدویژن رو دیدی؟ (در مورد تاخیر و ال سی دی)

        اتفاقا کند بودن ال سی دی تو کدویژن (البته اگه بافر باشه که نمیشه بهش گفت کند...) خیلی وقت ها مشکل ایجاد می کنه. یه تاپیک همین اطراف هست که ال سی دی برای ارتباط سریالش مشکل ایجاد کرده و باعث میشه قاطی کنه.
        اصلا ال سی دی کاراکتری چیزی نیست که بافر احتیاج داشته باشه! می تونه اونقدر سریع انجام بشه که ... کدهای توابع رو ببین. یا لااقل یه تست بکن. نمیدونم اصلا چرا تابع lcdInit تو کدویژن طول میکشه!!
        ضمنا واسه ال سی دی وقفه نداریم که بخواد در زمان خاص و به موقع اطلاعات ارسال بشه! اگرم بخواد نرم افزاری کنترل بشه که بدتر ...!

        البته من خودم avrlib رو خیلی هم از این نظر قبول ندارم که حتما بهینه باشه. کتابخونه زیاده تو اینترنت. کتابخونه هایی که تکامل یافته همین فایل های avrlib هستن و خیلی بهینه تر و حرفه ای تر شدن. مثل lcd4bit. خوبیه اپن سورس بودنش همینه ... و avrlib شروعی بوده واسه کتابخونه های حرفه ای winavr. و نویسنده ش واقعا کار بزرگی کرده.
        https://www.linkedin.com/in/mohammadhosseini69

        http://zakhar.blog.ir

        دیدگاه


          #19
          پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

          من از کد ویژن فقط برای ویزاردش کار میکنم ولی بقیه پروژه رو با WinAVR به سی و اسمبلی مینویسم. اما معمولا همیشه از لوپ های تاخیری برای ایجاد delay استفاده میشه. ولی جالبه که بدونی در avrlib روتین کذایی delay_ms از متغیر نوع double برای انجام این لوپ استفاده میکنه:

          به فقل از delay.h:


          void
          _delay_ms(double __ms)
          {
          uint16_t __ticks;
          double __tmp = ((F_CPU) / 4e3) * __ms;
          if (__tmp < 1.0)
          __ticks = 1;
          else if (__tmp > 65535)
          {
          // __ticks = requested delay in 1/10 ms
          __ticks = (uint16_t) (__ms * 10.0);
          while(__ticks)
          {
          // wait 1/10 ms
          _delay_loop_2(((F_CPU) / 4e3) / 10);
          __ticks --;
          }
          return;
          }
          else
          __ticks = (uint16_t)__tmp;
          _delay_loop_2(__ticks);
          }



          که خوب کد بزرگ و سنگینیه. ایضا در زمان لوپ زدن میزان توان تلفاتی میکرو حداکثره. که خوب البته میشه با استفاده از یک تایمر و حالت idle این مورد رو مینیمم کرد.
          ...

          دیدگاه


            #20
            پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

            نوشته اصلی توسط reza_agha
            من از کد ویژن فقط برای ویزاردش کار میکنم ولی بقیه پروژه رو با WinAVR به سی و اسمبلی مینویسم....
            فکر کردم می خوای با winavr دشمنی کنی!
            بهرحال ممنون.
            اگه افتخار میدی یه دستی به تاپیک بزن و چیزایی که بلدی رو یاد بده ...
            دلم نمی خواد فقط من اینجا بنویسم
            https://www.linkedin.com/in/mohammadhosseini69

            http://zakhar.blog.ir

            دیدگاه


              #21
              پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

              راجع به lcd هم فرض کن حجم زیادی اطلاعات قراره به lcd ارسال بشه. مثلا مثل یک کرونومتر. اگر سرعت بازسازی lcd از 10 هرتز بیشتر بشه نه چشم من و شما قادر به تشخیصش هست و نه عقلانیه که این همه اطلاعات روی lcd بفرستیم. راحتتر اینه که اطلاعات مربوطه روی حافظه میکرو ریخته بشه و مثلا هر 100 میلی ثانیه یکبار اطلاعات >>>در صورت تغییر>>> به lcd ارسال بشه.

              راجع به اون مورد قاطی کردن هم باید ببینم ولی احتمالا (ندیده) بخاطر این بوده که از وقفه برای ارتباط سریال استفاده نمیکرده و خوب طبیعیه data overrun پیش میومده.

              کد lcd_init رو هم چک کردم تقریبا روی سیستم 16 مگاهرتزی نزدیک 130 میلی ثانیه فقط init طول میکشه. و این بخاطر اینه که روال درست رو avrlib انجام میده و مرتبا برای اطمینان از دریافت اطلاعات توسط lcd خط رو چک میکنه. در صورتی که codevision از یک سری حلقه تاخیری استفاده میکنه.

              ایضا اگر کد توابع کدویژن رو خواستی ببینی میتونی به lst پروژه ات یا خود cvavr.exe یک سری بزنی.

              ولی تصدیق میکنم. فعلا همین فرمونی که داری میری درسته. بقیه رو محض اطلاع عرض کردم.

              دیدگاه


                #22
                پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                بر خلاف انتظار codevision چند تایی محسنات نسبت به winavr داره که از طرف دیگه ایرادی برای winavr محسوب نمیشه ولی خوب باید حواس جمع باشه.

                اول اینکه winavr فرقی بین روالهای near و far نمیذاره. اگر یادتون باشه در اسمبلی دو جور دستور فراخوانی داریم. rcall و call که دومی هم حجیم تره و هم کند تر. winavr بطور پیش فرض برای آی سی هایی با حجم فلش 4 کیلو و کمتر از دستور rcall و برای بقیه از دستور call استفاده میکنه. که باعث افزایش حجم برنامه و کاهش سرعت اجرا میشه.

                دوم اینکه بر خلاف کدویژن مفهومی با عنوان sw-stack و hw-stack وجود خارجی نداره. توجه شما رو به این نکته جلب میکنم که بعلت باگی که در تمامی نسخ avr از tiny تا mega وجود داره اگر SP در حافظه خارجی قرار بگیره (مثلا رم خارجی) در صورت بروز وقفه میکرو آدرس برگشتشو گم میکنه.

                اما از طرف دیگه اگر در codevision اطلاعاتی به حجم 4096 بایت در فلش قرار بدی و برای یک میکروی کم حجم مثل مگا هشت برنامه بنویسی احتمالا برنامه ات درست کار نمیکنه و شاید حتی درست هم کامپایل نشه. ولی winavr از این باگ های مسخره نداره.
                اینجوری بگم: codevision یک کار دانشجویی بوده که بعدا طرف گفته "بدی نیست یه کمی ازش پول دربیارم" ولی winavr یک کار حرفه ایه. ولی مسلما طبق گفته خودت avrlib رو میشه تکمیلش کرد.

                دیدگاه


                  #23
                  پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                  نوشته اصلی توسط reza_agha
                  راجع به lcd هم فرض کن حجم زیادی اطلاعات قراره به lcd ارسال بشه. مثلا مثل یک کرونومتر. اگر سرعت بازسازی lcd از 10 هرتز بیشتر بشه نه چشم من و شما قادر به تشخیصش هست و نه عقلانیه که این همه اطلاعات روی lcd بفرستیم. راحتتر اینه که اطلاعات مربوطه روی حافظه میکرو ریخته بشه و مثلا هر 100 میلی ثانیه یکبار اطلاعات >>>در صورت تغییر>>> به lcd ارسال بشه.
                  اگه قرار باشه اینطوری تاخیر ایجاد کنه که دراینصورت با ارسال مدام اطلاعات تو یه حلقه (مثل کرنومتر) زمان تاخیر به شکل تصاعدی بالا میره!!
                  ضمنا همین مورد رو امتحان کن. می بینی که نمایش winavr خیلی بهتر از کدویژن.

                  من فقط بلدم گیر بدم.
                  آره اتفاقا همین الان تو یه تاپیک c دیدم!
                  این بحث ها اصلا مهم نیست. کتابخونه های winavr اونقدر متنوع هستن که ... مطمئنا خیلی ها هستن که میخوان با usb ارتباط برقرار کنن یا ال سی دی گرافیکی و خیلی از چیپ های معروف ...
                  کدویژن جلوی پیشرفتمون رو میگیره...

                  اول اینکه winavr فرقی بین روالهای near و far نمیذاره.
                  Wow! این اطلاعات رو از کجا میاری!!
                  اینی که میگی مربوط میشه به اسمبلی بحث های اولیه کامپایل و ... winavr هم که از gcc و متعلقاتش استفاده می کنه و خیلی بعیده اینطوری که میگی باشه!!

                  اما از طرف دیگه اگر در codevision اطلاعاتی به حجم 4096 بایت در فلش قرار بدی و برای یک میکروی کم حجم مثل مگا هشت برنامه بنویسی احتمالا برنامه ات درست کار نمیکنه و شاید حتی درست هم کامپایل نشه. ولی winavr از این باگ های مسخره نداره.
                  خدارو شکرآ‌!!

                  من الان مسافرتم نمی تونم زیاد اینترنت بیام!! درست نیست!
                  بیخیال شو! 2 روز تاپیک رو بالا نگه دار تا من برگردم!!
                  https://www.linkedin.com/in/mohammadhosseini69

                  http://zakhar.blog.ir

                  دیدگاه


                    #24
                    پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                    چیزی که بنظر میاد توی avrlib خیلی جاش خالی باشه یک سری ماکروی کاربردیه. مثلا:


                    #define dim(x) (sizeof(x)/sizeof((x)[0]))
                    #define offsetof(typ,fld) ((int)&(((typ *)0)->fld))
                    #define LOBYTE(n) ((u08)(n))
                    #define HIBYTE(n) ((u08)((u16)(n)>>8))
                    #define MAKEWORD(l,h) (((u16)((u08)(h))<<8)|((u16)((u08)(l))))
                    #define LOWORD(n) ((u16)(n))
                    #define HIWORD(n) ((u16)((u32)(n)>>16))
                    #define MAKEDWORD(l,h) (((u32)((u16)(h))<<16)|((u32)((u16)(l))))



                    البته بعضی ها رو میشه بفرم inline assembly هم نوشت.

                    ---

                    ضمنا راجع به کرونومتر در نظر بگیر که اطلاعات قرار نیست مستقیما در زمان putc کردن به lcd ارسال بشه بلکه در یک بافر داخلی ذخیره میشه و در یک روتین تایمر مثلا 10 میلی ثانیه یکبار چک میشه که اگر lcd بایستی refresh بشه اطلاعات به lcd ارسال میشه و این عمل هر 100 میلی ثانیه یکبار انجام میشه. بنا براین اگر من 10 کیلو بایت دیتا هم روی lcd چاپ کنم فقط یکبار آنهم مثلا 32 بایت آخری به lcd ارسال میشه.

                    اینجوری حتی میشه مواردی مثل blinking و invert بودن رو هم مثل یک crt به اندازه lcd در روتینها اضافه کرد.

                    ---

                    راجع به near و far بودن و اینکه میگی بعید بنظر میرسه...این مورد مربوط به بهینه کردن زمان link هستش و فکر نکنم جزء چیزایی باشه که لینکر فعلی اونو ساپورت کنه. ایضا روالهای تولید کد avr به gcc اضافه شده تا این کامپایلر رو برای avr پورت کنه. ایضا لغت کلیدی خاصی برای مجبور کردن کامپایلر برای استفاده از rcall بجای call در winavr وجود نداره. (مثل borland-c یا msc یا lattice-c یا حتی aztec-c) حال میکنی با چند تا کامپایلر c آشنام؟!!!!

                    دیدگاه


                      #25
                      پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                      در یکی از پست های قبلی خودم قید کردم که codevision بیشتر به یک کار دانشجویی میخوره نه حرفه ای.
                      یک موردی که امروز به ذهنم رسید و چک کردم مسئله تولید کد در codevision نسبت به winavr بود. شما مطمئنا میدونین که دستور switch از لحاظ تئوری مانند یک سری if-else پشت سر هم عمل میکنه ولی خیلی بهتر. بهتره بدونین که این عمل در کد ویژن دقیقا مثل تئوری عمل میکنه یعنی یک سری if-else تولید میشه. بنا براین صرف نظر از حجم بالای کد تولید شده زمان اجرای دستور سوئیچ در شرایط متفاوت مقدار کلید بسار متفاوت هست. و این یعنی نمیشه تخمین زمانی دقیقی از اجرای کد نوشته شده با کد ویژن انجام داد. فراموش نکنیم که مهمترین مسئله در هنگام تولید یک سیستم real-time مشخص کردن دقیق زمان عکس العمل سیستم به ازای event های متفاوته.

                      مثال:

                      کد زیر رو در نظر بگیرید:

                      #include <mega8.h>

                      static int f1(int n)
                      {
                      #define X(n) case n:return n
                      switch(n)
                      {
                      X(0);
                      X(1);
                      X(2);
                      X(3);
                      X(4);
                      X(5);
                      X(6);
                      X(7);
                      X(8);
                      X(9);
                      }
                      return -1;
                      }

                      void main(void)
                      {
                      f1(0);
                      }


                      کدش با کدویژن اینطوری میشه (البته با حذف کد استارت و ماکروهای تولید شده):



                      ;CodeVisionAVR C Compiler V2.03.9 Standard
                      ;(C) Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
                      ;http://www.hpinfotech.com

                      ;Chip type : ATmega8
                      ;Program type : Application
                      ;Clock frequency : 4.000000 MHz
                      ;Memory model : Small
                      ;Optimize for : Size
                      ;(s)printf features : int, width
                      ;(s)scanf features : int, width
                      ;External RAM size : 0
                      ;Data Stack size : 256 byte(s)
                      ;Heap size : 0 byte(s)

                      .CSEG
                      _f1_G000:
                      ; n -> Y+0
                      LD R30,Y
                      LDD R31,Y+1
                      ;0000 000A X(0);
                      SBIW R30,0
                      BRNE _0x6
                      LDI R30,LOW(0)
                      LDI R31,HIGH(0)
                      RJMP _0x2000001
                      ;0000 000B X(1);
                      _0x6:
                      CPI R30,LOW(0x1)
                      LDI R26,HIGH(0x1)
                      CPC R31,R26
                      BRNE _0x7
                      LDI R30,LOW(1)
                      LDI R31,HIGH(1)
                      RJMP _0x2000001
                      ;0000 000C X(2);
                      _0x7:
                      CPI R30,LOW(0x2)
                      LDI R26,HIGH(0x2)
                      CPC R31,R26
                      BRNE _0x8
                      LDI R30,LOW(2)
                      LDI R31,HIGH(2)
                      RJMP _0x2000001
                      ;0000 000D X(3);
                      _0x8:
                      CPI R30,LOW(0x3)
                      LDI R26,HIGH(0x3)
                      CPC R31,R26
                      BRNE _0x9
                      LDI R30,LOW(3)
                      LDI R31,HIGH(3)
                      RJMP _0x2000001
                      ;0000 000E X(4);
                      _0x9:
                      CPI R30,LOW(0x4)
                      LDI R26,HIGH(0x4)
                      CPC R31,R26
                      BRNE _0xA
                      LDI R30,LOW(4)
                      LDI R31,HIGH(4)
                      RJMP _0x2000001
                      ;0000 000F X(5);
                      _0xA:
                      CPI R30,LOW(0x5)
                      LDI R26,HIGH(0x5)
                      CPC R31,R26
                      BRNE _0xB
                      LDI R30,LOW(5)
                      LDI R31,HIGH(5)
                      RJMP _0x2000001
                      ;0000 0010 X(6);
                      _0xB:
                      CPI R30,LOW(0x6)
                      LDI R26,HIGH(0x6)
                      CPC R31,R26
                      BRNE _0xC
                      LDI R30,LOW(6)
                      LDI R31,HIGH(6)
                      RJMP _0x2000001
                      ;0000 0011 X(7);
                      _0xC:
                      CPI R30,LOW(0x7)
                      LDI R26,HIGH(0x7)
                      CPC R31,R26
                      BRNE _0xD
                      LDI R30,LOW(7)
                      LDI R31,HIGH(7)
                      RJMP _0x2000001
                      ;0000 0012 X(8);
                      _0xD:
                      CPI R30,LOW(0x8)
                      LDI R26,HIGH(0x8)
                      CPC R31,R26
                      BRNE _0xE
                      LDI R30,LOW(8)
                      LDI R31,HIGH(8)
                      RJMP _0x2000001
                      ;0000 0013 X(9);
                      _0xE:
                      CPI R30,LOW(0x9)
                      LDI R26,HIGH(0x9)
                      CPC R31,R26
                      BRNE _0x5
                      LDI R30,LOW(9)
                      LDI R31,HIGH(9)
                      RJMP _0x2000001
                      ;0000 0014 }
                      _0x5:
                      ;0000 0015 return -1;
                      LDI R30,LOW(65535)
                      LDI R31,HIGH(65535)
                      _0x2000001:
                      ADIW R28,2
                      RET
                      ;0000 0016 }
                      ;
                      ;void main(void)
                      ;0000 0019 {
                      _main:
                      ;0000 001A f1(0);
                      LDI R30,LOW(0)
                      LDI R31,HIGH(0)
                      ST -Y,R31
                      ST -Y,R30
                      RCALL _f1_G000
                      ;0000 001B }
                      _0x10:
                      RJMP _0x10



                      در winavr مجبور شدم که یک متغیر عمومی استفاده کنم تا کد تابع f توسط کامپایلر حذف نشه.



                      ;;; 0000FFED <f1 switch jump table>
                      26: 2f c0 rjmp .+94 ; 0x86 <f1+0x14>
                      28: 2b c0 rjmp .+86 ; 0x80 <f1+0xe>
                      2a: 30 c0 rjmp .+96 ; 0x8c <f1+0x1a>
                      2c: 32 c0 rjmp .+100 ; 0x92 <f1+0x20>
                      2e: 34 c0 rjmp .+104 ; 0x98 <f1+0x26>
                      30: 36 c0 rjmp .+108 ; 0x9e <f1+0x2c>
                      32: 38 c0 rjmp .+112 ; 0xa4 <f1+0x32>
                      34: 3a c0 rjmp .+116 ; 0xaa <f1+0x38>
                      36: 3c c0 rjmp .+120 ; 0xb0 <f1+0x3e>
                      38: 3e c0 rjmp .+124 ; 0xb6 <f1+0x44>


                      00000072 <f1>:
                      int f1(int n)
                      {
                      #define X(n) case n:return n
                      switch(n)
                      72: fc 01 movw r30, r24
                      74: 8a 30 cpi r24, 0x0A ; 10
                      76: 91 05 cpc r25, r1
                      78: 08 f5 brcc .+66 ; 0xbc <f1+0x4a>
                      7a: ed 5e subi r30, 0xED ; 237
                      7c: ff 4f sbci r31, 0xFF ; 255
                      7e: 09 94 ijmp
                      80: 21 e0 ldi r18, 0x01 ; 1
                      82: 30 e0 ldi r19, 0x00 ; 0
                      84: 1d c0 rjmp .+58 ; 0xc0 <f1+0x4e>
                      86: 20 e0 ldi r18, 0x00 ; 0
                      88: 30 e0 ldi r19, 0x00 ; 0
                      8a: 1a c0 rjmp .+52 ; 0xc0 <f1+0x4e>
                      8c: 22 e0 ldi r18, 0x02 ; 2
                      8e: 30 e0 ldi r19, 0x00 ; 0
                      90: 17 c0 rjmp .+46 ; 0xc0 <f1+0x4e>
                      {
                      X(0);
                      X(1);
                      X(2);
                      92: 23 e0 ldi r18, 0x03 ; 3
                      94: 30 e0 ldi r19, 0x00 ; 0
                      96: 14 c0 rjmp .+40 ; 0xc0 <f1+0x4e>
                      X(3);
                      98: 24 e0 ldi r18, 0x04 ; 4
                      9a: 30 e0 ldi r19, 0x00 ; 0
                      9c: 11 c0 rjmp .+34 ; 0xc0 <f1+0x4e>
                      X(4);
                      9e: 25 e0 ldi r18, 0x05 ; 5
                      a0: 30 e0 ldi r19, 0x00 ; 0
                      a2: 0e c0 rjmp .+28 ; 0xc0 <f1+0x4e>
                      X(5);
                      a4: 26 e0 ldi r18, 0x06 ; 6
                      a6: 30 e0 ldi r19, 0x00 ; 0
                      a8: 0b c0 rjmp .+22 ; 0xc0 <f1+0x4e>
                      X(6);
                      aa: 27 e0 ldi r18, 0x07 ; 7
                      ac: 30 e0 ldi r19, 0x00 ; 0
                      ae: 08 c0 rjmp .+16 ; 0xc0 <f1+0x4e>
                      X(7);
                      b0: 28 e0 ldi r18, 0x08 ; 8
                      b2: 30 e0 ldi r19, 0x00 ; 0
                      b4: 05 c0 rjmp .+10 ; 0xc0 <f1+0x4e>
                      X(8);
                      b6: 29 e0 ldi r18, 0x09 ; 9
                      b8: 30 e0 ldi r19, 0x00 ; 0
                      ba: 02 c0 rjmp .+4 ; 0xc0 <f1+0x4e>
                      X(9);
                      bc: 2f ef ldi r18, 0xFF ; 255
                      be: 3f ef ldi r19, 0xFF ; 255
                      }
                      return -1;
                      }
                      c0: c9 01 movw r24, r18
                      c2: 08 95 ret

                      000000c4 <main>:

                      int t;

                      void main(void)
                      {
                      t = f1(0);
                      c4: 80 e0 ldi r24, 0x00 ; 0
                      c6: 90 e0 ldi r25, 0x00 ; 0
                      c8: d4 df rcall .-88 ; 0x72 <f1>
                      ca: 90 93 61 00 sts 0x0061, r25
                      ce: 80 93 60 00 sts 0x0060, r24
                      }
                      d2: 08 95 ret



                      ......

                      دیدگاه


                        #26
                        پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                        ....
                        همونطور که میبینین کدویژن:

                        اولا نفهمید که استفاده از تابع f بیخوده و کد رو حذف نکرد.
                        ثانیا بجای جدول پرش از یک سری if-else استفاده کرد که اینکار حجم کد رو به 148 بایت رسوند در صورتی که در winavr معادل 102 بایته. تازه اگر تعداد case ها اضافه میشد به ازای هر کدوم کد ویژن 14 بایت و winavr دقیقا 8 بایت کد اضافه تولید میکرد.
                        ثالثا اجرای کد به شرطی که متغیر n صفر یا 9 باشه در winavr تغییری نمیکنه و مساوی با 16 سیکل هستش ولی در codevision به ازای مقدار صفر برابر با 11 سیکل و برای 9 تقریبا برابر با 49 سیکل است و این یعنی فاجعه!!!

                        کد در هر دو مورد کار میکنه ولی در کد ویژن شدیدا غیر قابل تخمین و (از این لغت بهتر پیدا نکردم) مزخرف!

                        علاوه بر تمام اینها در winavr مقادیر پارامترها در رجیستر پاس میشود و در codevision در memory. البته برای کد توابع خیلی پیچیده و همان باگ کذایی افتادن SP خارج از حافظه داخلی این خیلی بکار میاد ولی چون عمدتا تعداد پارامتر ها در کد های نوشته شده در میکرو کم هست و معمولا کد ها خیلی پیچیده نیست این مورد خیلی جاها اتلاف سرعت محسوب میشه.

                        اینجوری بگم.

                        با winavr میتونی کد خوب یا بد یا عالی بنویسی. این بستگی به خودت داره. اما codevision کد عالی تو نهایتا به نسبتا خوب تبدیل میکنه.

                        بنابراین تنها چیزی که اینجا خیلی اهمیت پیدا میکنه حجم کدهای آماده ای هست که برای winavr یا codevision موجود هست. اگر تمامی lib های کد ویژن در winavr موجود باشه. صرف نظر از ویزاردش بهترین مورد استفاده از codevision ارسالش به recycle-bin هستش.

                        دیدگاه


                          #27
                          پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                          قبلا راجع به مشکل codevision راجع به جدول حجیم در flash یک اشاره ای کرده بودم. اما خودتون میتونین یک چکی بکنین. کد زیر رو در نظر بگیرین:


                          #include <mega8.h>

                          static flash char some_arr[4096]={1};

                          int t;

                          void main(void)
                          {
                          t = some_arr[0];
                          }


                          خلاصه کد تولید شده اینه:



                          ;CodeVisionAVR C Compiler V2.03.9 Standard
                          ;(C) Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
                          ;http://www.hpinfotech.com

                          ;Chip type : ATmega8
                          ;Program type : Application
                          ;Clock frequency : 4.000000 MHz
                          ;Memory model : Small
                          ;Optimize for : Size
                          ;(s)printf features : int, width
                          ;(s)scanf features : int, width
                          ;External RAM size : 0
                          ;Data Stack size : 256 byte(s)
                          ;Heap size : 0 byte(s)
                          ;Promote char to int : Yes
                          ;char is unsigned : Yes
                          ;global const stored in FLASH : No
                          ;8 bit enums : Yes
                          ;Enhanced core instructions : On
                          ;Smart register allocation : On
                          ;Automatic register allocation : On

                          .DEF _t=R4

                          .CSEG
                          .ORG 0x00

                          ;INTERRUPT VECTORS
                          RJMP __RESET
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00
                          RJMP 0x00

                          _some_arr_G000:
                          .DB 0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0

                          __RESET:
                          CLI



                          همونطور که میبینین دستور rjmp reset قراره از روی جدولی پرش کنه که حجمش 4 کیلو بایته. (البته برای کم کردن حجم پست سطر دوم تا آخر جدول رو حذف کردم). بخاطر بیاریم که دستور rjmp حداکثر 4 کیلو بایت اینور و اونور تر میتونه پرش کنه که خب حجم جدول با حجم دستورهای rjmp وکتور دوم به بعد خیلی بیش از 4 کیلو بایت میشه. بنا براین این کد نبایستی کامپایل بشه. اما کد ویژن پیغام میده کامپایل شد بدون خطا. پس کدی که تولید شده اون کدی نیست که ما نوشتیم!! عجب کامپایلری! مثل اینکه توی جاده ای راه بری که بهت بگن "ممکنه مین زیر جاده باشه اما کجا و چند تا نمیدونیم" شما باشی توی همچین جاده ای ولو اتوبان شصت بانده راه میری؟

                          منکه اینکارو نمیکنم.

                          راستی من از کدویژن نسخه 2.0.3.9 استاندارد استفاده میکنم. در نسخ قبلیش هم این مشکل رو داشت.
                          این دقیقا مصداق سوئ استفاده از حسن ظن هست.

                          دیدگاه


                            #28
                            پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                            نوشته اصلی توسط reza_agha
                            قبلا راجع به مشکل codevision راجع به جدول حجیم در flash یک اشاره ای کرده بودم. اما خودتون میتونین یک چکی بکنین. کد زیر رو در نظر بگیرین:

                            #include <mega8.h>
                            static flash char some_arr[4096]={1};
                            int t;
                            void main(void)
                            {
                            t = some_arr[0];
                            }

                            خلاصه کد تولید شده اینه:

                            ;CodeVisionAVR C Compiler V2.03.9 Standard
                            ;(C) Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
                            ;http://www.hpinfotech.com

                            ;Chip type : ATmega8
                            ;Program type : Application
                            ;Clock frequency : 4.000000 MHz
                            ;Memory model : Small
                            ;Optimize for : Size
                            ;(s)printf features : int, width
                            ;(s)scanf features : int, width
                            ;External RAM size : 0
                            ;Data Stack size : 256 byte(s)
                            ;Heap size : 0 byte(s)
                            ;Promote char to int : Yes
                            ;char is unsigned : Yes
                            ;global const stored in FLASH : No
                            ;8 bit enums : Yes
                            ;Enhanced core instructions : On
                            ;Smart register allocation : On
                            ;Automatic register allocation : On

                            .DEF _t=R4

                            .CSEG
                            .ORG 0x00

                            ;INTERRUPT VECTORS
                            RJMP __RESET
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00
                            RJMP 0x00

                            _some_arr_G000:
                            .DB 0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0

                            __RESET:
                            CLI


                            همونطور که میبینین دستور rjmp reset قراره از روی جدولی پرش کنه که حجمش 4 کیلو بایته. (البته برای کم کردن حجم پست سطر دوم تا آخر جدول رو حذف کردم). بخاطر بیاریم که دستور rjmp حداکثر 4 کیلو بایت اینور و اونور تر میتونه پرش کنه که خب حجم جدول با حجم دستورهای rjmp وکتور دوم به بعد خیلی بیش از 4 کیلو بایت میشه. بنا براین این کد نبایستی کامپایل بشه. اما کد ویژن پیغام میده کامپایل شد بدون خطا. پس کدی که تولید شده اون کدی نیست که ما نوشتیم!! عجب کامپایلری! مثل اینکه توی جاده ای راه بری که بهت بگن "ممکنه مین زیر جاده باشه اما کجا و چند تا نمیدونیم" شما باشی توی همچین جاده ای ولو اتوبان شصت بانده راه میری؟
                            منکه اینکارو نمیکنم.
                            ضمن موافقت کامل با بحث تولید نامناسب کد توسط CodeVision، در مورد مثال شما و دستور rjmp، کامپایلر درست عمل می کند.
                            علت هم این است که محدودیت دستور rjmp برای حافظه flash بیش از 4 کیلو word است و در میکروکنترلرهای با flash به میزان 8 کیلوبایت یا کمتر،به تمام نقاط flash دسترسی دارد. بنابراین با پرش در جهت مثبت یا منفی می تواند از جدول 4 کیلوبایتی ( 2 کیلو word) در برنامه عبور کند.
                            برنامه فوق در نسخه 2.04.4a کامپایل شد و کد معادل اسمبلی آن در AVRStudio مشاهده شد. برای mega8، کامپایلر اولین دستور را بصورت rjmp PC-0x07ed می نویسد و با پرش در جهت مخالف به آدرس بعد از جدول مورد نظر دست پیدا می کند و بنابراین اشکالی از این جهت در کد کامپایل شده وجود ندارد.
                            اوژن: به معنای افکننده و شکست دهنده است
                            دانایی، توانایی است-Knowledge is POWER
                            برای حرفه ای شدن در الکترونیک باید با آن زندگی کرد
                            وضعمان بهتر می شود، اگر همه نسبت به جامعه و اطراف خود مسوول باشیم و نگوئیم به ما چه
                            قوی شدن و خوب ماندن - خوبی کردن به دیگران یک لذت ماندگار است
                            اگر قرار باشد نفت و منابع خام را بدهیم و چرخ بگیریم، بهتر است چرخ را از نو اختراع کنیم
                            ساعت کار بدن اکثر انسان ها کمتر از 800000 ساعت است و بعد از آن از کار می افتد

                            دیدگاه


                              #29
                              پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                              خیلی از دوستانی که با win avr کار میکنند در مورد کار با ریجستر های میکرو به صورت بیتی اطلاع کافی دارند اما اونایی که تازه کارند ممکنه با این مسئله مشکل داشته باشند. توی کد ویژن خیلی راحت مینوشتیمPORTA.3=1;
                              ولی توی win avr این کار اشتباهه.ضمن اینکه توی کد ویژن هم امکان استفاده از این دستور در IO های توسعه یافته نیست.یعنی عبارت PORTG.2=1 در کد ویژن هم خطاست.
                              در win avr توی کتابخونه ی avrlibdefs.h یه دستوری وجود داره به اسم BV(bit).
                              این دستور در حقیقت یک 1 منطقی رو به تعداد بیت به چپ شیفت میده. برای معادل سازی PORTA.3=1 در win avr اینجوری مینویسیم: PORTA|=BV(3); با این کار PORT A رو با مقدار 1000 or منطقی میکنیم که نتیجه ی اون ست شدن PORTA.3 هست.حالا اگر بخواییم همون بیت رو مساوی صفر بزاریم مینویسیم:PORTA&=~BV(3);
                              با این کار مقدار متمم 1000 رو با AND PORT منطقی میکنیم .که نتیجش reset شدت PORTA.3 هست.
                              با کمی کار بر روی عملگر های منطقی خیلی راحت میتونید کنترل بهتری روی ریجستر ها داشته باشید.
                              [hr]
                              دوستانی که از کد های بلند برای درک بهتر استفاده میکنند لطف کنند و کد خودشون رو بین [code ]کدتون[/code ] این علامت قرار بدن تا صفحات زیاد طولانی نشه و مرور کردنش راحت تر باشه.
                              [img width=477 height=100]http://www.eca.ir/pic/upload/agazade.png[/img]

                              دیدگاه


                                #30
                                پاسخ : آموزش winavr و avrlib - مهاجرت از codevision به winavr avr gcc

                                خوب حالا به بررسی این موضوع بپردازیم که برای ست یا ریست کردن یه io هرکدوم از این کامپایلر ها به چند سیکل نیاز دارند!
                                کدویژن :برای این کار از دستور SBI و CBI استفاده میکنه.(البته به غیر از IO های توسعه یافته)این دو دستور جز دستور هایی هستند که به 2 سیکل نیاز دارند.
                                win avr :برای ست کردن یک io ما اول یه عمل شیفت انجام میدیم که به یک سیکل زما ن نیاز داره و یک تساوی که اون هم یک سیکل نیاز داره.یعنی کلا دو سیکل.
                                اما برای ریست کردن یک io ما نیاز به یه شیفت داریم.بعد معکوس کردن نتیجه و در آخر یک تساوی که میشه سه سیکل.
                                یه روش دیگه ای هم برای ریست کردن یک IO هست ولی برای استفاده از اون [glow=red,2,300]باید[/glow] مطمئن بود که در حال حاضر اون io یک هست.PORTA^=BV(3); .این دستور هم مانند دستور ست نیاز به 2 سیکل برای اجرا داره ولی به خاطر مشکلی که داره زیاد ازش استفاده نمیشه.
                                اگه تو محاسباتم اشتباه کردم دوستان لطف کنند و درستشو بگند.

                                دوم اینکه بر خلاف کدویژن مفهومی با عنوان sw-stack و hw-stack وجود خارجی نداره. توجه شما رو به این نکته جلب میکنم که بعلت باگی که در تمامی نسخ avr از tiny تا mega وجود داره اگر SP در حافظه خارجی قرار بگیره (مثلا رم خارجی) در صورت بروز وقفه میکرو آدرس برگشتشو گم میکنه.
                                اگه مفهوم stack وجود نداره پس win avr آدرس برگشت توابع رو از کجا میاره؟؟ :question:
                                [img width=477 height=100]http://www.eca.ir/pic/upload/agazade.png[/img]

                                دیدگاه

                                لطفا صبر کنید...
                                X