Frage

Auf einem Embedded-System haben wir ein Setup, das wir beliebige Daten über eine Kommandozeile-Schnittstelle für Diagnosezwecke lesen kann. Für die meisten Daten, das funktioniert gut, wir benutzen memcpy() Daten an der gewünschten Adresse zu kopieren und zurück über eine serielle Verbindung senden.

Doch für 16-Bit-Hardware-Register, verursacht memcpy() einige Probleme. Wenn ich versuche, ein 16-Bit-Hardware-Register zuzugreifen zwei mit 8-Bit-Zugriffe, wird das höherwertige Byte nicht richtig gelesen.

Hat jemand dieses Problem gestoßen? Ich bin ein 'High-Level' (C # / Java / Python / Ruby-) Typ, der auf die Hardware näher bewegt sich, und das ist fremd Gebiet.

Was ist der beste Weg, dies zu umgehen? Ich sehe einige Informationen, und zwar eine etwas verwirrend [mir] Beitrag hier . Der Autor dieses Beitrags hat genau die gleiche Frage, die ich tue, aber ich hasse es, eine Lösung zu implementieren, ohne genau zu wissen, was ich tue.

Jedes Licht, das Sie zu diesem Thema vergießen kann, ist sehr geschätzt. Dank!

War es hilfreich?

Lösung

Zusätzlich zu dem, was Eddie sagte , Sie in der Regel benötigen einen flüchtigen Zeiger verwenden, um ein Hardware-Register zu lesen (unter der Annahme ein Memory-Mapped-Register, das nicht der Fall für alle Systeme, aber es klingt wie für Ihre wahr ist). So etwas wie:

// using types from stdint.h to ensure particular size values
// most systems that access hardware registers will have typedefs
// for something similar (for 16-bit values might be uint16_t, INT16U,
// or something)

uint16_t volatile* pReg = (int16_t volatile*) 0x1234abcd;  // whatever the reg address is

uint16_t val = *pReg;  // read the 16-bit wide register

Hier ist eine Reihe von Artikeln von Dan Saks, die Ihnen so ziemlich alles, was Sie wissen müssen, geben sollen, um effektiv Speicher in der Lage sein verwenden abgebildet Register in C / C ++:

Andere Tipps

Jedes Register in dieser Hardware als ein Zwei-Byte-Array ausgesetzt ist, das erste Element an einer zwei-Byte-Grenze ausgerichtet ist (die Adresse ist gerade). memcpy () führt einen Zyklus und kopiert ein Byte bei jeder Iteration, so dass er Kopien von diesen Registern auf diese Weise (alle Schleifen entrollt, Saibling ist ein Byte):

*((char*)target) = *((char*)register);// evenly aligned - address is always even
*((char*)target + 1) = *((char*)register + 1);//oddly aligned - address is always odd

Allerdings ist die zweite Zeile funktioniert nicht richtig für einige Hardware-spezifische Gründe. Wenn Sie zwei Bytes auf einmal kopieren, anstatt einen nach dem anderen, wird es stattdessen so gemacht (short int ist zwei Bytes):

*((short int*)target) = *((short*)register;// evenly aligned

Hier kopieren Sie zwei Bytes in einem Arbeitsgang und das erste Byte wird gleichmäßig ausgerichtet sind. Da es von einer seltsam ausgerichteten Adresse kein separates Kopieren ist, funktioniert es.

Die geänderten Memcpy überprüft, ob die Adressen venely ausgerichtet sind und Kopien im Schlepptau Bytes Brocken, wenn sie sind.

Wenn Sie den Zugriff auf Hardware-Register einer bestimmten Größe benötigen, dann haben Sie zwei Möglichkeiten:

  • Verstehen Sie, wie Sie Ihre C-Compiler Code erzeugt, so dass Sie die entsprechende Integer-Typ verwenden können, auf den Speicher zuzugreifen, oder
  • Embed einige Montag den Zugang mit der richtigen Byte oder Wortgröße zu tun.

Hardware-Leseregister Seite wirkt sich haben kann, abhängig von dem Register und seine Funktion, natürlich, so ist es wichtig, Hardware-Register mit der richtigen Größe den Zugang zugreifen, so dass Sie das gesamte Register in einem Rutsch lesen kann.

In der Regel ist es ausreichend, einen Integer-Typen zu verwenden, die die gleiche Größe wie Ihr Register ist. Auf die meisten Compiler, ein kurzes sind 16 Bit.

void wordcpy(short *dest, const short *src, size_t bytecount)
{
    int i;
    for (i = 0;  i < bytecount/2;  ++i)
        *dest++ = *src++;
}

Ich denke, alle Details in diesem Thread enthalten ist, Sie auf dem Laufenden, so werde ich versuchen, und es brechen ein wenig;

Im Einzelnen;

If you access a 16-bit hardware register using two 8-bit
accesses, the high-order byte doesn't read correctly (it
always read as 0xFF for me). This is fair enough since
TI's docs state that 16-bit hardware registers must be
read and written using 16-bit-wide instructions, and
normally would be, unless you're using memcpy() to
read them.

So ist das Problem hier ist, dass die Hardware-Register nur den richtigen Wert melden, wenn ihre Werte in einem einzigen 16-Bit-Lesevorgang gelesen werden. Dies wäre gleichbedeutend mit zu tun;

uint16 value = *(regAddress);

Diese liest aus der Adresse in das Wertregister einer einzige 16-Byte-Lese verwenden. Auf der anderen Seite haben Sie Memcpy die Daten, die ein Single-Byte zu einem Zeitpunkt zu kopieren. So etwas wie;

while (n--)
{
  *(uint8*)pDest++ = *(uint8*)pSource++;
}

So bewirkt dies die Register 8-Bit gelesen werden (1 Byte) zu einem Zeitpunkt, was die Werte ungültig.

Die Lösung in diesem Thread geschrieben ist eine Version von memcpy zu verwenden, die die Daten unter Verwendung von 16-Bit liest kopiert wo auch immer die Quelle und das Ziel ist a6-Bit ausgerichtet ist.

Was müssen Sie wissen? Sie haben bereits festgestellt, einen separaten Beitrag erklärt er. Anscheinend ist die CPU-Dokumentation erfordert , die 16-Bit-Hardware-Register zugegriffen werden mit 16-Bit liest und schreibt, aber Ihre Implementierung von memcpy verwendet 8-Bit liest / schreibt. So arbeiten sie nicht zusammen.

Die Lösung ist einfach nicht memcpy zu verwenden, um dieses Register zuzugreifen. Stattdessen schreiben Sie Ihre eigene Routine, die Kopien 16-Bit-Werte.

Nicht sicher genau das, was die Frage ist - ich denke, dass Post die richtige Lösung. Wie Sie erwähnen, ist das Problem, dass die Standard-memcpy () Routine ein Byte zu einem Zeitpunkt liest, die nicht richtig für Speicher abgebildeten Hardwareregister funktioniert. Das ist eine Beschränkung des Prozessors -. Es gibt einfach keine Möglichkeit, einen gültigen Wert liest ein Byte an zum Zeitpunkt zu bekommen

Die vorgeschlagene Lösung ist Ihre eigene memcpy () zu schreiben, die auf Wort-ausgerichteten Adressen funktioniert nur, und liest 16-Bit-Wörter auf einmal. Dies ist relativ einfach - der Link gibt sowohl eine c und eine Montageversion. Die einzige Gotcha ist sicherzustellen, dass Sie immer haben die 16-Bit-Kopien von rechtsgültig ausgerichteten Adresse. Sie können in zwei Möglichkeiten, dies zu tun:. Entweder Linker-Befehle oder Pragmas verwenden, um sicher die Dinge ausgerichtet sind, oder einen Sonderfall für die Extra-Byte an der Vorderseite eines nicht ausgerichteten Puffer hinzufügen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top