STM32 Bagian 1: Dasar-Dasar

Anda tidak dapat mempercayai kode yang tidak Anda tulis sendiri sepenuhnya. - Ken Thompson
Mungkin kutipan favorit saya. Dialah yang menjadi alasan mengapa saya memutuskan untuk menyelam ke dasar lubang kelinci. Saya memulai perjalanan saya ke dunia pemrograman baru-baru ini, hanya sekitar satu bulan berlalu dan saya memutuskan untuk menulis artikel untuk mengkonsolidasikan materi. Semuanya dimulai dengan tugas sederhana, untuk menyinkronkan lampu di studio foto Anda menggunakan Arduina. Masalahnya sudah dipecahkan, tetapi saya tidak pergi ke studio foto lagi, tidak ada waktu. Sejak saat itu, saya memutuskan untuk benar-benar terlibat dalam pemrograman mikrokontroler. Arduin, meskipun menarik dalam kesederhanaannya, saya tidak suka platformnya. Pilihan jatuh pada perusahaan ST dan produk populer mereka. Pada saat itu, saya masih tidak tahu apa bedanya, tetapi sebagai konsumen biasa saya membandingkan kecepatan "prosesor" dan jumlah memori, saya membeli sendiri papan yang mengesankan dengan tampilan STM32F746NG - Discovery.Saya akan merindukan saat-saat keputusasaan dan langsung ke titik.

Tenggelam dalam citra seorang programmer, saya banyak membaca, belajar, bereksperimen. Dan seperti yang sudah saya jelaskan di atas, saya ingin belajar dengan baik, itu saja. Dan untuk ini saya menetapkan tujuan, bukan solusi yang sudah jadi, hanya milik saya. Dan jika semuanya berhasil untuk saya maka Anda akan berhasil.

Daftar semua yang Anda butuhkan:

  1. Ubuntu 16+ mesin virtual atau apa pun
  2. arm compiler - unduh di developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads
  3. debugger dan programmer openocd - Anda tidak akan bisa mengunduh dari tautan, kami kumpulkan dari sumbernya, instruksi terlampir

    git clone https://git.code.sf.net/p/openocd/code openocd
  4. Editor teks sesuai dengan keinginan Anda

Setelah semuanya diinstal dan dirakit, kita dapat melanjutkan ke proyek pertama! Dan tidak, itu bahkan bukan bola lampu yang berkedip. Untuk memulainya, kita harus mempelajari proses inisialisasi microwell itu sendiri.

Apa yang kita butuhkan:

  1. Makefile
  2. Linker.ld
  3. Init.c

Mari kita mulai dengan paragraf terakhir, Init.c. Pertama-tama, mk kami harus memuat alamat "stack pointer" adalah pointer ke alamat memori yang digunakan untuk instruksi PUSH dan POP. Saya sangat menyarankan Anda mempelajari kedua instruksi ini dengan seksama, karena saya tidak akan menjelaskan secara rinci semua instruksi. Bagaimana cara mengimplementasikannya, lihat di bawah.

extern void *_estack;
void *vectors[] __attribute__((section(".isr_vector"), used)) = {
    &_estack
}

Sekarang mari kita lihat contoh ini. Extern berarti simbol tersebut eksternal, dan kami menyatakan simbol ini dalam file Linker.ld, kami akan kembali sedikit nanti.

 __attribute__((section(".isr_vector"), used))

Di sini kita menggunakan atribut yang memberitahu kompiler untuk menempatkan array di bagian isr_vector dan bahkan jika kita tidak menggunakannya dalam kode, itu masih harus dimasukkan dalam program. Dan elemen pertamanya adalah pointer yang sama.

Sekarang mari kita cari tahu mengapa array ini dan apa yang akan dimakan. Tidak seperti prosesor konvensional, mik pada arsitektur arm memulai eksekusi ketika bukan dari alamat nol, tetapi dari alamat yang ditunjuk oleh pointer dalam array ini, semuanya rumit. Juga, pointer pertama dalam array ini selalu menunjuk ke awal stack, tetapi yang kedua sudah menunjuk ke awal kode kita.

Saya akan memberi contoh. diberikan bahwa tumpukan dimulai dengan 0x20010000 dan kode programnya adalah 0x0800008. maka array dapat ditulis sebagai

void *vectors[] __attribute__((section(".isr_vector"), used)) = {
    0x20010000,
    0x08000008
}

Artinya, controller pertama menginisialisasi stack, dan kemudian mempertimbangkan alamat instruksi pertama dan memuatnya ke register program register. Sekarang yang paling penting, tergantung pada modelnya, angka-angka ini mungkin berbeda, tetapi dengan contoh stm32f7 saya dapat dengan yakin mengatakan bahwa array ini harus ada dalam memori di alamat 0x08000000. Dari alamat ini mk akan mulai bekerja setelah dihidupkan atau diatur ulang.

Sekarang kita akan berhenti dan memperhatikan cara menempatkan array ini di bagian yang kita butuhkan. Ini dilakukan oleh "ld" atau tautan. Program ini mengumpulkan seluruh program kami bersama-sama dan skrip Linker.ld digunakan untuk ini. Saya memberi contoh dan menganalisisnya lebih lanjut.

MEMORY{
	ROM_AXIM (rx) : ORIGIN = 0x08000000, LENGTH = 1M
	RAM_DTCM (rwx): ORIGIN = 0x20000000, LENGTH = 64K
}

_estack = LENGTH(RAM_DTCM) + ORIGIN(RAM_DTCM);

SECTIONS{
	.isr_vector : {
	KEEP(*(.isr_vector))
	} >ROM_AXIM</code>
}

Mari kita lihat apa yang terjadi di sini. MEMORY mendefinisikan bagian memori dan BAGIAN mendefinisikan bagian. di sini kita melihat _estack kita dan fakta bahwa itu sama dengan jumlah dari awal ingatan dan panjangnya, yaitu, akhir ingatan kita. Bagian .isr_vector di mana kita meletakkan array kita juga ditentukan. >ROM_AXIMpada akhir bagian kami berarti bahwa bagian ini harus ditempatkan di bagian memori yang dimulai dengan 0x08000000 seperti yang dipersyaratkan oleh mikron kami.

Kami meletakkan array di tempat yang diperlukan sekarang kami membutuhkan beberapa jenis instruksi agar mikron kami berfungsi. Inilah init.c yang ditambahkan:

extern void *_estack;

void Reset_Handler();

void *vectors[] __attribute__((section(".isr_vector"), used)) = {
    &_estack,
    &Reset_Handler
};

void __attribute__((naked, noreturn)) Reset_Handler()
{
    while(1);
}

Seperti yang saya sebutkan sebelumnya, alamat kedua harus menjadi penunjuk ke fungsi atau instruksi pertama. Dan sekali lagi, atributnya, tetapi semuanya sederhana, fungsinya tidak mengembalikan nilai apa pun dan mengikuti ABI di pintu masuk, yaitu telanjang "telanjang". Dalam fungsi seperti itu, assembler yang biasa didorong.

Sekarang saatnya mengkompilasi kode kita, dan melihat apa yang ada di balik tudung. Kami tidak akan menyentuh Makefile untuk saat ini.

arm-none-eabi-gcc -c init.c -o init.o -mthumb

arm-none-eabi-gcc -TLinker.ld -o prog.elf init.o -Wl,--gc-sections -nostartfiles -nodefaultlibs -nostdlib

Dan di sini kita melihat banyak hal yang tidak dapat dipahami. dalam urutan:

  1. kompilasi -mthumb untuk armv7, yang hanya menggunakan instruksi ibu jari
  2. -TLinker.ld tentukan skrip tautan. secara default, ini dikompilasi untuk dieksekusi di lingkungan Linux
  3. -Wl, - gc-section -nostartfiles -nodefaultlibs -nostdlib menghapus semua pustaka standar, file inisialisasi C lingkungan, dan semua pustaka tambahan lainnya seperti matematika.

Tentu saja, tidak ada gunanya memuat ini ke dalam mikron. Tetapi ada perasaan dalam melihat dan mempelajari biner.

objcopy -O ihex prog.elf prog.bin

hexdump prog.bin

Dan kemudian kita akan melihat kesimpulannya. "00000000: 00 01 00 02 09 00 00 08" yang akan melambangkan kesuksesan kami. Ini adalah artikel pertama saya dan saya tidak dapat sepenuhnya mengungkapkan semua bahan dan esensi, jadi di berikutnya saya akan menjelaskan mekanisme lebih detail dan kami teman-teman akan dapat pergi ke program yang tidak akan berkedip cahaya, tetapi mengkonfigurasi jam prosesor dan bus.

All Articles