STM32 Bagian 3: Proyek Pertama

Kami mengamati masyarakat yang semakin bergantung pada mesin, tetapi pada saat yang sama menggunakannya dengan lebih tidak efisien. - Douglas Rushkoff


Frasa ini harus berfungsi sebagai motivasi bagi setiap programmer. Lagi pula, Andalah yang memutuskan bagaimana mesin menggunakan sumber dayanya. Tetapi sejak awal waktu, seseorang mempercayakan haknya untuk memutuskan kepada pihak ketiga dengan imbalan cara mudah. Sebelum bertanya kepada saya tentang manfaat artikel saya ketika ada "Kubus", tanyakan pada diri sendiri mengapa "kubus" memutuskan untuk saya.

STM32 Bagian 1: Dasar-Dasar
STM32 Bagian 2: Inisialisasi

Jadi, mari kita lanjutkan petualangan kita. Kami telah menulis skrip inisialisasi, menemukan penghubung dan kompiler. Saatnya berkedip LED. Pada artikel ini, kita akan membahas dasar-dasar blok RCC dan GPIO, dan menambahkan beberapa header, yang akan kita gunakan dalam proyek-proyek masa depan. Pergilah.

RCC - Reset dan Clock Control, blok register yang mengontrol jam prosesor dan periferal. Beberapa sumber jam dikontrol oleh unit ini: HSI (kecepatan tinggi internal), HSE (kecepatan tinggi eksternal), PLL / PLLSAI / PLLI2S (kunci loop bertahap). Ketiga sumber jam ini dapat digunakan oleh prosesor, tentu saja, jika register blok RCC dikonfigurasikan dengan benar. Kami akan membicarakan hal ini secara rinci di artikel selanjutnya.

GPIO - Input dan Output Tujuan Umum. Blok register yang dibuat untuk memasang LED, yaitu blok untuk mengontrol kaki mikron kita, portal ke dunia nyata. Berbeda dengan Atmega328p (Arduino) yang akrab, stm32 menawarkan kustomisasi kaki yang lebih luas. Misalnya, fungsi kaki Drain Terbuka tidak tersedia di mega. Juga, kontrol kecepatan dengan uk menaikkan tegangan pada kaki dapat dikonfigurasi.

Jadi mari kita berkedip, ya. Pertama kita perlu dua header di mana kita menggambarkan struktur register ini. Oleh karena itu, kami mendapatkan manual rujukan dan mempelajarinya untuk mencari informasi yang kami butuhkan. Saya bekerja pada STM32F746NG - Discovery jadi semua kode untuk board ini.

Hal pertama yang kita butuhkan adalah alamat dari blok-blok ini, dasar. Mari kita mulai dengan blok RCC dan membuat header rcc.h. Di dalamnya kita akan membuat RCC_BASE makro, dan juga menggambarkan struktur blok register, dan membuat pointer ke struktur.

rcc.h

#define RCC_BASE   0x40023800

typedef struct
{
  volatile unsigned int CR;           
  volatile unsigned int PLLCFGR;      
  volatile unsigned int CFGR;         
  volatile unsigned int CIR;          
  volatile unsigned int AHB1RSTR;     
  volatile unsigned int AHB2RSTR;     
  volatile unsigned int AHB3RSTR;     
  unsigned int          RESERVED0;    
  volatile unsigned int APB1RSTR;     
  volatile unsigned int APB2RSTR;     
  unsigned int          RESERVED1[2]; 
  volatile unsigned int AHB1ENR;      
  volatile unsigned int AHB2ENR;      
  volatile unsigned int AHB3ENR;      
  unsigned int          RESERVED2;    
  volatile unsigned int APB1ENR;      
  volatile unsigned int APB2ENR;      
  unsigned int          RESERVED3[2]; 
  volatile unsigned int AHB1LPENR;    
  volatile unsigned int AHB2LPENR;    
  volatile unsigned int AHB3LPENR;    
  unsigned int          RESERVED4;    
  volatile unsigned int APB1LPENR;    
  volatile unsigned int APB2LPENR;    
  unsigned int          RESERVED5[2]; 
  volatile unsigned int BDCR;         
  volatile unsigned int CSR;          
  unsigned int          RESERVED6[2]; 
  volatile unsigned int SSCGR;        
  volatile unsigned int PLLI2SCFGR;   
  volatile unsigned int PLLSAICFGR;   
  volatile unsigned int DCKCFGR1;     
  volatile unsigned int DCKCFGR2;     

} RCC_Struct;

#define RCC ((RCC_Struct *) RCC_BASE)


Mari kita lakukan operasi yang sama dengan blok register GPIO, hanya tanpa pointer dan tambahkan makro, GPIO_OFFSET. bicarakan di bawah ini.

gpio.h

#define GPIO_BASE   0x40020000
#define GPIO_OFFSET 0x400

typedef struct
{
   volatile unsigned int MODER;   
   volatile unsigned int OTYPER;  
   volatile unsigned int OSPEEDR; 
   volatile unsigned int PUPDR;   
   volatile unsigned int IDR;     
   volatile unsigned int ODR;     
   volatile unsigned int BSRR;    
   volatile unsigned int LCKR;    
   volatile unsigned int AFR[2];  

} GPIO_Struct;


Mari kita lihat apa yang terjadi di sini dan mengapa kita membutuhkan struktur. Faktanya adalah bahwa kita dapat mengakses register melalui pointer ke struktur, kita tidak perlu menginisialisasi karena secara fisik sudah ada. Sebagai contoh:

RCC->AHB1ENR = 0; 


Ini menghemat ruang memori, dan terkadang tidak memerlukannya sama sekali. Tapi bukan tentang menabung hari ini.

Jadi kami memiliki dua tajuk yang siap, masih harus belajar cara melompat dengan bantuan register ini dan membuat int main();. Semuanya sederhana dan tidak sepenuhnya. Di STM32, untuk mengakses blok register, pertama-tama kita harus menerapkan jam padanya, jika tidak data akan mencapainya. Saya tidak akan masuk jauh ke dalam struktur ban, tetapi hanya mengatakan apa adanya. Blok ditempatkan pada ban yang berbeda. Unit kami terletak di bus AHB1. Yaitu, kita perlu mengaktifkan port tertentu pada bus AHB1, dalam kasus saya ini adalah port I. Sebagai permulaan, tentu saja kita memerlukan fungsi utama.

Mari kita perbarui sedikit file startup kita dan tambahkan int main (); dan kemudian buat file main.c itu sendiri

extern void *_estack;

void Reset_Handler();
void Default_Handler();

//   
int  main();

void NMI_Handler()                    __attribute__ ((weak, alias ("Default_Handler")));
void HardFault_Handler()              __attribute__ ((weak, alias ("Default_Handler")));

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

extern void *_sidata, *_sdata, *_edata, *_sbss, *_ebss;



void __attribute__((naked, noreturn)) Reset_Handler()
{


	void **pSource, **pDest;
	for (pSource = &_sidata, pDest = &_sdata; pDest != &_edata; pSource++, pDest++)
		*pDest = *pSource;

	for (pDest = &_sbss; pDest != &_ebss; pDest++)
		*pDest = 0;

    //   
    main();

	while(1);
}

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


Dan sekarang kita membuat file main.c. sendiri Dalam file tersebut, saya mencoba untuk melukis segala sesuatu di komentar ke kode, jadi kami membaca dan menyelami itu. Jika Anda memiliki pertanyaan, tulis komentar di bawah ini yang akan saya jawab.

#include "rcc.h"
#include "gpio.h"


int main()
{
    //  GPIO I ,   8 ( )
    RCC->AHB1ENR |= (1<<8);

    //     
    //          
    //      
    volatile GPIO_Struct *GPIOI = (GPIO_Struct *)(GPIO_BASE + (GPIO_OFFSET*8));  

    //     ""
    GPIOI->MODER |= (1<<2);

    //   ,   , push-pull,   .
    //   push pull
    GPIOI->OTYPER &= ~(1<<1);

    //      ,       
    GPIOI->OSPEEDR |= (2<<2);

    //   
    while(1){
        for(volatile int i = 0; i < 1000000; i++){
            // 
        }

        // ,   1   0  .
        GPIOI->ODR ^= (1<<1);
    }

    return 0;
}


Sekarang kita harus mengumpulkan proyek dan melemparkannya ke mikron, demi verifikasi. Saya memasang repositori di Github yang perlu dilakukan hanyalah menjalankan utilitas Make.
make


Terima kasih atas perhatian Anda, di artikel selanjutnya kami akan berbicara lebih banyak tentang unit RCC dan bagaimana cara mengatasinya.

All Articles