تسجيل C ++ ، metaprogramming و متحكم

مرحبا يا هابر!


لعدة سنوات حتى الآن ، كنت أقوم بجميع مشاريعي لخط متحكم stm32 في C ++.


خلال هذا الوقت ، جمعت كمية معينة من المواد التي قد تهم مطورين آخرين.


لتجنب الأسئلة غير الضرورية: أستخدم مجموعة من QtCreator + gcc + gdb + openocd. لقد تم وصف كيفية العمل معها عدة مرات ، لذلك لن أتوقف عند هذا الحد ، ولكن سأخبرك بالمزيد عن أساليبي للعمل مع وحدات التحكم الدقيقة.


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


أحاول ، قدر الإمكان ، عدم العبث مع الوحوش مثل SPL و HAL و ، سامحني الله ، CubeMX ، باستثناء إنهاء مشاريع الآخرين من أجل المال. إن أيديولوجية الإطار "كما هو الحال في الآلات الكبيرة" ، في رأيي ، شريرة هناك. تتصور الوظائف المرنة والمريحة للاستخدام (على الرغم من أن البعض سيجادل في ذلك) تتحول إلى رمز آلة كبير إلى حد ما دون المستوى الأمثل ، حيث يتم تنفيذ العديد من العمليات غير الضرورية على وحدة التحكم الدقيقة في وقت التشغيل. نعم ، وحدات التحكم الحديثة قوية ، لكن جهاز الكمبيوتر الذي نجمع عليه المشروع أقوى بكثير ، لذا دعها تفعل كل شيء.


لقد حددت لنفسي المتطلبات الأساسية لتنفيذ الإدارة الطرفية:


  • يجب حساب جميع التعبيرات الثابتة في مرحلة التجميع وتندرج في رمز الآلة كأرقام ؛
  • يجب على المترجم أن يقوم بنصيب الأسد من العمل ، بالإضافة إلى التحكم في الأنواع التي تم تمريرها إلى الوظائف ؛
  • وحدات الماكرو لا حاجة يجب استخدام الحد الأدنى ، حيث لا يؤدي ذلك إلى إضعاف التحكم في النوع ؛
  • يجب أن تدعم واجهة برمجة التطبيق إمكانية قراءة التعليمات البرمجية.

ربما كسول فقط لم يخترع دراجته للعمل مع حقول التسجيل. هذا هو التحول بالإضافة إلى العمليات المنطقية و CMSIS ، وجميع أنواع وحدات الماكرو التي تخفي نفس العمليات في أحشاءها المعقدة وهي في نمط المكتبات من ST. في وقت من الأوقات ، عملت حتى من خلال حقول صغيرة ، حتى توصلت أخيرًا إلى حل ، أود أن أقدمه لك.


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



flash CMSIS 72:


FLASH->ACR = (FLASH->ACR &
              (~(FLASH_ACR_LATENCY_Msk
                 | FLASH_ACR_PRFTBE_Msk ))) //    
             | FLASH_ACR_LATENCY_1          //   ,    
             | FLASH_ACR_PRFTBE;

, ? , - , , . . , , :


0x80001ec                  04 4a        ldr r2, [pc, #16]   ; (0x8000200 <main()+20>)
0x80001ee  <+    2>        13 68        ldr r3, [r2, #0]
0x80001f0  <+    4>        23 f0 17 03  bic.w   r3, r3, #23
0x80001f4  <+    8>        43 f0 12 03  orr.w   r3, r3, #18
0x80001f8  <+   12>        13 60        str r3, [r2, #0]

, : --. ?


. .


, . . flash :


struct Regs {
    uint32_t ACR;   
    //      
};

:


struct ACR {
    constexpr static uint8_t LATENCY[]{ 0, 3 };
    constexpr static uint8_t HLFCYA[]{ 3, 1 };
    constexpr static uint8_t PRFTBE[]{ 4, 1 };
    constexpr static uint8_t PRFTBS[]{ 5, 1 };
};  

— , — . Python SVD .


, . constexpr :


constexpr static uint32_t base = 0x40022000; //    
INLINE constexpr static volatile Regs* rg()
{
    return reinterpret_cast<volatile Regs*>(base);
}

base , (, , , , ) . .


INLINE


#ifndef INLINE
#define INLINE __attribute__((__always_inline__)) inline 
#endif

, . , , gcc .


flash :


INLINE static void setLatency(Flash::Latency latency, bool prefetchBufferEnable = false) 
{ 
    setRegister(rg()->ACR,
        ACR::LATENCY, static_cast<uint8_t>(latency),
        ACR::PRFTBE, prefetchBufferEnable
    ); 
}

, : , . latency , . static_cast<uint8_t>(latency) , , , Latency :


enum class Latency : uint8_t {
    zeroWaitState = 0b000,
    oneWaitState = 0b001,
    twoWaitStates = 0b010
};


Flash::setLatency(Flash::Latency::twoWaitStates, true);

:


0x80001ec                  04 4a        ldr r2, [pc, #16]   ; (0x8000200 <main()+20>)
0x80001ee  <+    2>        13 68        ldr r3, [r2, #0]
0x80001f0  <+    4>        23 f0 17 03  bic.w   r3, r3, #23
0x80001f4  <+    8>        43 f0 12 03  orr.w   r3, r3, #18
0x80001f8  <+    12>       13 60        str r3, [r2, #0]

CMSIS: --, .


? setRegister. :


template<typename T, typename V, typename... Args>
INLINE constexpr static void setRegister(volatile uint32_t& reg,
                                         const T field,
                                         const V value,
                                         const Args... args)
{
    uint32_t mask = setMaskR(field, value, args...);
    uint32_t val = setBitsR(field, value, args...);

    reg = (reg & (~mask)) | val;
}

( uint32_t) — . .
:


template<typename V, typename T>
INLINE constexpr static uint32_t setBitsR(T field, V val)
{
    return (val << (field[0]));
}

template<typename V, typename T, typename... Args>
INLINE constexpr static uint32_t  setBitsR(T field, V val, Args... args)
{
    return (val << (field[0])) | setBitsR(args...);
}  

template<typename V, typename T>
INLINE constexpr static uint32_t setMaskR(T field, V val)
{
    return ((((1 << field[1]) - 1) << field[0]));
}

template<typename V, typename T, typename... Args>
INLINE constexpr static uint32_t  setMaskR(T field, V val, Args... args)
{
    return ((((1 << field[1]) - 1) << field[0])) | setMaskR(args...);
}

"" . " " , , , , , , .


setRegister? . , - - — . , , , , volatile, , . , , .


. :


Flash::setLatency(Flash::Latency::twoWaitStates, true);
Flash::setLatency(Flash::Latency::oneWaitState, true);

--:


0x80001ec                  07 4a        ldr r2, [pc, #28]   ; (0x800020c <main()+32>)
0x80001ee  <+    2>        13 68        ldr r3, [r2, #0]
0x80001f0  <+    4>        23 f0 17 03  bic.w   r3, r3, #23
0x80001f4  <+    8>        43 f0 12 03  orr.w   r3, r3, #18
0x80001f8  <+   12>        13 60        str r3, [r2, #0]        ;  
0x80001fa  <+   14>        13 68        ldr r3, [r2, #0]
0x80001fc  <+   16>        23 f0 17 03  bic.w   r3, r3, #23
0x8000200  <+   20>        43 f0 11 03  orr.w   r3, r3, #17
0x8000204  <+   24>        13 60        str r3, [r2, #0]        ;  

:


template<typename T>
INLINE constexpr static uint32_t getRegField(volatile uint32_t& reg,
                                             const T field)
{
    uint32_t mask = (((1 << field[1]) - 1) << field[0]); 
    return ((reg & mask) >> field[0]);
}

.


— :


INLINE static bool getLatencyPrefetch()
{
    return getRegField(rg()->ACR,
                       ACR::LATENCY,
                       ACR::PRFTBE);
}

flash :


struct Flash {
    constexpr static uint32_t base = 0x40022000; //<   

struct ACR {
    constexpr static uint8_t LATENCY[]{ 0, 3 };
    constexpr static uint8_t HLFCYA[]{ 3, 1 };
    constexpr static uint8_t PRFTBE[]{ 4, 1 };
    constexpr static uint8_t PRFTBS[]{ 5, 1 };
};    

enum class Latency : uint8_t {
    zeroWaitState = 0b000,
    oneWaitState = 0b001,
    twoWaitStates = 0b010
};

INLINE constexpr static volatile Regs* rg()
{
    return reinterpret_cast<volatile Regs*>(base);
}

INLINE static void setLatency(Flash::Latency latency, bool prefetchBufferEnable = false) 
{ 
    Utility::setRegister(rg()->ACR,
        ACR::LATENCY, static_cast<uint8_t>(latency),
        ACR::PRFTBE, prefetchBufferEnable
    ); 
}
INLINE static bool getLatencyPrefetch()
{
    return getRegField(rg()->ACR,
                       ACR::LATENCY,
                       ACR::PRFTBE);
}
};    

. , , . .


- , .


, . , DSP-. — .


All Articles