Ich schreibe ein Programm auf STM32F4 Discovery, wo ich die Adresse des CCR-Registers des Timers in einem Zeiger speichern und dann das Register über diesen Zeiger ändern muss, dh
volatile uint32_t* tim_ccr_reg = reinterpret_cast<uint32_t*>(TIM4_BASE + 0x34);
// 0x34 = offset of CCR1 register
*tim_ccr_reg = 1999; // Set CCR1 to 1999
Wenn ich dies allein in einem "leeren Programm" teste, funktioniert es, aber wenn ich mein gesamtes Programm (zusammen mit allen anderen von mir implementierten Funktionen) verwende, verursacht es bei einer dieser Zuweisungen einen schweren Fehler. Jetzt finde ich heraus, ob es mein anderer Code ist, der etwas im Speicher verdrängt, oder ich speichere die Registeradresse falsch und es wird nur angezeigt, wenn ein komplexeres Programm geladen wird. In der Dokumentation habe ich gelesen
Der einfachste Weg, speicherabgebildete Variablen zu implementieren, besteht darin, Zeiger auf feste Adressen zu verwenden.
#define PORTBASE 0x40000000
unsigned int volatile * const port = (unsigned int *) PORTBASE;
Der variable Port ist ein konstanter Zeiger auf eine flüchtige Ganzzahl ohne Vorzeichen, sodass wir auf das speicherabgebildete Register zugreifen können mit:
*port = value; /* write to port */
value = *port; /* read from port */
Dieser Ansatz kann verwendet werden, um auf 8-, 16- oder 32-Bit-Register zuzugreifen, aber achten Sie darauf, die Variable mit dem entsprechenden Typ für ihre Größe zu deklarieren, dh unsigned int für 32-Bit-Register, unsigned short für 16-Bit und unsigned char für 8bit. Sie sollten auch sicherstellen, dass die speicherabgebildeten Register an geeigneten Adressgrenzen liegen, z. B. entweder alle wortausgerichtet oder an ihren natürlichen Größengrenzen ausgerichtet sind, dh 16-Bit-Register müssen auf Halbwortadressen ausgerichtet sein (aber beachten Sie, dass ARM empfiehlt, dass alle Register, unabhängig von ihrer Größe, an Wortgrenzen ausgerichtet werden.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3750.html
Dann ging ich zur Dokumentation für CCR-Register für Timer und es heißt
Also bin ich mir jetzt nicht sicher, ist das Register immer 32-Bit und nur 16-Bit werden in einigen Timern verwendet oder ist das Register in einigen Fällen nur 16-Bit und ich muss einen 16-Bit-Zeiger verwenden, um darauf zu schreiben?
Auf jeden Fall würde ich gerne wissen, wie das Timer-CCR-Register richtig in einer Variablen gespeichert wird. Wenn ich im folgenden Befehl auf CCR1 klicke
TIM4->CCR1 = 1999;
und klicke auf "go to definition", es bringt mich zu einem seltsamen Stück Code
/** \brief ITM Send Character
This function transmits a character via the ITM channel 0.
It just returns when no debugger is connected that has booked the output.
It is blocking when a debugger is connected, but the previous character send is not transmitted.
\param [in] ch Character to transmit
\return Character to transmit
*/
static __INLINE uint32_t ITM_SendChar (uint32_t ch)
{
if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) && /* Trace enabled */
(ITM->TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled */
(ITM->TER & (1UL << 0) ) ) /* ITM Port #0 enabled */
{
while (ITM->PORT[0].u32 == 0);
ITM->PORT[0].u8 = (uint8_t) ch;
}
return (ch);
}
Ich bin sehr verwirrt.
Im einfachsten Fall wandeln Sie die Adresse in einen "Zeiger auf einen 32-Bit-Wert" um, dereferenzieren sie und erhalten den Wert.
x=*((int*)(0x40000800+0x34))
(int*) ist das Casting, wodurch die Zahl zu einem Zeiger wird, der auf einen int-Typ zeigt.
*(....) soll den Zeiger dereferenzieren.
0x40000800+0x34 steht in Klammern, um einen Additionsfehler zu vermeiden. Casting hat Vorrang vor der Addition, und die Addition einer ganzen Zahl zu einem Zeiger ist nicht dasselbe wie die Addition von ganzen Zahlen.
Um noch einen Schritt weiter zu gehen, definieren Sie die Peripherie als Strukturen. Es muss vom Compiler garantiert werden, dass es so im Speicher stattfindet, wie die von Ihnen geschriebene Sequenz. Vergessen Sie nicht, dass Strukturen virtuelle Definitionen wie „int“ sind. Zum Beispiel:
struct TIMg_st {volatile u32 CR1,bos0,SMCR,DIER,SR,EGR,CCMR1,bos1,CCER,CNT,PSC,ARR,bos2,CCR1,bos3[6],OR;};
Wenn Sie einen Zeiger erstellen, der auf diese Struktur zeigt (also diesmal kein int-Typ), zum Beispiel:
(struct TIMg_st*)0x40000800
Sie können seine Elemente problemlos erreichen. Zum Beispiel:
*((struct TIMg_st*)0x40000800).CCR1
Oder für ein einfacheres Scripting;
((struct TIMg_st*)0x40000800)->CCR1
Um die Dinge einfacher zu machen, wandeln Sie es einfach in eine Definition um:
#define TIM4 ((struct TIMg_st*)0x40000800)
So jetzt ist es eben
TIM4->CCR1
und dies ist einfach ein vorzeichenloser 32-Bit-Wert. Der Wert im Register kann 16 Bit oder 8 Bit sein, das ist kein Problem. Wichtig ist ihre Zuordnungsbreite und Sie gestalten die Struktur entsprechend. Alle Elemente der Struktur sind uint32, da sie alle 32-Bit-zugewiesen sind.
Chris Stratton
olltsu
Terraviper-5
Chris Stratton
Terraviper-5