اطلاعیه

Collapse
No announcement yet.

مشکل با DMA برای خواندن USART

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

    مشکل با DMA برای خواندن USART

    سلام
    من میخواستم از با DMA از سریال بخونم و بریزم توی یک آرایه ای بعد وقتی تعداد بایت ها 32 تا شد داده هامو بریزم توی یک آرایه دیگری که داره توی یک جای دیگه قراره ازش استفاده بشه.دقیقا نشستم عین دیتاشیت خود اتمل دونه دونه رجیسترها مقدار دهی کردم. ولی متاسفانه توی اینتراپت اصلا نمیره به نظر شما مشکل چیه؟
    اینم کد من :
    کد:
    #include <io.h>
    #include <stdint.h>
    unsigned char ali_test[32],i;
    unsigned char ali_test2[2000];
    unsigned int index=0;
    void system_clocks_init(void)
    {
    unsigned char n,s;
    #pragma optsize-
    s=SREG;
    #asm("cli")
    
    OSC.XOSCCTRL=OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
    OSC.CTRL|=OSC_XOSCEN_bm;
    while ((OSC.STATUS & OSC_XOSCRDY_bm)==0);
    n=(OSC.PLLCTRL & (~(OSC_PLLSRC_gm | OSC_PLLFAC_gm))) |
       OSC_PLLSRC_XOSC_gc | 8;
    CCP=CCP_IOREG_gc;
    OSC.PLLCTRL=n;
    OSC.CTRL|=OSC_PLLEN_bm;
    n=(CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm | CLK_PSBCDIV0_bm))) |
       CLK_PSADIV_1_gc | CLK_PSBCDIV_2_2_gc;
    CCP=CCP_IOREG_gc;
    CLK.PSCTRL=n;
    while ((OSC.STATUS & OSC_PLLRDY_bm)==0);
    n=(CLK.CTRL & (~CLK_SCLKSEL_gm)) | CLK_SCLKSEL_PLL_gc;
    CCP=CCP_IOREG_gc;
    CLK.CTRL=n;
    OSC.CTRL&= ~(OSC_RC2MEN_bm | OSC_RC32MEN_bm | OSC_RC32KEN_bm);
    PORTCFG.CLKEVOUT&= ~PORTCFG_CLKOUT_gm;
    SREG=s;
    #pragma optsize_default
    }
    
    void usarte0_init(void)
    {
    PORTE.OUTSET=0x08;
    USARTE0.CTRLC=USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
    USARTE0.CTRLA=(USARTE0.CTRLA & (~(USART_RXCINTLVL_gm | USART_TXCINTLVL_gm | USART_DREINTLVL_gm))) |
       USART_RXCINTLVL_OFF_gc | USART_TXCINTLVL_OFF_gc | USART_DREINTLVL_OFF_gc;
    USARTE0.BAUDCTRLA=0xF5;
    USARTE0.BAUDCTRLB=((0x0C << USART_BSCALE_gp) & USART_BSCALE_gm) | 0x0C;
    USARTE0.CTRLB=(USARTE0.CTRLB & (~(USART_RXEN_bm | USART_TXEN_bm | USART_CLK2X_bm | USART_MPCM_bm | USART_TXB8_bm))) |
       USART_RXEN_bm | USART_TXEN_bm;
    }
    
    interrupt [DMA_CH0_vect] void dma_ch0_isr(void)
    {
       for ( i =0 ; i < 32 ; i++)
       {
          ali_test2[index] = ali_test[i];
          index++;
       }
    }
    void main(void)
    {
    unsigned char n;
    volatile DMA_CH_t * channel;
    #pragma optsize-
    #asm("cli")
    n=(PMIC.CTRL & (~(PMIC_RREN_bm | PMIC_IVSEL_bm | PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm))) |
       PMIC_LOLVLEN_bm | PMIC_HILVLEN_bm;
    CCP=CCP_IOREG_gc;
    PMIC.CTRL=n;
    PMIC.INTPRI=0x00;
    #pragma optsize_default
    system_clocks_init();
    PORTE.OUT=0x08;
    PORTE.DIR=0x08;
    usarte0_init();
    
    
     channel = &DMA.CH0;
     DMA.CTRL = 0;
     DMA.CTRL = DMA_RESET_bm;
     while ((DMA.CTRL & DMA_RESET_bm) != 0);
     channel->CTRLB   = (channel->CTRLB & ~(DMA_CH_ERRINTLVL_gm | DMA_CH_TRNINTLVL_gm)) |
              DMA_CH_TRNINTLVL_LO_gc | DMA_CH_ERRINTLVL_LO_gc ;
     DMA.CTRL = DMA_CH_ENABLE_bm | DMA_DBUFMODE_CH01_gc;
     channel->REPCNT  = 0;
     channel->CTRLA   |= DMA_CH_SINGLE_bm;
     channel->CTRLA   |= DMA_CH_REPEAT_bm;
     channel->CTRLA   |= DMA_CH_BURSTLEN_1BYTE_gc;
     channel->ADDRCTRL |= DMA_CH_SRCRELOAD_BURST_gc;
     channel->ADDRCTRL |= DMA_CH_SRCDIR_FIXED_gc;
     channel->ADDRCTRL |= DMA_CH_DESTDIR_INC_gc;
     channel->TRIGSRC  = DMA_CH_TRIGSRC_USARTE0_RXC_gc;
     channel->TRFCNT  = 32;
     channel->SRCADDR0 = (( (uint32_t) &USARTE0.DATA) >> 0*8 ) & 0xFF;
     channel->SRCADDR1 = (( (uint32_t) &USARTE0.DATA) >> 1*8 ) & 0xFF;
     channel->SRCADDR2 = (( (uint32_t) &USARTE0.DATA) >> 2*8 ) & 0xFF;
     channel->DESTADDR0 = (( (uint32_t) &ali_test) >> 0*8 ) & 0xFF;
     channel->DESTADDR1 = (( (uint32_t) &ali_test) >> 1*8 ) & 0xFF;
     channel->DESTADDR2 = (( (uint32_t) &ali_test) >> 2*8 ) & 0xFF;
     channel->CTRLA  |= DMA_CH_ENABLE_bm;
     //DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm
    #asm("sei")
    while (1);
    }
    با تشکر
    يا حق

    #2
    پاسخ : مشکل با DMA برای خواندن USART

    مشکلات مختلفی در جزئیات کد شما قابل مشاهده است که نشان می دهد باید با دقت بیشتری Manual را مطالعه کنید. در اینجا به مواردی اشاره می کنم:

    1- مد double buffer بیجهت فعال شده است.
    2- برای مقصد در فرض تکرار سیکل، وضعیت Reload مشخص نشده است.
    3- flag وقفه باید در روتین آن بصورت دستی پاک شود.
    4- کلا مشخص نیست که نوشتن در آرایه باید یک بار انجام شود یا بصورت مداوم انجام می شود که در هر یک از این دو صورت باید نوع کد نویسی متفاوت باشد.
    اوژن: به معنای افکننده و شکست دهنده است
    دانایی، توانایی است-Knowledge is POWER
    برای حرفه ای شدن در الکترونیک باید با آن زندگی کرد
    وضعمان بهتر می شود، اگر همه نسبت به جامعه و اطراف خود مسوول باشیم و نگوئیم به ما چه
    قوی شدن و خوب ماندن - خوبی کردن به دیگران یک لذت ماندگار است
    اگر قرار باشد نفت و منابع خام را بدهیم و چرخ بگیریم، بهتر است چرخ را از نو اختراع کنیم
    ساعت کار بدن اکثر انسان ها کمتر از 800000 ساعت است و بعد از آن از کار می افتد

    دیدگاه


      #3
      پاسخ : مشکل با DMA برای خواندن USART

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

      کد اصلاح شده جدید:
      کد:
      #include <io.h>
      #include <stdint.h>
      unsigned char ali_test[32],i;
      unsigned char ali_test2[4000];
      unsigned int index=0;
      void system_clocks_init(void)
      {
      unsigned char n,s;
      #pragma optsize-
      s=SREG;
      #asm("cli")
      
      OSC.XOSCCTRL=OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
      OSC.CTRL|=OSC_XOSCEN_bm;
      while ((OSC.STATUS & OSC_XOSCRDY_bm)==0);
      n=(OSC.PLLCTRL & (~(OSC_PLLSRC_gm | OSC_PLLFAC_gm))) |
         OSC_PLLSRC_XOSC_gc | 8;
      CCP=CCP_IOREG_gc;
      OSC.PLLCTRL=n;
      OSC.CTRL|=OSC_PLLEN_bm;
      n=(CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm | CLK_PSBCDIV0_bm))) |
         CLK_PSADIV_1_gc | CLK_PSBCDIV_2_2_gc;
      CCP=CCP_IOREG_gc;
      CLK.PSCTRL=n;
      while ((OSC.STATUS & OSC_PLLRDY_bm)==0);
      n=(CLK.CTRL & (~CLK_SCLKSEL_gm)) | CLK_SCLKSEL_PLL_gc;
      CCP=CCP_IOREG_gc;
      CLK.CTRL=n;
      OSC.CTRL&= ~(OSC_RC2MEN_bm | OSC_RC32MEN_bm | OSC_RC32KEN_bm);
      PORTCFG.CLKEVOUT&= ~PORTCFG_CLKOUT_gm;
      SREG=s;
      #pragma optsize_default
      }
      
      void usarte0_init(void)
      {
      PORTE.OUTSET=0x08;
      USARTE0.CTRLC=USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
      USARTE0.CTRLA=(USARTE0.CTRLA & (~(USART_RXCINTLVL_gm | USART_TXCINTLVL_gm | USART_DREINTLVL_gm))) |
         USART_RXCINTLVL_OFF_gc | USART_TXCINTLVL_OFF_gc | USART_DREINTLVL_OFF_gc;
      USARTE0.BAUDCTRLA=0xF5;
      USARTE0.BAUDCTRLB=((0x0C << USART_BSCALE_gp) & USART_BSCALE_gm) | 0x0C;
      USARTE0.CTRLB=(USARTE0.CTRLB & (~(USART_RXEN_bm | USART_TXEN_bm | USART_CLK2X_bm | USART_MPCM_bm | USART_TXB8_bm))) |
         USART_RXEN_bm | USART_TXEN_bm;
      }
      
      interrupt [DMA_CH0_vect] void dma_ch0_isr(void)
      {
         DMA.INTFLAGS = 0;
         for ( i =0 ; i < 32 ; i++)
         {
            ali_test2[index] = ali_test[i];
            index++;
         }
      }
      void main(void)
      {
      unsigned char n;
      volatile DMA_CH_t * channel;
      #pragma optsize-
      #asm("cli")
      n=(PMIC.CTRL & (~(PMIC_RREN_bm | PMIC_IVSEL_bm | PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm))) |
         PMIC_LOLVLEN_bm | PMIC_HILVLEN_bm;
      CCP=CCP_IOREG_gc;
      PMIC.CTRL=n;
      PMIC.INTPRI=0x00;
      #pragma optsize_default
      system_clocks_init();
      PORTE.OUT=0x08;
      PORTE.DIR=0x08;
      usarte0_init();
      
      
       channel = &DMA.CH0;
       DMA.CTRL = 0;
       DMA.CTRL = DMA_RESET_bm;
       while ((DMA.CTRL & DMA_RESET_bm) != 0);
       channel->CTRLB   = (channel->CTRLB & ~(DMA_CH_ERRINTLVL_gm | DMA_CH_TRNINTLVL_gm)) |
                DMA_CH_TRNINTLVL_LO_gc | DMA_CH_ERRINTLVL_LO_gc ;
       DMA.CTRL = DMA_CH_ENABLE_bm ;
       channel->REPCNT  = 0;
       channel->CTRLA   |= DMA_CH_SINGLE_bm;
       channel->CTRLA   |= DMA_CH_REPEAT_bm;
       channel->CTRLA   |= DMA_CH_BURSTLEN_1BYTE_gc;
       channel->ADDRCTRL |= DMA_CH_SRCRELOAD_BURST_gc;
       channel->ADDRCTRL |= DMA_CH_SRCDIR_FIXED_gc;
       channel->ADDRCTRL |= DMA_CH_DESTRELOAD_BURST_gc;
       channel->ADDRCTRL |= DMA_CH_DESTDIR_INC_gc;
       channel->TRIGSRC  = DMA_CH_TRIGSRC_USARTE0_RXC_gc;
       channel->TRFCNT  = 32;
       channel->SRCADDR0 = (( (uint32_t) &USARTE0.DATA) >> 0*8 ) & 0xFF;
       channel->SRCADDR1 = (( (uint32_t) &USARTE0.DATA) >> 1*8 ) & 0xFF;
       channel->SRCADDR2 = (( (uint32_t) &USARTE0.DATA) >> 2*8 ) & 0xFF;
       channel->DESTADDR0 = (( (uint32_t) &ali_test) >> 0*8 ) & 0xFF;
       channel->DESTADDR1 = (( (uint32_t) &ali_test) >> 1*8 ) & 0xFF;
       channel->DESTADDR2 = (( (uint32_t) &ali_test) >> 2*8 ) & 0xFF;
       channel->CTRLA  |= DMA_CH_ENABLE_bm;
      #asm("sei")
      while (1);
      }
      يا حق

      دیدگاه


        #4
        پاسخ : مشکل با DMA برای خواندن USART

        کد اصلاح شده بالا رو امتحان کردم ولی باز اینتراپت فعال نشد. مشکل کار کجاست؟
        يا حق

        دیدگاه


          #5
          پاسخ : مشکل با DMA برای خواندن USART

          مواردی را هم من اضافه میکنم:
          1- برای DESTRELOAD باید حالت BLOCK قرار داده شود.
          2- برای پاک کردن flag وقفه باید در محل آن 1 نوشته شود.
          3- طبق توضیحات قسمت Transfer Triggers پس از اتمام انتقال هر Block کانال مربوطه غیر فعال می شود.
          4- چون آدرس وقفه هر کانال برای حالت اتمام انتقال و حالت خطا مشترک هست باید در روتین وقفه حالت بوجود آمده چک شود و مطابق با آن عملیاتی انجام شود.
          [code=c]ISR(DMA_CH0_vect)
          {
          if (DMA.CH0.CTRLB & DMA_CH_TRNIF_bm)
          {
          DMA.CH0.CTRLB |= DMA_CH_TRNIF_bm;
          DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
          . . .
          }
          else
          {
          DMA.CH.CTRLB |= DMA_CH0_ERRIF_bm;
          . . .
          }
          }
          [/code]
          گاهی افرادی به موفقیت های بزرگ می رسند، تنها به این دلیل ساده که نمی دانند کاری که به آن دست زده اند بسیار دشوار، بلکه غیر ممکن است.

          دیدگاه


            #6
            پاسخ : مشکل با DMA برای خواندن USART

            بسیار بسیار ممنون . با کمک راهنمایی آقای طراح و آقا حامد مشکل برطرف شد. :wow: :applause:
            ظاهرا دائم داخل اینتراپت میرفت ولی چون دائم داخل اینتراپت میرفت من متوجه نمی شدم . این مشکل با 1 کردن برطرف شد ولی باز با هر کاراکتر وارد اینتراپت می شد. و با فعال کردن دوباره single shot این مشکل برطرف شد.
            بسیار از لطف شما سپاسگزارم.
            يا حق

            دیدگاه

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