STM32F2: Makefile สคริปต์ตัวเชื่อมโยงและการรวมไฟล์เริ่มต้นโดยไม่มี IDE เชิงพาณิชย์


16

ฉันทำงานกับ STM32F2 (โดยเฉพาะคือ STM32F217IGH6 ในคณะกรรมการพัฒนา) เป็นเวลาประมาณสองเดือน ปัญหาที่ใหญ่ที่สุดของฉันเกี่ยวกับ "การตั้งค่า" ซึ่งรวมถึง makefile, linker script และไฟล์เริ่มต้น

โดยเฉพาะอย่างยิ่งฉันไม่สามารถตั้งค่าตารางเวกเตอร์ขัดจังหวะและเรียกตัวจัดการขัดจังหวะได้อย่างถูกต้อง ST ให้ตัวอย่างที่ปรับให้เหมาะกับ IDE เชิงพาณิชย์ แต่ฉันใช้การรวบรวมใหม่ Yagarto ของ toolchain GCC (และ OpenOCD เพื่อโหลดภาพผ่าน JTAG)

มีตัวอย่างโครงการสำหรับบอร์ดของฉัน (หรือลูกพี่ลูกน้องที่ใกล้ชิด) ซึ่งมี makefile, linker script และการรวมไฟล์เริ่มต้นสำหรับ IDE ที่ไม่ใช่เชิงพาณิชย์ที่ถูกตั้งค่าสำหรับตัวจัดการอินเตอร์รัปต์


2
คุณควรมองหาตัวอย่างของ Cortex M3 บอร์ดและโปรเซสเซอร์ที่แน่นอนนั้นไม่สำคัญสำหรับสิ่งที่คุณถาม คุณอาจต้องแก้ไขเลย์เอาต์ของหน่วยความจำในสคริปต์ตัวเชื่อมโยงและวิธีการกะพริบใน makefile แต่นั่นควรจะเป็นทั้งหมด
starblue

1
คุณสามารถใส่ทั้งหมดนี้ใน repo คอมไพล์และวางไว้บน GitHub หรืออะไร?
AngryEE

1
นี่คือเหตุผลที่ฉันหยุดใช้ STM ทันทีที่ฉันลอง หากพวกเขากำลังจะทำให้ชีวิตของฉันยากขึ้นด้วยห่วงโซ่เครื่องมือที่น่ารังเกียจฉันจะไปที่อื่น เมื่อฉันลอง IDE สำหรับ PSoC3 และ PSoC5 มันเป็นโลกที่แตกต่าง
Rocketmagnet

คุณมุ่งมั่นที่จะ Yagarto? ที่สมบูรณ์ดีและทำให้คำถามที่ดี แต่ฉันคุ้นเคยกับCodeSourcery Lite toolchain คำตอบสำหรับ toolchain ที่แตกต่างกันอาจถูกนำไปปรับใช้ แต่จะไม่สามารถทำได้นอกกรอบ
Kevin Vermeer

คำตอบ:


20

http://github.com/dwelch67

โดยเฉพาะอย่างยิ่ง stm32f4 และ stm32vld แต่คนอื่น ๆ อาจเป็นประโยชน์กับคุณเช่นกัน mbed และไดเร็กทอรี mzero ภายใต้ mbed (cortex-m0)

ฉันชอบวิธีการที่เรียบง่ายแบบเรียบง่ายสคริปต์ตัวเชื่อมโยงขั้นต่ำรหัสเริ่มต้นขั้นต่ำ ฯลฯ การทำงานนั้นทำโดยรหัสไม่ใช่ toolchain ใด ๆ

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

ฉันสร้าง gcc, binutils และ llvm / clang ของตัวเองรวมทั้งใช้ codesourcery เช่นกัน (ตอนนี้เป็น mentor graphics แต่คุณยังสามารถรับเวอร์ชั่นฟรี / lite ได้)

Esp เมื่อเริ่มต้นรวบรวมโครงการสำหรับเป้าหมายใหม่ที่คุณต้องทำการถอดแยกชิ้นส่วน โดยเฉพาะอย่างยิ่งเพื่อให้แน่ใจว่ารายการอยู่ในตำแหน่งที่คุณต้องการตัวอย่างเช่นตารางเวกเตอร์

ดูตัวอย่าง stm32f4d / blinker02 มันเริ่มต้นด้วย vectors.s ตารางข้อยกเว้น / เวกเตอร์บวกรูทีนการสนับสนุน asm:

/* vectors.s */
.cpu cortex-m3
.thumb

.word   0x20002000  /* stack top address */
.word   _start      /* 1 Reset */
.word   hang        /* 2 NMI */
.word   hang        /* 3 HardFault */
.word   hang        /* 4 MemManage */
.word   hang        /* 5 BusFault */
.word   hang        /* 6 UsageFault */
.word   hang        /* 7 RESERVED */
.word   hang        /* 8 RESERVED */
.word   hang        /* 9 RESERVED*/
.word   hang        /* 10 RESERVED */
.word   hang        /* 11 SVCall */
.word   hang        /* 12 Debug Monitor */
.word   hang        /* 13 RESERVED */
.word   hang        /* 14 PendSV */
.word   hang        /* 15 SysTick */
.word   hang        /* 16 External Interrupt(0) */
.word   hang        /* 17 External Interrupt(1) */
.word   hang        /* 18 External Interrupt(2) */
.word   hang        /* 19 ...   */

.thumb_func
.global _start
_start:
    /*ldr r0,stacktop */
    /*mov sp,r0*/
    bl notmain
    b hang

.thumb_func
hang:   b .

/*.align
stacktop: .word 0x20001000*/

;@-----------------------
.thumb_func
.globl PUT16
PUT16:
    strh r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET16
GET16:
    ldrh r0,[r0]
    bx lr

.end

ไม่มีการขัดจังหวะในตัวอย่างนี้ แต่สิ่งอื่น ๆ ที่คุณต้องการอยู่ที่นี่

blinker02.c มีเนื้อหาหลักของรหัส C ที่มีจุดเข้าใช้งาน C ที่ฉันเรียกว่า notmain () เพื่อหลีกเลี่ยงการเรียกมันว่า main (คอมไพเลอร์บางตัวเพิ่มขยะในไบนารีของคุณเมื่อคุณมี main ())

จะให้คุณตัดและวาง makefile บอกเล่าเรื่องราวเกี่ยวกับการรวบรวมและการเชื่อมโยง โปรดทราบว่าตัวอย่างจำนวนหนึ่งของฉันรวบรวมไบนารีสองตัวหรือมากกว่าจากรหัสเดียวกัน คอมไพเลอร์ gcc, คอมไพเลอร์เสียงดังกราวของ llvm, thumb only และ thumb2, การปรับให้เหมาะสมต่าง ๆ , เป็นต้น

เริ่มต้นด้วยการสร้างไฟล์วัตถุจากไฟล์ต้นฉบับ

vectors.o : vectors.s
    $(ARMGNU)-as vectors.s -o vectors.o

blinker02.gcc.thumb.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker02.c -o blinker02.gcc.thumb.o

blinker02.gcc.thumb2.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker02.c -o blinker02.gcc.thumb2.o

blinker02.gcc.thumb.bin : memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb.elf -T memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb.elf > blinker02.gcc.thumb.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb.elf blinker02.gcc.thumb.bin -O binary

blinker02.gcc.thumb2.bin : memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb2.elf -T memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb2.elf > blinker02.gcc.thumb2.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb2.elf blinker02.gcc.thumb2.bin -O binary

linker, ld, ใช้ linker script ซึ่งผมเรียกว่า memmap ซึ่งอาจเจ็บปวดอย่างมากบางครั้งก็มีเหตุผลที่ดี ฉันชอบวิธีที่น้อยกว่าคือมีขนาดที่เหมาะกับทุกคนมากขึ้นทุกอย่างยกเว้นวิธีเข้าครัว

ฉันไม่ใช้. data โดยทั่วไป (แทบไม่เคย) และตัวอย่างนี้ไม่จำเป็นต้องมี. bbs ดังนั้นนี่คือสคริปต์ linker ซึ่งเพียงพอที่จะวางโปรแกรม (.text) ที่มันต้องการโปรเซสเซอร์สำหรับพวกเขาในแบบที่ฉันเป็น ใช้มัน

MEMORY
{
    ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

ฉันมีพื้นที่หน่วยความจำเพื่อกำหนดว่าไม่มีอะไรพิเศษเกี่ยวกับชื่อ ram ที่คุณสามารถเรียกได้ว่า foo หรือ bar หรือ bob หรือ ted ไม่สำคัญว่ามันจะเชื่อมโยงรายการหน่วยความจำไปยังส่วนต่างๆ ส่วนกำหนดสิ่งต่าง ๆ เช่น. text, .data, .bss, .rodata และตำแหน่งที่จะไปในแผนผังหน่วยความจำ

เมื่อคุณสร้างสิ่งนี้คุณจะเห็นว่าฉันแยกชิ้นส่วนทุกอย่าง (objdump -D) ที่คุณเห็นนี้

Disassembly of section .text:

08000000 <_start-0x50>:
 8000000:       20002000        andcs   r2, r0, r0
 8000004:       08000051        stmdaeq r0, {r0, r4, r6}
 8000008:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 800000c:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 8000010:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}

สิ่งสำคัญที่ควรทราบคือที่อยู่ทางด้านซ้ายคือที่ที่เราต้องการรหัส vectors.s เป็นอันดับแรกในไบนารี (เพราะมันเป็นครั้งแรกในบรรทัดคำสั่ง ld เว้นแต่ว่าคุณจะทำบางสิ่งในสคริปต์ linker รายการจะแสดง ขึ้นในไบนารีตามลำดับพวกเขาอยู่ในบรรทัดคำสั่ง ld) สำหรับการบู๊ตอย่างถูกต้องคุณต้องมั่นใจว่าตารางเวคเตอร์ของคุณอยู่ในตำแหน่งที่ถูกต้อง รายการแรกคือที่อยู่สแต็กของฉันซึ่งใช้ได้ รายการที่สองคือที่อยู่ของ _start และควรเป็นเลขคี่ การใช้. thumb_func ก่อนที่ป้ายกำกับจะทำให้สิ่งนี้เกิดขึ้นดังนั้นคุณไม่จำเป็นต้องทำสิ่งที่ดูน่าเกลียด

08000050 <_start>:
 8000050:       f000 f822       bl      8000098 <notmain>
 8000054:       e7ff            b.n     8000056 <hang>

08000056 <hang>:
 8000056:       e7fe          

ดังนั้น 0x08000051 และ 0x08000057 เป็นรายการเวกเตอร์ที่เหมาะสมสำหรับ _start และ hang เริ่มการโทรไม่ได้หลัก ()

08000098 <notmain>:
 8000098:       b510            push    {

ที่ดูดี (พวกเขาไม่แสดงที่อยู่เลขคี่ในการถอดแยกชิ้นส่วน)

ทั้งหมดเป็นอย่างดี.

ข้ามไปที่ตัวอย่าง blinker05 อันนี้รองรับอินเตอร์รัปต์ และต้องการ ram บางตัวดังนั้น. BSS จึงถูกกำหนด

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x100000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .bss  : { *(.bss*) } > ram
}

จำ ram และ rom เป็นชื่อโดยพลการ, bob และ ted, foo และ bar ทำงานได้ดี

จะไม่แสดงเวกเตอร์ทั้งหมดเนื่องจาก cortex-m3 มีรายการ zillion ในตารางเวกเตอร์ถ้าคุณสร้างครบหนึ่งรายการ (แตกต่างกันไปจากแกนหนึ่งถึงแกนกลางและอาจอยู่ในแกนเดียวกันขึ้นอยู่กับตัวเลือกที่ผู้จำหน่ายชิปเลือก) ส่วนที่เกี่ยวข้องอยู่ที่นี่หลังจากถอดแยกชิ้นส่วน:

08000000 <_start-0x148>:
 8000000:       20020000        andcs   r0, r2, r0
 8000004:       08000149        stmdaeq r0, {r0, r3, r6, r8}
 8000008:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
...
8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

ใช้เวลาทดลองและข้อผิดพลาดในการวางตัวจัดการที่ตรงจุดตรวจสอบกับชิปของคุณที่มันไม่จำเป็นต้องอยู่ในสถานที่เดียวกันกับที่นี้และด้วยการขัดจังหวะจำนวนมากคุณอาจมองหาขัดจังหวะที่แตกต่างกันอยู่แล้ว ตัวประมวลผล cortex-m ซึ่งแตกต่างจากแขนปกติทำให้คุณไม่จำเป็นต้องใช้รหัสแทรมโพลีนสำหรับการขัดจังหวะพวกเขาสงวนจำนวนทะเบียนไว้และจัดการการสลับโหมดตัวประมวลผลผ่านลิงก์ลงทะเบียนเนื้อหา ตราบใดที่ฮาร์ดแวร์และ abi สำหรับคอมไพเลอร์อยู่ใกล้พอที่จะทำงานได้ทั้งหมด ในกรณีนี้ฉันจัดการใน C ซึ่งแตกต่างจากแพลตฟอร์มอื่น ๆ และที่ผ่านมาคุณไม่จำเป็นต้องทำอะไรเป็นพิเศษกับคอมไพเลอร์ / ไวยากรณ์เพียงแค่ทำให้ฟังก์ชั่น (แต่อย่าทำสิ่งที่โง่ในฟังก์ชั่น / จัดการ)

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//-------------------------------------------------------------------

makefile สำหรับ blinker05 ควรคล้ายกับตัวอย่างของ blinker02 ซึ่งส่วนใหญ่จะถูกตัดและวางสำหรับส่วนใหญ่ เปลี่ยนไฟล์ต้นฉบับให้เป็นวัตถุแล้วเชื่อมโยง ฉันสร้างสำหรับ thumb, thumb2 โดยใช้ gcc และ clang คุณสามารถเปลี่ยนบรรทัด: ในเวลาที่จะรวมรายการ gcc เท่านั้นหากคุณไม่ต้องการ / ต้องการ clang (llvm) ที่เกี่ยวข้อง ฉันใช้ binutils เพื่อประกอบและเชื่อมโยงเอาท์พุทเสียงดังกราว btw

โครงการทั้งหมดเหล่านี้ใช้ฟรีปิดชั้นวางโอเพนซอร์ซเครื่องมือ ไม่มีของ IDE บรรทัดคำสั่งเท่านั้น ใช่ฉันแค่ยุ่งกับ Linux และไม่ใช่ Windows แต่เครื่องมือเหล่านี้พร้อมใช้งานสำหรับผู้ใช้ windows เช่นกันเปลี่ยนสิ่งต่าง ๆ เช่น rm -f เพื่อลบบางสิ่งบางอย่างใน makefile สิ่งต่าง ๆ เช่นเมื่อสร้างบน windows หรือเรียกใช้ linux บน vmware หรือ virtualbox หรือ qemu การไม่ใช้ IDE หมายความว่าคุณเลือกโปรแกรมแก้ไขข้อความของคุณเช่นกันฉันจะไม่เป็นเช่นนั้นฉันมีสิ่งที่ฉันชอบ โปรดทราบว่าคุณลักษณะที่น่ารำคาญอย่างยิ่งของโปรแกรมสร้าง gnu คือต้องใช้แท็บจริงใน makefile ฉันเกลียดแท็บที่มองไม่เห็นด้วยความหลงใหล ดังนั้นหนึ่งแก้ไขข้อความสำหรับ makefiles ที่ออกจากแท็บอื่น ๆ สำหรับซอร์สโค้ดที่ทำให้ช่องว่าง ฉันไม่รู้เกี่ยวกับ windows

ฉันหวังว่านี่จะช่วยได้ไม่ใช่ชิพ / บอร์ดที่แน่นอน แต่ cortex-m4 ก็ดี m4 ไม่ใช่ m3 ใกล้พอสำหรับการอภิปรายนี้ ดู mbed หรือ stm32vld dir สำหรับ cortex-m3 ที่เกิดขึ้นจริง (ความแตกต่างไม่เพียงพอจาก m4 สำหรับ makefiles และ boot code ฯลฯ ) แต่ไม่ได้ทำโดย st คอร์เท็กซ์ -m3 คอร์เท็กซ์ควรจะเหมือนกันในผู้ขายคอร์เทกซ์ -m3 และคอร์เท็กซ์ -m4 นั้นมีทั้ง ARMv7m และอยู่ใกล้กว่าต่างกัน cortex-m0 นั้นเป็น ARMv6m แทบจะไม่ได้มีคำสั่ง thumb2 เพียงพอที่จะรบกวนคอมไพเลอร์ยังไม่ทันกับมันดังนั้นเพียงแค่ใช้นิ้วโป้งเท่านั้น เครื่องจำลองนิ้วหัวแม่มือของฉันคือนิ้วหัวแม่มือเท่านั้นไม่มี thumb2 มันอาจเป็นประโยชน์กับคุณเช่นกันฉันคิดว่าฉันทำให้มันขัดจังหวะในบางรูปแบบหรือแฟชั่น


ฉันอ่านคำตอบและฉันเดาว่าผู้เขียนสำหรับคำตอบนี้จะเป็นคุณ คำตอบของคุณได้ช่วยฉันมากและกระตุ้นให้ฉันย้ายไปที่หน่วยประมวลผล ARM กว่าเป็น AVR และ PIC Fanboy ขอบคุณ
MaNyYaCk

คุณจะยินดี ... จ่ายไปข้างหน้า ...
old_timer

2

คุณสามารถดูที่เว็บไซต์นี้ซึ่งพยายามอธิบายพื้นฐานของตัวเชื่อมโยงและ low_level_init ในรหัส

โปรดทราบว่าหน้านี้มุ่งเน้นไปที่การอธิบายปัญหาดังนั้นเวกเตอร์ nvic จึงมีขนาดเล็กที่สุด

จากนั้นคุณมีตัวอย่างที่สมบูรณ์มากขึ้นใน "ไลบรารีอุปกรณ์ต่อพ่วงมาตรฐาน STM32F2xx" เพียงแค่ดูในส่วน gcc (เนื่องจาก Yagarto เป็นแบบ gcc) และมีรหัสตัวอย่างในนั้นที่จะช่วยคุณในการตั้งค่าที่ถูกต้องของ nvic (ตารางเวกเตอร์ขัดจังหวะ)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.