GPIO registers and port manipulation

Post your cool example code here.
atacanteknik
Posts: 4
Joined: Mon May 08, 2017 4:23 am

Re: GPIO registers and port manipulation

Post by atacanteknik » Tue May 09, 2017 12:50 pm

how i add on integer port read like that

int state = DDRC & B00000011;

and write
DDRC = state | (bx<<5) | (by<<2);

edogaldo
Posts: 263
Joined: Fri Jun 03, 2016 8:19 am

Re: GPIO registers and port manipulation

Post by edogaldo » Tue May 09, 2017 8:11 pm

atacanteknik wrote:how i add on integer port read like that

int state = DDRC & B00000011;

and write
DDRC = state | (bx<<5) | (by<<2);
DDRx is the data direction register in AVRs; DDRx+PORTx in AVRs are almost the equivalent of GPIOx_CRH/CRL in STMs; details on how they work are specified in previous posts of the thread and in the related reference manuals.

dannyf
Posts: 140
Joined: Wed May 11, 2016 4:29 pm

Re: GPIO registers and port manipulation

Post by dannyf » Fri Jun 16, 2017 12:06 am

atacanteknik wrote:how i add on integer port read like that
it depends on your coding style.

I used a set of routines across 8/16/32-bit families.

Code: Select all

#define IO_SET(port, pins)  port |= (pins)  //set pins on port
#define IO_CLR(port, pins)  port &=~(pins)  //clear pins on port
#define IO_FLP(port, pins)  port ^= (pins)  //flip pins on port
#define IO_GET(port, pins) ((port) & (pins))  //read pins on port
so in your example, it would be something like this:

Code: Select all

  if (IO_GET(BTN_PORT, BTN)) IO_SET(RELAY_PORT, RELAY0);
  else IO_FLP(RELAY_PORT, RELAY1);
if BTN reads high, it set RELAY0;
if BTN reads low, it flips RELAY1.

Once you implement a set of routines like that on your target chip, your user code would compile and work as expected, making it immensely portable and debug much easier.

Ollie
Posts: 189
Joined: Thu Feb 25, 2016 7:27 pm

Re: GPIO registers and port manipulation

Post by Ollie » Fri Jun 16, 2017 8:57 am

If your application is using interrupts that could manipulate the target GPIO ports, the read-modify-write operation is not safe. That is the reason, why STM has designed BSRR registers to set and reset selected pins.

The monotonic pin manipulations can be done with macros

#define gpio_clear(GpioPort, GpioPins) GpioPort->BSRR = ((GpioPins) << 16)
#define gpio_set(GpioPort, GpioPins) GpioPort->BSRR = (GpioPins)

These are the fastest way to do GPIO pin updates.

erinqvnm
Posts: 2
Joined: Thu May 18, 2017 12:02 pm

Re: GPIO registers and port manipulation

Post by erinqvnm » Fri Sep 15, 2017 7:49 am

Hi, thanks for good explanation. Tried in my STM32F103 to increase bit-bang frequency instead of using digitalWrite. With a simple benchmarking:

Code: Select all

unsigned long time = micros();
for (uint32_t i = 0; i < 1000000; i++) {
	GPIOA->regs->BSRR = 0b0000000000000001;
	GPIOA->regs->BRR = 0b0000000000000001;
}
time = micros() - time;
Total time = 111190 us or ~9MHz. Which is close to 10MHz, so i think it was at speed mode '10'. Then i tried change to mode '11' (50Mhz max) to achieve higher frequency:

Code: Select all

GPIOA->regs->CRL = (GPIOA->regs->CRL & 0xFFFFFFF0) | 0x00000003;
unsigned long time = micros();
for (uint32_t i = 0; i < 1000000; i++) {
	GPIOA->regs->BSRR = 0b0000000000000001;
	GPIOA->regs->BRR = 0b0000000000000001;
}
time = micros() - time;
But, the total time now is 1250791us or ~8MHz, it just get worse. Changing to other modes gives the same result as before (~9MHz). Is there anything i did wrong?

dannyf
Posts: 140
Joined: Wed May 11, 2016 4:29 pm

Re: GPIO registers and port manipulation

Post by dannyf » Fri Sep 15, 2017 12:51 pm

the CRL settings are just for current drive capabilities.

the two measurements you got should be identical. the variation you saw is likely due to other factors and may go away if you run multiple trials.

edit:

as a test, I ran the following, to flip a pin using BSRR/BRR and tested speed for 1 million flips on a 48Mhz F103.

Code: Select all

int main(void) {
	int i;

	mcu_init();									//reset the  mcu
	//systick_init();
	coretick_init();							//reset coretick

	//initialize the pins to outout
	IO_OUT(LED_PORT, LED1 | LED2);				//led1/2 as output @ 10Mhz
	GPIO_DDR(LED_PORT, LED1 | LED2, 0x03);		//led1/2 as output @ 50Mhz
	IO_CLR(LED_PORT, LED1 | LED2);

	ei();										//enable global interrupts
	while (1) {
		time0 = coreticks();							//time stamp
		for (tmp=0; tmp < 1000000ul; tmp++) {FIO_SET(LED_PORT, LED2); FIO_CLR(LED_PORT, LED2);}
		time0 = coreticks() - time0;
		NOP();
	};
}
I got consistently 32M ticks regardless of the MODE settings.

compiler optimization settings impact the absolute speed but not the speed differentials between the two MODE settings, just as expected.

Post Reply