Forum: Mikrocontroller und Digitale Elektronik Registerbereich als array of structs betrachten


von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Hallo,

beim STM32 befindet sich z.B. ein Registersatz mit dem Type 
USB_OTG_INEndpointTypeDef für jeden In Enpoint ab offset 0x900 im 
Bereich der OTG Register.

Ich hatte versucht, diese Struktur als ein Array of structs 
anzusprechen:
1
USB_OTG_INEndpointTypeDef **in = (USB_OTG_INEndpointTypeDef **)(usbd_dev->driver->base_address +                                                               USB_OTG_IN_ENDPOINT_BASE);
und mit
1
in[i]->DIEPCTL
 anzusprechen. Leider geht das schief und
1
 &in[i]
 ist der Inhalt von DIEPCTL der i.ten Struktur.
Verwendet wurde arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors 
6-2017-q2-update) 6.3.1 20170620

Der Zugriff auf eine einzelne Struktur funktioniert wie erwertet:
1
USB_OTG_INEndpointTypeDef *in = (USB_OTG_INEndpointTypeDef *)(usbd_dev->driver->base_address +                                                               USB_OTG_IN_ENDPOINT_BASE);
2
in->DIEPCTL

Ist ein array of structs mit dem Zuweisen einer Adresse nicht erlaubt? 
Bei meiner Suche im Web meine ich Hinweise darauf gefunden zu haben. 
Oder wird ein bestimmter C Standard gebraucht?

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Du nutzt ja einen Doppel Pointer?! Variante 2 sollte auch automatisch 
für mehrere Register gehen. Ein Array ist in C ja fast das gleiche wie 
ein Pointer. Du musst nur dafür sorgen, dass die Größe des Element Typs 
dem Abstand zwischen zwei Registern gleichen Typs entspricht.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Bitte ein Codebeispiel. Ich habe schon tausende Möglichkeiten 
durchprobiert.

von Dr. Sommer (Gast)


Lesenswert?

Genau so wie du es geschrieben hast:
1
__IO USB_OTG_INEndpointTypeDef *in = (__IO USB_OTG_INEndpointTypeDef*) (usbd_dev->driver->base_address + USB_OTG_IN_ENDPOINT_BASE);
2
3
in[0].DIEPCTL = 42;
4
in[1].DIEPTSIZ = 21;

Beim Zugriff auf "in[i].DIEPCTL" wird auf die Adresse "in + 
sizeof(USB_OTG_INEndpointTypeDef)*i" zugegriffen. Da 
USB_OTG_INEndpointTypeDef praktischerweise so definiert ist dass es 32 
Bytes groß ist, und der Abstand zwischen DIEPCTL0 und DIEPCTL1 genau 32 
Bytes ist, kommt das so genau hin. In C++ könnte man das noch etwas 
verbessern:
1
__IO USB_OTG_INEndpointTypeDef (&in)[3] = *reinterpret_cast<__IO USB_OTG_INEndpointTypeDef (*) [3]> (usbd_dev->driver->base_address + USB_OTG_IN_ENDPOINT_BASE);
2
in[0].DIEPCTL = 42;
3
in[1].DIEPTSIZ = 21;

Dann ist die Arraygröße Teil des Typs und leichter ersichtlich. Leider 
warnt der GCC auch hier nicht, wenn der Array-Index zu groß wird...

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Danke, so gehts!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.