cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to write/read the state of GPIOs (HIGH/LOW) in parallel?

Luis Ber
Associate II

Hello,

I'm working with a STM32F746 microcontroller and communicating with a external driver with a parallel bus of 16 bits of data and 4 bits of address.

I set the data to the parallel bus doing a sequencial write of the GPIOS of the ports involved on the bus. The code is the following:

static __INLINE void ParallelBus_msp_SetDataToParallel(uint16_t data)
{
	/*!< D15 */
	if ( ((data & 0x8000) >> 15) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_8;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_8 << 16;
	}		
	/*!< D14 */
	if ( ((data & 0x4000) >> 14) == GPIO_PIN_SET )
	{
		GPIOC->BSRR = GPIO_PIN_9;
	}
	else
	{
		GPIOC->BSRR = (uint32_t)GPIO_PIN_9 << 16;
	}	
	/*!< D13 */
	if ( ((data & 0x2000) >> 13) == GPIO_PIN_SET )
	{
		GPIOA->BSRR = GPIO_PIN_9;
	}
	else
	{
		GPIOA->BSRR = (uint32_t)GPIO_PIN_9 << 16;
	}		
	/*!< D12 */
	if ( ((data & 0x1000) >> 12) == GPIO_PIN_SET )
	{
		GPIOA->BSRR = GPIO_PIN_8;
	}
	else
	{
		GPIOA->BSRR = (uint32_t)GPIO_PIN_8 << 16;
	}	
	/*!< D11 */
	if ( ((data & 0x0800) >> 11) == GPIO_PIN_SET )
	{
		GPIOE->BSRR = GPIO_PIN_15;
	}
	else
	{
		GPIOE->BSRR = (uint32_t)GPIO_PIN_15 << 16;
	}
	/*!< D10 */
	if ( ((data & 0x0400) >> 10) == GPIO_PIN_SET )
	{
		GPIOC->BSRR = GPIO_PIN_6;
	}
	else
	{
		GPIOC->BSRR = (uint32_t)GPIO_PIN_6 << 16;
	}
	/*!< D9 */
	if ( ((data & 0x0200) >> 9) == GPIO_PIN_SET )
	{
		GPIOD->BSRR = GPIO_PIN_12;
	}
	else
	{
		GPIOD->BSRR = (uint32_t)GPIO_PIN_12 << 16;
	}	
	/*!< D8 */
	if ( ((data & 0x0100) >> 8) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_6;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_6 << 16;
	}	
	/*!< D7 */
	if ( ((data & 0x0080) >> 7) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_4;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_4 << 16;
	}		
	/*!< D6 */
	if ( ((data & 0x0040) >> 6) == GPIO_PIN_SET )
	{
		GPIOC->BSRR = GPIO_PIN_8;
	}
	else
	{
		GPIOC->BSRR = (uint32_t)GPIO_PIN_8 << 16;
	}		
	/*!< D5 */
	if ( ((data & 0x0020) >> 5) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_2;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_2 << 16;
	}		
	/*!< D4 */
	if ( ((data & 0x0010) >> 4) == GPIO_PIN_SET )
	{
		GPIOC->BSRR = GPIO_PIN_7;
	}
	else
	{
		GPIOC->BSRR = (uint32_t)GPIO_PIN_7 << 16;
	}			
	/*!< D3 */
	if ( ((data & 0x0008) >> 3) == GPIO_PIN_SET )
	{
		GPIOD->BSRR = GPIO_PIN_11;
	}
	else
	{
		GPIOD->BSRR = (uint32_t)GPIO_PIN_11 << 16;
	}		
	/*!< D2 */
	if ( ((data & 0x0004) >> 2) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_7;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_7 << 16;
	}		
	/*!< D1 */
	if ( ((data & 0x0002) >> 1) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_5;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_5 << 16;
	}		
	/*!< D0 */
	if ( ((data & 0x0001)) == GPIO_PIN_SET )
	{
		GPIOG->BSRR = GPIO_PIN_3;
	}
	else
	{
		GPIOG->BSRR = (uint32_t)GPIO_PIN_3 << 16;
	}	
}

The same procedure is done for the four bits of address.

I need to improve the speed of this writing because I'm losing a lot of time in these writings. It is a procedure that is executed in a loop in order to transmit the data to the driver.

Exists some way to perform a real parallel write of the GPIOS of the microcontroller? Is it also possible to read the bus in parallel?

Thank you in advance.

3 REPLIES 3
Pavel A.
Evangelist III

Yes, you can set and/or clear all 16 GPIOs of one "port" at once.

As @berendi advises, better use FMC for the bus.

-- pa

Create tmp variables, then write it them to each BSRR ONCE

A smarter move would have been to group in a single bank, in ideal bit order, that way you could shift/mask appropriately.

Condense stuff on to one or two banks, not FIVE

>>Exists some way to perform a real parallel write of the GPIOS of the microcontroller? Is it also possible to read the bus in parallel?

No, and No, this is a load/store architecture each operation is separate

On one GPIO bank you can read all in one operation, and write all in one operation.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
berendi
Principal

There are a couple of ways to improve it. The most efficient way were to use the FMC controller data and address pins instead, then everything would be handled automatically by the FMC contrioller. Runner-up is to rearrange all data pins to a single port in the same order, so that the data could be written directly to the GPIO data register.

However if you have already ordered 50000 PCBs, there are still a few tricks. Whether it would work or you have to ditch all of them and redesign depends on the required speed of the interface.

Of course it is possible to set as many bits of BSRR at once as you want. Also note that if both the reset and set bits for a pin are set in BSRR, the pin will be set to high. E.g.

uint32_t bsrr;
bsrr = (GPIO_PIN_12 | GPIO_PIN_11) << 16; // these pins will be either set or reset
bsrr |= (data & 0x0200) << (12 - 9); bit 9 is shifted to bit 12
bsrr |= (data & 0x0008) << (11 - 3); bit 3 is shifted to bit 11
GPIOD->BSRR = bsrr;

repeat this for the rest of the GPIO ports. GPIOG might deserve some special treatment in the form of a lookup table. 6 of the 7 bits affecting GPIOG are grouped in bits 0-8 of the data, the person responsible for this pinout should be punished by building the 512-element lookup table indexed by (data & 0x01A7).