Отображение памяти периферийных регистров с использованием массива указателей - PullRequest
0 голосов
/ 04 октября 2018

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

Я немного запутался в отображении памяти

Из этого post , если 8-битная память отображается в 0X123, тогда я могу использовать следующие

uint8_t volatile * p_reg = (uint8_t volatile *) 0x1234;

или

#define PORT 0X1234
uint8_t volatile * p_reg = (uint8_t volatile *) PORT;

или в случае массива указателей

#define PORT 0X1234
uint8_t volatile * const portsout[NUM_PORTS] =
    {
        (uint8_t*)PORTB, ....,
    };

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

uint8_t volatile * const portsout[NUM_PORTS] =
{
    (uint8_t*)&PORTB, (uint8_t*)&PORTC, (uint8_t*)&PORTD,
};

PORTB определен в заголовочном файле "avr / io.h"как это

#define PORTB   _SFR_IO8 (0x05)

Что я не понимаю, так это необходимость & в массиве указателей ??

Когда у меня возникла ошибка компиляции при использовании lpc2148, я отправляюписьмо автору и в своем ответном письме он упомянул

Тогда похоже, что ваши массивы указателей на самом деле не могут быть указателями.Например:

(uint32_t *) и IOPIN0, (uint32_t *) и IOPIN1,

могут фактически быть

(uint32_t *) IOPIN0, (uint32_t *) IOPIN1,

в зависимости от того, как IOPIN0 и IOPIN1 определены для вашей части

Макрос IOPIN0 для lpc2148 равен

#define IOPIN0          (*((volatile unsigned long *) 0xE0028000))

У меня нет большого опыта в C. Я знаюесли макрос ссылается на память, мне не нужно использовать & при определении массивов указателей.Как я могу знать, если макрос (например: PORTB, IOPIN0) ссылается на адрес или значение ??

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

При написании карт регистров обычно это делается с помощью метода, который оставляет регистры так же, как если бы они были переменными:

#define REGISTER (*(volatile uint8_t*)0x1234)

, где левый * разыменовывает указанный адрес,Это означает, что теперь вы можете использовать REGISTER, как и любую обычную переменную.Вот почему вы должны написать &PORTB, который после раскрытия макроса заканчивается как &*pointer.И это гарантированно эквивалентно pointer, C (c17 6.5.3.2):

Унарный оператор & выдает адрес своего операнда./ - /
Если операнд является результатом унарного * оператора, ни этот оператор, ни оператор & не оцениваются, и результат такой, как если бы оба опущены

Что касается if & нужен или нет, он действительно зависит от того, как регистры определены в карте регистров.Который должен быть доступен в виде заголовочного файла, который вы можете проверить, независимо от системы.

Как примечание: ваши приведения являются подозрительными.(uint8_t*)&PORTB не должно быть нужно.Это говорит о некотором несоответствии квалификатора volatile и const.В общем, всегда можно перейти от указателя к уточненному указателю, но не наоборот.

На основе вашего примера с IOPIN0 код должен выглядеть примерно так:

volatile uint32_t*const portsout [NUM_PORTS] =
{
  &IOPIN0, ...
};
0 голосов
/ 04 октября 2018

определяет для C что-то вроде этого:

#if __AVR_ARCH__ >= 100
#    define __SFR_OFFSET 0x00
#else
#    define __SFR_OFFSET 0x20
#endif

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define PORTB   _SFR_IO8(0x05)

Это означает, что PORTB расширяется до чего-то вроде:

// presuming __AVR_ARCH__ >= 100
(*(volatile uint8_t *)(0x05 + 0x00))

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

volatile uint8_t * p = &PORTB;
...