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: Mapas de registro . Estas pautas son similares a ARM CMSIS (Estándar de interfaz de software de microcontrolador de Cortex) para escribir código C.
Tengo un problema al escribir mapas de registro de control del sistema (consulte la sección 5.5, página 237 en adelante en la hoja de datos) usando la estructura C. Todos los registros tienen un tamaño de 32 bits.
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 puede ser demasiado simple, pero no sé cómo hacerlo.
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, con fines de alineación. Esto depende del compilador: debe asegurarse de que no se use relleno (por ejemplo, a través de una afirmación estática).
Además, es fácil cometer errores cuando se escriben estructuras grandes que se supone que deben reflejar un mapa de registro, tienes que acertar cada byte o romperás todo. Esto hace que la estructura sea vulnerable durante el mantenimiento.
Le sugiero encarecidamente que escriba mapas de registro a través de macros, 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 a 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 lo siguiente:
void sci_init (SCI_port port, ...)
{
SCICR1(port) = THIS | THAT;
SCICR2(port) = SOMETHING_ELSE;
...
}
Esto es muy útil cuando tiene muchos periféricos idénticos en la MCU, con los mismos registros, pero solo quiere un código para controlarlos.
__attribute__((packed))
static_assert(sizeof(mystruct) == sizeof(mystruct.obj1) + sizeofmystruct.obj2) + ..., "Struct padding detected");
En primer lugar, ARM recomienda usar __packed
para obtener el embalaje mínimo. En segundo lugar, si realmente necesita grandes espacios en su estructura (y estos no pueden ser dos estructuras por alguna razón), puede simplemente poner algo como una char[30] reserved1
matriz en el medio y así sucesivamente para los otros grandes espacios. Asegúrate de poner los tamaños correctos para estos. Puede verificar dos veces con una afirmación que el desplazamiento del siguiente campo realmente está donde piensa; offsetof() le dará el desplazamiento de un campo.
Escribí esto con un poco de prisa, si necesita más detalles, pregunte a continuación y lo ampliaré (aunque no por varias horas).
Por cierto, parece que TI ya ha escrito el archivo de encabezado en cuestión para usted. Parece que les gusta usar #define
para todo.
Majenko
señal_mixta_antigua
nurabha