C > Struct > Pointer - Adresszuweisung

OP #7751542
Lesenswert?

Hallo Bit Freunde,

ich möchte gerne weiter meine C Kenntnisse auffrischen..

Dieser Variable möchte ich gerne die Adresse zuordnen, jedoch zeigt der Online Compiler ein Fehler an (was vermutlich auch richtig ist..)

Was mache ich falsch?

1
  //GPIO->OutReg       = (uint32_t*)((0x0554 + (4 * 8)));
1
/******************************************************************************
2

3
                            Online C Compiler.
4
                Code, Compile, Run and Debug C program online.
5
Write your code in this editor and press "Run" button to compile and execute it.
6

7
*******************************************************************************/
8

9
#include <stdio.h>
10
#include <stdint.h>
11

12
#define GPIO_BASE 0x60004000ul
13

14
typedef struct
15
{
16
  volatile uint32_t *FuncOutCnfg;
17
  volatile uint32_t *OutReg;
18
  volatile uint32_t *EnableReg;
19
}sGPIO;
20

21
volatile sGPIO *GPIO;
22

23

24

25
int main()
26
{
27
  //GPIO->FuncOutCnfg  = (uint32_t*)(GPIO_BASE + 0x0004);
28
  //GPIO->EnableReg    = (uint32_t*)(GPIO_BASE + 0x0020);
29
  GPIO->OutReg       = (uint32_t*)(GPIO_BASE + (0x0554 + (4 * 8)));
30
  
31
  //GPIO->OutReg       = (uint32_t*)((0x0554 + (4 * 8)));
32
    
33
    
34
  printf( "%p", GPIO->OutReg);
35

36
    return 0;
37
}
Moderator (Firma: Titel) Persönliche Seite #7751605
Lesenswert?

Jan H. schrieb:

jedoch zeigt der Online Compiler ein Fehler an (was

Sollen wir jetzt raten, welcher Compiler welchen Fehler anzeigt?

ich möchte gerne weiter meine C Kenntnisse auffrischen..

Wozu einen neuen Thread für das exakt selbe Problem? Reicht der Beitrag "Mit dem ESP32C3 laufen lernen" nicht?

Jan H. schrieb:

Dann bin ich mal auf deine Erklärung gespannt..

Denk mal da drüber nach:

1
#include <stdio.h>
2

3
#define GPIO_BASE 0x60004000ul
4

5
typedef struct
6
{
7
  volatile unsigned long *FuncOutCnfg;
8
  volatile unsigned long *OutReg;
9
  volatile unsigned long *EnableReg;
10
} sGPIO;
11

12
volatile sGPIO GPIO;
13
volatile sGPIO *pGPIO;
14

15
int main()
16
{
17
  pGPIO = (sGPIO*)(&GPIO);
18

19
  GPIO.OutReg    = (unsigned long*)(GPIO_BASE + 4);
20
  printf( "%p\n",  pGPIO->OutReg);
21
  printf( "%p\n\n", GPIO.OutReg);  
22
  
23
  pGPIO->OutReg  = (unsigned long*)(GPIO_BASE) + 4;
24
  printf( "%p\n",  pGPIO->OutReg);
25
  printf( "%p\n\n", GPIO.OutReg);  
26
    return 0;
27
}
OP #7752041
Lesenswert?

Ich versuche es mal wie folgt zu lösen..

1
//Mapping Address
2
//GPIO 0x6000_4000 to 0x6000_4FFF 
3

4
#define GPIO_BASE 0x60004000ul
5

6
typedef struct
7
{
8
  struct 
9
  {
10
    // mapped @GPIO_BASE
11
    uint32_t Bt_Select_Reg;
12
    uint32_t Out_Reg;
13
    uint32_t Out_W1TS_Reg;
14
    uint32_t Out_W1TC_Reg;
15
    uint32_t Enable_Reg;
16
    uint32_t Enable_W1TS_Reg;
17
    uint32_t Enable_W1TC_Reg;
18
    uint32_t Strap_Reg;
19
    uint32_t In_Reg;
20
    uint32_t Status_Reg;
21
    uint32_t Status_W1TS_Reg;
22
    uint32_t Status_W1TC_Reg;
23
    uint32_t PCPU_Int_Reg;
24
    uint32_t Status_Next_Reg;    
25
  }Cnfg_Reg;
26
  
27

28

29
  //mapped @GPIO_BASE + 0x554
30
  struct 
31
  {
32
    uint32_t Func0_Out_Sel_Cnfg;
33
    uint32_t Func1_Out_Sel_Cnfg;
34
    uint32_t Func2_Out_Sel_Cnfg;
35
    uint32_t Func3_Out_Sel_Cnfg;
36
    uint32_t Func4_Out_Sel_Cnfg;
37
    uint32_t Func5_Out_Sel_Cnfg;
38
    uint32_t Func6_Out_Sel_Cnfg;
39
    uint32_t Func7_Out_Sel_Cnfg;
40
    uint32_t Func8_Out_Sel_Cnfg;
41
  }Out_Func_Reg;
42

43
}GPIO_struct;
44
 
45
volatile GPIO_struct*    const sGPIO = (GPIO_struct*)GPIO_BASE;

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?

#7752062
Lesenswert?

Jan H. schrieb:

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?

Moderator (Firma: Titel) Persönliche Seite #7752065
Lesenswert?

Jan H. schrieb:

Wie würde man sowas lösen?

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.

Bruno V. schrieb:

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.

OP #7752080
Lesenswert?

Kann ich denn irgendwie sehen was der Compiler für Adressen als "Endergbnis" liefert?

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

1
//Mapping Address
2
//GPIO 0x6000_4000 to 0x6000_4FFF 
3

4
#define GPIO_BASE 0x60004000ul
5

6
typedef struct 
7
{
8
    // mapped @GPIO_BASE
9
    uint32_t Bt_Select_Reg;
10
    uint32_t Out_Reg;
11
    uint32_t Out_W1TS_Reg;
12
    uint32_t Out_W1TC_Reg;
13
    uint32_t Enable_Reg;
14
    uint32_t Enable_W1TS_Reg;
15
    uint32_t Enable_W1TC_Reg;
16
    uint32_t Strap_Reg;
17
    uint32_t In_Reg;
18
    uint32_t Status_Reg;
19
    uint32_t Status_W1TS_Reg;
20
    uint32_t Status_W1TC_Reg;
21
    uint32_t PCPU_Int_Reg;
22
    uint32_t Status_Next_Reg;    
23

24
}GPIO_Cnfg_Reg_t;
25
 
26
typedef struct
27
{
28
  //mapped @GPIO_BASE + 0x554
29
    uint32_t Func0_Out_Sel_Cnfg;
30
    uint32_t Func1_Out_Sel_Cnfg;
31
    uint32_t Func2_Out_Sel_Cnfg;
32
    uint32_t Func3_Out_Sel_Cnfg;
33
    uint32_t Func4_Out_Sel_Cnfg;
34
    uint32_t Func5_Out_Sel_Cnfg;
35
    uint32_t Func6_Out_Sel_Cnfg;
36
    uint32_t Func7_Out_Sel_Cnfg;
37
    uint32_t Func8_Out_Sel_Cnfg;
38

39
}GPIO_Func_Sel_Reg_t;
40

41
volatile GPIO_Func_Sel_Reg_t*     const sGPIO_Func_Sel_Reg  = (GPIO_Func_Sel_Reg_t*)(GPIO_BASE + 0x0554);
42
volatile GPIO_Cnfg_Reg_t*         const sGPIO_Cnfg_Reg      = (GPIO_Cnfg_Reg_t*)GPIO_BASE;
43

44
void setup() 
45
{
46
  sGPIO_Func_Sel_Reg->Func8_Out_Sel_Cnfg |= 0x80;
47
  sGPIO_Cnfg_Reg->Enable_Reg |= 1<<8;
48

49
  // gpio8 auf low setzen
50
  sGPIO_Cnfg_Reg->Out_Reg &= ~(1<<8);
51
}
OP #7752097
Lesenswert?

Bruno V. schrieb:

Jan H. schrieb:

sGPIO_Func_Sel_Reg->Func8_Out_Sel_Cnfg |= 0x80; sGPIO_Cnfg_Reg->Enable_Reg |= 1<<8; // gpio8 auf low setzen sGPIO_Cnfg_Reg->Out_Reg &= ~(1<<8);

sollen die alle das gleiche bit beschreiben? Mal 0x80, mal 0x100.

Nein natürlich nicht. Habe mich hier an dieses Beispiel gehalten (mit der Struktur und den ganzen Registern)

https://blog.feabhas.com/2019/01/peripheral-register-access-using-c-structs-part-1/

Beitrag #7752281 wurde von einem Moderator gelöscht.
OP #7752283
Lesenswert?

Jan H. schrieb:

Bruno V. schrieb:

Jan H. schrieb:

sGPIO_Func_Sel_Reg->Func8_Out_Sel_Cnfg |= 0x80; sGPIO_Cnfg_Reg->Enable_Reg |= 1<<8; // gpio8 auf low setzen sGPIO_Cnfg_Reg->Out_Reg &= ~(1<<8);

sollen die alle das gleiche bit beschreiben? Mal 0x80, mal 0x100.

Nein natürlich nicht. Habe mich hier an dieses Beispiel gehalten (mit der Struktur und den ganzen Registern)

https://blog.feabhas.com/2019/01/peripheral-register-access-using-c-structs-part-1/

Ich verstehe deine Antwort nicht. Die Register haben jeweils unterschiedliche Werte.

#7752606
Lesenswert?

Jan H. schrieb:

Ich verstehe deine Antwort nicht. Die Register haben jeweils unterschiedliche Werte.

Ich kenne Dein System nicht. Du schreibst nur

Jan H. schrieb:

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.

OP #7752729
Lesenswert?

Bruno V. schrieb:

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:

1
volatile uint32_t* Func_Reg = (uint32_t*)(GPIO_BASE + 0x0574);
2
volatile uint32_t* Enable_Reg = (uint32_t*)(GPIO_BASE + 0x0020);
3
volatile uint32_t* Out_Reg = (uint32_t*)(GPIO_BASE + 0x0004);
4

5
void setup() {
6

7
 *Func_Reg = 0x80; // set special index
8
 *Enable_Reg = 1<<8; // enable gpio 8
9
 *Out_Reg = 0; // set all @low level
10

11
}

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

1
volatile GPIO_Cnfg_Reg_t*         const sGPIO_Cnfg_Reg      = (GPIO_Cnfg_Reg_t*)GPIO_BASE;

So wie ich mir das jetzt vorstelle. Meine Struktur mit den ganzen Konfigurations Register:

1
typedef struct 
2
{
3
    // mapped @GPIO_BASE
4
    uint32_t Bt_Select_Reg;
5
    uint32_t Out_Reg;
6
    uint32_t Out_W1TS_Reg;
7
    uint32_t Out_W1TC_Reg;
8
    uint32_t Enable_Reg;
9
    uint32_t Enable_W1TS_Reg;
10
    uint32_t Enable_W1TC_Reg;
11
    uint32_t Strap_Reg;
12
    uint32_t In_Reg;
13
    uint32_t Status_Reg;
14
    uint32_t Status_W1TS_Reg;
15
    uint32_t Status_W1TC_Reg;
16
    uint32_t PCPU_Int_Reg;
17
    uint32_t Status_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?

Angehängte Dateien:
#7752735
Lesenswert?

Jan H. schrieb:

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.

#7752763
Lesenswert?

Jan H. schrieb:

Damit möchte ich einfach vermeiden das ich die ganzen Register Adressen von Hand in den Code tippen muss..

Musst Du ja auch nicht. Du machst an /einer/ Stelle ein #define, und das war's dann.

So arbeitet der Rest der Welt, und so sind i.d.R. auch die von Controllerherstellern gelieferten Headerdateien für ihre µCs aufgebaut.

Und man kann so ein Macro auch so definieren, daß man es direkt als "Pseudovariable" verwenden kann.

1
#define Func_Reg (*((uint32_t *) (GPIO_BASE + 0x0574)))

Das dereferenziert die I/O-Adresse, so daß Du im Code einfach so etwas schreiben kannst:

1
Func_Reg = 4;
2

3
int x = 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).

OP #7752764
Lesenswert?

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.

#7752794
Lesenswert?

Jan H. schrieb:

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
typedef struct
2
{
3
    __IO uint32_t GPIO_BT_SELECT_REG; // 0x0000
4
    __IO uint32_t GPIO_OUT_REG;       // 0x0004
5
    __IO uint32_t GPIO_OUT_W1TS_REG;  // 0x0008
6
    __IO uint32_t GPIO_OUT_W1TC_REG;  // 0x000C
7
    __IO uint32_t UNUSED_BLOCK_0[4];
8
    __IO uint32_t GPIO_ENABLE_REG;    // 0x0020
9
   ... etc.
10
    __IO uint32_t GPIO_PIN21_REG      // 0x00C8
11
    __IO uint32_t UNUSED_BLOCK_x[35];
12
    __IO uint32_t GPIO_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.

Persönliche Seite #7752933
Lesenswert?

Lothar M. schrieb:

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:

https://gcc.gnu.org/onlinedocs/gcc/C-Implementation.html https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Implementation.html

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.

OP #7752946
Lesenswert?

Wieso funktioniert das mit den Registern dann bei z.B einem Xmega von ATMEL bzw. Microchip?

1
/* I/O Ports */
2
typedef struct PORT_struct
3
{
4
    register8_t DIR;  /* I/O Port Data Direction */
5
    register8_t DIRSET;  /* I/O Port Data Direction Set */
6
    register8_t DIRCLR;  /* I/O Port Data Direction Clear */
7
    register8_t DIRTGL;  /* I/O Port Data Direction Toggle */
8
    register8_t OUT;  /* I/O Port Output */
9
    register8_t OUTSET;  /* I/O Port Output Set */
10
    register8_t OUTCLR;  /* I/O Port Output Clear */
11
    register8_t OUTTGL;  /* I/O Port Output Toggle */
12
    register8_t IN;  /* I/O port Input */
13
    register8_t INTCTRL;  /* Interrupt Control Register */
14
    register8_t INT0MASK;  /* Port Interrupt 0 Mask */
15
    register8_t INT1MASK;  /* Port Interrupt 1 Mask */
16
    register8_t INTFLAGS;  /* Interrupt Flag Register */
17
    register8_t reserved_0x0D;
18
    register8_t REMAP;  /* I/O Port Pin Remap Register */
19
    register8_t reserved_0x0F;
20
    register8_t PIN0CTRL;  /* Pin 0 Control Register */
21
    register8_t PIN1CTRL;  /* Pin 1 Control Register */
22
    register8_t PIN2CTRL;  /* Pin 2 Control Register */
23
    register8_t PIN3CTRL;  /* Pin 3 Control Register */
24
    register8_t PIN4CTRL;  /* Pin 4 Control Register */
25
    register8_t PIN5CTRL;  /* Pin 5 Control Register */
26
    register8_t PIN6CTRL;  /* Pin 6 Control Register */
27
    register8_t PIN7CTRL;  /* Pin 7 Control Register */
28
} PORT_t;
29
.
30
.
31
.
32
.
33
.
34
#define PORTA    (*(PORT_t *) 0x0600)  /* Port A */
35
#define PORTB    (*(PORT_t *) 0x0620)  /* Port B */
36
#define PORTC    (*(PORT_t *) 0x0640)  /* Port C */
37
#define PORTD    (*(PORT_t *) 0x0660)  /* Port D */
38
#define PORTE    (*(PORT_t *) 0x0680)  /* Port E */
39
#define PORTF    (*(PORT_t *) 0x06A0)  /* Port F */
40
#define PORTH    (*(PORT_t *) 0x06E0)  /* Port H */
41
#define PORTJ    (*(PORT_t *) 0x0700)  /* Port J */
42
#define PORTK    (*(PORT_t *) 0x0720)  /* Port K */
43
#define PORTQ    (*(PORT_t *) 0x07C0)  /* Port Q */
44
#define PORTR    (*(PORT_t *) 0x07E0)  /* Port R */
#7753018
Lesenswert?

Jan H. schrieb:

volatile uint32_t* Enable_Reg = (uint32_t*)(GPIO_BASE + 0x0020);

das ist ein offset von 32, also das 9te Element.

Jan H. schrieb:

typedef struct { // mapped @GPIO_BASE uint32_t Bt_Select_Reg; uint32_t Out_Reg; uint32_t Out_W1TS_Reg; uint32_t Out_W1TC_Reg; uint32_t Enable_Reg; uint32_t Enable_W1TS_Reg; uint32_t Enable_W1TC_Reg;

Hier ist es das 5te Element.

Ein Problem ist, dass Du zwar mehrere Beispiele hast, aber niemals dabei sagst, ob es das gleiche oder was verschiedenes zeigt.

OP #7753022
Lesenswert?

Ich werde

Bruno V. schrieb:

Jan H. schrieb:

volatile uint32_t* Enable_Reg = (uint32_t*)(GPIO_BASE + 0x0020);

das ist ein offset von 32, also das 9te Element.

Jan H. schrieb:

typedef struct { // mapped @GPIO_BASE uint32_t Bt_Select_Reg; uint32_t Out_Reg; uint32_t Out_W1TS_Reg; uint32_t Out_W1TC_Reg; uint32_t Enable_Reg; uint32_t Enable_W1TS_Reg; uint32_t Enable_W1TC_Reg;

Hier ist es das 5te Element.

Ein Problem ist, dass Du zwar mehrere Beispiele hast, aber niemals dabei sagst, ob es das gleiche oder was verschiedenes zeigt.

Ich werde leider nicht wirklich aus deinen Kommentaren schlau. Was genau meinst Du? Es ist immer noch das gleiche Projekt was ich vor mir habe.

#7753023
Lesenswert?

Jan H. schrieb:

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.

#7753028
Lesenswert?

Jan H. schrieb:

Ich werde leider nicht wirklich aus deinen Kommentaren schlau. Was genau meinst Du? Es ist immer noch das gleiche Projekt was ich vor mir habe.

Du sagst

Jan H. schrieb:

wenn ich es mit fester Adresse teste, funktioniert es: ... volatile uint32_t* Enable_Reg = (uint32_t*)(GPIO_BASE + 0x0020);

hast bei der "Struktur-Version" Enable_Reg aber an einer ganz anderen Adresse (GPIO_BASE + 20 statt +0x20)

Mag sein, dass das ein Tippfehler ist (0x20 statt 20), mag sein, dass Füll-Elemente fehlen.

OP #7753034
Lesenswert?

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?!

#7753040
Lesenswert?

Jan H. schrieb:

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?!

Ja. Dann sähe dein Struct aber so aus. Mit, wie

Harald K. schrieb:

sehr vielen "Füllregistern" für unbenutzte Registeradressen [..] typedef struct

1
> {
2
>     __IO uint32_t GPIO_BT_SELECT_REG; // 0x0000
3
>     __IO uint32_t GPIO_OUT_REG;       // 0x0004
4
>     __IO uint32_t GPIO_OUT_W1TS_REG;  // 0x0008
5
>     __IO uint32_t GPIO_OUT_W1TC_REG;  // 0x000C
6
>     __IO uint32_t UNUSED_BLOCK_0[4];
7
>     __IO uint32_t GPIO_ENABLE_REG;    // 0x0020
8
>    ... etc.

In Deinem Beispiel fehlen die Füllregister, hier UNUSED_BLOCK_0

#7753070
Lesenswert?

Jan H. schrieb:

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

1
assert(&sGPIO_Cnfg_Reg->Out_Reg == Out_Reg);
2
assert(&sGPIO_Cnfg_Reg->Enable_Reg == Enable_Reg);
3
assert(&sGPIO_Func_Sel_Reg->Func8_Out_Sel_Cnfg == Func_Reg);

gezeigt.

OP #7753076
Lesenswert?

Harald schrieb:

Jan H. schrieb:

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

1
assert(&sGPIO_Cnfg_Reg->Out_Reg == Out_Reg);
2
assert(&sGPIO_Cnfg_Reg->Enable_Reg == Enable_Reg);
3
assert(&sGPIO_Func_Sel_Reg->Func8_Out_Sel_Cnfg == Func_Reg);

gezeigt.

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.

So funktioniert es ;)

1
//Mapping Address
2
//GPIO 0x6000_4000 to 0x6000_4FFF 
3

4
#define GPIO_BASE 0x60004000
5

6
/* Configuration Registers @DB Page 171 */
7
#define GPIO_BT_SELECT_REG      (*(volatile uint32_t*)(GPIO_BASE))
8
#define GPIO_OUT_REG            (*(volatile uint32_t*)(GPIO_BASE + 0x0004))
9
#define GPIO_OUT_W1TS_REG       (*(volatile uint32_t*)(GPIO_BASE + 0x0008))
10
#define GPIO_OUT_W1TC_REG       (*(volatile uint32_t*)(GPIO_BASE + 0x000C)) 
11
#define GPIO_ENABLE_REG         (*(volatile uint32_t*)(GPIO_BASE + 0x0020))
12
#define GPIO_ENABLE_W1TS_REG    (*(volatile uint32_t*)(GPIO_BASE + 0x0024))
13
#define GPIO_ENABLE_W1TC_REG    (*(volatile uint32_t*)(GPIO_BASE + 0x0028))
14
#define GPIO_STRAP_REG          (*(volatile uint32_t*)(GPIO_BASE + 0x0038))
15
#define GPIO_IN_REG             (*(volatile uint32_t*)(GPIO_BASE + 0x003C))
16
#define GPIO_STATUS_REG         (*(volatile uint32_t*)(GPIO_BASE + 0x0044))
17
#define GPIO_STATUS_W1TS_REG    (*(volatile uint32_t*)(GPIO_BASE + 0x0048))
18
#define GPIO_STATUS_W1TC_REG    (*(volatile uint32_t*)(GPIO_BASE + 0x004C)) 
19
#define GPIO_PCPU_INT_REG       (*(volatile uint32_t*)(GPIO_BASE + 0x005C))
20
#define GPIO_STATUS_NEXT_REG    (*(volatile uint32_t*)(GPIO_BASE + 0x014C))
21

22
#define GPIO_FUNC0_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0554)) 
23
#define GPIO_FUNC1_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0558)) 
24
#define GPIO_FUNC2_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x055C)) 
25
#define GPIO_FUNC3_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0560)) 
26
#define GPIO_FUNC4_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0564)) 
27
#define GPIO_FUNC5_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0568)) 
28
#define GPIO_FUNC6_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x056C)) 
29
#define GPIO_FUNC7_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0570)) 
30
#define GPIO_FUNC8_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0574)) 
31
#define GPIO_FUNC9_OUT_SEL_CFG_REG      (*(volatile uint32_t*)(GPIO_BASE + 0x0578)) 
32
#define GPIO_FUNC10_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x057C))  
33
#define GPIO_FUNC11_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0580)) 
34
#define GPIO_FUNC12_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0584)) 
35
#define GPIO_FUNC13_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0588)) 
36
#define GPIO_FUNC14_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x058C)) 
37
#define GPIO_FUNC15_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0590)) 
38
#define GPIO_FUNC16_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0594)) 
39
#define GPIO_FUNC17_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x0598)) 
40
#define GPIO_FUNC18_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x059C)) 
41
#define GPIO_FUNC19_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x05A0)) 
42
#define GPIO_FUNC20_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x05A4)) 
43
#define GPIO_FUNC21_OUT_SEL_CFG_REG     (*(volatile uint32_t*)(GPIO_BASE + 0x05A8))
#7753100
Lesenswert?

Johann L. schrieb:

Lothar M. schrieb:

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.

OP #7771635
Lesenswert?

ich habe da nochmal eine Frage:

1
#define SPI_LL_GET_HW(ID) (((ID)==1) ? &GPSPI2 : NULL)

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
static inline void spi_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?

Angehängte Dateien:
#7771857
Lesenswert?

Jan H. schrieb:

SPI_LL_GET_HW bekommt die Adresse von "GPSPI2", richtig?

Das Makro wählt mittels ID zwischen verschiedenen Instanzen aus. Hier allerdings ist nur GPSPI2 für ID==1 vorhanden.

Solche Wrapper sollte man nur verwenden, wenn man sie braucht, also wenn der Code mehrere Instanzen händelt.

Jan H. schrieb:

Wo bekommt "*hw" bzw. "GPSPI2" die Basisadresse von der SPI Einheit her?

hw bekommt die Adresse beim Aufruf. GPSPI2 beim Beispiel vorher ist bei seiner Definition an die richtige Adresse gelegt worden.

Es gibt eine ähnliche Zeile wie

extern spi_dev_t GPSPI2;

Die heißt dann z.B.

spi_dev_t GPSPI2 @0x10000;

wobei das @xxx, also die Adresszuweisung, compilerspezifisch ist.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren