Problema al escribir mapas de registro usando la estructura C para un microcontrolador TI

4

Estoy escribiendo mapas de registro en C para una placa de microcontrolador basada en TI ARM. Aquí está el enlace a la hoja de datos .

Estoy usando las siguientes pautas sobre cómo se deben escribir los mapas de Registro en C: Registrar mapas . Estas pautas son similares a las ARM CMSIS (Cortex Microcontroller Software Interface Standard) para escribir el código C

Estoy enfrentando un problema al escribir los mapas del Registro de control del sistema (consulte la sección 5.5, página 237 en adelante en la hoja de datos) usando C struct. Todos los registros son de 32 bits de tamaño

  • La dirección base es 0x400F.E000.
  • Registro 1: Identificación de dispositivo 0 (DID0), desplazamiento 0x000
  • Registro 2: Identificación del dispositivo 1 (DID1), desplazamiento 0x004
  • Registro 3: Control de restablecimiento de salida de tensión (PBORCTL), desplazamiento 0x030
  • Registro 4: estado de interrupción sin formato (RIS), desplazamiento 0x050
  • etc ...

Si ahora escribo una estructura como esta:

typedef struct
{
   uint32_t DID0;      // offset 0x000. distance: 0
   uint32_t DID1;      // offset 0x004. distance: 4
   uint32_t PBORCTL;   // **HOW to place this at offset 0x030 ?**
   uint32_t RIS;       // **HOW  to place this at offset 0x050 ?**
   // ...and so on
 }PER_REG_MAP_T;

#define PERIPH_BASE ((uint32_t)0x400FE000)
#define MY_PERIPH_A ((PER_REG_MAP_T*)PERIPH_BASE)

void Reset(PER_REG_MAP_T* PERIPH_A)
{
  PERIPH_A->DID0 = 0;
  PERIPH_A->DID1= 0;
  PERIPH_A->PBORCTL= 1;
  PERIPH_A->RIS= 0;
  // .. and so on
}

El problema principal al que me enfrento es cómo colocar PBORCTL y RIS dentro de la estructura, ya que están en el desplazamiento 0x030 y 0x050 con respecto a la dirección base de la estructura. No he hecho demasiada programación en C a nivel de bits antes, por lo que esta pregunta podría ser demasiado simple, pero no sé cómo hacerlo.

    
pregunta nurabha

2 respuestas

2

Las estructuras no son adecuadas para escribir mapas de registro, porque una estructura puede tener bytes de relleno agregados en cualquier lugar dentro de ella, para propósitos de alineación. Esto depende del compilador: debe asegurarse de que no se use relleno (por ejemplo, a través de una aserción estática).

Además, es fácil cometer errores al escribir grandes estructuras que se supone que reflejan un mapa de registro, debe acertar cada byte o romperá todo. Esto hace que la estructura sea vulnerable durante el mantenimiento.

Le sugiero encarecidamente que escriba los mapas de registro a través de macros, tales como:

#define PERIPH_A_DID0 (*(volatile uint32_t*)0x400FE000u))
#define PERIPH_A_DID1 (*(volatile uint32_t*)0x400FE004u))

Esto también tiene la ventaja de ser 100% portátil para cualquier compilador de C

.

Alternativamente, podrías hacer algo más complejo como esto:

typedef volatile uint8_t* SCI_port;
#ifndef SCI0
  #define SCI0 (&SCI0BDH)
  #define SCI1 (&SCI1BDH)
#endif

#define SCIBDH(x)   (*((SCI_port)x + 0x00))   /* SCI Baud Rate Register High             */
#define SCIBDL(x)   (*((SCI_port)x + 0x01))   /* SCI Baud Rate Register Low              */
#define SCICR1(x)   (*((SCI_port)x + 0x02))   /* SCI Control Register1                   */
#define SCICR2(x)   (*((SCI_port)x + 0x03))   /* SCI Control Register 2                  */
#define SCISR1(x)   (*((SCI_port)x + 0x04))   /* SCI Status Register 1                   */
#define SCISR2(x)   (*((SCI_port)x + 0x05))   /* SCI Status Register 2                   */
#define SCIDRH(x)   (*((SCI_port)x + 0x06))   /* SCI Data Register High                  */
#define SCIDRL(x)   (*((SCI_port)x + 0x07))   /* SCI Data Register Low                   */

Luego, al escribir su controlador, puede hacer esto:

void sci_init (SCI_port port, ...)
{
  SCICR1(port) = THIS | THAT;
  SCICR2(port) = SOMETHING_ELSE;
  ...
}

Esto es muy útil cuando tienes muchos periféricos idénticos en la MCU, con los mismos registros, pero solo quieres que un código los controle.

    
respondido por el Lundin
2

Primero ARM recomienda utilizando __packed para obtener el embalaje mínimo. En segundo lugar, si realmente necesita grandes huecos en su estructura (y estas no pueden ser dos estructuras por alguna razón), puede poner algo así como una matriz char[30] reserved1 en medio y así sucesivamente para las otras grandes lagunas. Asegúrate de poner los tamaños correctos para estos. Podría verificar dos veces con una afirmación de que el desplazamiento del siguiente campo realmente es donde usted piensa; offsetof () le dará el desplazamiento de un campo.

Escribí esto un poco apurado, si necesita más detalles, pregunte a continuación y expandiré (aunque no por un número de horas).

Por cierto, parece que TI ya ha escrito el archivo de encabezado en cuestión para ti. Parece que les gusta usar #define para todo.

    
respondido por el Fizz

Lea otras preguntas en las etiquetas