Registres C ++, métaprogrammation et microcontrÎleur

Bonjour, Habr!


Depuis plusieurs années, je réalise tous mes projets pour la gamme de microcontrÎleurs stm32 en C ++.


Pendant ce temps, j'ai accumulé une certaine quantité de matériel qui pourrait intéresser d'autres développeurs.


Pour Ă©viter des questions inutiles: j'utilise un tas de QtCreator + gcc + gdb + openocd. La façon de travailler avec elle a Ă©tĂ© dĂ©crite Ă  plusieurs reprises, donc je ne m'arrĂȘterai pas lĂ , mais je vais vous en dire plus sur mes approches de travail avec les microcontrĂŽleurs.


Au niveau inférieur du projet, il y a généralement des pilotes périphériques. Commençons par eux.


J'essaie, si possible, de ne pas jouer avec des monstres comme SPL, HAL et, Dieu me pardonne, CubeMX, sauf pour terminer les projets des autres pour de l'argent. L'idĂ©ologie du cadre "comme pour les grosses machines", Ă  mon avis, y est vicieuse. Conçues par des fonctions flexibles et faciles Ă  utiliser (bien que quelqu'un conteste cela), les fonctions se transforment en un code machine assez grand et sous-optimal, oĂč de nombreuses opĂ©rations inutiles sont effectuĂ©es sur le microcontrĂŽleur en cours d'exĂ©cution. Oui, les contrĂŽleurs modernes sont puissants, mais l'ordinateur sur lequel nous assemblons le projet est beaucoup plus puissant, alors laissez-le tout faire.


J'ai dĂ©terminĂ© par moi-mĂȘme les exigences de base pour la mise en Ɠuvre de la gestion pĂ©riphĂ©rique:


  • toutes les expressions constantes doivent ĂȘtre calculĂ©es au stade de la compilation et tomber dans le code machine sous forme de nombres;
  • , ;
  • , ;
  • .

, . - 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