Gibt es eine Möglichkeit die Struktur "Out_Func_Reg" an die Adresse "GPIO_BASE + 0x554" zu mappen also quasi das direkt schon bei der definition des Structs? Wie würde man sowas lösen?
Gibt es eine Möglichkeit die Struktur "Out_Func_Reg" an die Adresse
"GPIO_BASE + 0x554" zu mappen also quasi das direkt schon bei der
definition des Structs?
Nein.
Wie würde man sowas lösen?
mit einem Datenfeld entsprechender Größe dazwischen. unsigned char _dummy[0x554-4*14]; oder so
Oder 2 Structs. Wenn es zwei Bereiche sind, warum dann nicht auch zwei Strukturen?
Nachdem du zum Glück nicht der erste bist, der solche Registerdefinitionen in seinem C-Programmen verwednen will, wäre es sicher sinnvoll, mal zu schauen, wie seit vielen Jahren andere derartige Probleme lösen.
mit einem Datenfeld entsprechender Größe dazwischen. unsigned char
_dummy[0x554-4*14]; oder so
Ich finde diese verschachtelten Structs ungünstig, weil die jeder Compiler so interpretieren kann, wie es ihm gerade gefällt. Oder andersrum: es ist im Grunde Zufall wie diese Structs im Speicher abgelegt werden. Es kann sein, dass das mit den Dummy-Bytes zwischen den structs heute funktioniert. Es kann aber auch sein, dass es nach einem Compilerupdate oder nach dem Einschalten von Optimierungen nicht mehr funktioniert.
Kann ich denn irgendwie sehen was der Compiler für Adressen als
"Endergbnis" liefert?
Fuer die Mutigen mit gcc/binutils toolchain, die sich durch den Assembler lesen wollen:
entweder gcc -save-temps ....
und dann im .s File stoebern
oder objdump -D bla.o | less
und dann g'schwind lesen.
Ich bin gerade dabei bei einem Board eine LED zum Leben zu erwecken aber
ich habe das Gefühl das irgendwas mit den Adressen nicht ganz so
hinhaut..
aber nicht, was nicht funktioniert oder (noch wichtiger) was funktioniert.
Wenn Du Angst hast, dass die Adresse falsch sein könnte ... dann schreib sie direkt hin, probier es aus und wenn es funktioniert, dann nimm den Struct-Weg und probier erneut. Das brauchst Du ja nur ein Mal exemplarisch zu machen.
Oder Du hast einen Debugger am laufen, dann setze den Brakepoint davor, schaue Dir das Register an und geh im Singlestep drüber.
Ohne Debugger scheitert es an den unmöglichsten Dingen, angefangen von Konfigurationsbits und der Quarz läuft gar nicht los. Oder das Signal toggelt so schnell, dass Du es nicht siehst. Hast Du Debugger, LSA oder Oszi?
Die Struct-Adressfrage ist ja genügend beleuchtet. Das ist aber Kür wenn der direkte Weg funktioniert.
Ohne Debugger scheitert es an den unmöglichsten Dingen, angefangen von
Konfigurationsbits und der Quarz läuft gar nicht los. Oder das Signal
toggelt so schnell, dass Du es nicht siehst. Hast Du Debugger, LSA oder
Oszi?
Für ATMEL habe ich alles da, ja. Oszi. habe ich auch. Bringt mir jetzt gerade nur nichts.
Es muss an meiner Initalisierung von dem Struct liegen bzw. der Adressen.
Leider kann ich mir nicht erklären was genau das Problem ist.
Wenn ich es mit fester Adresse teste, funktioniert es:
Mache ich es mit der Struktur haut es aufeinmal nicht mehr hin..
Ich vermute mal das der Compiler? Da andere Adressen interpretiert als ich mir das vorstelle?!
Hier ist mein Zeiger auf die Basis Adresse des GPIO´s
So wie ich mir das jetzt vorstelle. Meine Struktur mit den ganzen Konfigurations Register:
1
typedefstruct
2
{
3
// mapped @GPIO_BASE
4
uint32_tBt_Select_Reg;
5
uint32_tOut_Reg;
6
uint32_tOut_W1TS_Reg;
7
uint32_tOut_W1TC_Reg;
8
uint32_tEnable_Reg;
9
uint32_tEnable_W1TS_Reg;
10
uint32_tEnable_W1TC_Reg;
11
uint32_tStrap_Reg;
12
uint32_tIn_Reg;
13
uint32_tStatus_Reg;
14
uint32_tStatus_W1TS_Reg;
15
uint32_tStatus_W1TC_Reg;
16
uint32_tPCPU_Int_Reg;
17
uint32_tStatus_Next_Reg;
18
19
}GPIO_Cnfg_Reg_t;
Halte ich mit der Maus jetzt auf den ersten Member so erhalte ich folgendes Bild (siehe Anhang).
Dort zeigt mir die Arduino IDE an das "Bt_Select_Reg" einen Offset von 0 hat. Gehe ich mit der Maus jetzt auf den letzten Eintrag "Status_Next_Reg" sagt die IDE mir das es sich um einen Offset von 52 Bytes handelt.
Das würde dann dem letzten Register (Adresse) vom Datenblatt entsprechen oder verstehe ich das falsch?
Dort zeigt mir die Arduino IDE an das "Bt_Select_Reg" einen Offset von 0
hat. Gehe ich mit der Maus jetzt auf den letzten Eintrag
"Status_Next_Reg" sagt die IDE mir das es sich um einen Offset von 52
Bytes handelt.
Das sind die Offsets der Strukturelemente relativ zum Beginn der Struktur.
Mit Deinen Registeradressen hat das, wenn überhaupt, nur rein zufällig zu tun.
Wozu soll bei Deinem Projekt eigentlich die Struktur dienen? Welches Problem meinst Du, damit lösen zu können?
Ich sehe hier nur eine zusätzliche Abstraktionsebene, die Du einziehst, und die Dich heftigst herausfordert.
Das dereferenziert die I/O-Adresse, so daß Du im Code einfach so etwas schreiben kannst:
1
Func_Reg=4;
2
3
intx=Func_Reg;
Eine Struktur ist da nicht erforderlich, sondern höchstens ein besseres Namensschema (ich würde das Ding GPIO_FUNC_REG nennen, auch um zu zeigen, daß das ein Macro/#define ist).
Danke für den Vorschlag.
Meinen Ansatz hatte ich mal in einen Online C Compiler gehauen und da hatte es komischerweise gepasst mit den Adressen von daher bin ich ausgegangen das es so funktionieren kann. Auf einigen Webseiten wird es für diverse Atmels auch so praktiziert.
Auf einigen Webseiten wird es
für diverse Atmels auch so praktiziert.
Auf Webseiten wird viel praktiziert.
Es gibt im Zusammenhang mit HAL-Abstraktionen verschiedener µC-Hersteller die Tendenz, statt einzelner Registerdefinitionen (wie oben) Pseudostrukturen zu definieren, die ein Peripherieobjekt abbilden.
Wenn bei einem Peripheriebaustein die zusammengehörenden Register monoton aufsteigend angeordnet sind, dann kann das so aussehen, wie hier diskutiert:
Beitrag "Ich verstehe diesen Code nicht"
Die Registerstruktur im ESP32, um den es Dir ja letztendlich geht, ist für diese Herangehensweise nicht geeignet, da die Register recht willkürliche Adressen haben (wie Dein Offset von 0x574 ja schon zeigt).
Da müsste man die Struktur mit sehr, sehr vielen "Füllregistern" für unbenutzte Registeradressen definieren):
1
typedefstruct
2
{
3
__IOuint32_tGPIO_BT_SELECT_REG;// 0x0000
4
__IOuint32_tGPIO_OUT_REG;// 0x0004
5
__IOuint32_tGPIO_OUT_W1TS_REG;// 0x0008
6
__IOuint32_tGPIO_OUT_W1TC_REG;// 0x000C
7
__IOuint32_tUNUSED_BLOCK_0[4];
8
__IOuint32_tGPIO_ENABLE_REG;// 0x0020
9
...etc.
10
__IOuint32_tGPIO_PIN21_REG// 0x00C8
11
__IOuint32_tUNUSED_BLOCK_x[35];
12
__IOuint32_tGPIO_FUNC0_IN_SEL_CFG_REG// 0x0154
13
...etc.
14
15
16
}ESP32_GPIO_T;
(bezogen auf das Datenblatt, Seite 171, Tabelle mit GPIO-Registern)
Du siehst, daß das sehr unhandlich und vor allem fehlerträchtig wird.
Oder andersrum: es ist im Grunde Zufall wie diese Structs
im Speicher abgelegt werden.
Natürlich ist es kein Zufall, sondern es wird im [E]ABI (Applicaton Binary Interface) festgelegt / beschrieben.
Nicht alle Features von C/C++ werden im Sprachstandard festgelegt; es gibt auch Dinge, die sind Implementation Defined. Einige davon werden von der C/C++ Implmemtation festgelegt, für GCC etwa:
andere werden im ABI festgelegt, welches idR Hardware- und OS-abhängig ist. Und auch Eigenschaften des Binärformats (z.B. welche RELOCs im ELF wie festgelegt sind) sind Sache des ABIs.
Damit möchte ich einfach vermeiden das ich die ganzen Register Adressen
von Hand in den Code tippen muss..
So wie hier..volatile uint32_t* Func_Reg = (uint32_t*)(GPIO_BASE +
0x0574);
Ist zwar O.T., aber wenn die Adressen sowieso ungeordnet bzw. fragmentiert vorliegen, ist die Tipparbeit selbst mit Editoren aus dem letzten Jahrhundert in Summe geringer.
Du schreibst Die Namen und Adressen runter
1
Func_Reg 0x0574
2
Dings_Reg 0x0588
3
...
und machst den Pre- ("volatile uint32t* ") Mid- (" = (uint32_t*)(GPIO_BASE +
") und Postfix (");") in wenigen Sekunden für alle.
Der Vorteil: Du siehst später sofort den echten Wert und musst ihn nicht abzählen. Hat zwar auch ein paar Nachteile, aber vorerst reicht das.
Okay.
Also laut Datenblatt sind die Konfigurations Register 32 Bit lang, also 4 Bytes und fangen bei der Adresse "0x0000".
Das "Enable" - Register liegt bei Adresse "0x0020".
Wenn ich jetzt eine Struktur habe wo alle Elemente 32 Bit lang sind also 4 Bytes und das "Enable" Register an der richtigen Stelle steht, müsste es doch von der Adresse passen?!
Wenn ich jetzt eine Struktur habe wo alle Elemente 32 Bit lang sind also
4 Bytes und das "Enable" Register an der richtigen Stelle steht, müsste
es doch von der Adresse passen?!
Mache ich es mit der Struktur haut es aufeinmal nicht mehr hin..
Ich war genauso blind, hab den Fehler einfach übersehen.
In solchen Fällen sind assertions überaus hilfreich. Dass und auch wo im code der Unterschied herkommt hat mir
Mache ich es mit der Struktur haut es aufeinmal nicht mehr hin..
Ich war genauso blind, hab den Fehler einfach übersehen.
In solchen Fällen sind assertions überaus hilfreich. Dass und auch wo im
code der Unterschied herkommt hat mir
Mit assert habe ich noch nicht gearbeitet. Muss ich mir mal anschauen.
Danke für deine Hilfe Harald! Einer von wenigen der nicht nur "ironisch" helfen will.
Oder andersrum: es ist im Grunde Zufall wie diese Structs
im Speicher abgelegt werden.
Natürlich ist es kein Zufall, sondern es wird im [E]ABI (Applicaton
Binary Interface) festgelegt / beschrieben.
Zudem gibt es auch in C static_assert, sizeof() und Direktiven zum Ausrichten und Packen von structs. Damit kann man sicherstellen dass (oder zumindest prüfen ob) Daten z.B. auf einem avr genauso abgebildet werden wie auf x64.
SPI_LL_GET_HW bekommt die Adresse von "GPSPI2", richtig?
1
/**
2
* Initialize SPI peripheral (master).
3
*
4
* @param hw Beginning address of the peripheral registers.
5
*/
6
staticinlinevoidspi_ll_master_init(spi_dev_t*hw)
7
{
8
//Reset timing
9
hw->user1.cs_setup_time=0;
10
hw->user1.cs_hold_time=0;
11
12
//use all 64 bytes of the buffer
13
hw->user.usr_miso_highpart=0;
14
hw->user.usr_mosi_highpart=0;
15
16
//Disable unneeded ints
17
hw->slave.val=0;
18
hw->user.val=0;
19
20
hw->clk_gate.mst_clk_active=1;
21
hw->clk_gate.mst_clk_sel=1;
22
23
hw->dma_conf.val=0;
24
hw->dma_conf.tx_seg_trans_clr_en=1;
25
hw->dma_conf.rx_seg_trans_clr_en=1;
26
hw->dma_conf.dma_seg_trans_en=0;
27
}
Hier wird mit (vermutlich) schon den Hardware Registern gearbeitet, sehe ich das richtig? Zumindest sehe ich sonst keine Funktion mehr die die Register behandelt.
Wo bekommt "*hw" bzw. "GPSPI2" die Basisadresse von der SPI Einheit her?
Die muss doch irgendwo zugewiesen werden?
Die "spi_struct.h" die sich im Anfang befindet definiert "GPSPI2" stellt jedoch noch keine "Basis Adresse" da, lediglich evtl. die Offsets für die einzelnen Register?