Registros estructurados en bits para hardware integrado

1

Así que diseñé una pieza de hardware que tiene un microcontrolador Atmega168pa que se comunica con un IC externo a través de un bus SPI. El dispositivo externo tiene algunos registros, con bits de hardware asignados.

Estoy buscando una manera de manipular fácilmente estos datos de bits estructurados en el Atmega. La primera solución obvia es un campo de bits, pero no he tenido mucho éxito.

El objetivo es tratar de asignar esto a 3 bytes para que pueda:
A) acceder a los datos de manera simple, por ejemplo, n_reg.b_counter = 230
B) Escriba este byte a byte de datos estructurados con una función de tipo spi_write(uint_8t) . Obviamente, esto tendría que iterar a través de los tres bytes, tal vez con algún tipo de índice.

Lo que he intentado hasta ahora:

struct PLL_N_REG 
{
    uint32_t control_bits : 2;
    uint32_t a_counter : 5;
    uint32_t reserved : 1;
    uint32_t b_counter : 13;
    uint32_t cp_gain : 1;
    uint32_t div_by_2 : 1;
    uint32_t div_by_sel : 1;
};

struct PLL_N_REG n_reg;
n_reg.div_by_sel = 1;
n_reg.b_counter = 230;
n_reg.control_bits = 2;

Esto cumple con el objetivo A , ya que es de fácil acceso, pero no sé cómo agarraría fácilmente cada byte para enviar a la función spi_write(uint8_t) .

He intentado hacer algo similar con proyectos de hardware en el pasado, pero terminé usando soluciones alternativas. Me gustaría un método que pueda aplicar fácilmente a cualquier hardware que necesite implementar. Todos los otros ejemplos que he encontrado han sido para mapear registros de hardware internos del microcontrolador.

Muchas gracias de antemano!

    
pregunta RabidAlpaca

2 respuestas

3

Desafortunadamente, el estándar C no garantiza que su estructura tenga el mismo tamaño que un uint32_t , ya que no es necesario que los campos de bits se almacenen de forma compacta. Incluso si lo fueran, todavía tienes que descubrir en cuál de los 32 bits estás interesado. ¿Los primeros 24? Últimos 24? En algún lugar en el medio (poco probable, pero posible)? Esto no es portátil.

Si está de acuerdo con el impacto de rendimiento, puede escribir una función auxiliar que empaquetará los componentes constituyentes para usted.

uint32_t pll_n_reg_pack(PLL_N_REG field)
{
    uint32_t res = n_reg.control_bits;
    res |= n_reg.a_counter << 2;
    res |= n_reg.reserved << 7;
    res |= n_reg.b_counter << 8;
    res |= n_reg.cp_gain << 21;
    res |= n_reg.div_by_2 << 22;
    res |= n_reg.div_by_sel << 23;
    return res;
}

Si el rendimiento es crítico y el compilador no puede optimizar esto, es posible que desee considerar trabajar con un uint32_t (o uint8_t[3] ) sin procesar y localizar el código de manera que el desplazamiento / enmascaramiento de bits sea limitado.

Más información útil:

respondido por el helloworld922
1

Puedes convertir la dirección de tu objeto de estructura a un uint8_t * como este.

struct PLL_N_REG n_reg;
uint8_t * ptr = (uint8_t*)&n_reg;

Si spi_write() toma realmente un uint8_t , llámalo así.

int byte;
for (byte = 0; byte < 3; byte++)
{
    spi_write(*ptr);
    ptr++;
}

O si spi_write() toma uint8_t* en lugar de llamarlo así.

int byte;
for (byte = 0; byte < 3; byte++)
{
    spi_write(ptr);
    ptr++;
}
    
respondido por el kkrambo

Lea otras preguntas en las etiquetas