Перейти к содержанию
    

Как вы работаете с регистрами GPIOx_AFR?

а как этот правильный путь поможет задать альтернативные функции LPC? или право делать процы с альтернативными функциями пинов на арм ядре только у СТМ:)?

 

Если мне придётся снова работать с LPC'хами, буду делать библиотеку по образу и подобию.

Когда-то у меня был набор макросов (в принципе, то же самое - задавался порт, пин, режим пина), но эти хитрые шаблоны удобнее.

 

Варианты ЯadiatoR и AlanDrakes, которые прочитали даташит, явно неудобные. Пусть компилятор нужные смещения считает, он железный.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Инициализирую все выводы в одном месте init_GPIO()

	GPIOA->MODER = 0
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN0)	// ( 6) free
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN1)	// ( 7) free
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN2)	// ( 8) USART1_TX (console)
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN3)	// ( 9) USART1_RX (console)
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN4)	// (10) WORKLED
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN5)	// (11) free
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN6)	// (12) TIM3_CH1
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN7)	// (13) free
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN9)	// (17) TIM1_CH2
	| (GPIO_MODE_OUTPUT	<< GPIO_MODER_PIN10)	// (18) free
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN13)	// (19) SWDIO (debug)
	| (GPIO_MODE_ALTERNATE	<< GPIO_MODER_PIN14);	// (20) SWCLK (debug)

GPIOA->AFR[0] = 0
	| (AF_PA2_USART1_TX	<< GPIO_AFR0_PIN2)
	| (AF_PA3_USART1_RX	<< GPIO_AFR0_PIN3)
	| (AF_PA6_TIM3_CH1	<< GPIO_AFR0_PIN6);

GPIOA->AFR[1] = 0
	| (AF_PA9_TIM1_CH2	<< GPIO_AFR1_PIN9)
	| (AF_PA13_SWDIO 	<< GPIO_AFR1_PIN13)
	| (AF_PA14_SWCLK	<< GPIO_AFR1_PIN14);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Инициалиация в одном месте хорошо. Но иногда не прокатывает: при работе с встраиваемыми модулями (GSM и прочие) сразу инициализировать ноги нельзя, вначале надо подать на модуль питание. И, соотвественно, иницалиировать в третье состяоние при снятии питания.

Таким образом, инциализация ног происходит не разово, а постоянно в работе.

Для LPC и STM создан "drv_gpio"

 

Все регистры для установки ног вычиляются внутри функции IO_SetupPin(..)

С одной стороны, лишние накладные расходы, с другой - код намного читабельнее и понятнее.

Единстенное, что никак не стандартизируешь - вариант альтернативной конфиграции ноги. Тут уж придется лезть в даташит.

 

#ifndef __DRV_IOPORTS_H
 #define __DRV_IOPORTS_H

enum __pindirection {
 PIN_IN,
 PIN_OUT,
 PIN_ALTOUT
};

enum __pullupmode {
 ppullINACTIVE = 0,
 ppullDOWN,
 ppullUP,
 ppullREPEATER
};

enum __pinslew {
 pslewENABLED  = 0,
 pslewDISABLED = 1
};

enum __pinmode {
 pinNORMAL	 = 0,
 pinOPENDRAIN  = 1,
 pinANALOG	 = 2,
};

enum __pinfilter {
 pglfENABLED  = 0,
 pglfDISABLED = 1
};

enum __pinntest_res {
 PIN_OK,
 PIN_SHORTLOW,
 PIN_SHORTHIGH
};

#define pmANALOG	0
#define pmDIGITAL   1

#define PORTA	   A
#define PORTB	   B
#define PORTC	   C
#define PORTD	   D
#define PORTE	   E
#define PORTF	   F

#define PORTABASE   ((void*)&GPIOA_CRL)
#define PORTBBASE   ((void*)&GPIOB_CRL)
#define PORTCBASE   ((void*)&GPIOC_CRL)
#define PORTDBASE   ((void*)&GPIOD_CRL)
#define PORTEBASE   ((void*)&GPIOE_CRL)

#define _PORTBASE(port)  ((void*)&(GPIO ## port ## _CRL))

#define _PORTSET(port)  GPIO ## port ## _BSRR
#define _PORTCLR(port)  GPIO ## port ## _BRR
#define _PORTPIN(port)  GPIO ## port ## _IDR

#define PORTSET(port)   _PORTSET(port)
#define PORTCLR(port)   _PORTCLR(port)
#define PORTPIN(port)   _PORTPIN(port)
#define PINSET(port, pin)  _PORTSET(port) = BIT(pin)
#define PINCLR(port, pin)  _PORTCLR(port) = BIT(pin)
#define PINREAD(port, pin) (!!(_PORTPIN(port) & BIT(pin)))

#define PINSETUP(port, pin, dir, pu, pm, s, f) \
IO_SetupPin(_PORTBASE(port), pin, dir, pu, pm, s, f)

#define PINMODE(port, pin, mode)  

#define PINDIR(dir, port, pin) IO_PinDir(dir, port, (1UL << pin))


#ifdef __cplusplus
extern "C" {
#endif

void IO_Init(void);

void IO_SetupPin(void * portbase,
			 int pin,
			 enum __pindirection dir,
			 enum __pullupmode   pumode,
			 enum __pinmode	  pinmode,
			 enum __pinslew	  slewrate,
			 enum __pinfilter	filter);


enum __pinntest_res 
 IO_PinTest(int port, int pin);

void IO_PinDir(enum __pindirection dir, int port, unsigned long pinmask);

#ifdef __cplusplus
}
#endif


#endif //__DRV_IOPORTS_H

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если мне придётся снова работать с LPC'хами, буду делать библиотеку по образу и подобию.

Когда-то у меня был набор макросов (в принципе, то же самое - задавался порт, пин, режим пина), но эти хитрые шаблоны удобнее.

Года 3 назад делал библиотеку шаблонов для LPC 2119/2368/2468. Кому-то такие объявления могут показаться избыточными, но мне самому пользоваться очень нравилось.

CPU::WATCHDOGTIMER<> wdt( CPU::PLL::PeriodToTicks(10), CPU::WATCHDOGTIMER<>::DEBUG );

CPU::TIMER<0> ustimer( CPU::PLL::FreqToTicks(1000000) );
CPU::CALLBACKTIMER<1, MEASURETIMERCB, IRQP_MEASURETIMER> measuretimer( CPU::PLL::FreqToTicks(FADC) );

CPU::GPIO0::PINGROUP<0,2> _uartusb_rx_tx(1);
USBQUEYECLASS usbq(115200);

CPU::GPIO0::PINGROUP<8,2> _uartrs485_rx_tx(1);
CPU::GPIO0::PIN<10> uartrs485_txen(0, CPU::GPIO0::OUTPUT);
RS485QUEYECLASS rs485q(19200, 8, RS485QUEYECLASS::EVEN, 1);

CPU::GPIO1::PIN<23> disp_d7_busy(0, CPU::GPIO1::OUTPUT);
CPU::GPIO0::PIN<13> disp_rs(0, CPU::GPIO0::OUTPUT);
CPU::GPIO0::PIN<BUTTON1PIN, CPU::GPIO0::PININVERTED> button1_pressed(0, CPU::GPIO0::INPUT);

CPU::GPIO0::PIN<17> spi_sck(2);
CPU::GPIO0::PIN<18> spi_miso(2);
CPU::GPIO0::PIN<19> spi_mosi(2);
CPU::SPI<1> spi(2000000, CPU::SPI<1>::MASTER, CPU::SPI<1>::MSB, 16);

AD7656< CPU::SPI<1>, spi, CPU::GPIO0::PIN<5>, adc_st, CPU::GPIO0::PIN<20>, adc_cs1, CPU::GPIO0::PIN<3>, adc_busy1> adc_gen_out;
AD7656< CPU::SPI<1>, spi, CPU::GPIO0::PIN<5>, adc_st, CPU::GPIO0::PIN<4>, adc_cs2, CPU::GPIO0::PIN<7>, adc_busy2> adc_gen_excitation;

Естественно, пины можно и в рантайме перенастроить.

Сейчас выкладывать библиотеку стыдновато, я уже тогда хотел всё переделать =)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Дам ссылку на уже упомянутую в этой теме мою библиотеку для stm32: stm32tpl.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

GPIOB->AFR[1]|=0x0003; А вот так просто нельзя, просто глянуть в таблицу. Или нужно выпендросы с "простынями" кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#define GPIO_CAN_RX			XGPIO_DEF4('B', 8, 0, 9)
#define GPIO_CAN_TX			XGPIO_DEF4('B', 9, 0, 9)

...
  
	GPIO_set_mode_FUNCTION(GPIO_CAN_RX);
	GPIO_set_mode_FUNCTION(GPIO_CAN_TX);

...
  
#define XGPIO_DECODE(xGPIO)	\
	GPIO_TypeDef	*GPIO = (GPIO_TypeDef *) (GPIOA_BASE + 0x0400 * XGPIO_GET_PORT(xGPIO)); \
	int		N = XGPIO_GET_N(xGPIO);

void GPIO_set_mode_FUNCTION(int xGPIO)
{
	XGPIO_DECODE(xGPIO);

	MODIFY_REG(GPIO->AFR[(N > 7) ? 1 : 0], 15UL << ((N & 7) * 4),
			(XGPIO_GET_FUNC(xGPIO) & 0xF) << ((N & 7) * 4));

	MODIFY_REG(GPIO->MODER, 3UL << (N * 2), 2UL << (N * 2));
}

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 hours ago, Shalfey said:

GPIOB->AFR[1]|=0x0003; А вот так просто нельзя, просто глянуть в таблицу. Или нужно выпендросы с "простынями" кода.

Практиковал такое. Но пришел к выводу, что настройки Куба именно для пинов для меня более комфортны.

     GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
     GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
     GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
     GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
     GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
     GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
     LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

PS.Сейчас досмотрелся. Первый пост через 11 лет после регистрации в тему шестилетней давности! Однако...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/20/2015 at 9:24 AM, RadiatoR said:

 

В вашем случае так:

GPIOA->AFR[1]|=0x770;

Объясните пожалуйста, как сопоставляется этот код, а именно AFR[1] с тем что написано в RM (в частности на STM32F411(сопоставимо с STM32F405/STM32F407); информацию надо смотреть в двух документах?)

По Datasheet(?) смотрим маппинг на выводах PA9/PA10 для USART1. Это AF07.

По RM0090  смотрим биты для AF7 => 0111.

Но в даташите указан регистр GPIOA_AFRH, а у нас GPIOA->AFR[1].

Я так понимаю, что нехватает еще какогото документа :girl_wacko:

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, SDFV said:

GPIOA_AFRH, а у нас GPIOA->AFR[1]

Очевидно, GPIOA_AFRL соответствует GPIOA->AFR[0]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то аналогичное в голове крутится).

Но хотелось бы прочитать первоисточник.

Полгода назад разбирался с этим регистром на STM32F103, в каком то блоге. Тогда более менее стало понятно.

Теперь вот с STM32F4 опять возник данный вопрос...

У Cortex-M4 регистры только AFR[0] и AFR[1] ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, SDFV сказал:

У Cortex-M4 регистры только AFR[0] и AFR[1] ?

Это косяк STM. В документации эти регистры называются AFRL и AFRH, а в поставляемом заголовочном файле описаны как массив из двух регистров. Примите это как есть и не создавайте проблему там где её нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да обозвали всего лишь по-другому, не вижу проблем. С индексом массива код писать проще.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 10/20/2015 at 10:53 AM, GenaSPB said:

Или так...

        #define arm_stm32f30x_hardware_pio_altfn(gpio, opins, afn) \
            { \
                const portholder_t lo = power4((opins) >> 0); \
                const portholder_t hi = power4((opins) >> 8); \
                (gpio)->AFR [0] = ((gpio)->AFR [0] & ~ (lo * 0x0f)) | (lo * (afn)); \
                (gpio)->AFR [1] = ((gpio)->AFR [1] & ~ (hi * 0x0f)) | (hi * (afn)); \
            } while (0)

У меня такой вопрос "back to roots": в чём глубинный смысл { ... } while (0) вместо просто { ... } ? У меня и второй вариант всегда работал...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, KnightIgor said:

в чём глубинный смысл { ... } while (0) вместо просто { ... } У меня и второй вариант всегда работал...

 

Так не будет работать:

#define f() { ... }

if (cond)
	f();
else
	...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...