
ومرة أخرى ، نكتشف كيف لا نكتب البرامج الثابتة للميكروكونترولر. أثارت المقالة السابقة الكثير من المشاعر لدى الناس ، ويبدو لي أن القليل من الناس فهموا ، وربما تم شرحه بشكل سيء لي لماذا بدأ كل هذا.
لذلك ، قمت بإعداد مثال .
على الرغم من أن هذه مجرد عينة من قرص DMA_Polling من مكتبة الأجهزة الطرفية القياسية.
ولكن هذه هي ميزة هذا النهج ، حيث يمكنك استخدام جميع التطورات من التعليمات البرمجية المنفذة على متحكم ، بما في ذلك المكتبات من الشركة المصنعة MK مثل HAL أو Standard Peripherals Library. وهذا يجب أن يكون عادلاً لأي وحدة تحكم تدعم openOCD - على الأقل STM32 و Atmel و PIC32 وغيرها على القائمة . في الوقت نفسه ، يمكننا استخدام جميع مكتبات الكمبيوتر المضيف ، وكذلك استخدام معايير لغة C ++ الجديدة. وإذا كتبت أغلفة ، فيمكنك عمومًا استخدام أي لغة. لكنني لم تعقّد الكثير هنا. لقد قررت فقط إظهار الوظائف والميزات الأساسية.
في المثال ، بالطبع ، سوف نرمش LED. وكذلك إرسال البيانات على UART وعلى UART آخر لاستقبالهم باستخدام DMA. باستخدام DMA يعطي مكافأة ضخمة. غالبًا ما يكون من الممكن التخلص من المقاطعات التي لا يمكننا استخدامها هنا ، والاقتراع ، الذي يكون بسبب مصحح الأخطاء الخاص بي بطيئًا جدًا ، ولكنه لا يزال أقل وقتًا لالتقاط البيانات على الواجهات. وأيضا توليد بسرعة. لذلك ، من السهل جدًا إنشاء مولد إشارة قابل للبرمجة ومتشمم للواجهات المختلفة.
تبقى المعدات التي سنختبرها من وقت المقالة الأولى

هنا قمت بتوصيل الأسلاك البيضاء UART1 (PA9 pin) مع Rx UART2 (PA3 pin).
إذا نظرت إلى الكودconst char * message = "AddressIntercept PinTool UART DMA example"; int main() { sizeMemoryTranslate_t s = 0; memoryTranslate *p = getMemoryMap(&s); pAddrPERIPH = p[0].start_addr; pAddrSRAM = p[1].start_addr; init(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio; gpio.GPIO_Pin = GPIO_Pin_13; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &gpio); const size_t _SIZE_MESSAGE = strlen(message); printf("sending message "); for (int i = 0; i < _SIZE_MESSAGE; i++) { USART_SendData(USARTy, message[i]); GPIO_SetBits(GPIOC, GPIO_Pin_13); while (USART_GetFlagStatus(USARTy, USART_FLAG_TXE) == RESET); printf("."); fflush(stdout); GPIO_ResetBits(GPIOC, GPIO_Pin_13); } printf("\n"); printf("qty of sent bytes %d\n", strlen(message)); const uint16_t rec = DMA_GetCurrDataCounter(USARTz_Rx_DMA_Channel); printf("qty of received byte using DMA : %d\n", sizeDMAbuf - rec); printf("read message from buffer DMA : "); const uint8_t *pM = (uint8_t *)pAddrSRAM; for (int r = 0; r < _SIZE_MESSAGE; r++) { printf("%c", pM[r]); fflush(stdout); } printf("\n"); assert(strncmp(message, (const char *)pM, _SIZE_MESSAGE) == 0); printf("Received and sent bytes are equal!\n"); return 0; }
يمكنك أن ترى أنه باستثناء وظيفتنا المتمثلة في تحويل العناوين والوظائف من المكتبة القياسية ، فإن كل شيء آخر مأخوذ من SPL من ST ، من حيث المبدأ ، كان من الممكن استخدامه من وظيفة HAL. لكنني أكثر دراية بالحركة الشعبية القديمة الجيدة.
كيفية تجميع وتشغيل كل شيء
هذا مثال للكمبيوتر الشخصي مع Ubuntu 16.04 64 بت:
تحتاج أولاً إلى تنزيل Pintool v3.7
عملية فك الارتباط مريحة ، ثم يمكنك تحديد المتغير PIN_ROOT لإنشاء عميل PinTool أو ببساطة تحديد موقع عميلنا في
pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/
أفعل الطريقة الثانية
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/ git clone git@github.com:ser-mk/AddressIntercept.git cd AddressIntercept
بعد ذلك ، تحتاج إلى إنشاء عميل 32 بت
make TARGET=ia32
سوف يكون هنا ثنائي obj-ia32 / addrIntercept.so. مطلوب 32 بت ، لأنه في ARM ortex مثل حجم العنوان.
الآن يمكنك جمع المثال نفسه. أنا نسخها مباشرة إلى المجلد إلى عميل pintool
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept Git clone https://github.com/ser-mk/addrIntercept-example-UART-DMA Cd addrIntercept-example-UART-DMA Make
ونحن نحصل على ثنائي في الدليل test.elf. علاوة على بساطة التجربة ، سأضع الملف في دليل عميل Pintool AddressIntercept الخاص بنا
قبل البدء في كل شيء ، نحتاج إلى إنشاء FIFOs مسمى للتواصل مع عميل OpenOCD
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept mkfifo in.fifo out.fifo
in.fifo out.fifo - الأسماء الافتراضية لعملائنا ، يمكنك إعطاء أسماء أخرى ، ولكن بعد ذلك سيتعين تحديدها بشكل صريح عند بدء العملاء.
دعنا نبدأ عميل openOCD ، في حالتي أحتاج لتمرير خادم ip openOCD إليه ، سيكون 192.168.0.111 ، سيترك المنفذ 6666 القياسي ، لذلك أنا لا أحدده.
لذلك ، ركض بالترتيب
cd pin-3.7-97619-g0d0c92f4f-gcc-linux/source/tools/AddressIntercept python3.5m OCDclient.py -ip 192.168.0.111 & ../../../pin -t obj-ia32/addrIntercept.so -- addrIntercept-example-UART-DMA/test.elf
والنتيجة يجب أن تكون مثل هذا:

آمل مثال توضيحي. بالفعل دليل على المفهوم الذي يمكن استخدامه.
علاوة على ذلك ، يجب أن يعمل كل شيء ، بما في ذلك على MacOS و Windows (هنا ، قد تضطر إلى تعديل العمل باستخدام fifo المسمى أو استبداله بما هو موجود في "windows").
علاوة على ذلك ، في المقالات التالية ، إذا كان الأمر ممتعًا ، يمكنك التحدث عن REPL كما في GIF من المقالة السابقة وطرق أخرى لاعتراض العناوين ، دون تقييد نظام Intel الأساسي.