cancel
Showing results for 
Search instead for 
Did you mean: 

Quickest way to set multiple port pins

JReed.1856
Associate II

Hi,

I am trying to connect to a 16 bit parallel display interface. To write new data, I have to use pins on five different ports (GPIOs A, B, C, D, E). Right now I am setting these pins like this:

PORT_D15->BSRR = (PIN_D15 << 16) |  (((data >> 15) & 0x01) * PIN_D15) ;

repeat for all other 15 pins.

This is causing the display to update slowly, you can see the screen 'rolling in' from the top.

On a previous controller all pins were in one port, and one access to

PORT_DISPLAY->ODR

was enough to set all pins.

Is there a quicker way to set all those port pins?

18 REPLIES 18

mask is a constant, so no need to AND it.

But yes, you are right, data would need to be masked with the same mask. Okay, so that's one more AND.

Still, the negation, masking AND and left-shift for the BRx portion would be spared down.

JW

Thanks, Jan. That indeed was a "typo" - initial version was a bit different, I edited it and left the wrong operator. Fixed it now.

By the way, the code will work even if mask is not a constant, but of course there will be an additional shift operation done at runtime.

If the data variable can have non-display bits set, then indeed you have to do it, but that's and additional operation. As you are asking for quickest way, it's better to ensure the data variable only uses the display related bits.

Actually the absolute quickest way is the one suggested by user ".". Lock the non-display pins at the port and just write data to ODR register. Sorry, this is also wrong because locking lock only the configuration registers, not data registers. Reference manual:

The frozen registers are GPIOx_MODER, GPIOx_OTYPER, GPIOx_OSPEEDR, GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH.

JReed.1856
Associate II

I just tried to implement it and I think this approach overlooks the fact, that my pins are not in order.

So lets say, the used display pins on GPIOC are on PC2, PC7, PC12, however PC2 has Bit4, PC7 has Bit12 and PC12 has Bit9 of the parallel data to be written.

masking GPIOC->BSRR works for the higher reset pins, but when it comes to setting, I can't see a way to mask the data, so that the pins are set correctly right away.

To me it seems there still has to be the assignment of pins like in TDKs answer.

So this would only work if PC2 was databit2, PC7 data bit 7 and PC12 bit 12.

Store data in memory with bits in the order of display.

Or...

...you can increase your pain...

JW

unfortunately also not possible since PC12 has bit9 and PB12 has bit 15.

only way would be to have separate data arrays for every port and that would require getting those from the original data variable, which would be just as costly as the usual bit shifts.

It seems increasing my pain is the only outcome here

Post the exact layout and your current solution together with disasm (mixed with source would be the best), with some benchmark.

JW

JReed.1856
Associate II

So the subjectively quickest way looks like this:

pin defines

#define ILI9341_PORT_D0          GPIOB
#define ILI9341_PORT_D1          GPIOE
#define ILI9341_PORT_D2          GPIOE
#define ILI9341_PORT_D3          GPIOB
#define ILI9341_PORT_D4          GPIOC
#define ILI9341_PORT_D5          GPIOA
#define ILI9341_PORT_D6          GPIOB
#define ILI9341_PORT_D7          GPIOD
#define ILI9341_PORT_D8          GPIOD
#define ILI9341_PORT_D9          GPIOC
#define ILI9341_PORT_D10         GPIOC		//changed, orig GPIOA
#define ILI9341_PORT_D11         GPIOA
#define ILI9341_PORT_D12         GPIOC
#define ILI9341_PORT_D13         GPIOB
#define ILI9341_PORT_D14         GPIOB
#define ILI9341_PORT_D15         GPIOB
 
#define ILI9341_PIN_D0          GPIO_PIN_11
#define ILI9341_PIN_D1          GPIO_PIN_11
#define ILI9341_PIN_D2          GPIO_PIN_9
#define ILI9341_PIN_D3          GPIO_PIN_2
#define ILI9341_PIN_D4          GPIO_PIN_2
#define ILI9341_PIN_D5          GPIO_PIN_0
#define ILI9341_PIN_D6          GPIO_PIN_4
#define ILI9341_PIN_D7          GPIO_PIN_7
#define ILI9341_PIN_D8          GPIO_PIN_4
#define ILI9341_PIN_D9          GPIO_PIN_12
#define ILI9341_PIN_D10         GPIO_PIN_11
#define ILI9341_PIN_D11         GPIO_PIN_8
#define ILI9341_PIN_D12         GPIO_PIN_7
#define ILI9341_PIN_D13         GPIO_PIN_13
#define ILI9341_PIN_D14         GPIO_PIN_14
#define ILI9341_PIN_D15         GPIO_PIN_12
static uint8_t ili9341_Write(uint16_t data) {
	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
				(ILI9341_PIN_D11 << 16) >>  (((data >> 11) & 0x01) * 16);
 
	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
					(ILI9341_PIN_D0 << 16) >>  (((data >> 0) & 0x01) * 16) |
					(ILI9341_PIN_D6 << 16) >>  (((data >> 6) & 0x01) * 16) |
					(ILI9341_PIN_D13 << 16) >>  (((data >> 13) & 0x01) * 16) |
					(ILI9341_PIN_D14 << 16) >>  (((data >> 14) & 0x01) * 16) |
					(ILI9341_PIN_D15 << 16) >>  (((data >> 15) & 0x01) * 16);
 
	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
					(ILI9341_PIN_D9 << 16) >>  (((data >> 9) & 0x01) * 16) |
					(ILI9341_PIN_D10 << 16) >>  (((data >> 10) & 0x01) * 16) |
					(ILI9341_PIN_D12 << 16) >>  (((data >> 12) & 0x01) * 16);
 
	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
					(ILI9341_PIN_D7 << 16) >>  (((data >> 7) & 0x01) * 16);
 
	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
					(ILI9341_PIN_D2 << 16) >>  (((data >> 2) & 0x01) * 16);
 
	ILI9341_PORT_WR->BSRR = (ILI9341_PIN_WR << 16)
			| (ILI9341_WR_LOW * ILI9341_PIN_WR);
	ILI9341_PORT_WR->BSRR = (ILI9341_PIN_WR << 16)
			| (ILI9341_WR_HIGH * ILI9341_PIN_WR);
 
	return 1;
}

disassembly in next post

08005512:   mov.w   r7, #268435456  ; 0x10000000
125       	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
08005516:   ubfx    r1, r0, #3, #1
126       					(ILI9341_PIN_D0 << 16) >>  (((data >> 0) & 0x01) * 16) |
0800551a:   lsls    r3, r3, #4
130       					(ILI9341_PIN_D15 << 16) >>  (((data >> 15) & 0x01) * 16);
0800551c:   lsls    r4, r4, #4
0800551e:   asr.w   r4, r7, r4
125       	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
08005522:   mov.w   lr, #262144     ; 0x40000
126       					(ILI9341_PIN_D0 << 16) >>  (((data >> 0) & 0x01) * 16) |
08005526:   asr.w   r3, r12, r3
133       					(ILI9341_PIN_D9 << 16) >>  (((data >> 9) & 0x01) * 16) |
0800552a:   ubfx    r2, r0, #9, #1
125       	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
0800552e:   lsls    r1, r1, #4
08005530:   asr.w   r1, lr, r1
129       					(ILI9341_PIN_D14 << 16) >>  (((data >> 14) & 0x01) * 16) |
08005534:   orrs    r3, r4
133       					(ILI9341_PIN_D9 << 16) >>  (((data >> 9) & 0x01) * 16) |
08005536:   lsls    r2, r2, #4
08005538:   asr.w   r5, r7, r2
0800553c:   orrs    r3, r1
132       	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
0800553e:   and.w   r2, r0, #16
134       					(ILI9341_PIN_D10 << 16) >>  (((data >> 10) & 0x01) * 16) |
08005542:   ubfx    r1, r0, #10, #1
132       	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
08005546:   asr.w   r2, lr, r2
134       					(ILI9341_PIN_D10 << 16) >>  (((data >> 10) & 0x01) * 16) |
0800554a:   lsls    r1, r1, #4
0800554c:   asr.w   r1, r12, r1
08005550:   orrs    r2, r5
127       					(ILI9341_PIN_D6 << 16) >>  (((data >> 6) & 0x01) * 16) |
08005552:   ubfx    r6, r0, #6, #1
133       					(ILI9341_PIN_D9 << 16) >>  (((data >> 9) & 0x01) * 16) |
08005556:   orrs    r2, r1
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
08005558:   ubfx    r1, r0, #8, #1
127       					(ILI9341_PIN_D6 << 16) >>  (((data >> 6) & 0x01) * 16) |
0800555c:   mov.w   r4, #1048576    ; 0x100000
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
08005560:   lsls    r1, r1, #4
08005562:   lsls    r6, r6, #4
08005564:   asr.w   r6, r4, r6
128       					(ILI9341_PIN_D13 << 16) >>  (((data >> 13) & 0x01) * 16) |
08005568:   ubfx    r8, r0, #13, #1
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
0800556c:   asrs    r4, r1
140       	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
0800556e:   ubfx    r1, r0, #1, #1
122       	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
08005572:   ubfx    r7, r0, #5, #1
128       					(ILI9341_PIN_D13 << 16) >>  (((data >> 13) & 0x01) * 16) |
08005576:   mov.w   r9, #536870912  ; 0x20000000
123       				(ILI9341_PIN_D11 << 16) >>  (((data >> 11) & 0x01) * 16);
0800557a:   ubfx    lr, r0, #11, #1
128       					(ILI9341_PIN_D13 << 16) >>  (((data >> 13) & 0x01) * 16) |
0800557e:   mov.w   r8, r8, lsl #4
140       	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
08005582:   lsls    r1, r1, #4
128       					(ILI9341_PIN_D13 << 16) >>  (((data >> 13) & 0x01) * 16) |
08005584:   asr.w   r8, r9, r8
140       	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
08005588:   asr.w   r1, r12, r1
122       	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
0800558c:   mov.w   r9, r7, lsl #4
123       				(ILI9341_PIN_D11 << 16) >>  (((data >> 11) & 0x01) * 16);
08005590:   mov.w   r12, #16777216  ; 0x1000000
08005594:   mov.w   lr, lr, lsl #4
122       	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
08005598:   mov.w   r7, #65536      ; 0x10000
123       				(ILI9341_PIN_D11 << 16) >>  (((data >> 11) & 0x01) * 16);
0800559c:   asr.w   lr, r12, lr
080055a0:   orrs    r3, r6
122       	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
080055a2:   asr.w   r7, r7, r9
129       					(ILI9341_PIN_D14 << 16) >>  (((data >> 14) & 0x01) * 16) |
080055a6:   ubfx    r6, r0, #14, #1
080055aa:   orr.w   r7, r7, lr
080055ae:   mov.w   r5, #1073741824 ; 0x40000000
080055b2:   ldr.w   lr, [pc, #120]  ; 0x800562c <ili9341_Write+296>
080055b6:   lsls    r6, r6, #4
080055b8:   asr.w   r6, r5, r6
135       					(ILI9341_PIN_D12 << 16) >>  (((data >> 12) & 0x01) * 16);
080055bc:   ubfx    r5, r0, #12, #1
122       	GPIOA->BSRR = (ILI9341_PIN_D5 << 16) >>  (((data >> 5) & 0x01) * 16) |
080055c0:   str.w   r7, [lr, #24]
129       					(ILI9341_PIN_D14 << 16) >>  (((data >> 14) & 0x01) * 16) |
080055c4:   orr.w   r3, r3, r8
135       					(ILI9341_PIN_D12 << 16) >>  (((data >> 12) & 0x01) * 16);
080055c8:   mov.w   r7, #8388608    ; 0x800000
080055cc:   lsls    r5, r5, #4
138       					(ILI9341_PIN_D7 << 16) >>  (((data >> 7) & 0x01) * 16);
080055ce:   ubfx    r8, r0, #7, #1
141       					(ILI9341_PIN_D2 << 16) >>  (((data >> 2) & 0x01) * 16);
080055d2:   ubfx    r0, r0, #2, #1
135       					(ILI9341_PIN_D12 << 16) >>  (((data >> 12) & 0x01) * 16);
080055d6:   asr.w   lr, r7, r5
129       					(ILI9341_PIN_D14 << 16) >>  (((data >> 14) & 0x01) * 16) |
080055da:   orrs    r6, r3
080055dc:   mov.w   r5, #33554432   ; 0x2000000
125       	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
080055e0:   ldr     r3, [pc, #60]   ; (0x8005620 <ili9341_Write+284>)
141       					(ILI9341_PIN_D2 << 16) >>  (((data >> 2) & 0x01) * 16);
080055e2:   lsls    r0, r0, #4
080055e4:   asr.w   r0, r5, r0
138       					(ILI9341_PIN_D7 << 16) >>  (((data >> 7) & 0x01) * 16);
080055e8:   mov.w   r8, r8, lsl #4
132       	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
080055ec:   add.w   r5, r5, #1040187392     ; 0x3e000000
125       	GPIOB->BSRR = (ILI9341_PIN_D3 << 16) >>  (((data >> 3) & 0x01) * 16) |
080055f0:   str     r6, [r3, #24]
138       					(ILI9341_PIN_D7 << 16) >>  (((data >> 7) & 0x01) * 16);
080055f2:   asr.w   r8, r7, r8
132       	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
080055f6:   add.w   r5, r5, #133120 ; 0x20800
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
080055fa:   ldr     r7, [pc, #40]   ; (0x8005624 <ili9341_Write+288>)
140       	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
080055fc:   ldr     r6, [pc, #40]   ; (0x8005628 <ili9341_Write+292>)
134       					(ILI9341_PIN_D10 << 16) >>  (((data >> 10) & 0x01) * 16) |
080055fe:   orr.w   r2, r2, lr
08005602:   orrs    r1, r0
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
08005604:   orr.w   r4, r4, r8
196       	ILI9341_PORT_WR->BSRR = (ILI9341_PIN_WR << 16)
08005608:   mov.w   lr, #16777472   ; 0x1000100
132       	GPIOC->BSRR = (ILI9341_PIN_D4 << 16) >>  (((data >> 4) & 0x01) * 16) |
0800560c:   str     r2, [r5, #24]
200       }
0800560e:   movs    r0, #1
137       	GPIOD->BSRR = (ILI9341_PIN_D8 << 16) >>  (((data >> 8) & 0x01) * 16) |
08005610:   str     r4, [r7, #24]
140       	GPIOE->BSRR = (ILI9341_PIN_D1 << 16) >>  (((data >> 1) & 0x01) * 16) |
08005612:   str     r1, [r6, #24]
194       	ILI9341_PORT_WR->BSRR = (ILI9341_PIN_WR << 16)
08005614:   str.w   r12, [r3, #24]
196       	ILI9341_PORT_WR->BSRR = (ILI9341_PIN_WR << 16)
08005618:   str.w   lr, [r3, #24]
200       }