STM32 الجزء الثالث: المشروع الأول

نلاحظ مجتمعًا يعتمد بشكل متزايد على الآلات ، ولكن في نفس الوقت يستخدمها بشكل أكثر فاعلية. - دوجلاس روشكوف


يجب أن تكون هذه العبارة بمثابة حافز لكل مبرمج. بعد كل شيء ، أنت من يقرر كيف تستخدم الآلة مواردها. ولكن اعتبارًا من بداية الوقت ، يعهد الشخص بحقه في اتخاذ القرار لأطراف ثالثة مقابل الطريقة السهلة. قبل أن تسألني عن مزايا مقالاتي عندما يكون هناك "مكعب" ، اسأل نفسك لماذا يقرر "المكعب" بالنسبة لي.

STM32 الجزء الأول: أساسيات
STM32 الجزء 2: التهيئة

لذا ، دعنا نواصل مغامرتنا. لقد كتبنا بالفعل نص التهيئة ، اكتشفنا الرابط والمترجم. حان الوقت وميض LED. في هذه المقالة ، سنستعرض أساسيات كتلة RCC و GPIO ، ونضيف زوجين من العناوين ، التي سنستخدمها في المشاريع المستقبلية. اذهب.

RCC - إعادة الضبط والتحكم في الساعة ، كتلة من السجلات التي تتحكم في ساعة المعالج والأجهزة الطرفية. يتم التحكم في العديد من مصادر الساعة بواسطة هذه الوحدة: HSI (داخلي عالي السرعة) ، HSE (خارجي عالي السرعة) ، PLL / PLLSAI / PLLI2S (قفل حلقة متدرجة). يمكن للمعالج استخدام جميع مصادر الساعة الثلاثة هذه ، بالطبع ، إذا تم تكوين سجلات كتلة RCC بشكل صحيح. سنتحدث عن هذا بالتفصيل في المقالة التالية.

GPIO - الإدخال والإخراج للأغراض العامة. كتلة السجلات التي تم إنشاؤها لمصابيح LED الوامضة ، أي أنها كتلة للتحكم في أرجل ميكروناتنا ، وهي بوابة للعالم الحقيقي. على عكس Atmega328p (Arduino) المألوف ، يقدم stm32 تخصيصًا أوسع للأرجل. على سبيل المثال ، وظيفة القدم المفتوحة غير متاحة في ميجا. أيضا ، يمكن تكوين التحكم في السرعة الذي ترفع فيه المملكة المتحدة الجهد على الساق.

لذا ، فلنومض بالفعل ، نعم. نحتاج أولاً إلى عنوانين نصف فيهما بنية هذه السجلات. لذلك ، نحصل على الدليل المرجعي وندرسه بحثًا عن المعلومات التي نحتاجها. أنا أعمل على STM32F746NG - اكتشاف حتى كل التعليمات البرمجية لهذا المنتدى.

أول شيء نحتاجه هو عناوين هذه الكتل ، الأساسية. لنبدأ مع كتلة RCC وإنشاء رأس rcc.h. سنقوم فيه بإنشاء ماكرو RCC_BASE ، وكذلك وصف بنية كتلة التسجيل ، وإنشاء مؤشر للبنية.

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)


دعنا نقوم بنفس العملية مع كتلة تسجيل GPIO ، فقط بدون مؤشر ، وإضافة ماكرو آخر ، GPIO_OFFSET. نتحدث عنه أدناه.

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;


دعونا نرى ما هو الأمر هنا ولماذا نحتاج إلى الهياكل. والحقيقة هي أنه يمكننا الوصول إلى السجل من خلال مؤشر إلى هيكل ، ولا نحتاج إلى تهيئته لأنه موجود بالفعل فعليًا. فمثلا:

RCC->AHB1ENR = 0; 


هذا يوفر مساحة الذاكرة ، وأحيانًا لا يتطلبها على الإطلاق. ولكن ليس عن إنقاذ اليوم.

لذا لدينا رأسان جاهزان ، يبقى تعلم كيفية القفز بمساعدة هذه السجلات وإنشاء int main();. كل شيء بسيط وليس تمامًا. في STM32 ، للوصول إلى كتلة التسجيل ، يجب علينا أولاً تطبيق ساعة عليها ، وإلا ستصل البيانات إليها. لن أتعمق في هيكل الإطار ، ولكن فقط أقول كما هو. توضع الكتل على إطارات مختلفة. تقع وحدتنا في حافلة AHB1. أي أننا بحاجة إلى تمكين منفذ معين على ناقل AHB1 ، في حالتي هو المنفذ الأول. بالنسبة للمبتدئين ، بالطبع نحتاج إلى الوظيفة الرئيسية.

دعونا نقوم بتحديث ملف بدء التشغيل الخاص بنا قليلاً ونضيف int main () ؛ إليه. ثم قم بإنشاء ملف main.c نفسه

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);
}


والآن نقوم بإنشاء ملف main.c. نفسه في الملف ، حاولت أن أرسم كل شيء في التعليقات على الشفرة ، لذلك نقرأها ونتعمق فيها. إذا كانت لديك أسئلة ، فاكتب في التعليقات أدناه وسأجيب.

#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;
}


الآن علينا أن نضع مشروعًا ونضعه على الميكرونات للتحقق. لقد قمت بنشر مستودع على Github كل ما عليك القيام به هو تشغيل الأداة المساعدة Make.
make


شكرًا لكم جميعًا على اهتمامكم ، في المقالة التالية سنتحدث أكثر عن وحدة RCC وكيفية العمل معها.

All Articles