ARM, STM32, آموزش, توصیه شده, دوره آموزشی STM32, میکروکنترلر

آموزش میکروکنترلر STM32 قسمت دهم: واحد DMA در رابط سریال UART

آموزش میکروکنترلر STM32 قسمت دهم: واحد DMA در رابط سریال UART

آموزش میکروکنترلر STM32 ; سیسوگ در قسمت نهم از آموزش میکروکنترلر STM32  طریقه کار با وقفه رابط سریال را با استفاده و بدون استفاده از توابع کتابخانه hal  آموزش داد. در این قسمت از آموزش میکروکنترلر STM32 قصد دارد وارد قسمت آموزش کار با DMA رابط سریال UART شود. در مجموعه آموزشی ” آموزش میکروکنترلر STM32 ” با سیسوگ همراه باشید.

 

DMA در رابط سریال UART

اول از همه بهتر است در چند جمله کوتاه کار و قابلیت این امکان در این رابط سریال را توضیح دهیم. فرض کنید برنامه‌ای داریم که میخواهیم 500 بایت اطلاعات را به رابط سریال ارسال کنیم، بدون اینکه دست از کارهای دیگرمان بکشیم و وقتی صرف نماییم و یا اینکه مثلا 500 بایت از رابط سریال دریافت کنیم بدون اینکه بخواهیم وقتی صرف کنیم و منتظر دریافت باشیم. در موارد یاد شده ما از واحد DMA استفاده خواهیم کرد، به علاوه این قابلیت که وقتی عملیات به پایان رسید از طریق یک وقفه با خبر خواهیم شد و کدهای مناسب را در ادامه اجرا خواهیم کرد. ما برای شروع در این قسمت ابتدا آموزش کار با DMA را در قسمت دریافت قرار می‌دهیم. برای شروع دوباره به نرم افزار CubeMX می‌رویم و در قسمت تنظیمات UART1 به پنجره DMA settings می‌رویم و طبق عکس زیر تنظیمات را انجام می‌دهیم.

 تنظیمات UART1 پنجره DMA settings

آموزش میکروکنترلر STM32

بعد از انتخاب گزینه مورد نظر حالا می‌توانیم از طریق گزینه Mode در پایین سمت چپ مشخص کنیم دیتا به چه صورت دریافت شود، بصورت عادی Normal یا به صورت Circular و چرخشی. در حالت عادی ما هر بار باید بعد از اتمام دریافت اطلاعات دوباره پیکره‌بندی را انجام دهیم ولی در حالت چرخشی این عمل لازم نیست و بصورت خودکار بعد از اتمام دریافت دوباره آماده دریافت اطلاعات می‌شویم.

تنظیمات UART1 پنجره DMA settings

و در قسمت Data width هم نوع اطلاعاتی را که می‌خواهیم منتقل کنیم، مشخص می‌کنیم:

تنظیمات UART1 پنجره DMA settings

توجه داشته باشید در اینجا Byte به معنی 8 بیتی و Half Word به معنی 16 بیتی و Word به معنی دیتا از نوع 32 بیتی می‌باشد. ما در اینجا چون اطلاعاتی که جابجا می‌کنیم هشت بیتی است همان Byte را انتخاب می‌کنیم. بعد از ok کردن تنظیمات از CubeMX خروجی می‌گیریم و به محیط نرم افزار keil می‌رویم.

حال به توضیح فرمان‌های کتابخانه hal در این قسمت می‌پردازیم. برای ارسال یک آرایه اطلاعات به رابط سریال uart ما از فرمان زیر استفاده خواهیم کرد:

 

در آرگومان *huart تابع نام uart مورد استفاده ما قرار می‌گیرد و در آرگومان *pData رشته ای که قرار است اطلاعات دریافتی از رابط سریال در داخل آن قرار بگیرد. در آرگومان Size سایز یا تعداد بایتی که قرار است دریافت شود تعیین می‌شود. در نتیجه ما باید در ابتدای محلی که می‌خواهیم دریافت اطلاعات شروع شود از این فرمان استفاده کنیم. برای فهم بیشتر مسئله به عکس زیر توجه کنید.

 ارسال اطلاعات به رابط سریال uart

همانطور که میبینید در قسمت مشخص شده از عکس بالا، ما قرار است 20 بایت از رابط سریال huart1 دریافت کنیم و بایت‌های دریافتی هم داخل آرایه str ریخته شود. خوب تا اینجا مشکلی نیست، ولی می‌خواهیم بدانیم چطور از نتیجه عملیات باخبر شویم. یعنی اولا از کجا بفهمیم عملیات انتقال تا کجا پیش رفته یعنی چند بایت تا الان دریافت شده و دوم اینکه نصف بایت‌هایی که می‌خواستیم دریافت شده و سوم اینکه چطور بفهمیم همه 20 بایتی که می‌خواستیم کاملا دریافت شده است. در جواب سوال اول، ما می‌توانیم با چک کردن وضعیت رجیستر CNDTR از رجیستر‌های واحد DMA مورد استفاده خودمان متوجه شویم تا الان چند بایت دیگر از 20 بایت برای دریافت باقیمانده برای فهم بیشتر به کد زیر توجه کنید:

 

 

بر طبق کد‌نویسی بالا 20 بایتی که می‌خواستیم در یک مرحله دریافت شود، از تعداد بایتی که برای دریافت باقیمانده کم می‌شود و نتیجه می‌شود تعداد بایتی که تا الان دریافت شده بواقع عملکرد رجیستر CNDTR دقیقا مشابه عملکرد همان رجیستر RxXferCount است که پیش از این ذکر کردیم. یعنی با هر بار استفاده از فرمان HAL_UART_Receive_DMA این رجیستر با تعداد بایت درخواستی که ما در اینجا همان 20 است پر می‌شود و با هر واحد (در اینجا بایت) دریافت اطلاعات یکی از مقدار آن کم می‌شود تا به صفر برسد و بواقع عملیات دریافت پایان پذیرد.

راه حل دیگری که می‌توان از طریق آن متوجه شد آیا واحد DMA هنوز در حال تبادل اطلاعات است یا کار آن به پایان رسیده، چک کردن وضعیت State واحد DMA مورد نظر است. برای فهم بیشتر مسئله به عکس کدنویسی زیر توجه کنید.

چک کردن وضعیت State واحد DMA

همانطور که در عکس بالا میبینید ما چک می‌کنیم اگر وضعیت State در حالت HAL_DMA_STATE_READY است، یعنی عملیات تمام شده و واحد مورد نظر دوباره آماده پذیرش است و در خط 133 هم اطلاعات دریافتی را نمایش می‌دهیم . در خط 134 بافر دریافت را پاک میکنیم، در خط 135 بدلیل اینکه در مد عادی هستیم و از حالت چرخشی استفاده نکردیم دوباره پیکره بندی را انجام می‌دهیم. توجه داشته باشید که State در ابتدای شروع متن تابع HAL_UART_Receive_DMA به حالت HAL_UART_STATE_BUSY_RX می‌رود و تا پایان عملیات دریافت در همین وضعیت باقی می‌ماند و اصولا تابع HAL_UART_Receive_DMA هم تنها زمانی اجرا می‌شود که State در وضعیت ازاد یا همان HAL_DMA_STATE_READY باشد. برای فهم بیشتر متن تابع مورد نظر را در برگه مربوطه مطالعه نمائید. بیاد داشته باشید این قائده تنها مخصوص این تابع نمی‌باشد، بلکه خیلی توابع دیگر از کتابخانه hal از این رویه پیروی می‌کنند. خوب حالا بسراغ توابع وقفه رابط DMA می‌رویم که این وقفه به اجبار در همان نرم افزار CubeMX انتخاب شده بوده بدنه روتین وقفه در همان برگه stm32f1xx_it.c وجود دارد که در عکس زیر مشاهده مینمائید.

توابع وقفه رابط DMA

در اینجا ما می‌خواهیم از دو وقفه مختلف برای دریافت رابط DMA استفاده کنیم و از توابع Callback که می‌توانیم در  برگه main.c برنامه خود ان را جاسازی کنیم استفاده می‌کنیم. اولین تابع Callback وقفه دریافت کامل است و دیگری مربوط به دریافت نیمی از اطلاعات درخواستی یعنی وقتی 20 بایت می‌خواهیم از رابط سریال دریافت کنیم بعد از دریافت 10 بایت که نیمی از اطلاعات درخواستی ماست به این تابع می‌رویم. در عکس زیر می‌توانید این توابع را به همراه کدهای مورد نظرمان که می‌خواهیم داخل این توابع اجرا شود در برگه main.c برنامه ببنید.

تابع Callback وقفه رابط DMA

همانطور که در کدنویسی‌ها مشخص است تابع بالا مربوط می‌شود به دریافت کامل و تابع پایینی مربوط می‌شود به دریافتی نیمی از اطلاعات. و در عکس هم توضیح داده شده است که فرمان خط 251 تنها باید زمانی نوشته شود که از حالت معمولی استفاده شده و در حالت چرخشی یا Circular احتیاجی به دوباره نوشتن این فرمان برای دریافت دوباره نیست. برای فهم بیشتر مسئله به تصویری از محیط نرم افزار terminal برای ارتباط سریال با کامپیوتر توجه کنید.

 محیط نرم افزار terminal برای ارتباط سریال با کامپیوتر

ارسال از طریق DMA

بعد از آموزش طریقه دریافت بوسیله واحد DMA وارد آموزش ارسال از طریق DMA می‌گردیم. برای این منظور دوباره به محیط CubeMX برمی‌گردیم و باز به سراغ پنجره DMA settings می‌رویم و طبق عکس زیر تنظیمات را انجام می‌دهیم.

 پنجره DMA settings در محیط CubeMX

بعد از ok کردن تنظیمات از CubeMX خروجی می‌گیریم و به محیط نرم افزار keil وارد می‌شویم. حال می‌خواهیم ببنیم از طریق چه فرمانی از کتابخانه hal می‌توانیم محتوای یک بافر را از طریق واحد DMA به رابط سریال ارسال کنیم.

 

 

در آرگومان *huart تابع نام uart مورد استفاده ما قرار می‌گیرد و در آرگومان *pData رشته‌ای که قرار است اطلاعات آن به رابط سریال ارسال شود. در آرگومان Size سایز یا تعداد بایتی که قرار است ارسال شود را تعیین می‌شود. بعنوان مثال فرمان زیر را تحیلیل می‌کنیم.

 

 

از طریق این فرمان ما 20 بایت از آرایه str به درگاه سریال huart1 ارسال می‌کنیم. حال اگر حالت عادی را انتخاب کرده باشیم این ارسال یکبار صورت می‌گیرد و اگر حالت چرخشی را انتخاب کرده باشید بصورت مداوم اطلاعات به رابط سریال ارسال می‌گردد . توجه داشته باشید برای حالت ارسال هم دو وقفه مشابه حالت دریافت بصورت Callback بکار گرفته می‌شود. یکی بعد از اتمام نیمی از بافر با نام HAL_UART_TxHalfCpltCallback و دومی بعد از اتمام همه محتویات بافر با نام HAL_UART_TxCpltCallback منتها در حالت عادی تنها وقفه ارسال نیمی از بافر قابل دسترسی است، منتها شما خودتان می‌توانید با دستکاری تابع UART_DMATransmitCplt در برگه stm32f1xx_hal_uart.c می‌توانید برای حالت عادی هم از آن وقفه استفاده کنید.

تنظیملت DMA در رابط سریال UART

توجه داشته باشید در حالت ارسال هم می‌توانیم با چک کردن رجیستر CNDTR  متوجه شویم چند بایت تا الان ارسال شده و همچنین با چک کردن وضعیت State به مانند حالت دریافت میتوانیم از اتمام عملیات باخبر شویم ، بعد از توضیح و اموزش دریافت و ارسال توسط DMA توسط رابط UART بد نیست به چند دستور دیگر از کتابخانه hal که معمولا کاربرد دارند اشاره شود.

 

 

متوقف کردن ادامه انتقال

 

 

ادامه انتقالی که قبلا متوقف شده بود

 

 

توقف کلی انتقال

 

 

برای توقف انتقال‌های جاری که البته در حالت چرخشی مجاز نیست و باعث می‌شود برنامه بعضا بعد از مدتی قفل کند.

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

 

سیسوگ در قسمت یازدهم از مجموعه آموزش میکروکنترلر STM32 به آموزش تنظیمات نرم‌افزار CubeMX برای رابط RTC  در خانواده CORTEXM3 می‌پردازد. در مجموعه آموزش میکروکنترلر STM32 با سیسوگ همراه باشید.

 

 

 

انتشار مطالب با ذکر نام و آدرس وب سایت سیسوگ، بلامانع است.

شما نیز میتوانید یکی از نویسندگان سیسوگ باشید.   همکاری با سیسوگ

نوشته های مشابه

32 دیدگاه در “آموزش میکروکنترلر STM32 قسمت دهم: واحد DMA در رابط سریال UART

  1. Avatar for elecNoob elecNoob گفت:

    سلام
    مشکلی که برای من پیش اومد و راه حلی که باهاش مشکلم رو برطرف کردم (البته نمیدونم این راه حل کار درست و منطقی هست یا نه):
    هدفم این بود که توسط یه ابزار خارجی مثل پورت COM کامپیوتر یه دیتایی رو به میکرو واحد uart ارسال کنم و میکرو این اطلاعات رو بگیره و به کامپیوتر برگردونه و تمام این کارها توسط واحد DMA انجام بشه.
    مشکل: زمانی که توسط دستور HAL_UART_Transmit_DMA() یه تعداد دیتا رو ارسال میکردم برای بار اول بدرستی کار میکرد اما دفعه بعد که ازش میخواستم استفاده کنم از ادامه اون خونه ای در بافر ارسال، ارسال رو ادامه میداد که دفعه قبل ارسال رو تمام کرده بود
    یعنی اگر در دفعه اول دیتایی با طول 5 کاراکتر ارسال کرده بودم و بعد بافر (رشته) ارسال رو کامل با مقدار NULL (NULL == مقدار 0 است) پاک میکردم بعد یه دیتای مثلا 3 یا 10 یا هر تعداد دیگه ای رو میخواستم ارسال کنم از کاراکتر 6 (با توجه به اینکه بار اول 5 تا کاراکتر ارسال کرده بودم حالا کاراکتر 6 رو در نظر میگرفت) و ارسال میکرد!
    هر کاری کردم که بشه دوباره از خونه 0 شروع کنه به ارسال فقط با شیوه زیر جواب گرفتم:
    بعد از اتمام ارسال، تابع HAL_UART_Abort() رو فراخونی میکنم و بعد دوباره از تابع ارسال استفاده میکنم.

    1. Avatar for Zeus ‌ Zeus ‌ گفت:

      ممنونیم که تجربتون رو به اشتراک گذاشتید 🙂

  2. Avatar for محمدمهدی محمدمهدی گفت:

    با سلام و وقت بخیر و تشکر از مطلب بسیار خوبتون
    من دیتای خروجی ماژول gps رو با dma میکرو دریافت می کنم توی حالت normal ، صد بایت دریافت میکنم و بعد از اون دیتای مورد نظرم رو استخراج میکنم و بعد توی تابع HAL_UART_RxCpltCallback دوباره درخواست میدم که بره صد بایت دیگه بخونه
    همه چی اوکیه ، اما بورد بعد از دو سه روز که کار میکنه دیگه دریافت اطلاعاتش رو انجام نمیده و نمیدونم چه مشکلی براش پیش میاد که این طور میشه
    ممنون میشم کمکم کنید

    1. Avatar for Zeus ‌ Zeus ‌ گفت:

      سلام فکر میکنم این شکل استفاده از DMA برای دریافت اطلاعات درست نباشه
      شما باید به رینگ بافر با DMAبسازید که بدون توقف ورودی رو بخونه، بعد توی روال دیگری دیتای دریافت شده رو تحلیل کنید

      1. Avatar for محمدمهدی محمدمهدی گفت:

        با سلام
        منظورتون این هست که از مد Circular استفاده کنم ؟؟

  3. Avatar for سینا مختاری سینا مختاری گفت:

    خیلی خوب بود ممنونم

    1. Avatar for Sisoog Os Sisoog Os گفت:

      سلام خواهش میکنم دوست عزیز

  4. Avatar for ahmadlou.mo ahmadlou.mo گفت:

    با سلام
    ممنونم از مطلب بسیار عالی شما
    یه سوال داشتم. بعد از اولین ارسال توسط تابع HAL_UART_Transmit_DMA چگونه باید تابع را از حالت Busy خارج کرد و به حالت Ready برد تا برای ارسال دیگر آماده شود ؟

    با تشکر

    1. Avatar photo سیاوش گفت:

      سلام دوست عزیز، خوشحالیم که آموزش‌ها مورد توجه شماست.
      در مورد سوالتون (البته اگر من درست متوجه شده باشم)، خب DMA به مقدار مشخص شده پکت به UART میده برای ارسال، UART هم بعد از هر ارسال اعلام میکنه که منتظر ارسال بعدیه.
      حالا اگه DMA توی حالت Normal تنظیم شده باشه بعد اتمام ارسال داده‌ها خود به خود آماده ارسال مجدد میشه و اگه شما قصدتون اینه قبل از ارسال کامل داده‌ها مجددا دستور ارسال بدین(به همین واحد UART) باید از دستور HAL_UART_DMAStop استفاده کنید.

  5. Avatar for محمد عزیز محمد عزیز گفت:

    سلام و وقت بخیر
    سپاس از آموزش خوبتان
    من یک مشکلی دارم موقع تحلیل پیام دریافتی از sim800 با DMA مدل پردازنده Stm32f103rb و Keil
    طبق آموزش شما پیش رفتم، دستور رو در تابع اصلی قبل از حلقه while(1) نوشتم با این تفاوت که رو مد circular گذاشتم و بازفراخوانی رو انجام ندادم و فقط بدنه تابع recal رو نوشتم اما توش خالیه چون با stmstudio نظاره گر اطلاعات بافر هستم.
    اما مشکل !
    پس از تحلیل پیام بافر 100 آرایه ایم رو با دستور memset بازنشانی میکنم به صفر .
    اما در شروع دریافت پیام بعد متوجه روی هم افتادگی اطلاعات شدم ، سایز رو کردم 150 و دیدم اطلاعات داره دقیقا از آخرین آرایه ای که در سری قبل دریافت شده رایت میشه روی بافرم!
    یعنی بجای اینکه بیاد از آرایه صفر شروع به نوشتن کنه از همون آرایه مثلا 100 میره جلو تا 117 مثلا هنگام دریافت پیام.
    و تراژدی اونجا غمناک تر میشه که حتی با یک تماس بافر چند خانه اش (مثلا تا خانه 8 پر میشه طبق رشته ring !!!) پر میشه و پس از پاک کردن با memset باز موقع دریافت پیام از همون خانه 8 شروع به پر کردن میکنه بجای آرایه صفر.
    خیلی تلاش کردم و متاسفانه حرفه ای هم نیستم و هنوز علی رغم دست و پاهایی که زدم نتونستم این مشکلو حل کنم که پس از بازنشانی خانه های بافر بیاد از آرایه صفر شروع به نوشتن کنه.
    کارهایی که خودم تابحال کردم استفاده از توایع دیگر hal مثل hal_abort , hal_init_, hal_deinit و غیره بوده که هیچکدام جواب نداده.
    ممنون میشم به من بی نوا کمک کنید

    1. Avatar photo سیاوش گفت:

      خب طبق چیزی که من متوجه شدم شما میخواید مثلا 100 خونه از حافظه که توسط بافرتون مشخص شده، به وسیله DMA پر بشه و بعد برای عملیات دوم دوباره از ابتدای این بافر شروع به نوشتن کنه. برای این منظور شما باید آدرس ابتدای بافر و تعداد خونه‌هایی که قصد نوشتن توشون رو دارید یک برای عملیات اول و بعد هم یک بار برای عملیات دوم به حافظه بدین. بسته به پروژه و نوع میکروکنترلر ممکنه نیاز باشه که DMA رو هم غیر فعال و دوباره فعال کرد.

      1. Avatar for محمد محمد گفت:

        سلام بله مشکل اینه که آرایه های بافر بدون ترمز بصورت افزایشی پر میشند تا سرریز شند و از ابتدا شروع کنند نه از صفر.
        در روش ریجستری تو بعضی منابع مبحثی هست برای رسیت کانتر داخلی تابع دریافت DMA با کتابخوانه CMSIS اما اینکه وسط کتابخونه HAL با CMSIS ریجستری بنویسیم احتمال زیاد ارور میده چون اون داره یک تابع کامل رو اجرا میکنه مگر اینکه از خود کتابخونه HAL مجدد استفاده شه.
        من با دستورات دیگش کار کردم و تست کردم اما هنوز جوابی نگرفتم متاسفانه برای رفع این مشکل که خیلی هم بده.
        HAL_Abort_DMA ، HAL_Init_DMA , HAL_DeInit_DMA , HAL_Stop_DMA
        اینها رو که در انتها استفاده میکنم کلا ارتباط قطع میشه چون HAL_Receive_DMA قبل از While تو تابع اصلی نوشته شده.
        البته امروز هم قراره با کد ور برم نتیجه رو حتما اینجا اعلام میکنم که کسی این مشکل رو نداشته باشه البته اگر حل شد ?

    2. Avatar for محمد عزیز محمد عزیز گفت:

      حل شد !
      باید برای جلوگیری از مشکل فوق ابتدا دستور را بازنشانی و سپس مجدد استارت کنید.

      1. Avatar for Zeus ‌ Zeus ‌ گفت:

        بسیار عالی
        ممنونم که تجربه خودتون با ما به اشتراک گذاشتید 🙂

        1. Avatar for محمد محمد گفت:

          خواهش میکنم، من از سیسوگ بهم رسیده و کم سعادتم بخاطر مشغله که نمیتونم فعال باشم انشا… در آینده زکات علم ناچیزمو همینجا خواهم داد.
          حالا که حضرت زئوس از المپ تشریف آوردند تکمیل ترش میکنم :
          HAL_DeInit_DMA جهت بازنشانی مقادیر به صفر و
          HAL_UART_START_RECEIVE_DMA جهت استارت مجدد دستور

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

          1. Avatar for Zeus ‌ Zeus ‌ گفت:

            سلام و درود
            بسیار سپاسگذارم 🙂

  6. Avatar for مصطفی مصطفی گفت:

    من چند سایت رو برای موضوع DMA بررسی کردم , توضیحات شما بسیار کاربردی و مناسب بود.
    ممنون

    1. Avatar for Sisoog Os Sisoog Os گفت:

      خواهش میکنم

  7. Avatar for علی علی گفت:

    سلام
    اگر در حالت چرخشی از فرمان
    HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    برای دریافت دوباره استفاده بشه چه اتفاقی می افته؟

    1. Avatar for Zeus Zeus گفت:

      اگر به موقع بافر رو نخونید آور رایت میشه اطلاعات و اطلاعات از دست میره

  8. Avatar for hamid hamid گفت:

    با سلام.
    در زمانی ک دریافت اطلاعات در DMA به پایان نرسیده است(مثلا قرار است 200 دیتا دریافت شود ولی تنها 25 تا دریافت شده است) میتوان ب اطلاعاتی ک تا آن زمان دریافت شده است(مثلا دیتا 24) دسترسی داشت یا خیر؟
    با تشکر

    1. Avatar for zeus zeus گفت:

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

  9. Avatar for amir amir گفت:

    با عرض خسته نباشید خدمت شما
    چنتا سوال داشتم از خدمتتون ممنون میشم بهم جواب بدین
    سوال اول:بخش size در دستور ارسال یا دریافت بر اساس حجم کلی یا چیز دیگه من زمانیی که کاراکتری که مقدار ان 255 میفرستادم زمانی که به جای size عدد 3 میگزاشتم عدد رو کامل میفرستاد ولی زمانی که 1 میزاشتم 2 رو فقط میفرسستاد در صورتی که گفته بودین size تعداد byte هایی که میفرستمی و 1 هست یعن یهمون یه کاکتر
    سوال دوم: من با استفاده از ارتباط uart بین دو عدد stm32f103 ارتباط بر قرار کردم در حالت uart بدون استفاده از dma ارتباط درست بود ولی بین برنامه هام تداخل ایجاد میکرد برای همین از dma استفاده کردم ولی مشکل این است که دیتایی که میفرستم بادیتا که میاد تفاوت داره وخیلی عجیبه ارسالم رو چک کردم به وسیله ttl به usb درست بود ولی دیتای دریافتیم درست نیست چه کنم
    سوال سوم :سرعت انتقال دیتای من کمه با مولتی متر که گرفتم 42khz بود ولی خیلی بیشتر از این ها باید باشه

    ممنون

    1. Avatar for زئوس Zeus زئوس Zeus گفت:

      ج۱ – خوب size در واقع طولی بایت هایی هست که قراره از طریق واحد uart ارسال بشه – فرض کنید شما میخواید عبارت salam رو در خروجی ظاهر کنید – برای این باید مقدار size رو برابر ۵ قرار بدید.
      ج۲ – اگه با مبدل چک کردید باس رو و دیتای درستی ارسال میشه – مشکل توی فرایند دریافت است واگر باز بدون dma دریافت درسته مشکل از تنظیمات dma است. چک کنید آیا بافری که قراره دیتا رو بخونه به اندازه لازم طولانی باشه
      ج۳ – متوجه منظورتون نشدم ؟ یعنی چی سرعت انتقال کمه ؟ باوود رو روی چه عددی گذاشتید ؟

  10. Avatar for َAmir َAmir گفت:

    سلام
    خسته نباشید
    سوالی داشتم:
    DMA در حالت ارسال بدون تاخیر ارسال میکنه ؟ اگه بخواهیم مثلا 10 بایت را بصورت مداوم اما بین هر ارسال مثلا 100 میلی ثانیه تاخیر باشه باید چکار کنیم ؟
    واینکه وقتی ارسال تکمیل بشه تابع HAL_UART_TxCpltCallback اجرا میشه ؟

    ممنون

    1. Avatar for زئوس Zeus زئوس Zeus گفت:

      خوب این کار رو صد در صد با dma نمیتونید هندل کنید – در واقع dma هیچ تنظیمی برای زمان دادن نداره و بافر ورودی رو با سریعترین حالت ممکن توی خروجی ظاهر میکنه !!
      برای زمان دادن میتونید از تایمر و cpu رو کمک بگیرید که دیگه هیچ ربطی به dma نداره

  11. Avatar for سروش سروش گفت:

    با عرض سلام و احترام
    سوالی از آموزشتون برام پیش اومده بود که ممنون خواهم شد اگر جواب بدین.
    در قسمت پنجره Dma setting یه قسمت هست به نام priority که Low گذاشتین . از کجا می شه فهمید باید High گذاشت یا Low . چون من در مثال های دیگه ای که مثل همین بود حالتهای مختلفی دیدم.یک جا هر دو را Low گذاشته بودند یک جای دیگه High برای RX و Low برای TX گذاشته بودند.
    از جناب آقای زئوس بزرگ هم کمال تشکر را دارم . موفق و سربلند باشید!

    1. Avatar for زئوس Zeus زئوس Zeus گفت:

      سلام دوست عزیز، ممنون از لطف شما
      خوب همونطور که از اسم priority برمیآد ، برای مشخص کردن اولویت کاربرد داره ، اما اولویت چی بر چی ؛ ببینید توی میکروکنترلر یه باس RAM در هر لحظه میتونه میزبان تراکنش باشه (البته باس رم خیلی سریعه و فکر میکنم سرعتی در حدود گیگاهرتز داره تو مدل m4) ولی به هر حال ، حالا فرض کنید هم زمان شما دوتا کانال Dma رو فعال کردید ، و شرایطی پیش میآد که دقیقا نیاز در یک لحظه مشخص به حافظه RAM دسترسی پیدا بکنند ، چه اتفاقی می تونه بیفته ؟
      شما میتونید با دادن اولویت مشخص کنید که کدام کانال DMA از اولویت بالاتری برخورداره و زودتر به RAM دسترسی پیدا بکنه ! البته میگم فقط توی چنین شرایطی !

    2. Avatar for سروش سروش گفت:

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

      1. Avatar for زئوس Zeus زئوس Zeus گفت:

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

  12. Avatar for سروش سروش گفت:

    سلام آقا مهدی
    خسته نباشید . امیدوارم همینطور به آموزشتون ادامه بدید.
    خیلی خیلی ممنون.
    از سایت سیسوگ هم تشکر ویژه – علم برای همه رایگان –
    می خواستم اگه امکانش هم بود در مورد حالت mem to mem واحد dma هم یه قسمت آموزشی بزارید.
    موفق و سر بلند باشید.

    1. Avatar for زئوس Zeus زئوس Zeus گفت:

      خواهش میکنم دوست عزیز
      خوشحالیم اگر توانسته باشیم کمکی هر چند کوچک کرده باشیم

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *