Autor Tema: [C] Escribir/Leer campos de bits de un registro de un IC.  (Leído 3014 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
[C] Escribir/Leer campos de bits de un registro de un IC.
« en: 21 de Septiembre de 2017, 23:55:32 »
Que tal,
Estoy comunicándome por SPI con un integrado, los registros de configuración del IC son de 8bits, algunos de los registros tienen campos de configuración de varios bits y no he podido implementar funciones que lean y escriban en esos campos.

Tengo pseudo código pero no se si es correcto, tengo dudas en como calcular la variable *mask*.

Para calcular *mask*:
Según lo veo se recorren *len* bits (en 1 lógico) *lsb* (least significant bit) posiciones a la izquierda, no se como hacer para obtener esos bits en 1 lógico en *mask*.

Ejemplo:
Para un campo de bits que se compone de dos bits y tiene el lsb en la posición 2, se calcula el siguiente valor de *mask*:
const uint8_t mask = 0b0000_1100; // lo puse en bits para que se vean los bits individuales
- el primer bit en 1 lógico de derecha a izquierda esta en la posición 2 (lsb=2)
- a partir de ese bit se tienen dos bits en 1 (len=2)

para leer un campo de bits:
Código: [Seleccionar]
uint8_t read_bitfield(const uint8_t register, const uint8_t lsb, const uint8_t len)
{
    // const uint8_t mask = 0b0000_1100;
    uint8_t mask = 0x0C;
   
    // leemos el contenido del registro del IC
    uint8_t temp_reg = read_register(register);

    // 'multiplicamos' el contenido actual del registro con la mascara
    // los bits que no nos interesan (todos los 0's en *mask*) se volveran 0, solo manteniendo
    // intactos los bits que valen 1 en *mask*
    temp_reg = temp_reg & mask;

    // recorremos temp_reg *len* posiciones a la derecha
    // porque solo nos interesa el valor del 'campo'
    return temp_reg >> len;
}

para escribir un campo de bits:
Código: [Seleccionar]
uint8_t write_bitfield(const uint8_t register, const uint8_t val, const uint8_t lsb, const uint8_t len)
{
    // const uint8_t mask = 0b0000_1100;
    uint8_t mask = 0x0C;
   
    // leemos el contenido del registro del IC
    uint8_t temp_reg = read_register(register);

    // multiplicando temp_reg con el inverso de mask
    // se mantendran intactos los bits que no queremos modificar (1's en *mask* invertido) y
    // ponemos se pondran en 0 el campo de bits que pretendemos escribir (0's en *mask* invertido)
    temp_reg = temp_reg & (~(mask));

    // recorremos a la izquierda el valor que queremos escribir *len* posiciones y lo escribimos en temp_reg
    temp_reg = temp_reg | (val << len);
   
    // escribimos el nuevo temp_reg al registro del IC
    write_register(reg, temp_reg);
}

¿alguna forma con la cual pueda calcular la variable *mask*?
¿algun consejo con respecto al pseudo código?

Saludos
Carlos

Desconectado Geo

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 922
    • Mexchip
Re:[C] Escribir/Leer campos de bits de un registro de un IC.
« Respuesta #1 en: 22 de Septiembre de 2017, 04:09:18 »
¿alguna forma con la cual pueda calcular la variable *mask*?
Una posible forma:
Código: C
  1. uint8_t calc_mask(const uint8_t lsb, const uint8_t len)
  2. {
  3.     uint8_t mask = 0;
  4.  
  5.     for (int i = lsb; i < lsb + len; i++) {
  6.         mask |= (1 << i);
  7.     }
  8.  
  9.     return mask;
  10. }

¿algun consejo con respecto al pseudo código?
en la función write_bitfield deberías asegurarte de que el argumento val contiene un valor que en efecto sea representable solamente por len bits, de otra forma corres riesgo de que alteres otros bits que no se espera sean afectados.
La imaginación es el límite.
Visita mi blog, en inglés o en español :).
Mini curso de introducción a VHDL en MEXCHIP :-/

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:[C] Escribir/Leer campos de bits de un registro de un IC.
« Respuesta #2 en: 22 de Septiembre de 2017, 10:07:08 »
Disculpa Carl pero no entiendo que estas intentando hacer. Me refiero a hacer todo eso. Por ahora voy a seguir tu codigo, luego te digo lo que pienso que para mi seria lo mas simple.

Citar
¿alguna forma con la cual pueda calcular la variable *mask*?
Te doy otra opcion ademas de la que te dio Geo.

Código: C
  1. uint8_t calc_mask[8] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF};
  2.  
  3. if(len > 7) len = 7; // Proteccion
  4. calc_mask[len];

Citar
¿algun consejo con respecto al pseudo código?
Como te decia al comienzo, te comento el porque decia antes eso.

¿Por que lo digo?
Supongamos por un momento que tengamos un IC con registros de 8bits y quisieramos obtener el estado de 1 o 2 de los bits. Primero lo que haria es una funcion que simplemente lea el registro completo sin ninguna mascara. Luego crearia un par de #define con los bits de interes
Quiero saber de algun bit?, supongamos que el bit se llama DONE, registro STATUS, integrado ADS9999 (inventado)

Funcion de lectura:
Código: C
  1. uint8_t ADS9999_Read(uint8_t RegisterAddress)
  2. {
  3.     // Simplemente leer el registro completo y nada mas
  4. }

En el .h de la libreria del ADS
Código: C
  1. #define ADS9999_STATUS_BASE     0x84
  2. #define ADS9999_STATUS_DONE    0x08
Para saber si ese bit esta activo:

Código: C
  1. if ( ADS9999_Read(ADS9999_STATUS_BASE) & ADS9999_STATUS_DONE )
  2. {
  3.     // aca dentro detectado
  4. }

En tu codigo,

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
Re:[C] Escribir/Leer campos de bits de un registro de un IC.
« Respuesta #3 en: 22 de Septiembre de 2017, 14:08:51 »
Disculpa Carl pero no entiendo que estas intentando hacer. Me refiero a hacer todo eso. Por ahora voy a seguir tu codigo, luego te digo lo que pienso que para mi seria lo mas simple.

Citar
¿alguna forma con la cual pueda calcular la variable *mask*?
Te doy otra opcion ademas de la que te dio Geo.

Código: C
  1. uint8_t calc_mask[8] = {0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF};
  2.  
  3. if(len > 7) len = 7; // Proteccion
  4. calc_mask[len];

Citar
¿algun consejo con respecto al pseudo código?
Como te decia al comienzo, te comento el porque decia antes eso.

¿Por que lo digo?
Supongamos por un momento que tengamos un IC con registros de 8bits y quisieramos obtener el estado de 1 o 2 de los bits. Primero lo que haria es una funcion que simplemente lea el registro completo sin ninguna mascara. Luego crearia un par de #define con los bits de interes
Quiero saber de algun bit?, supongamos que el bit se llama DONE, registro STATUS, integrado ADS9999 (inventado)

Funcion de lectura:
Código: C
  1. uint8_t ADS9999_Read(uint8_t RegisterAddress)
  2. {
  3.     // Simplemente leer el registro completo y nada mas
  4. }

En el .h de la libreria del ADS
Código: C
  1. #define ADS9999_STATUS_BASE     0x84
  2. #define ADS9999_STATUS_DONE    0x08
Para saber si ese bit esta activo:

Código: C
  1. if ( ADS9999_Read(ADS9999_STATUS_BASE) & ADS9999_STATUS_DONE )
  2. {
  3.     // aca dentro detectado
  4. }

En tu codigo,
Hola, y si, me re complique la vida, haciendo lo que propones (leer el registro y hacer & con algun valor ya establecido) es mucho más fácil, así no tengo que añadir más funciones a la librería, sólo algunos define.

Gracias por la idea
Carlos

Desconectado Carl47D

  • PIC16
  • ***
  • Mensajes: 160
Re:[C] Escribir/Leer campos de bits de un registro de un IC.
« Respuesta #4 en: 22 de Septiembre de 2017, 14:12:38 »
¿alguna forma con la cual pueda calcular la variable *mask*?
Una posible forma:
Código: C
  1. uint8_t calc_mask(const uint8_t lsb, const uint8_t len)
  2. {
  3.     uint8_t mask = 0;
  4.  
  5.     for (int i = lsb; i < lsb + len; i++) {
  6.         mask |= (1 << i);
  7.     }
  8.  
  9.     return mask;
  10. }

¿algun consejo con respecto al pseudo código?
en la función write_bitfield deberías asegurarte de que el argumento val contiene un valor que en efecto sea representable solamente por len bits, de otra forma corres riesgo de que alteres otros bits que no se espera sean afectados.
Hola,
En efecto parece que la función para calcular mask es correcta pero como dice Killer lo que pensaba hacer es complicarse de más, igualmente tendría que validar todos los parámetros comome recomiendas al final, gracias por la ayuda.

Saludos
Carlos