Registerbereich als array of structs betrachten

OP (Firma: TU Darmstadt) #5201296
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?
Gast #5201324
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.
Gast #5201413
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...

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