Fastest way to bit-bang (set / clear) port pin on PSOC 4

A catchall for PSoC Mixed-Signal Array (microcontroller) discussions not captured by the other forums.

Moderator: ericb

Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Fri Jan 24, 2014 7:17 pm

I see some other PSOC 4 posts in this forum, so I'll ask my question here. For non-obvious and unavoidable reasons, I need to do some bit-banging SPI on a PSoC 4.

I Here is a fragment of my C code:

Code: Select all
register int
  byte_read;
//Get a register based pointer to the port
register reg32
  *ptr_to_LCD_SCK_DR;
ptr_to_LCD_SCK_DR=(reg32 *)LCD_SCK__DR;

byte_read=0;

//Set clock high
*ptr_to_LCD_SCK_DR|=LCD_SCK_MASK;
//read data
if(LCD_DATA_PS & LCD_DATA_MASK)
  byte_read|=0x40;
//Set clock low
*ptr_to_LCD_SCK_DR&=~LCD_SCK_MASK;


Here is the assembly listing:

Code: Select all
197:.\LCD_Draw.c **** //Clock in bit 6
198:.\LCD_Draw.c **** *ptr_to_LCD_SCK_DR|=LCD_SCK_MASK;
243 .loc 1 198 0
244 0108 2368 ldr   r3, [r4]
245 010a 1022 mov   r2, #16
246 010c 1343 orr   r3, r2
247 010e 2360 str   r3, [r4]
199:.\LCD_Draw.c **** if(LCD_DATA_PS & LCD_DATA_MASK) byte_read|=0x40;
248 .loc 1 199 0
249 0110 464B ldr   r3, .L13+24
250 0112 1A68 ldr   r2, [r3]
251 0114 8023 mov   r3, #128
252 0116 1340 and   r3, r2
253 0118 01D0 beq   .L4
254 .loc 1 199 0 is_stmt 0 discriminator 1
255 011a 4023 mov   r3, #64
256 011c 1D43 orr   r5, r3
257 .L4:
200:.\LCD_Draw.c **** *ptr_to_LCD_SCK_DR&=~LCD_SCK_MASK;
258 .loc 1 200 0 is_stmt 1
259 011e 2368 ldr   r3, [r4]
260 0120 1022 mov   r2, #16
261 0122 9343 bic   r3, r2
262 0124 2360 str   r3, [r4]


The set and clear C lines turn into 4 instructions each. I would think there is a simpler & faster way to set or clear a single port pin.

Is the compiler being stupid? I was under the impression that there was a single instruction bit-set and bit-clear on the ARM? Maybe this is a limitation of the M0?

Please let me know if there is a faster way to set and clear a port pin.
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby danadak » Sat Jan 25, 2014 4:19 am

The M0 uses ARM Thumb2 instruction set. Your code did a 32 bit operation,
whereas mov instruction in thumb2 can resolve to 8 bits in writing data to
register for GPIO. Inline ASM appropriate here ?

Regards, Dana.
Field Application Engineer
KB1RHB Mostly listen :)
Semi Retired
User avatar
danadak
The Big Cheese
The Big Cheese
 
Posts: 2008
Joined: Thu Dec 27, 2007 8:42 am
Location: New Hampshire

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Sat Jan 25, 2014 10:28 am

> Your code did a 32 bit operation, whereas mov instruction in
> thumb2 can resolve to 8 bits in writing data to register for GPIO

I certainly do not know as much about the M0 instruction set as I should. I'll see what happens if I make the port 8-bit instead of 32.

Here is what I have in the meantime. By pre-computing the port values and storing them in a register the bit set and bit clear is down to two instructions.
Code: Select all
  unsigned char
   line[32*3+1];
  register unsigned char
    *line_ptr;
  int
   y;
  register int
   x;
  register int
   SCK_HIGH;
  register int
   SCK_LOW;
  register int
   byte_read;   
  //Somehow, these end up being a speed + size enhancement.
  register reg32
   *ptr_to_LCD_SCK_DR;
  ptr_to_LCD_SCK_DR=(reg32 *)LCD_SCK__DR;   
  register reg32
   *ptr_to_LCD_DATA_PS;
  ptr_to_LCD_DATA_PS=(reg32 *)LCD_DATA__PS;   

  //Pre-calculate the port values that will set or clear
  //the SCK line. This is decidedly the opposite of
  //volatile, and will not be friendly to any interrupt
  //access of the port.
  SCK_LOW=SCK_HIGH=*ptr_to_LCD_SCK_DR;
  SCK_HIGH|=LCD_SCK_MASK;
  SCK_LOW&=~LCD_SCK_MASK;

. . . .

      //Clock in bit 4
      *ptr_to_LCD_SCK_DR=SCK_HIGH;
      if(*ptr_to_LCD_DATA_PS & LCD_DATA_MASK) byte_read|=0x10;
      *ptr_to_LCD_SCK_DR=SCK_LOW;

And the listing of the toggle section:
Code: Select all
 177:.\LCD_Draw.c  ****       *ptr_to_LCD_SCK_DR=SCK_LOW;
 208                    .loc 1 177 0 is_stmt 1
 209 00c0 5346           mov   r3, sl
 210 00c2 2360           str   r3, [r4]
 178:.\LCD_Draw.c  ****
 179:.\LCD_Draw.c  ****       //Clock in bit 4
 180:.\LCD_Draw.c  ****       *ptr_to_LCD_SCK_DR=SCK_HIGH;
 211                    .loc 1 180 0
 212 00c4 4B46           mov   r3, r9
 213 00c6 2360           str   r3, [r4]
 181:.\LCD_Draw.c  ****       if(*ptr_to_LCD_DATA_PS & LCD_DATA_MASK) byte_read|=0x10;
 214                    .loc 1 181 0
 215 00c8 3268           ldr   r2, [r6]
 216 00ca 8023           mov   r3, #128
 217 00cc 1340           and   r3, r2
 218 00ce 01D0           beq   .L7
 219                    .loc 1 181 0 is_stmt 0 discriminator 1
 220 00d0 1023           mov   r3, #16
 221 00d2 1D43           orr   r5, r3
 222                 .L7:
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Sat Jan 25, 2014 10:44 am

I did a quick hack to the port stuff, making the targets 8-bit:
Code: Select all
  unsigned char
   line[32*3+1];
  register unsigned char
    *line_ptr;
  int
   y;
  register int
   x;
  register uint8
   SCK_HIGH;
  register uint8
   SCK_LOW;
   
  register uint8
   byte_read;   
  //Somehow, these end up being a speed + size enhancement.
  register reg8
   *ptr_to_LCD_SCK_DR;
  ptr_to_LCD_SCK_DR=(reg8 *)LCD_SCK__DR;   
  register reg8
   *ptr_to_LCD_DATA_PS;
  ptr_to_LCD_DATA_PS=(reg8 *)LCD_DATA__PS;   

  //Pre-calculate the port values that will set or clear
  //the SCK line. This is decidedly the opposite of
  //volatile, and will not be friendly to any interrupt
  //access of the port.
  SCK_LOW=SCK_HIGH=*ptr_to_LCD_SCK_DR;
  SCK_HIGH|=LCD_SCK_MASK;
  SCK_LOW&=~LCD_SCK_MASK;

It breaks the code and makes things bigger by 56 bytes. Here is a snippet from the listing:
Code: Select all
 179:.\LCD_Draw.c  ****       //Clock in bit 4
 180:.\LCD_Draw.c  ****       *ptr_to_LCD_SCK_DR=SCK_HIGH;
 228                    .loc 1 180 0
 229 00e6 4346           mov   r3, r8
 230 00e8 2370           strb   r3, [r4]
 181:.\LCD_Draw.c  ****       if(*ptr_to_LCD_DATA_PS & LCD_DATA_MASK) byte_read|=0x10;
 231                    .loc 1 181 0
 232 00ea 5246           mov   r2, sl
 233 00ec 1378           ldrb   r3, [r2]
 234 00ee DBB2           uxtb   r3, r3
 235 00f0 DBB2           uxtb   r3, r3
 236 00f2 5BB2           sxtb   r3, r3
 237 00f4 002B           cmp   r3, #0
 238 00f6 02DA           bge   .L7
 239                    .loc 1 181 0 is_stmt 0 discriminator 1
 240 00f8 1023           mov   r3, #16
 241 00fa 2B43           orr   r3, r5
 242 00fc DDB2           uxtb   r5, r3
 243                 .L7:
 182:.\LCD_Draw.c  ****       *ptr_to_LCD_SCK_DR=SCK_LOW;
 244                    .loc 1 182 0 is_stmt 1
 245 00fe 4B46           mov   r3, r9
 246 0100 2370           strb   r3, [r4]


I think the reason it does not work is because I used the defines that point to 32-bit registers, and since I am pointing to an 8-bit register I would have to add a 0 to 3 byte offset to the 8-bit target pointer. Then the access would not be 32-bit aligned . . would that incur a penalty? In any case, there is still 2 instructions per pin state change. According to this: http://infocenter.arm.com/help/index.js ... CICDF.html both STR and STRB take 2 cycles, so I would not expect the STRB code to be faster than the STR code.
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby moxbox » Sun Jan 26, 2014 7:58 am

The ARM Cortex family has something known as the "bit-banding" region:
"Bit-banding maps a complete word of memory onto a single bit in the bit-band region.
For example, writing to one of the alias words sets or clears the corresponding bit in the bit-band region.
This enables every individual bit in the bit-banding region to be directly accessible from a word-aligned address using a single LDR instruction.
It also enables individual bits to be toggled without performing a read-modify-write sequence of instructions.
The bit-band wrapper supports two bit-band regions. These occupy the lowest 1MB of the SRAM, 0x20000000,
and peripheral memory, 0x40000000, regions respectively.
These bit-band regions map each word in an alias region of memory to a bit in a bit-band region of memory."
from
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0479b/ch03s11s01.html

So, if you access the GPIO port address from the peripheral memory region (0x40000000),
you can likely speed up your operation considerably.

;-) Tom Moxon
@PatternAgents
If we knew what we were doing, it wouldn't be called research, would it?
-- Albert Einstein
moxbox
Cheese Cube
Cheese Cube
 
Posts: 41
Joined: Thu Oct 15, 2009 9:59 am
Website: http://www.moxon.com
Location: Portland, OR

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Sun Jan 26, 2014 9:24 am

Tom:

Thank you for your reply.

> The ARM Cortex family has something known as the "bit-banding" region . . .

One of our products I have worked on is an ARM 9 + Linux device that supported bit-banding, but I guess I never thought about the M0 having that feature. I just figured it was way too stripped down.

> So, if you access the GPIO port address from the peripheral memory region (0x40000000)

The registers I am accessing eventually are defined like this:
Code: Select all
cydevice_trm.h:
  #define CYREG_PRT3_DR 0x40040300u
cyfitter.h:
  #define LCD_SCK__DR CYREG_PRT3_DR
LCD_SCK.c:
  #define LCD_SCK_DR (* (reg32 *) LCD_SCK__DR)

So it looks like I can access stuff in the 0x4000000u range.

The immediate questions would then be:

1) How is bit banding enabled
2) How do the ports map to the address

And the larger question:

3) Why isn't Cypress all over this cool feature?

Off to do research on M0 bit banding.
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby bobmarlowe » Sun Jan 26, 2014 12:50 pm

There is nothing Cypress-specific within the m0 core, so there seemingly was no reason for Cypress to write an own manual concerning the CPU inside a PSoC4.
Visite the ARM website and download the "Cortex M0 Generic User Guide" which shows how the relation between real and bit-banding addresses are.

A question I have is: Why are you interested in manually accessing port bits? What is the problem you try to solve?? Why not using hardware???

Bob
User avatar
bobmarlowe
The Big Cheese
The Big Cheese
 
Posts: 1490
Joined: Thu Oct 06, 2011 2:03 am
Location: Germany

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Sun Jan 26, 2014 1:49 pm

> Why are you interested in manually accessing port bits? What is the problem you try to solve?? Why not using hardware???

I am using a SPIM block to do most of the work for my peripheral, it writes fine. The trouble is this goofy chip I'm talking to has a weird way of reading that I cannot coax the SPIM into doing, so that portion of the code is bit-banged.

I am still looking at the ARM M0 bit-banding stuff. A couple places mention that the vendor can choose to include the bit-banding. I have asked Cypress tech support for a definitive answer.

Pending that I guess I will have to write some code to attempt to change the port based on bit-banding access . . . the problem there is that if my test code does not work, I will not know if my code is in error or if Cypress chose to not include bit-banding in the PSoC 4.

Ideally (and this would work well with my laziness), someone has already used bit-banding on the PSoC 4 and has an example, or knows definitively that it was not implemented.
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby bobmarlowe » Sun Jan 26, 2014 11:45 pm

Fastes way to toggle a single pin is to set / reset a bit in the appropiate port-register. This read-modify-write sequence WILL need some instructions ans so a couple of CPU cycles.

A way out could be to modify the SPIM implementation of the underlying DataPath object, which needs some knowledge of VeriLog as HDL.
With VeriLog you are able to toggle a pin directly in hardware which can be done with a clock of ~60MHz resulting in a 30MHz toggle rate.
So if you can be a bit (or byte :mrgreen: ) more specific about the read-problem (link to your device's datasheet) we could give you more hints.

And when you post your questions in a PSoC4 thread (not PSoC1) some more people will see it.

Bob
User avatar
bobmarlowe
The Big Cheese
The Big Cheese
 
Posts: 1490
Joined: Thu Oct 06, 2011 2:03 am
Location: Germany

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby baxsie » Mon Jan 27, 2014 7:49 am

Thanks for your reply.

> when you post your questions in a PSoC4 thread (not PSoC1) some more people will see it.

I looked, but did not see a PSoC 4 forum. Did I miss something?

Sadly, it looks like bit-banding is not supported in the PSoC 4. From Cypress tech support:
Yes, doing bit-wise operations in C would translate to large number of assembly instructions as Cortex-M0 does not support bit wise operation (bit banding region) which Cortex-M3 does.


> knowledge of VeriLog as HDL
Maybe one day. For now I have it setting and clearing at 2 instructions/bit:
Code: Select all
 179:.\LCD_Draw.c  ****       //Clock in bit 4
 180:.\LCD_Draw.c  ****       *ptr_to_LCD_SCK_DR=SCK_HIGH;
 212 00c4 4B46           mov   r3, r9
 213 00c6 2360           str   r3, [r4]

Which seems to be near the limit for software. This can work, I just hate to leave possible performance on the table.

> a bit (or byte :mrgreen: ) more specific about the read-problem

You really ready for that dive? :)

To get the best write performance, I feed 48MHz HFCLK into the SPIM block (not SBC based) for 24MHz SPICLK. This writes nicely to the display's controller (Sitronix ST7735 Datasheet), even if it is a bit on the "overclocked" side. However you have to slow down the transfer for reads (~6MHz?). You also need to clock ONE extra cycle at the start of the read data cycle, in addition to the first BYTE being garbage. So I could use GPIO to make the one extra clock cycle easy enough, but I do not see any way to sometimes clock the SPIM with 48MHz and other times with a lower frequency. I have tried a mux and logic deigned in the schematic, but none will build with the 48MHz HFCLK going into them:

Image

Image

Image

Image

Theoretically someone could write that block in verilog, but that is not something I can do (today).

Any suggestions welcome :)
I'm not getting older. I'm getting bitter.
baxsie
The Big Cheese
The Big Cheese
 
Posts: 420
Joined: Mon Dec 22, 2003 10:08 pm

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby bobmarlowe » Mon Jan 27, 2014 8:44 am

The clock distributing in a PSoC4 differs from the other PSoCs, so it is really not easy (if not impossible) to create new clocks to drive components. Have a look here

Bob
User avatar
bobmarlowe
The Big Cheese
The Big Cheese
 
Posts: 1490
Joined: Thu Oct 06, 2011 2:03 am
Location: Germany

Re: Fastest way to bit-bang (set / clear) port pin on PSOC 4

Postby danadak » Mon Jan 27, 2014 3:15 pm

Some thoughts -

1) There is no PSOC 4 Forum on psocdeveloper.com

2) ARM has a wrapper for M0 for bit banding -

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0479b/ch03s11s01.html

I do not know if it was used on Cypress implementation.

3) This discussion states PSOC 4 has some additional pin capabilities as well as its restrictions are
logical in light of PSOC 3/5LP allowing one to create in deterministic clock timing. Eg. Creator has
restricted allowing this to happen.

http://www.cypress.com/?rID=80799

4) Additional clock capabilities in PSOC 4 are -

http://www.cypress.com/?rID=81383&cache=0

Regards, Dana.
Field Application Engineer
KB1RHB Mostly listen :)
Semi Retired
User avatar
danadak
The Big Cheese
The Big Cheese
 
Posts: 2008
Joined: Thu Dec 27, 2007 8:42 am
Location: New Hampshire


Return to “%s” PSoC1 General

Who is online

Users browsing this forum: No registered users and 1 guest

cron