2017-01-03 1 views
0

Ich möchte eine Klasse erstellen, die die Bitband-Funktion eines Cortex-M3-Geräts verwaltet. Für diejenigen, die es nicht wissen: Der Prozessor bildet jedes Bit in einem bestimmten Bereich auf ein ganzes Wort ab. Dies ermöglicht atomare Mengenoperationen für spezifische Bits. Die Klasse selbst arbeitet mit std :: uintptr_t. Für den Konstruktor möchte ich einen beliebigen Zeiger zulassen, da es mir egal ist, auf was er zeigt. Es kann eine Struktur sein, die im Gerätekopf definiert ist.Ist es möglich, in C++ einen beliebigen Zeiger als Eingabeargument zu verwenden?

Meine aktuelle Implementierung gibt die Konstrukteure mit:

Bitband(uintptr_t address, uint32_t bitNumber); 
Bitband(void * ptr, uint32_t bitNumber); 

meine Anwendung ruft der Konstruktor wie folgt aus:

Bitband foo(reinterpret_cast<uintptr_t>(&gpioPort->IDR), pin); 

Wenn ich auslassen er reinterpret_cast ich keine bekannte Umwandlung für ‚uintptr_t‘ bekommen und 'void *'. Gibt es einen sauberen Weg, um diese reinterpret_cast für jeden Aufruf loszuwerden und einen beliebigen Zeiger als Argument für meinen Konstruktor zu nehmen?

Edit: Hier ist meine aktuellen Code für die Klasse BitBand und mein Einsatz für Turing eine LED ein- oder ausgeschaltet:

bitband.hpp

#pragma once 

#include <stdint.h> 

class Bitband 
{ 
public: 
    Bitband(uintptr_t address, uint32_t bitNumber); 
    Bitband(void * address, uint32_t bitNumber); 

    inline void Set(bool val) const 
    { 
    uint32_t * const pData = reinterpret_cast<uint32_t *>(this->bbAddress); 
    *pData = val; 
    } 

    inline bool Get() const 
    { 
    uint32_t * const pData = reinterpret_cast<uint32_t *>(this->bbAddress); 
    return *pData; 
    } 
private: 
    static uintptr_t GetBitBandAddress(uintptr_t address, uint32_t bit); 
    static bool IsSramAddress(uintptr_t address); 
    static bool IsPeripheralAddress(uintptr_t address); 

    uintptr_t const bbAddress; 

/* Constants for bit band calculation for SRAM */ 
    static uintptr_t const sramStartAddress = 0x20000000; 
    static uintptr_t const sramEndAddress = 0x200FFFFF; 
    static uintptr_t const sramBbBaseAddress = 0x22000000; 

/* Constants for bit band calculation for Peripherals */ 
    static uintptr_t const peripheralsStartAddress = 0x40000000; 
    static uintptr_t const peripheralsEndAddress = 0x400FFFFF; 
    static uintptr_t const peripheralsBbBaseAddress = 0x42000000; 
}; 

bitband.cpp

#include "bitband.hpp" 
#include <cassert> 

Bitband::Bitband(uintptr_t address, uint32_t bitNumber) : 
    bbAddress(GetBitBandAddress(address, bitNumber)) {} 

Bitband::Bitband(void * address, uint32_t bitNumber) : 
    bbAddress(GetBitBandAddress(reinterpret_cast<uintptr_t>(address), bitNumber)) {} 

uintptr_t Bitband::GetBitBandAddress(uintptr_t const address, 
             uint32_t const bitNumber) 
{ 
    uintptr_t bbBase; 
    uintptr_t regionStartAddress; 

    assert(Bitband::IsPeripheralAddress(address) 
      || Bitband::IsSramAddress(address)); 

    /* Set the parameters depending on wether we are in peripherals region or sram 
    region. */ 
    if(Bitband::IsSramAddress(address)) 
    { 
    bbBase = Bitband::sramBbBaseAddress; 
    regionStartAddress = Bitband::sramStartAddress; 
    } 
    else if(Bitband::IsPeripheralAddress(address)) 
    { 
    bbBase = Bitband::peripheralsBbBaseAddress; 
    regionStartAddress = Bitband::peripheralsStartAddress; 
    } 
    else 
    { 
    /* Invalid parameter */ 
    __breakpoint(0); 
    } 

    uintptr_t byteOffset = address - regionStartAddress; 
    auto bitWordOffset = (byteOffset * 32) + (bitNumber * sizeof(uint32_t)); 
    auto bitWordAddr = bbBase + bitWordOffset; 

    return bitWordAddr; 
} 

bool Bitband::IsSramAddress(uintptr_t address) 
{ 
    return (address >= Bitband::sramStartAddress) 
      && (address <= Bitband::sramEndAddress); 
} 

bool Bitband::IsPeripheralAddress(uintptr_t address) 
{ 
    return (address >= Bitband::peripheralsStartAddress) 
      && (address <= Bitband::peripheralsEndAddress); 
} 

Es wird von meiner Klasse geführt (für te M. Ich schalte Just/off einige LEDs)

led.hpp

#pragma once 

#include <stdint.h> 
#include "stm32l1xx.h"     // Keil::Device:Startup 
#include "bitband.hpp" 

class Led 
{ 
public: 
    Led(GPIO_TypeDef * const ledPort, uint16_t ledPin); 
    inline void Set(bool newState) { this->ledOutputBitBand.Set(!newState); } 
private: 
    Bitband ledOutputBitBand; 
}; 

led.cpp

#include <led.hpp> 
#include <cassert> 

Led::Led(GPIO_TypeDef * const port, uint16_t const pin) : 
    ledOutputBitBand(reinterpret_cast<uintptr_t>(&port->ODR), pin) 
{ 
    assert(pin < 16); 

    /* Set port mode to push pull */ 
    port->MODER |= 1 << (2 * pin); 
} 

Verwendung innerhalb Hauptanwendung

Led greenLed(GPIOD, 0); 
greenLed.Set(true); 

Wenn ich verließ das reinterpret_cast ich folgende Meldungen raus:

Src/led.cpp(5): error: no matching constructor for initialization of 'Bitband' 
    ledOutputBitBand(&port->ODR, pin) 
    ^    ~~~~~~~~~~~~~~~ 

./Inc/bitband.hpp(9): note: candidate constructor not viable: no known conversion from 'volatile uint16_t *' (aka 'volatile unsigned short *') to 'uintptr_t' (aka 'unsigned int') for 1st argument; remove & 
    Bitband(uintptr_t address, uint32_t bitNumber); 
^

./Inc/bitband.hpp(10): note: candidate constructor not viable: no known conversion from 'volatile uint16_t *' (aka 'volatile unsigned short *') to 'void *' for 1st argument 
    Bitband(void * address, uint32_t bitNumber); 
^

./Inc/bitband.hpp(6): note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided 
class Bitband 
    ^

./Inc/bitband.hpp(6): note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided 
1 error generated. 

Damit ich nehme an, wenn ich die Klasse BitBand in einem anderen Kontext verwenden möchten würde ich die reinterpret_cast wieder verwenden müssen?

+0

Es sollte kein Problem sein, '& gpioPort-> IDR' in' void * 'umzuwandeln (es sei denn' IDR' ist 'const'). Bitte kopieren und fügen Sie die gesamte Fehlermeldung und den Code, der sie verursacht, ein. – molbdnilo

+0

Ich habe das nicht versucht, aber was passiert, wenn Sie den Konstruktor eine Vorlage machen, die einen Zeiger auf den Vorlagentyp nimmt und dann die Umwandlung in den Konstruktor selbst uminterpretiert? Wenn Sie tatsächlich den Konstruktor tatsächlich mit unterschiedlichen Zeigertypen aufrufen, kann dies dazu führen, dass Sie Ihren Code vergrößern (wenn er nicht optimiert wird), aber Ihre Aufrufe werden dadurch sauberer. Alternativ können Sie ein Makro verwenden, um die Wortiness Ihrer Neuinterpretation zu verkürzen. –

Antwort

3

Angesichts der Anforderungen, die Sie zur Verfügung gestellt haben, ist der saubere Weg, es zu tun.

Ich verstehe nicht wirklich, welchen Konstruktor Sie anrufen möchten (Sie machen Ihre Ziele nicht klar), aber so oder so, ein reinterpret_cast scheint am nächsten zu dem, was sinnvoll ist.

Es ist ausführlich, um Sie daran zu erinnern, dass Sie Ihr Design erneut besuchen sollten, und sich eines vorstellen, das diese Umwandlung überhaupt nicht erfordert. Weil wir nicht mehr in den 1970er Jahren leben.:)

Wenn Sie auf alte Stile bestehen, obwohl, könnte man stattdessen einen C-Casts verwenden:

Bitband foo((void*)&gpioPort->IDR, pin); 

ich Sie bitten, nicht zu.

Verwandte Themen