C ++, register pemrograman dan mikrokontroler

Halo, Habr!


Selama beberapa tahun sekarang, saya telah melakukan semua proyek saya untuk jalur mikrokontroler stm32 di C ++.


Selama waktu ini, saya telah mengakumulasikan sejumlah materi yang mungkin menarik bagi pengembang lain.


Untuk menghindari pertanyaan yang tidak perlu: Saya menggunakan banyak QtCreator + gcc + gdb + openocd. Cara bekerja dengannya telah dijelaskan berulang kali, jadi saya tidak akan berhenti di situ, tetapi saya akan memberi tahu Anda lebih banyak tentang pendekatan saya untuk bekerja dengan mikrokontroler.


Pada tingkat yang lebih rendah dari proyek, sebagai suatu peraturan, ada driver periferal. Mari kita mulai dengan mereka.


Saya mencoba, jika mungkin, untuk tidak mengacaukan monster seperti SPL, HAL dan, Tuhan maafkan saya, CubeMX, kecuali untuk menyelesaikan proyek orang lain demi uang. Ideologi kerangka kerja "seperti untuk mesin-mesin besar", menurut pendapat saya, jahat di sana. Diciptakan oleh fungsi yang fleksibel dan mudah digunakan (meskipun seseorang akan membantahnya) berubah menjadi kode mesin yang agak besar dan suboptimal, di mana banyak operasi yang tidak perlu dilakukan pada mikrokontroler saat runtime. Ya, pengendali modern sangat kuat, tetapi komputer tempat kami menyusun proyek jauh lebih kuat, jadi biarkan ia melakukan semuanya.


Saya menentukan sendiri persyaratan dasar untuk penerapan manajemen periferal:


  • semua ekspresi konstan harus dihitung pada tahap kompilasi dan dimasukkan ke dalam kode mesin sebagai angka;
  • , ;
  • , ;
  • .

, . - CMSIS, , ST. , , , , .


STM32f103 Flash access control register, , .



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