كيف يمكن للتحكم الدقيق قراءة البيانات بسرعة 1.6 جيجابت في الثانية

يوم جيد للجميع! هذا لم يحدث هنا مرة أخرى . لقد مر وقت طويل منذ مقالي الأخير ، وهو يطرح تحديات جديدة. وإذا كنت معتادًا على نقل البيانات بسرعة 100 ميجابت في الثانية ، فقد اضطررت الآن للتأرجح بسرعة 1600 ميغابت في الثانية ...

على KDPV - بطل روايتنا - كان قادرًا على قراءة البيانات بهذه السرعة!



لذا ، طلب مشروعي التالي قراءة دفق بيانات 32 بت بسرعة 50 ميجاهرتز (وهذا ، بالمناسبة ، سيكون 1.6 جيجابت في الثانية) في مقدار معروف مسبقًا - فليكن 10000. سيكون من الجيد قراءة الفور باستخدام DMA من منفذ واحد - ولكن لسوء الحظ ، لم تكن هناك معالجات مناسبة (آمل أن يصحح شخص ما هذه المسألة في التعليقات) ، لسبب ما ، جميع المنافذ المناسبة للسرعة هي لسبب ما 16 بت.

لكن هذا التافه لن يمنعنا - سنقرأ من منفذين في وقت واحد! صحيح أن هذا في الحالة العامة لن يكون ممكنًا دائمًا بالقدر اللازم من التحكم والتزامن ، ولكن في حالتنا ، ليس كل شيء محزنًا للغاية - فهناك إشارة يتم بعدها الاحتفاظ ببيانات 20 ns على المنفذ.

وبما أن المعالج لدينا هو stm32h750 بسرعة 400 ميغاهرتز ، والحافلة وأجهزة ضبط الوقت على 200 ميغاهيرتز ، ثم يجب أن يعمل كل شيء.

يبدو حالة بسيطة - لتشغيل إعادة توجيه DMA واحد على إشارة. لكن DMA فقط ليس لديه مثل هذه الفرصة - يمكن للميناء إصدار مقاطعة ، لكن لا يمكنه التحكم في DMA. لكن معالجنا لديه شيء جيد - DMAMUX ، حيث يوجد مولد حدث لقناة DMA ، لكن هذا المولد لديه خياران مناسبان - إما استخدام مقاطعة EXTIT0 أو الإشارة من جهاز ضبط الوقت TIM12 (كان لدى مطوري الرقاقة مثل هذا الخيال الغريب).

ليس لدينا وقت للإنقطاع - نحتاج حتى حوالي 47 دورة من ساعات العمل حتى تنفجر ، ودورة الساعة لدينا تبلغ 2.5 ثانية ...

ولكن في الوقت المناسب لجهاز توقيت. يبقى فقط إخراج الموقت من إشارة خارجية قدرها 100 ميجاهرتز ، وتعيين طول الموقت إلى 1 وسيؤدي إخراج TRGO إلى تشغيل مولد DMAMUX ، ثم يصدر أمرًا لإرسال DMA وسيقوم بقراءة المنفذ وإرسال البيانات إلى الذاكرة.

لكن توقف! المنفذ 16 بت ، لكن لدينا 32 ... حسنًا ، يمكنك محاولة قراءة منفذ ثانٍ آخر ... لهذا فقط نحتاج إلى قناة DMA ثانية ، وسوف يستغرق الأمر نفس الحافلة - أي ، سيكون لدينا وقت للقراءة ، لكن يمكننا ليس لديك وقت لكتابة البيانات إلى الذاكرة. حسنًا ، من الناحية النظرية ، يحتوي هذا المعالج على أنواع مختلفة من الذاكرة ، وفي صورة كبيرة لهيكل المعالج يمكنك أن ترى أن كلاً من ذاكرة DMA و RAM_D1 يجلسان على نفس الحافلة بتردد 200 ميجاهرتز. يبقى للتحقق في الممارسة العملية.

DMA1->LIFCR |= ~0; DMA1_Stream0->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream0->M0AR = (uint32_t) data; DMA1_Stream0->PAR = (uint32_t) &(GPIOE->IDR); DMA1_Stream0->NDTR = 10000; DMA1_Stream1->CR = (0b11 << DMA_SxCR_PL_Pos) | (0b01 << DMA_SxCR_MSIZE_Pos) | (0b01 << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC; DMA1_Stream1->M0AR = (uint32_t) data2; DMA1_Stream1->PAR = (uint32_t) &(GPIOD->IDR); DMA1_Stream1->NDTR = 10000; DMAMUX1_Channel0->CCR = DMAMUX_CxCR_EGE | (1); DMAMUX1_Channel1->CCR = DMAMUX_CxCR_EGE | (2); DMAMUX1_RequestGenerator0->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMAMUX1_RequestGenerator1->RGCR = DMAMUX_RGxCR_GE | (0b01 << DMAMUX_RGxCR_GPOL_Pos) | (7); DMA1_Stream0->CR |= DMA_SxCR_EN; DMA1_Stream1->CR |= DMA_SxCR_EN; TIM12->CNT = 0; TIM12->CCMR1 |= TIM_CCMR1_CC2S_0; TIM12->CR2 = (0b010 << TIM_CR2_MMS_Pos); TIM12->CR1 |= TIM_CR1_CEN; while (DMA1_Stream0->NDTR) i++; TIM12->CR1 &= ~TIM_CR1_CEN; 

وبالطبع ، تحتاج إلى وضع صفائف البيانات والبيانات 2 في مقطع الذاكرة المطلوب ، ويتم ذلك على النحو التالي:

 __attribute__((section(".dma_buffer"))) uint16_t data[10240],data2[10240]; 

وفي الملف الخاص بالرابط ، أشر إلى:

 .dma_buffer : { *(.dma_buffer) } >RAM_D1 

للتحقق ، حسناً ، وكخيار أول ، تم تنفيذ مجرد نسخ غبية باستخدام
وحدة المعالجة المركزية (لا تزال 400 ميغاهيرتز):

  uint16_t * ptr = cpudata; volatile uint16_t * src = &(GPIOE->IDR); volatile uint16_t * src2 = &(GPIOD->IDR); for (register int i = 0; i < 10000; i++) { *ptr++ = *src; *ptr++ = *src2; } 

للتحقق ، كانت بيانات cpudata موجودة في ذاكرة مختلفة ، وكان الأسرع (جيدًا ، صحيح ، 64 كيلو بايت فقط) هو أسرع ذاكرة (DTCMRAM) أيضًا (MHz 400).

النتائج


خلال الاختبارات ، اتضح أنه بمساعدة وحدة المعالجة المركزية من الممكن أن تقرأ بسرعة 12.5 ميغاهيرتز من اثنين من المنافذ. و 25 ميغاهيرتز من واحد. وبالتالي فإن الخيار لا يعمل ...

بمساعدة DMA ومثل هذه الأم ، تمكنت TIM12 من القراءة بنجاح بسرعة 50 ميجاهرتز ، وفي غضون ساعات قليلة لم يكن هناك اختبار خطأ واحد. تمت قراءة كلا المنفذين ، لكن لم يكن من الممكن بعد قياس مدى تأخر القراءة على DMA الثانية ...

في حالتي (المنحدرة قليلاً) ، تمكنت من تحقيق سرعة نقل المعلومات إلى معالج stm32h750 بسرعة 32 × 50 = 1600 ميجابت في الثانية.

Source: https://habr.com/ru/post/ar467459/


All Articles