สารบัญ:

ส่วนที่ 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 ขั้นตอน
ส่วนที่ 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 ขั้นตอน

วีดีโอ: ส่วนที่ 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 ขั้นตอน

วีดีโอ: ส่วนที่ 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo: 16 ขั้นตอน
วีดีโอ: Part 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo 2024, พฤศจิกายน
Anonim
Image
Image

จุดเน้นของคำแนะนำนี้คือไมโครคอนโทรลเลอร์ STM32 Nucleo แรงจูงใจในการสร้างโครงการประกอบจากกระดูกเปล่า สิ่งนี้จะช่วยให้เราเจาะลึกและเข้าใจโครงการ MSP432 Launchpad (TI-RSLK) ที่เป็นหัวข้อของ Instructables หลายตัวแล้ว

ไม่มีความช่วยเหลือออนไลน์มากนักในการสร้างโปรเจ็กต์สำหรับแอสเซมบลีเท่านั้นสำหรับ MSP432 โดยใช้ Code Composer Studio จนถึงตอนนี้ เราเพิ่งคัดลอก/วางจากโครงการประกอบที่มีอยู่แล้ว แนวทางนี้ให้บริการเราเป็นอย่างดี

อย่างไรก็ตาม สำหรับ Lab 7 เราพบปัญหาเล็กน้อย หรืออย่างน้อยก็สะอึกชั่วคราว Lab 7 นำเสนอเครื่องที่มีสถานะจำกัด และสิ่งแรกที่เราพบคือความจำเป็นในการสร้างและใช้อาร์เรย์ของค่าต่างๆ เนื่องจากหลักสูตร TI ใช้การเขียนโปรแกรม C เป็นหลัก จึงไม่เป็นปัญหา แต่ Instructables เหล่านี้มุ่งเน้นไปที่การประกอบไม่ใช่ C.

นอกจากนี้ เนื่องจากอาร์เรย์เป็นค่าแบบอ่านอย่างเดียว จึงควรใส่ไว้ในหน่วยความจำแฟลช ไม่ใช่ RAM

ดูเหมือนว่าจะมีความช่วยเหลือออนไลน์อีกมากมายสำหรับโครงการแอสเซมบลีโดยใช้ STM32 MCU ดังนั้นเราจึงเริ่มต้นด้วยคำแนะนำนี้โดยมีเป้าหมายในการใช้สิ่งที่เรียนรู้เพื่อนำไปใช้กับ MSP432 และ Code Composer Studio

บนเส้นทางสู่เป้าหมายนั้น เรายังจะได้รับประสบการณ์กับไมโครคอนโทรลเลอร์ยอดนิยมอีกตัวหนึ่งอีกด้วย

ขั้นตอนที่ 1: การทดสอบเบื้องต้นของอุปกรณ์

การทดสอบเบื้องต้นของอุปกรณ์
การทดสอบเบื้องต้นของอุปกรณ์
การทดสอบเบื้องต้นของอุปกรณ์
การทดสอบเบื้องต้นของอุปกรณ์
การทดสอบเบื้องต้นของอุปกรณ์
การทดสอบเบื้องต้นของอุปกรณ์

อีกครั้ง เหตุใดจึงเลือก STM32 Nucleo โดยเฉพาะ?

อย่างจริงใจ? เพราะฉันกำลังค้นหาบทความดีๆ เกี่ยวกับโปรเจ็กต์การประกอบ Bare-Metal สำหรับตัวควบคุม ARM และฉันก็เจอซีรีส์นี้ และเพราะว่า STM32 ดูเหมือนจะเป็น MCU ยอดนิยม

ฉันได้ค้นคว้ามาแล้ว (มีหลายเวอร์ชันให้เลือก - ดูภาพด้านบน) แต่ในท้ายที่สุด มันก็กลายเป็นสิ่งที่ฉันทำได้จริง เนื่องจากฉันจะใช้ Amazon (ในสหรัฐอเมริกา)

มาในแพ็คเกจที่เรียบง่ายแต่เป็นมืออาชีพ พร้อมคำแนะนำในการเริ่มต้นใช้งาน ค่อนข้างตลกที่เห็นว่าการสาธิตที่เขียนลงในคอนโทรลเลอร์นั้นเกือบจะเหมือนกับสิ่งที่เราเคยทำใน Instructables ที่ผ่านมา - LED กะพริบและเปลี่ยนความเร็วตามการกดปุ่ม

ดูเหมือนว่าบอร์ดพัฒนานี้จะคล้ายกับ MSP432 มาก โดยมีไฟ LED 2 ดวง และปุ่มกดสำหรับผู้ใช้หนึ่งปุ่ม MSP432 มีปุ่มผู้ใช้ 2 ปุ่ม

อย่างที่คุณเห็นในรูปภาพ ฉันค่อนข้างแปลกใจที่บอร์ดมี mini ไม่ใช่ micro USB ต้องวิ่งออกไปซื้อสาย

การทดสอบที่ดีอีกประการหนึ่งคือ เมื่อคุณเชื่อมต่อกับคอมพิวเตอร์ของคุณ (ฉันใช้กล่อง Linux) การทดสอบจะแสดงขึ้นในตัวจัดการไฟล์ของฉัน เป็นระบบไฟล์ที่เรียกว่า "NODE_F303RE" การเปิดที่แสดงสองไฟล์ หนึ่ง HTML และหนึ่งข้อความ

แค่นั้นแหละ แต่อย่างน้อยก็ยังบอกว่าการเชื่อมต่อดูค่อนข้างง่าย

ตอนนี้เราพร้อมที่จะเริ่มต้นแล้ว

ฉันจะพยายามไม่พูดถึงข้อมูลดีๆ จากบทความชุด IVONOMICON Bare Metal ซ้ำ แต่ควรปรับปรุงให้ดียิ่งขึ้น

ขั้นตอนที่ 2: สิ่งจำเป็น

สิ่งแรกที่เราต้องการคือคอมไพเลอร์

จากนั้น เราต้องการดีบักเกอร์:

devchu@chubox:~$ sudo apt-get install gdb-arm-none-eabiReading รายการแพ็คเกจ… เสร็จสิ้น การสร้างแผนผังการพึ่งพา กำลังอ่านข้อมูลสถานะ… เสร็จสิ้น แพ็คเกจใหม่ต่อไปนี้จะถูกติดตั้ง: gdb-arm-none-eabi 0 อัปเกรดแล้ว 1 ใหม่ ติดตั้งแล้ว 0 เพื่อลบและ 8 ไม่ได้อัพเกรด ต้องการไฟล์เก็บถาวร 2, 722 kB หลังจากการดำเนินการนี้ จะใช้พื้นที่ดิสก์เพิ่มเติม 7, 738 kB รับ:1 https://us.archive.ubuntu.com/ubuntu xenial/universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3+9 [2, 722 kB] ดึงข้อมูล 2, 722 kB ใน 1 วินาที (1, 988 kB/s) การเลือกแพ็คเกจที่ยกเลิกการเลือกก่อนหน้านี้ gdb-arm-none-eabi (กำลังอ่านฐานข้อมูล … 262428 ไฟล์และไดเรกทอรีที่ติดตั้งอยู่ในปัจจุบัน) กำลังเตรียมที่จะแกะ …/gdb-arm-none-eabi_7.10-1ubuntu3+9_amd64.deb … กำลังแกะ gdb-arm-none-eabi (7.10-1ubuntu3+9) … กำลังประมวลผล ทริกเกอร์สำหรับ man-db (2.7.5-1) … กำลังตั้งค่า gdb-arm-none-eabi (7.10-1ubuntu3+9) …

ขั้นตอนที่ 3: สิ่งจำเป็น - Windows

ขั้นตอนข้างต้นถือว่าเรากำลังใช้ Linux เกิดอะไรขึ้นถ้าเราใช้ Windows?

คุณสามารถไปที่ไซต์นักพัฒนาซอฟต์แวร์และมีตัวเลือกการดาวน์โหลดหลายแบบให้เลือก ฉันใช้เครื่อง Windows 8

ระหว่างการติดตั้ง ฉันเลือกที่จะติดตั้งลงในไดรฟ์ root "C:\" แทน Program Files เพียงเพราะฉันใช้ cygwin ด้วย และสร้างลิงก์จาก bin ในเครื่องของฉันไปยังโฟลเดอร์ root C: ได้ง่ายกว่าทั้งหมด ยุ่งในเส้นทางไปยัง Program Files (มีช่องว่าง ฯลฯ)

ดังนั้นสภาพแวดล้อมและเส้นทาง cygwin ของฉัน ฯลฯ จึงเป็นดังนี้:

C:\cygwin64\home\bin\arm-none-eabi-gcc โดยที่ arm-none-eabi-gcc เป็นลิงก์ไปยัง C:\GNUToolsArmEmbedded\7.2018.q2.update\bin\arm-none-eabi- จีซีซี

จากนั้นฉันก็สร้างโฟลเดอร์ "dev" ภายใต้หน้าแรกของ cygwin และนั่นคือที่ที่ฉันวางไฟล์ core. S และรันคำสั่งคอมไพเลอร์ (ดูเพิ่มเติมด้านล่างสำหรับสิ่งที่คอมไพเลอร์)

ฉันทำสิ่งเดียวกันกับ gdb (arm-none-eabi-gdb)

ขั้นตอนที่ 4: สิ่งจำเป็นคืออะไร

แล้ว "gcc-arm-none-eabi" คืออะไร?

คอมไพเลอร์ gnu (GCC) จะคอมไพล์ภาษาโปรแกรม (เช่น C) เป็นโค้ดเนทีฟสำหรับเครื่องที่กำลังทำงานอยู่ ตัวอย่างเช่น หากคุณต้องคอมไพล์โค้ด C โดยใช้ GCC บนเครื่อง Windows ของคุณ โค้ดนั้นก็จะถูกสร้างมาให้ทำงานบนเครื่อง Windows ไฟล์เรียกทำงานที่สร้างขึ้นจะไม่ทำงาน (โดยทั่วไป) บนไมโครคอนโทรลเลอร์ ARM

ดังนั้น ในการสร้างโปรแกรมที่จะดาวน์โหลดและเบิร์นลงในไมโครคอนโทรลเลอร์ ARM (ในกรณีปัจจุบันของเราคือ STM32 Nucelo) เราจำเป็นต้องให้ GCC เป็นอย่างอื่น: ความสามารถในการ "คอมไพล์ข้าม" นั่นคือความสามารถในการสร้างไฟล์สั่งการ ไม่ใช่สำหรับระบบเนทีฟ (และโปรเซสเซอร์) แต่สำหรับระบบเป้าหมาย (ไมโครคอนโทรลเลอร์ ARM) นั่นคือที่มาของ "gcc-arm-none-eabi"

แล้ว "gdb-arm-none-eabi" คืออะไร?

เมื่อเราดาวน์โหลดและเบิร์น (แฟลช) โปรแกรมสั่งการที่สร้างขึ้นใหม่ลงในไมโครคอนโทรลเลอร์แล้ว เราอาจต้องการแก้ไขข้อบกพร่อง - ทีละขั้นตอนของโค้ด GDB เป็นตัวดีบัก gnu และก็ต้องการวิธีการทำงานเช่นกัน แต่มุ่งเป้าไปที่ระบบอื่น

ดังนั้น gdb-arm-none-eabi คือ GDB gcc-arm-none-eabi คืออะไรสำหรับ GCC

การติดตั้งแพ็คเกจอื่นที่แนะนำคือ "libnewlib-arm-none-eabi" อันนั้นคืออะไร?

Newlib เป็นไลบรารี C และไลบรารีคณิตศาสตร์สำหรับใช้กับระบบฝังตัว เป็นการรวมกลุ่มของส่วนต่างๆ ของห้องสมุด ซึ่งทั้งหมดอยู่ภายใต้ลิขสิทธิ์ซอฟต์แวร์ฟรี ซึ่งทำให้ใช้งานได้ง่ายบนผลิตภัณฑ์แบบฝัง

และสุดท้าย แพ็คเกจ "libstdc++-arm-none-eabi" นั่นค่อนข้างชัดเจน เป็นไลบรารี C++ สำหรับคอมไพเลอร์ข้าม สำหรับไมโครคอนโทรลเลอร์ ARM แบบฝัง

ขั้นตอนที่ 5: ไฟล์ Linker

ไฟล์ลิงเกอร์
ไฟล์ลิงเกอร์
ไฟล์ลิงเกอร์
ไฟล์ลิงเกอร์

มาสร้างสคริปต์ตัวเชื่อมโยงกัน

ส่วนสำคัญหรือบล็อกหนึ่งในไฟล์นี้คือคำสั่ง MEMORY

--- จาก sourceware.org:

การกำหนดค่าเริ่มต้นของตัวเชื่อมโยงอนุญาตการจัดสรรหน่วยความจำที่มีอยู่ทั้งหมด คุณสามารถแทนที่สิ่งนี้ได้โดยใช้คำสั่ง MEMORY คำสั่ง MEMORY อธิบายตำแหน่งและขนาดของบล็อกของหน่วยความจำในเป้าหมาย คุณสามารถใช้เพื่ออธิบายขอบเขตหน่วยความจำที่อาจใช้โดยตัวเชื่อมโยง และขอบเขตหน่วยความจำที่ต้องหลีกเลี่ยง จากนั้นคุณสามารถกำหนดส่วนให้กับขอบเขตหน่วยความจำเฉพาะได้ ตัวเชื่อมโยงจะตั้งค่าที่อยู่ของส่วนตามขอบเขตของหน่วยความจำ และจะเตือนเกี่ยวกับพื้นที่ที่เต็มเกินไป ตัวเชื่อมโยงจะไม่สับเปลี่ยนส่วนต่างๆ เพื่อให้พอดีกับพื้นที่ที่มีอยู่ สคริปต์ตัวเชื่อมโยงอาจมีการใช้งานคำสั่ง MEMORY หลายอย่าง อย่างไรก็ตาม บล็อกหน่วยความจำทั้งหมดที่กำหนดไว้จะถือว่าถูกระบุไว้ในคำสั่ง MEMORY คำสั่งเดียว ไวยากรณ์สำหรับ MEMORY คือ:

หน่วยความจำ

{ ชื่อ [(attr)]: ORIGIN = ต้นทาง, LENGTH = len … }

ตัวอย่างในบทความ:

/* กำหนดจุดสิ้นสุดของ RAM และขีดจำกัดของหน่วยความจำสแต็ก *//* (4KB SRAM บนบรรทัด STM32F031x6, 4096 = 0x1000) */ /* (RAM เริ่มต้นที่ที่อยู่ 0x20000000) _estack = 0x20001000;

หน่วยความจำ

{ แฟลช (rx): ORIGIN = 0x08000000, LENGTH = 32K RAM (rxw): ORIGIN = 0x20000000, LENGTH = 4K }

ดังนั้นเราจึงต้องหาจำนวน FLASH (สำหรับโปรแกรมและค่าคงที่ของเรา ฯลฯ) และจำนวน RAM (สำหรับใช้งานโดยโปรแกรม; ฮีปและสแต็ก ฯลฯ) สำหรับบอร์ดของเราโดยเฉพาะ สิ่งนี้น่าสนใจเล็กน้อย

การ์ดเล็ก ๆ ที่ดีที่มาพร้อมกับ Nucleo บอกว่ามีหน่วยความจำแฟลช 512 Kbytes และ SRAM คือ 80 Kbytes อย่างไรก็ตาม เมื่อเชื่อมต่อกับ USB จะได้รับการติดตั้งเป็นระบบไฟล์ที่มีสองไฟล์ และทั้งตัวจัดการไฟล์และ GParted ระบุว่ามีพื้นที่มากกว่า 540+ Kbytes (แกะ?).

แต่การพยายามลบทั้งสองไฟล์โดยใช้ตัวจัดการไฟล์ ยกเลิกการเชื่อมต่อแล้วเชื่อมต่ออุปกรณ์ใหม่ ยังคงแสดงไฟล์ทั้งสอง (และตัวจัดการไฟล์จำบางอย่างได้เพราะมีไอคอน "ล็อก" เล็กๆ ในแต่ละไฟล์

ไปดูตัวเลขบนการ์ดกันเลยดีกว่า ตอนนี้เรานำตัวอย่างข้างต้นและแปลงเป็นบอร์ดเฉพาะของเรา

คุณอาจต้องการใช้บางอย่างเช่นตัวแปลงหน่วยความจำออนไลน์นี้ เพื่อเปลี่ยนจาก KB ทั่วไปเป็นจำนวนไบต์ที่ระบุ

จากนั้นคุณอาจต้องการใช้ตัวแปลงทศนิยมออนไลน์เป็นฐานสิบหก

/* กำหนดจุดสิ้นสุดของ RAM และขีด จำกัด ของหน่วยความจำสแต็ก */

/* (4KB SRAM บนบรรทัด STM32F031x6, 4096 = 0x1000) *//* ตัวอย่าง*/

/* ขั้นตอนที่ 1: (80KB SRAM บน STM32F303RE, 81920 = 0x14000) *//* บอร์ดของเรา */

/* ขั้นตอนที่ 2 เพิ่มขนาดฐานสิบหกให้กับที่อยู่เริ่มต้นฐานสิบหก (ด้านล่าง) */

/* (RAM เริ่มต้นที่ที่อยู่ 0x20000000) */

_estack = 0x20001000; /* ตัวอย่าง */

_estack = 0x20014000; /* กระดานของเรา */

หน่วยความจำ {

แฟลช (rx): ORIGIN = 0x08000000, LENGTH = 512K

RAM (rxw): ORIGIN = 0x20000000, LENGTH = 80K

}

ให้เรียกไฟล์ด้านบนว่า "linker.script.ld"

ขั้นตอนที่ 6: ตารางเวกเตอร์

ตารางเวกเตอร์
ตารางเวกเตอร์

ตอนนี้เรากำลังจะสร้างไฟล์แอสเซมบลีขนาดเล็ก (พร้อมคำสั่ง) เพื่อทำการจัดการขัดจังหวะขั้นพื้นฐาน เราจะทำตามตัวอย่างของบทความและสร้างไฟล์ชื่อ "core. S"

อีกครั้ง นี่คือตัวอย่างเนื้อหาไฟล์ แต่ฉันได้ทำการเปลี่ยนแปลงสำหรับบอร์ดเฉพาะของเรา:

// คำแนะนำเหล่านี้กำหนดคุณสมบัติของชิปของเราและ

// ภาษาแอสเซมบลีที่เราจะใช้:.syntax unified /* ดูด้านล่างหลังจากพื้นที่โค้ดนี้ */ /*.cpu cortex-m0 */ /*แสดงความคิดเห็นในบรรทัดนี้ของตัวอย่าง */.cpu cortex-m4 /* เพิ่มแทนเปลือกนอกของกระดานของเรา ดูภาพด้านบนในขั้นตอนนี้ */ /*.fpu softvfp */ /* แสดงความคิดเห็นบรรทัดนี้ของตัวอย่าง */.fpu vfpv4 /* เพิ่มแทนบอร์ดของเรา; มันมี FPU */.thumb // ตำแหน่งหน่วยความจำส่วนกลาง.global vtable.global reset_handler /* * ตารางเวกเตอร์จริง * รวมเฉพาะขนาดของ RAM และตัวจัดการ 'รีเซ็ต' เพื่อความเรียบง่าย */.type vtable, %object vtable:.word _estack.word reset_handler.size vtable,.-vtable

อืม.. ไม่มีคำสั่ง '.align'

อย่างไรก็ตาม นั่นไม่สำคัญ เพิ่มเติมเกี่ยวกับที่ (อาจจะ) ในภายหลัง

.syntax unified

.syntax [รวม | แยก]

คำสั่งนี้ตั้งค่าไวยากรณ์ชุดคำสั่งตามที่อธิบายไว้ในส่วน ARM-Instruction-Set

9.4.2.1 Instruction Set Syntax สองรูปแบบที่แตกต่างกันเล็กน้อยรองรับคำสั่ง ARM และ THUMB ค่าดีฟอลต์ ถูกแบ่ง ใช้รูปแบบเก่าที่คำสั่ง ARM และ THUMB มีไวยากรณ์แยกจากกัน ไวยากรณ์ใหม่ที่เป็นหนึ่งเดียว ซึ่งสามารถเลือกได้ผ่านคำสั่ง.syntax

.fpu vfpv4

คอมไพเลอร์ GCC สามารถสร้างไบนารีที่มีตัวเลือกมากมายเกี่ยวกับจุดลอยตัว: นุ่ม - เหมาะสำหรับการรันบน CPU ที่ไม่มี FPU - การคำนวณจะทำในซอฟต์แวร์โดยคอมไพเลอร์ที่สร้าง softfp - เหมาะสำหรับการรันบน CPU ที่มีหรือไม่มี FPU - จะใช้ FPU หากมี. สำหรับกรณีเฉพาะของเรา (คุณจะต้องทำการวิจัยของคุณเอง) FPU ของบอร์ดนี้สอดคล้องกับ vfpv4 คุณอาจต้องเล่นกับสิ่งนี้ หรือแม้แต่ปล่อยไว้ที่ softfp

.thumb (เทียบกับ.arm)

ไมโครคอนโทรลเลอร์ ARM เหล่านี้มีชุดคำสั่งผสมกัน หนึ่งคือ ARM อีกอันคือ THUMB ข้อแตกต่างประการหนึ่งคือคำสั่งแบบ 16 บิตและคำสั่งแบบ 32 บิต ดังนั้น คำสั่งนี้บอกให้คอมไพเลอร์ปฏิบัติต่อคำสั่งที่ตามมาเป็น THUMB หรือ ARM

เราจะใช้ส่วนที่เหลือของไฟล์ตามที่เป็นอยู่เนื่องจาก Instructables เหล่านี้ยังไม่ได้เจาะลึกในการเขียนโปรแกรมแอสเซมบลีที่ขับเคลื่อนด้วยอินเตอร์รัปต์

ขั้นตอนที่ 7: เวอร์ชันแอสเซมบลีของโปรแกรม 'Hello World'

ข้อมูลต่อไปนี้ยังสามารถเข้าไปในไฟล์ "core. S" ที่สร้างไว้ก่อนหน้านี้ นี่เป็นอีกครั้งจากตัวอย่างในบทความ

/* * ตัวจัดการการรีเซ็ต เรียกว่ารีเซ็ต */.type reset_handler, %function reset_handler: // ตั้งค่าตัวชี้สแต็กไว้ที่จุดสิ้นสุดของสแต็ก // ค่า '_estack' ถูกกำหนดไว้ในสคริปต์ตัวเชื่อมโยงของเรา LDR r0, =_estack MOV sp, r0

// ตั้งค่าจำลองบางอย่าง เมื่อเราเห็นค่าเหล่านี้

// ในโปรแกรมดีบั๊ก เราจะรู้ว่าโปรแกรมของเรา // โหลดอยู่บนชิปแล้วและทำงานได้ LDR r7, =0xDEADBEEF MOVS r0, #0 main_loop: // เพิ่ม 1 เพื่อลงทะเบียน 'r0' เพิ่ม r0, r0, #1 // วนกลับ B main_loop.size reset_handler,.-reset_handler

ดังนั้น แรงผลักดันของโปรแกรมข้างต้นคือการโหลดรูปแบบที่รู้จักลงในการลงทะเบียน MCU หลักหนึ่งรายการ (ในกรณีนี้คือ R7) และค่าที่เพิ่มขึ้นเริ่มต้นที่ศูนย์ในการลงทะเบียน MCU หลักอีกรายการหนึ่ง (ในกรณีนี้คือ R0) หากเราดำเนินการตามโค้ดที่รันอยู่ เราควรจะเห็นข้อมูลของ R0 เพิ่มขึ้น

หากคุณได้ปฏิบัติตามคำแนะนำเกี่ยวกับ MSP432 และหลักสูตร/แล็บ TI-RSLK แล้ว โปรแกรมข้างต้นทั้งหมดน่าจะคุ้นเคยกับคุณเป็นอย่างดี

สิ่งเดียวที่ฉันเห็นคือการใช้ "=" เมื่อโหลด "DEADBEEF" เพื่อลงทะเบียน R7 เราไม่ได้ใช้มัน

ไฟล์ "core. S" ที่แนบมาที่นี่มีแหล่งที่มาที่สมบูรณ์

ขั้นตอนที่ 8: รวบรวมรหัส

ได้เวลาทำสิ่งที่บรรทัดคำสั่งบางอย่าง บางสิ่งบางอย่างจริงในที่สุด

อย่างไรก็ตาม เราไม่ได้อยู่ที่นั่น เราต้องปรับแต่งคำสั่งในบทความอีกครั้ง และแก้ไขให้เข้ากับสถานการณ์ของเราเอง

นี่คือตัวอย่างโค้ด:

arm-none-eabi-gcc -x assembler-with-cpp -c -O0 -mcpu=cortex-m0 -mthumb -Wall core. S -o core.o

ถ้าเราไปที่ไซต์ gnu.org สำหรับ GCC (ในกรณีนี้คือเวอร์ชัน 7.3)

NS

-x คือการระบุภาษา มิฉะนั้นหากไม่มี -x คอมไพเลอร์จะพยายามเดาโดยใช้นามสกุลไฟล์ (ในกรณีของเรา *. S)

ตัวอย่างข้างต้นจากบทความระบุ assembler-with-cpp แต่เราสามารถทำแอสเซมเบลอร์ได้

-c บอกว่า คอมไพล์แต่อย่าลิงก์

O0

-O คือการกำหนดระดับการเพิ่มประสิทธิภาพ การใช้ -O0 (oh-zero) ระบุว่า "ลดเวลาในการคอมไพล์และทำให้การดีบักสร้างผลลัพธ์ที่คาดหวัง นี่คือค่าเริ่มต้น"

mcpu=cortex-m0

-mcpu ระบุชื่อของตัวประมวลผลเป้าหมาย ในกรณีของเรา มันจะเป็น cortex-m4

mthumb

-mthumb ระบุการเลือกระหว่างการสร้างรหัสที่รันสถานะ ARM และ THUMB

กำแพง

-Wall เป็นเรื่องธรรมดาและเป็นที่รู้จักกันดี มันเปิดแฟล็กการเตือนทั้งหมด

สุดท้าย ที่ส่วนท้ายของคำสั่ง เรามีไฟล์อินพุต core. S และไฟล์เอาต์พุต core.o

นี่คือผลลัพธ์บรรทัดคำสั่งใหม่เพื่อให้พอดีกับกรณีของเรา

arm-none-eabi-gcc -x assembler -c -O0 -mcpu=cortex-m4 -mthumb -Wall core. S -o core.o

และที่รวบรวมมานั้น

ขั้นตอนที่ 9: การเชื่อมโยงโปรแกรม

จากตัวอย่างในบทความโดยตรง เรามีสิ่งนี้:

arm-none-eabi-gcc core.o -mcpu=cortex-m0 -mthumb -Wall --specs=nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

ส่วนใหญ่ข้างต้นที่คุณเคยเห็น ด้านล่างนี้คือสิ่งใหม่

-specs=nosys.specs

อันนี้ค่อนข้างยากที่จะอธิบาย

มันเกี่ยวข้องกับ "semihosting" และ "retargeting" และเกี่ยวข้องกับอินพุต / เอาต์พุต นอกจากนี้ยังเกี่ยวข้องกับการเรียกระบบและไลบรารี

โดยปกติ ระบบฝังตัวจะไม่มีอุปกรณ์อินพุต/เอาท์พุตมาตรฐาน สิ่งนี้จะส่งผลต่อการเรียกของระบบหรือไลบรารี (ตัวอย่าง: printf())

Semihosting หมายถึงดีบักเกอร์ (ดูภาพขั้นตอนที่ 11 ที่มีส่วนดีบักเกอร์ในวงกลมสีแดง) มีช่องพิเศษและใช้โปรโตคอล semihosting และคุณสามารถเห็นผลลัพธ์ของ printf() บนเครื่องโฮสต์ (ผ่านตัวดีบั๊ก)

ในทางกลับกัน การกำหนดเป้าหมายใหม่หมายถึงการเรียกระบบหรือการเรียกไลบรารีเดียวกันนั้นมีความหมายอย่างอื่น พวกเขาทำอย่างอื่นที่เหมาะสมกับระบบฝังตัว ในแง่หนึ่ง สมมติว่าสำหรับ printf() มีการใช้งานใหม่ การนำไปใช้งานแบบกำหนดเป้าหมายใหม่ของฟังก์ชันนั้น

เมื่อกล่าวทั้งหมดนั้น --specs=nosys.specs หมายความว่าเราจะไม่กึ่งโฮสต์ ซึ่งปกติแล้วจะหมายความว่าเรากำลังกำหนดเป้าหมายใหม่ นั่นนำเราไปสู่ธงต่อไป

nostdlib

อ็อพชันตัวเชื่อมโยง -nostdlib ใช้เพื่อลิงก์โปรแกรมที่มุ่งหมายให้รันแบบสแตนด์อโลน -nostdlib หมายถึงตัวเลือกแต่ละตัว -nodefaultlibs และ -nostartfiles ด้านล่างเราจะพูดถึงสองตัวเลือกแยกกัน แต่การใช้งานทั่วไปส่วนใหญ่เป็นเพียง nostdlib สำหรับการช็อปปิ้งแบบครบวงจร เมื่อเชื่อมโยงโปรแกรมที่โฮสต์ ไลบรารีระบบมาตรฐาน เช่น libc จะถูกเชื่อมโยงโดยค่าเริ่มต้น ทำให้โปรแกรมสามารถเข้าถึงฟังก์ชันมาตรฐานทั้งหมด (printf, สตรองและผองเพื่อน) ตัวเลือกตัวเชื่อมโยง -nodefaultlibs ปิดใช้งานการลิงก์กับไลบรารีเริ่มต้นเหล่านั้น ไลบรารีเดียวที่ลิงก์คือไลบรารีที่คุณตั้งชื่อให้กับตัวเชื่อมโยงอย่างชัดเจนโดยใช้แฟล็ก -l

lgcc

libgcc.a เป็นไลบรารีมาตรฐานที่จัดเตรียมรูทีนย่อยภายในเพื่อเอาชนะข้อบกพร่องของเครื่องบางเครื่อง ตัวอย่างเช่น โปรเซสเซอร์ ARM ไม่มีคำสั่งการแบ่ง libgcc.a เวอร์ชัน ARM มีฟังก์ชันการแบ่งและคอมไพเลอร์ส่งการเรียกไปยังฟังก์ชันนั้นเมื่อจำเป็น

NS

นี่เป็นเพียงวิธีบอกให้ผู้เชื่อมโยงใช้ไฟล์นี้เป็นสคริปต์ตัวเชื่อมโยง ในกรณีของเรา ชื่อไฟล์คือ linker.script.ld

o main.elf

สุดท้าย เราบอก linker ว่าอะไรคือชื่อของไฟล์รูปภาพที่ส่งออกสุดท้ายที่จะถูกเบิร์น/แฟลชลงในอุปกรณ์ของเรา

นี่คือเวอร์ชันของบรรทัดคำสั่งที่สมบูรณ์ ซึ่งแก้ไขสำหรับสถานการณ์เฉพาะของเรา:

arm-none-eabi-gcc core.o -mcpu=cortex-m4 -mthumb -Wall --specs=nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

เราตรวจสอบให้แน่ใจว่าไฟล์สคริปต์และไฟล์ core.o อยู่ในไดเร็กทอรีเดียวกัน ซึ่งเราจะเรียกใช้บรรทัดคำสั่งด้านบน

และเชื่อมโยงได้โดยไม่มีปัญหา

เช็ค

จากนั้นเราเรียกใช้:

arm-none-eabi-nm main.elf

และเราได้รับ:

devchu@chubox:~/Development/Atollic/TrueSTUDIO/STM32_workspace_9.1$ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

ดูดี. คำสั่ง arm-none-eabi-nm เป็นวิธีแสดงรายการสัญลักษณ์ภายในไฟล์อ็อบเจ็กต์

ขั้นตอนที่ 10: การทดสอบการเชื่อมต่อกับ STM32 Nucleo-64

การทดสอบการเชื่อมต่อกับ STM32 Nucleo-64
การทดสอบการเชื่อมต่อกับ STM32 Nucleo-64
การทดสอบการเชื่อมต่อกับ STM32 Nucleo-64
การทดสอบการเชื่อมต่อกับ STM32 Nucleo-64

ภารกิจแรกของคุณ หากคุณเลือกที่จะยอมรับคือให้ระบบของคุณเห็นบอร์ดพัฒนาของคุณ

การใช้ Windows

สำหรับ Windows ฉันตัดสินใจติดตั้ง TrueSTUDIO จาก Atolic (เวอร์ชันฟรี) เป็นการติดตั้งที่ไม่เจ็บปวดและติดตั้งไดรเวอร์โดยอัตโนมัติ ดังนั้นฉันจึงสามารถใช้ st-link เพื่อทดสอบการเชื่อมต่อได้ เมื่อฉันติดตั้ง TrueSTUDIO และตัวจัดการอุปกรณ์เห็นอุปกรณ์แล้ว ฉันก็ดาวน์โหลดเครื่องมือ texan/stlink ที่แนะนำโดยบทความ Bare Metal ที่เราติดตาม ฉันวางโฟลเดอร์ไว้ใต้ "C:\" อีกครั้งโดยตรง และสร้างลิงก์จาก cygwin home bin ในเครื่องของฉันไปยังคำสั่งอีกครั้ง

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~/bin/st-info

ในการทดสอบเบื้องต้นเพื่อดูว่าเราสามารถสื่อสารกับอุปกรณ์ได้จริงหรือไม่ ฉันจึงดำเนินการดังนี้

st-info --probe

และกลับมา:

พบโปรแกรมเมอร์ stlink 1 คน

ตอนนี้เรารู้แล้วว่าสามารถพูดคุย/สอบถามบอร์ดพัฒนาของเราได้

การใช้ลินุกซ์

สำหรับ linux คุณไม่จำเป็นต้องมีไดรเวอร์จริงๆ แต่สำหรับ Debian คุณจะต้องสร้างเครื่องมือ st จากแหล่งที่มา

โคลน git

ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง libusb-1.0-0-dev

รายการ apt | grep -E "*libusb.*dev*"

คุณควรเห็น:

libusb-1.0-0-dev/xenial ตอนนี้ 2:1.0.20-1 amd64 [ติดตั้งแล้ว]

หรืออะไรทำนองนั้น

ในการติดตั้ง:

sudo apt-get ติดตั้ง libusb-1.0-0-dev

โปรดทราบว่าข้างต้นไม่เหมือนกับ:

sudo apt-get ติดตั้ง libusb-dev

libusb dev ที่หายไปที่ถูกต้องอาจทำให้ cmake มีปัญหาได้

ข้อผิดพลาด CMake: มีการใช้ตัวแปรต่อไปนี้ในโครงการนี้ แต่ถูกตั้งค่าเป็น NOTFOUND โปรดตั้งค่าหรือตรวจสอบให้แน่ใจว่ามีการตั้งค่าและทดสอบอย่างถูกต้องในไฟล์ CMake: LIBUSB_INCLUDE_DIR (ขั้นสูง)

เปลี่ยนเป็นไดเร็กทอรีรากของโปรเจ็กต์ (…blah/blah /stlink) ทำการ "ปล่อยตัว"

หลังจากสร้างแล้ว เครื่องมือควรอยู่ภายใต้ ".. /build/Release"

จากนั้นคุณสามารถเรียกใช้ "st-info --probe" นี่คือผลลัพธ์ที่เชื่อมต่อกับ Nucleo ไม่ใช่

devchu@chubox:~/Development/stlink$./build/Release/st-info --probeFound 1 stlink โปรแกรมเมอร์แบบอนุกรม: 3036364146463530343935363537 openocd: "\x30\x36\x36\x41\x46\x46\x35\x30\x34\ x39\x35\x35\x36\x35\x37" flash: 524288 (pagesize: 2048) sram: 65536 chipid: 0x0446 descr: F303 อุปกรณ์ความหนาแน่นสูง devchu@chubox:~/Development/stlink$./build/Release/st- ข้อมูล --probe พบ 0 stlink โปรแกรมเมอร์ devchu@chubox:~/Development/stlink$

ขั้นตอนที่ 11: มาใช้ GDB กับ Linux. กันเถอะ

มาใช้ GDB กับ Linux กันเถอะ
มาใช้ GDB กับ Linux กันเถอะ
มาใช้ GDB กับ Linux กันเถอะ
มาใช้ GDB กับ Linux กันเถอะ

หากคุณได้ลองมาทั้งหมดนี้แล้ว และมาไกลถึงขนาดนี้แล้ว เยี่ยมไปเลย! ยอดเยี่ยม. มาสนุกกันตอนนี้เลย

เมื่อคุณซื้อบอร์ดพัฒนา ARM เหล่านี้ ไม่ว่าจะเป็น MSP432 Launchpad จาก Texas Instruments หรืออันนี้ที่เรากำลังพูดถึงอยู่ Nucleo-F303 (STM32 Nucleo-64) มักจะมาพร้อมกับโปรแกรมที่กำลังทำงานอยู่ โปรแกรมกะพริบบางโปรแกรมรวมถึงการกดสวิตช์เพื่อเปลี่ยนอัตราการกะพริบของ LED

ก่อนที่เราจะรีบเขียนทับนั้น เรามาดูกันก่อนว่ามีอะไรให้ดูและทำบ้าง

ด้วย Linux ให้เปิดเทอร์มินัล เปลี่ยนไดเร็กทอรีโครงการ stlink git ที่เราเพิ่งสร้างขึ้น และค้นหาเครื่องมือ st-util

devchu@chubox:~/Development/stlink$ find. -name st-util

./build/Release/src/gdbserver/st-util

เรียกใช้เครื่องมือนั้น เนื่องจากเราได้ทดสอบการเชื่อมต่อของเรากับ st-info --probe แล้ว เราควรจะได้ผลลัพธ์ดังนี้:

st-util 1.4.0-50-g7fafee2 2018-10-20T18:33:23 INFO common.c: กำลังโหลดพารามิเตอร์อุปกรณ์…. 2018-10-20T18:33:23 INFO common.c: อุปกรณ์เชื่อมต่อคือ: F303 อุปกรณ์ความหนาแน่นสูง, id 0x10036446 2018-10-20T18:33:23 INFO common.c: ขนาด SRAM: 0x10000 ไบต์ (64 KiB), แฟลช: 0x80000 ไบต์ (512 KiB) ในหน้า 2048 ไบต์ 2018-10-20T18:33:23 INFO gdb-server.c: Chip ID คือ 00000446 Core ID คือ 2ba01477 2018-10-20T18:33:23 INFO gdb-server.c: กำลังฟังที่ *:4242…

นั่นคือเซิร์ฟเวอร์ GDB ที่ทำงานอยู่ในขณะนี้ และเห็นบอร์ดพัฒนาของเรา และที่สำคัญกว่านั้นคือ กำลังฟังบนพอร์ต 4242 (พอร์ตเริ่มต้น)

ตอนนี้เราพร้อมที่จะเริ่มต้นไคลเอ็นต์ GDB แล้ว

ใน Linux ให้เปิดเทอร์มินัลอื่น ป้อนสิ่งนี้:

arm-none-eabi-gdb -tui

นั่นก็เหมือนกับการรันบรรทัดคำสั่ง gdb อย่างเคร่งครัด แต่มันสร้างเทอร์มินัลแบบข้อความแทน (ฉันเดาว่ามันใช้คำสาป)

เรามีไคลเอ็นต์ GDB และเซิร์ฟเวอร์ GDB ทำงานอยู่ อย่างไรก็ตาม ไคลเอ็นต์ไม่ได้เชื่อมต่อกับเซิร์ฟเวอร์ ในขณะนี้ ยังไม่ทราบอะไรเกี่ยวกับนิวคลีโอของเรา (หรือบอร์ดที่คุณเลือก) เราต้องบอกต่อ ในเทอร์มินัล ข้อความแจ้งของคุณควรเป็น "(gdb)" เข้า:

ช่วยเป้าหมาย

มันจะให้รายการแก่คุณ ขอให้สังเกตว่าสิ่งที่เราต้องการคือเป้าหมายแบบขยายระยะไกล - ใช้คอมพิวเตอร์ระยะไกลผ่านสายซีเรียล

แต่เรายังต้องให้สถานที่ ดังนั้นที่พรอมต์ (gdb) ให้ป้อน:

(gdb) กำหนดเป้าหมาย localhost ระยะไกลแบบขยาย: 4242

คุณควรได้รับการตอบกลับเช่น:

(gdb) กำหนดเป้าหมาย localhost ระยะไกลแบบขยาย: 4242

การดีบักระยะไกลโดยใช้ localhost:4242 0x080028e4 ใน ?? ()

ในขณะเดียวกันที่เทอร์มินัลที่รัน st-util gdbserver เราได้สิ่งนี้:

2018-10-20T18:42:30 INFO gdb-server.c: พบการลงทะเบียนเบรกพอยต์ 6 hw

2018-10-20T18:42:30 INFO gdb-server.c: เชื่อมต่อ GDB แล้ว

ขั้นตอนที่ 12: มาทำซ้ำกับ Windows และ Flash โปรแกรมของเรา

มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา
มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา
มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา
มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา
มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา
มาย้ำกันด้วย Windows และ Flash โปรแกรมของเรา

ขั้นตอนในการรัน st-util gdbserver และไคลเอ็นต์ arm-none-eabi-gdb จะเหมือนกับที่เราทำในขั้นตอนก่อนหน้า คุณเปิดเทอร์มินัลสองเทอร์มินัล (cygwin, DOS cmd หรือ Windows Powershell) ค้นหาตำแหน่งของ st-util เรียกใช้ ในเทอร์มินัลอื่น ให้รันไคลเอ็นต์ arm-none-eabi-gdb ข้อแตกต่างเพียงอย่างเดียวคือโหมด -tui (มุมมองข้อความแบบเทอร์มินัล) มักไม่ได้รับการสนับสนุน

หากวิธีข้างต้นใช้งานได้ใน Windows คุณอาจต้องหยุดทำงาน (เฉพาะไคลเอ็นต์) ณ จุดนี้ คุณจะต้องเรียกใช้ไคลเอ็นต์ GDB โดยที่ไฟล์บิลด์ของคุณคือ ("core.out") หรือเพิ่มพาธทั้งหมดไปยังไฟล์นั้นเป็นอาร์กิวเมนต์ของไคลเอ็นต์ GDB

ฉันทำให้ชีวิตของฉันง่ายขึ้นโดยใช้ cygwin และสร้างลิงก์จากไดเร็กทอรี $HOME//bin ในเครื่องของฉันไปยังที่ที่เครื่องมือทั้งสองนั้นอยู่

ตกลง เราได้รวบรวมและเชื่อมโยงเหมือนเมื่อก่อน และเรามีไฟล์ main.elf พร้อมที่จะแฟลช

เรามี st-util ทำงานในหน้าต่างเดียว เราเริ่มต้นไคลเอ็นต์ GDB ใหม่อีกครั้ง คราวนี้เราทำ:

arm-none-eabi-gdb main.elf

เราปล่อยให้มันเริ่มทำงาน รอพร้อมต์ (gdb) ทำคำสั่งเชื่อมต่อเดียวกันกับเซิร์ฟเวอร์ GDB (st-util) และเราพร้อมที่จะแฟลชไฟล์เรียกทำงาน มันต่อต้านสภาพอากาศมาก:

(gdb) โหลด

การทำงานกับเทอร์มินัล cygwin มีปัญหาที่ทราบแล้วบางครั้งคำสั่งคอนโซลไม่แสดงผล ดังนั้น ในกรณีของเรา หน้าต่างที่เรียกใช้เซิร์ฟเวอร์จึงเงียบสนิท ตัวที่รันไคลเอนต์ที่เรารันโหลด ให้ส่งออกสิ่งนี้:

กำลังโหลดส่วน.text ขนาด 0x1c lma 0x8000000 ที่อยู่เริ่มต้น 0x8000000 ขนาดโหลด 28 อัตราการถ่ายโอน: 1 KB/วินาที 28 ไบต์/เขียน

ขั้นตอนที่ 13: กระพริบด้วย Linux - ให้รางวัลมากกว่า:D

กระพริบด้วย Linux - ให้รางวัลมากกว่า:D
กระพริบด้วย Linux - ให้รางวัลมากกว่า:D

ขั้นตอนที่ 14: มาดำน้ำกันสักหน่อย

ถ้าได้มานี่สุดยอด ไปต่อกันเลย

ทำไมไม่ดูภายในไฟล์ main.elf ไฟล์เรียกทำงานล่ะ? เรียกใช้สิ่งต่อไปนี้:

arm-none-eabi-objdump -d main.elf

คุณควรเห็นผลลัพธ์ดังนี้:

main.elf: รูปแบบไฟล์ elf32-littlearm

การถอดชิ้นส่วน.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [พีซี, #8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, #8]; (8000018) 800000e: 2000 movs r0, #0

08000010:

8000010: 3001 เพิ่ม r0, #1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

เราจะได้อะไรเล็ก ๆ น้อย ๆ จากผลลัพธ์ข้างต้น?

หากคุณจำได้เมื่อเราพูดถึงและสร้างไฟล์ linker.script.ld เราระบุว่าอุปกรณ์ ARM เหล่านี้มี RAM เริ่มต้นที่ 0x20000000 และหน่วยความจำ FLASH นั้นเริ่มต้นที่ 0x08000000

ดังนั้น เราจะเห็นได้ว่าโปรแกรมนั้นอยู่ในหน่วยความจำ FLASH ทั้งหมด

จากนั้น ด้านบน แต่เป็นขั้นตอนต่อมา เมื่อเราเลิกใช้ส่วน "Hello World" มีคำสั่งที่เราโหลดค่าตามตัวอักษร ("0xDEADBEEF") ในทันที ลงใน MCU core register ("R7")

คำสั่งคือ:

LDR R7, =0xDEADBEEF

ในโค้ดของเรา เป็นที่เดียวที่เราพูดถึง DEADBEEF ไม่มีที่ไหนอีกแล้ว และหากคุณดูคำแนะนำในการถอดประกอบ/สร้างใหม่ด้านบน ฯลฯ มีอะไรที่เกี่ยวข้องกับ DEADBEEF มากกว่าที่เราคิดไว้

ดังนั้น คอมไพเลอร์/ตัวเชื่อมโยงจึงตัดสินใจแฟลชค่าของ DEADBEEF เป็นที่อยู่ FLASH อย่างถาวร ณ ตำแหน่ง 0x8000018 จากนั้นคอมไพเลอร์เปลี่ยนคำสั่ง LDR ด้านบนของเราเป็น:

LDR R7, [พีซี, #8]

มันยังสร้างความคิดเห็นสำหรับเรา ดีแค่ไหน. และมันบอกให้เรานำค่าตัวนับของโปรแกรมปัจจุบัน (การลงทะเบียน PC) เพิ่ม 0x8 ให้กับค่านั้น และนั่นคือที่ที่ DEADBEEF ถูกเผา และรับค่านั้นและใส่ลงใน R7

นั่นหมายความว่าโปรแกรมนับ (PC) ชี้ไปที่ที่อยู่ 0x8000010 ซึ่งเป็นจุดเริ่มต้นของ main_loop และค่า DEADBEEF จะอยู่ที่สองที่อยู่หลังจากสิ้นสุด main_loop

ขั้นตอนที่ 15: สุดท้าย ดูสั้น ๆ ที่โปรแกรมกำลังทำงาน

แม้ว่าคุณจะออกจาก GDB เพียงป้อนคำสั่งอีกครั้ง คุณไม่จำเป็นต้องให้ไฟล์ใดๆ เราไม่ได้กระพริบอีกต่อไปเพียงแค่เรียกใช้

เมื่อคุณเชื่อมต่อไคลเอ็นต์ GDB กับเซิร์ฟเวอร์ GDB อีกครั้งแล้ว ที่พรอมต์คำสั่ง (gdb):

(gdb) การลงทะเบียนข้อมูล

คุณควรเห็นสิ่งนี้:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x8002 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x200196 0ffr cffr fffr

แต่จากนั้นที่พรอมต์ (gdb) ให้ป้อน:

(gdb) ทำต่อ

และกด CTRL-C อย่างรวดเร็ว ที่ควรหยุดโปรแกรมชั่วคราว ป้อนคำสั่ง "info registers" อีกครั้ง

คราวนี้มันดูแตกต่างออกไป:

(gdb) การลงทะเบียนข้อมูล

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 0 ffr01 0x096 0000000 16777216

เกิดอะไรขึ้น? ตรงตามที่เราต้องการ DEADBEEF ถูกโหลดลงใน R7 และ R0 ได้เพิ่มขึ้น (เร็วมาก) หากคุณทำซ้ำ คุณจะเห็น R0 อีกครั้งพร้อมค่าอื่น

ขั้นตอนที่ 16: เราต้องการสร้างอาร์เรย์แบบอ่านอย่างเดียวใน Flash

วิธีหนึ่งในการสร้างสิ่งที่เทียบเท่ากับอาร์เรย์โดยใช้แอสเซมบลีและคำสั่งมีดังนี้:

.type myarray, %object // ชื่อหรือป้ายกำกับ 'myarray' ถูกกำหนดเป็นประเภทวัตถุ

myarray: // นี่คือจุดเริ่มต้นของการประกาศ 'myarray' // (สิ่งที่จะประกอบด้วย).word 0x11111111 // สมาชิกหรือค่าแรกใน 'myarray'.word 0x222222222 //ค่าที่สอง (ที่อยู่ติดกัน).word 0x3333333 //และอื่นๆ.size myarray,.-myarray // คอมไพเลอร์/แอสเซมเบลอร์รู้แล้วว่าจุดสิ้นสุดหรือ // ขอบเขตของ 'myarray' อยู่ที่ไหน

ตอนนี้เราได้ตั้งค่าไว้ในหน่วยความจำ FLASH แล้ว เราก็สามารถใช้มันในโปรแกรมได้ ด้านล่างเป็นส่วน:

LDR R1, myarray // โหลดข้อมูลที่อยู่ในตำแหน่งที่ 1 ของ 'myarray' // นี่ไม่ใช่สิ่งที่เราต้องการ

LDR R1, =myarray // นี่โหลดค่าตำแหน่งเอง (ที่อยู่ที่ 1)

// ไม่ใช่ข้อมูล.. // นี่คือสิ่งที่เราต้องการ

MOV R2, #0 // R2 จะนับต่อไปเพื่อให้แน่ใจว่าเราจะไม่เดินจากไป

// สิ้นสุดอาร์เรย์ LDR R3, =myarrsize // R3 จะเท่ากับ 'myarrsize'

// R0 จะเก็บข้อมูลของเรา

main_loop:

LDR R0, [R1] // โหลดข้อมูลที่ R1 ชี้ไป ('myarray') ลงใน R0 CMP R2, R3 // เราถึงขีดจำกัดอาร์เรย์แล้วหรือยัง? BEQ main_loop // ถ้าใช่ เสร็จแล้ว เราจะวนซ้ำตลอดไป

ADD R2, #1 // มิฉะนั้น เราสามารถวนซ้ำผ่านอาร์เรย์ได้

ADD R1, #4 // เพิ่ม 4 เพื่อรีจิสเตอร์ R1 ดังนั้นจึงชี้ไปที่ next. ได้อย่างถูกต้อง

// ที่อยู่..

B main_loop // วนกลับ

วิดีโอดำเนินการทั้งหมดนี้ และมีข้อบกพร่องอยู่ในนั้น ดี; มันแสดงให้เห็นว่าเป็นรหัสการรันและดีบักที่สำคัญ มันแสดงให้เห็นกรณีคลาสสิกของการเดินออกจากส่วนท้ายของอาร์เรย์

แนะนำ: