Советы по переопределению регистров битового поля в C - PullRequest
3 голосов
/ 06 апреля 2010

Я изо всех сил пытаюсь найти чистый способ переопределить некоторые битовые поля регистров для использования на чипе, с которым я работаю.

Например, это то, что один из регистров конфигурации CAN определяется как:

extern volatile near unsigned char       BRGCON1;
extern volatile near struct {
  unsigned BRP0:1;
  unsigned BRP1:1;
  unsigned BRP2:1;
  unsigned BRP3:1;
  unsigned BRP4:1;
  unsigned BRP5:1;
  unsigned SJW0:1;
  unsigned SJW1:1;
} BRGCON1bits;

Ни одно из этих определений не является настолько полезным, поскольку мне нужно назначить BRP и SJW следующим образом:

struct
{
    unsigned BRP:6;
    unsigned SJW:2;
} GoodBRGbits;

Вот две попытки, которые я сделал:

Попытка # 1:

union
{
    byte Value;
    struct
    {
        unsigned Prescaler:6;
        unsigned SynchronizedJumpWidth:2;
    };    
} BaudRateConfig1 = {NULL};
BaudRateConfig1.Prescaler = 5;
BRGCON1 = BaudRateConfig1.Value;

Попытка № 2:

static volatile near struct
{
    unsigned Prescaler:6;
    unsigned SynchronizedJumpWidth:2;
} *BaudRateConfig1 = (volatile near void*)&BRGCON1;
BaudRateConfig1->Prescaler = 5;

Существуют ли "более чистые" способы достижения того, что я пытаюсь сделать? Кроме того, я немного раздражен из-за изменчивого ближнего кастинга в «Попытке № 2». Нужно ли указывать переменную рядом?

Ответы [ 2 ]

2 голосов
/ 06 апреля 2010

Лично я стараюсь избегать использования битовых полей по причинам переносимости. Вместо этого я склонен использовать битовые маски, чтобы я мог явно контролировать, какие биты используются.

Например (при условии, что порядок битов правильный) ...

#define BRP0  0x80
#define BRP1  0x40
#define BRP2  0x20
#define BRP3  0x10
#define BRP4  0x08
#define BRP5  0x04
#define SJW0  0x02
#define SJW1  0x01

Маски могут быть сгенерированы соответствующим образом, а значения могут быть назначены, прочитаны или протестированы Вы можете выбрать лучшие имена для макросов.

Надеюсь, это поможет.

1 голос
/ 06 апреля 2010

Я предлагаю, чтобы вы не смешивали объявление битового поля с адресом аппаратного регистра.

Ваш union / struct объявляет, как расположены битовые поля, затем вы указываете адресацию и ограничения доступа при объявлении указателя натакая структура.

// foo.h
// Declare struct, declare pointer to hw reg

struct com_setup_t {
  unsigned BRP:6;
  unsigned SJW:2;
};

extern volatile near struct com_setup_t *BaudRateConfig1;

// foo.c
// Initialise pointer

volatile near struct com_setup_t *BaudRateConfig1 = 
(volatile near struct com_setup_t *)0xfff...;

// access hw reg
foo() {
  ...
  BaudRateConfig1->BRP = 3;
  ...
}

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

...