studio - ¿Qué significa((Puerto*) 0x41004400UL) aquí?
atmel studio tutorial (2)
Estoy trabajando en una placa de desarrollo que tiene un microntroller basado en ARM de 32 bits (es decir, la placa es Atmel SAM D21J18A). Todavía estoy en la fase de aprendizaje y tengo mucho por hacer, pero realmente me gustan los sistemas integrados.
Tengo algunos antecedentes en C. Sin embargo, obviamente no es suficiente. Estaba mirando los códigos de un proyecto de ejemplo de Atmel, y realmente no obtuve algunas partes de él. Aqui esta uno de ellos:
#define PORT ((Port *)0x41004400UL) /**< /brief (PORT) APB Base Address */
El puerto se define como:
typedef struct {
PortGroup Group[2]; /**< /brief Offset: 0x00 PortGroup groups [GROUPS] */
} Port;
y PortGroup se define como:
typedef struct {
__IO PORT_DIR_Type DIR; /**< /brief Offset: 0x00 (R/W 32) Data Direction */
__IO PORT_DIRCLR_Type DIRCLR; /**< /brief Offset: 0x04 (R/W 32) Data Direction Clear */
__IO PORT_DIRSET_Type DIRSET; /**< /brief Offset: 0x08 (R/W 32) Data Direction Set */
__IO PORT_DIRTGL_Type DIRTGL; /**< /brief Offset: 0x0C (R/W 32) Data Direction Toggle */
__IO PORT_OUT_Type OUT; /**< /brief Offset: 0x10 (R/W 32) Data Output Value */
__IO PORT_OUTCLR_Type OUTCLR; /**< /brief Offset: 0x14 (R/W 32) Data Output Value Clear */
__IO PORT_OUTSET_Type OUTSET; /**< /brief Offset: 0x18 (R/W 32) Data Output Value Set */
__IO PORT_OUTTGL_Type OUTTGL; /**< /brief Offset: 0x1C (R/W 32) Data Output Value Toggle */
__I PORT_IN_Type IN; /**< /brief Offset: 0x20 (R/ 32) Data Input Value */
__IO PORT_CTRL_Type CTRL; /**< /brief Offset: 0x24 (R/W 32) Control */
__O PORT_WRCONFIG_Type WRCONFIG; /**< /brief Offset: 0x28 ( /W 32) Write Configuration */
RoReg8 Reserved1[0x4];
__IO PORT_PMUX_Type PMUX[16]; /**< /brief Offset: 0x30 (R/W 8) Peripheral Multiplexing n */
__IO PORT_PINCFG_Type PINCFG[32]; /**< /brief Offset: 0x40 (R/W 8) Pin Configuration n */
RoReg8 Reserved2[0x20];
} PortGroup;
Entonces, aquí, estamos viendo la dirección 0x41004400UL, obtenemos la información allí, y luego ¿qué sucede?
Lo busqué pero no pude encontrar nada útil. Si tiene alguna sugerencia (tutoriales, libros, etc.), déjeme saber.
No pasa nada, porque solo presentas algunas declaraciones. No estoy del todo seguro de cuál es la pregunta en realidad, sino de explicar brevemente ese código:
0x41004400UL
es obviamente una dirección en el espacio de E / S (memoria no regular) donde se inicia un puerto (un conjunto de registros de E / S)Este puerto consta de dos grupos con una disposición similar de registros individuales
struct
PortGroup
modela estos registros exactamente en el diseño presente en el hardware
Para saber el significado de los registros, busque la documentación del hardware.
En general, puede acceder a un registro de hardware en C de esta manera:
#define PORT (*(volatile uint8_t*)0x1234)
-
0x1234
es la dirección de registro -
uint8_t
es el tipo de registro, en este caso 1 byte grande. -
volatile
es necesario para que el compilador sepa que no puede optimizar dicha variable, pero que cada lectura o escritura de la variable indicada en el código debe hacerse. -
(volatile uint8_t*)
arroja el entero literal a una dirección del tipo deseado. - El que está más a la izquierda
*
toma el contenido de esa dirección, para que la macro se pueda usar como si PORT fuera una variable regular.
Tenga en cuenta que esto no asigna nada! Simplemente asume que hay un registro de hardware presente en la dirección dada, que se puede acceder por el tipo especificado ( uint8_t
).
Usando el mismo método, también puede tener otros tipos de datos C para corresponder directamente a los registros de hardware. Por ejemplo, al usar una estructura práctica, puede mapear todo el área de registro de un periférico de hardware particular. Sin embargo, tal código es un poco peligroso y cuestionable, ya que debe tomar cosas como el relleno de alineación / estructura y el alias en la cuenta.
En cuanto al código específico en su ejemplo, es un mapa de registro horrible típico para un periférico de hardware particular (parece un puerto de E / S de propósito general simple) en un cierto microcontrolador. Una de esas bestias típicamente se proporciona con cada compilador que soporta la MCU.
Dichos mapas de registro lamentablemente siempre están escritos de maneras horribles y completamente no portátiles. Por ejemplo, dos guiones bajos __
es un identificador prohibido en C. Ni el compilador ni el programador pueden declarar tales identificadores (7.1.3).
Lo realmente extraño es que han omitido la palabra clave volatile
. Esto significa que tienes uno de estos escenarios aquí:
- La palabra clave volátil está oculta debajo de la definición del
Port
. Es muy probable que este sea el caso, o - El mapa de registro está lleno de errores fatales, o
- El compilador es una mierda tan horrible que no optimiza las variables en absoluto. Lo que haría que los problemas con
volatile
desaparezcan.
Investigaría más esto.
En cuanto al relleno de estructuras y aliasing, es probable que el proveedor del compilador suponga implícitamente que solo se utilizará su compilador. No tienen interés en proporcionarle un mapa de registro portátil, para que pueda cambiar el compilador del competidor por el mismo MCU.