2017-02-17 4 views
0

В настоящее время я пишу в C для STM32F446RE (ARM-компилятор), и поскольку я хочу получить опыт встроенного программирования, я не пользуюсь никакими библиотеками. Для моей инициализации мне было интересно, было бы неплохо получить доступ к регистрам, увеличив один указатель на смещение этого регистра с периферийной базы.Могу ли я получить доступ к нескольким регистрам устройств с помощью одного указателя?

void I2C_Init(void) 
    { 
     volatile uint32_t *reg_ptr = (uint32_t *) GPIOB_LOC; 
     *(reg_ptr + GPIOB_MODE_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating 
     *(reg_ptr + GPIOB_MODE_OFFSET) |= ((0xAU<<16) | (0xAU<<20));  //set pins 8, 9, 10, 11 to alt func 
     *(reg_ptr + GPIOB_OTYPE_OFFSET) &= ~(0xFU<<8); //no types 
     *(reg_ptr + GPIOB_OSPEED_OFFSET) &= ~((0xFU<<16) | (0xFU<<20)); //clear before updating 
     *(reg_ptr + GPIOB_OSPEED_OFFSET) |= ((0x5U<<16) | (0x5U<<20));  //set to normal speed (will get overriden by alt func) 
     *(reg_ptr + GPIOB_PUPD_OFFSET) &= ~((0xFU<<16) | (0xFU<<20));  //no pull up or pull down 
     *(reg_ptr + GPIOB_AFH_OFFSET) &= ~0xFFFFU; //clear before updating 
     *(reg_ptr + GPIOB_AFH_OFFSET) |= 0x4444U;  //set pins 8, 9, 10, 11 to alt func 4 (i2c1 & i2c2 SCL and SDA respectively) 
    } 

В моем файле заголовка:

#define GPIOB_LOC  0x40020400UL //base 
    #define GPIOB_MODE_OFFSET (0x00) 
    #define GPIOB_OTYPE_OFFSET (0x04) 
    #define GPIOB_OSPEED_OFFSET (0x08) 
    #define GPIOB_PUPD_OFFSET (0x0C) 
    #define GPIOB_AFH_OFFSET (0x24) 

небезопасным ли эта практика? Есть ли лучший, более общепринятый способ доступа к нескольким регистрам устройств без накладных расходов на создание указателя для каждого конкретного регистра?

Спасибо, ребята! Это мой первый пост, так что дайте мне знать, есть ли что-нибудь, что я могу сделать, чтобы улучшить мой вопрос или любую дополнительную информацию, которая была бы полезной.

+1

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

+3

Вы должны быть осторожны при добавлении смещения к адресу (указателю?) В C. Если вы добавите 4 к значению от указателя к 32 биту, компилятор добавит 16. Арифметика указателя работает так же, как индексирование элемента массива, то есть он учитывает размер элемента. –

+1

Зачем вам это делать, а затем использовать заголовок stm32f4xx.h, предоставленный ST? Гораздо меньше подвержено ошибкам, полному и простому. – Clifford

ответ

1

Если смещения байт -на основе, это не безопасный.

Добавление что-то вроде 0x04 к uint32_t *reg_ptr вызовет полученный адрес для ссылки на смещение, которое в четыре uint32_t значения больше, чем то, что в reg_ptr - не четыре байта больше.

Например, добавление 0x04 к значению uint32_t * указателя 0x40020400UL приведет к фактическому значению указателя 0x40020410UL и НЕ ожидаемый 0x40020404UL.

+0

Вы не хотите говорить * не сохранять *, а скорее * неправильно * – tofro

+0

@tofro Ну, вопрос сформулирован как * «Является ли эта практика небезопасной?» * –

+0

Тогда ответ будет «нет». Это только неправильно. " :) – tofro

Смежные вопросы