Как передать битовое поле (по ссылке) функции?

#c #embedded #device-driver #microcontroller #bit-fields

#c #встроенный #драйвер устройства #микроконтроллер #битовые поля

Вопрос:

Мой вопрос заключается в том, как передать экземпляр битового поля по ссылке на функцию. Я выполнил это, как показано ниже, но когда я запускаю функцию DAC_set_gain_code, процессор выдает ошибку прерывания. Правильно ли то, что я делаю, в том, что касается передачи битового поля?

Я создал битовое поле (см. Ниже), которое представляет 24-битный регистр на микросхеме DAC, в который я хочу записать и который хранится в файле .h.

 typedef struct {
    uint8_t rdwr_u8:        1;
    uint8_t not_used_u8:    3;
    uint8_t address_u8:     4;
    uint8_t reserved_u8:    8;
    uint8_t data_u8:        8;
}GAIN_REG_st;
  

У меня есть функция, которая инициализирует битовое поле следующим образом:

 void init(void)
{
    GAIN_REG_st GAIN_x;  //Create instance of bitfield

    //other code here...

    DAC_set_gain_code(channel_u8, gain_code_i8, amp;GAIN_x);   //Pass address of bitfield

    return;
 }
  

Функция, которая фактически заполняет битовое поле, показана ниже:

 void DAC_set_gain_code(uint8_t channel_u8, int8_t gain_code_i8, GAIN_REG_st *GAIN)
{
    /* Populate ZERO_REG_st bitfield */
    GAIN->rdwr_u8       = 0;
    GAIN->not_used_u8 = 0;

    if(channel_u8==0){
        GAIN->address_u8 = GAIN_REGISTER_0;
    }
    else if(channel_u8==1){
        GAIN->address_u8 = GAIN_REGISTER_1;
    }
    else if(channel_u8==2){
        GAIN->address_u8 = GAIN_REGISTER_2;
    }
    else if(channel_u8==3){
        GAIN->address_u8 = GAIN_REGISTER_3;
    }

    GAIN->data_u8 = gain_code_i8;

    return;
}
  

Прототипом функции для hal_DAC_set_gain_code_uni является:

 void DAC_set_gain_code(uint8_t channel_u8, int8_t gain_code_i8, GAIN_REG_st *GAIN);
  

Приветствуется любой совет.

Спасибо.

Комментарии:

1. то, что вы опубликовали, возможно, не может быть скомпилировано, или вы не показываете, что вы на самом деле используете (несоответствие имен функций, не отображаются необъявленные переменные и / или глобальные переменные и неиспользуемые параметры)

2. все еще не получается. ZERO не определено в том, что вы опубликовали, и GAIN не используется в DAC_set_gain_code .

3. Извините за ошибки в сообщении. Теперь это должно совпадать с реальным кодом. Мой ГЛАВНЫЙ вопрос в том, правильно ли я передаю ссылку на битовое поле?

4. Мой код компилируется без ошибок, поэтому необъявленные переменные и несовпадения имен функций не являются проблемой.

5. ну, да, вы передаете указатель правильно (в C нет ссылок как таковых). Но опубликованный вами код по-прежнему отличается от того, что у вас есть (у GAIN нет имени элемента data_u16 . Вы уверены, что ваша программа умирает в этой функции, а не немного позже нее?

Ответ №1:

Поскольку реальное использование этого кода заключается в записи в аппаратный регистр, такие проблемы, как заполнение и выравнивание / упорядочение полей, ИМЕЮТ значение.

Я подозреваю, что компилятор использует 32-разрядные целые числа, и эта структура дополняется до 32 бит, но в самом отлаживаемом коде GAIN_X не является локальной переменной, вы передаете 0XNNNNNNNN (или эквивалент) — и адрес находится не на «правильной» границе (вполне возможно, поскольку это 24-разрядный регистр). Компилятор предположит, что вы передаете указатель на реальный адрес GAIN_REG_st, а не на адрес, определяемый типом, и поэтому, возможно, сделал предположения о выравнивании.

Чтобы получить доступ к оборудованию напрямую из C / C , вам нужно знать, как компилятор обрабатывает подобные вещи, и убедиться, что вы тщательно обманываете компилятор.

Ответ №2:

Может быть, это какая-то проблема с выравниванием?

Может быть, вы можете поиграть с параметрами выравнивания вашего компилятора? Или попробуйте заполнить вашу структуру фиктивным символом uint8 в конце?

Комментарии:

1. Но приведений нет, поэтому это не может быть проблемой выравнивания

2. Да, может возникнуть проблема с выравниванием. Когда дело доходит до битовых полей, C позволяет компилятору выходить из строя и выравнивать совершенно произвольными способами. Вы не можете знать, как выровнено битовое поле, или есть ли в его середине биты / байты заполнения, если вы не прочитали подробно документацию по серверной части компилятора. Существует также последовательность, порядок битов и т.д. и т.п.: бесчисленное множество неопределенных или определяемых реализацией действий. Лучшее решение — вообще не использовать битовые поля.

3. Когда я создаю экземпляр битового поля GAIN_REG_st GAIN_x и передаю его GAIN_x по ссылке, разве это не тот случай, когда я просто передаю указатель на битовое поле? Таким образом, использование выравнивания не будет проблемой, поскольку я фактически не перемещаю битовое поле в памяти?

4. Я не согласен с комментарием Лундина. Компилятор C должен быть в порядке с битовыми полями и передачей указателей на них. Комментарии Лундина могут быть применимы, если вы пытаетесь преобразовать битовые поля в / из других типов, таких как unsigned char массивы.

5. @Craig Судя по характеру этого битового поля, оно будет использоваться за пределами «необработанного логического буфера». Итак, все упомянутые проблемы могут существовать, а могут и не существовать.