Kami menulis program kami yang paling sederhana untuk ARM Cortex-M3

gambar Selamat siang Hari ini saya ingin memberi tahu Anda cara menulis program minimal yang berjalan pada ARM Cortex-M3 dan mencetak "Halo, Dunia!". Kami akan mencoba membuat langkah-langkah minimum yang diperlukan yang kami butuhkan untuk ini. Kami akan berjalan pada emulator QEMU. Karena itu, siapa pun dapat bereproduksi, walaupun ia tidak memiliki sepotong besi.

Jadi ayo pergi!

Emulator QEMU mendukung inti Cortex-M3 dan mengemulasi platform Stellaris LM3S811 dari Texas Instruments berdasarkan itu. Kami akan berjalan di platform ini. Kami membutuhkan arm-none-eabi- toolchain (Anda dapat mengunduhnya di sini ). Selanjutnya, kita perlu menulis logika utama program kita, kode awal, yang akan mentransfer kontrol ke program, dan skrip linker.

Pada habr sudah artikel yang cukup bagus tentang cara mengedipkan dioda pada sepotong besi dari awal. Oleh karena itu, di sini saya tidak akan menyelidiki apa dan bagaimana cara kerjanya, tetapi saya hanya akan memberikan set minimum pengetahuan yang diperlukan untuk memulai.

Halo world kami di file test.c:

static volatile unsigned int * const UART_DR = (unsigned int *)0x4000c000; static void uart_print(const char *s) { while (*s != '\0') { *UART_DR = *s; s++; } } void c_entry(void) { uart_print("Hello, World!\n"); while (1) ; } 

Alamat 0x4000c000 ini diambil dari dokumentasi, di situlah DR register nol nol. Kami tidak akan terlibat dalam pengaturan UART (ini perlu dilakukan pada perangkat keras), tetapi kami akan mencoba untuk segera menempatkan simbol di dalamnya secara langsung.

Sekarang, kita perlu mentransfer kontrol ke fungsi kita with_entry di file test.c. Untuk melakukan ini, buat kode berikut (file startup.S), dan kemudian taruh di gambar ELF akhir di awal.

 .type start, %function .word stack_top /*     */ .word start /*    PC */ .global start start: ldr r1, =c_entry bx r1 

Kata pertama pada 0x0 harus menjadi penunjuk ke atas tumpukan (SP). Pada 0x4 ada PC, yang, seperti SP, dimuat ke register. Perhatikan bahwa mulai dinyatakan tepat sebagai fungsi, dan bukan sebagai label karena kode Cortex-M dieksekusi dalam mode Thumb (ini adalah seperangkat perintah ARM yang disederhanakan), dan diperlukan bahwa alamat fungsi dalam vektor interupsi berada dalam bentuk (alamat | 0x1) - yaitu bit terakhir dari alamat tersebut harus 1.

Selanjutnya, fungsi mulai hanya memuat alamat fungsi c_entry () kami dari file test.c dan melewati kontrol melalui "bx r1" di sana.

Tinggal menyambungkan program kami dengan sukses. Untuk melakukan ini, Anda perlu mengatur kartu memori mikrokontroler kami. Dalam dokumentasi Anda dapat menemukan alamat dan ukuran memori flash (ROM) dan RAM (RAM). Berikut ini skrip linker test.ld:

 SECTIONS { . = 0x0; /*   (ROM) */ .text : { startup.o(.text) test.o(.text) } . = 0x20000000; /*     RAM */ .data : { *(.data) } .bss : { *(.bss) } . = ALIGN(8); . = . + 0x1000; /*    4 */ stack_top = .; } 

Penting untuk memperhatikan alamat. "." di skrip tautan menunjukkan posisi saat ini. Kami menempatkan bagian .text di awal ROM (alamat 0x0), mengikuti urutan - startup.o (.text) yang lebih dulu. Selanjutnya, buka RAM (. = 0x20000000;) dan letakkan data di sana (data global yang diinisialisasi) dan bss (data global yang tidak diinisialisasi). Di bawah ini kita melihat ALIGN (8) - ARM membutuhkan penyelarasan SP (Stack Pointer) oleh 8. Karena tumpukan turun, alokasi ruang di bawah tumpukan hanyalah tambahan. " =. + 0x1000 ”. Kami tahu program kami dengan baik, jadi tumpukan 4kB sudah cukup dengan margin besar.

Itu saja, masih harus disatukan. Saya membawa build.sh:

 #!/bin/sh arm-none-eabi-as -c -mthumb -mlittle-endian -march=armv7-m -mcpu=cortex-m3 startup.S -o startup.o arm-none-eabi-gcc -c -mthumb -ffreestanding -mlittle-endian -march=armv7-m -mcpu=cortex-m3 test.c -o test.o arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf 

Segala sesuatu di sini harus lebih atau kurang dipahami, dengan pengecualian dari bendera-berdiri. Dalam hal ini, Anda tidak perlu menambahkannya (Anda dapat memeriksanya), tetapi karena kami sedang menyiapkan gambar baremetal dari awal, lebih baik memberi tahu kompiler sehingga tidak memperhatikan fungsi seperti main ().

Akibatnya, kami mendapat file ELF test.elf. Jalankan di QEMU:

 $ qemu-system-arm -M lm3s811evb -kernel test.elf -nographic Hello, World! 

Itu bekerja.

Tentu saja, ini adalah studi kasus yang dirancang untuk memahami apa yang terjadi. Jika Anda membutuhkan fungsionalitas yang lebih bermakna, Anda harus menggunakan hal-hal yang sudah jadi. Kami telah menambahkan dukungan untuk platform ini di Embox . Template ini disebut platform / stellaris / lm3s811evb. Karena itu, jika seseorang ingin mencoba menjalankan hal yang sedikit lebih serius (konsol, timer, interupsi), maka Anda dapat mengumpulkan dan mencoba. Dalam hal ini, saya ulangi, Anda tidak perlu memiliki papan perangkat keras.

Dan mereka yang masih belum memiliki cukup emulator, atau yang ingin mengajukan pertanyaan kepada kami dan bermain dengan potongan - potongan besi, kami akan menunggu hari Sabtu dan Minggu ini di festival IT techtrain.ru di St. Petersburg. Kami akan memiliki berbagai potongan besi di dudukan, dan di zona demo kami akan mencoba memberi tahu cara memprogramnya.

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


All Articles