Speeding up a "for" loop (8051)

Mar 23, 2008 25 Replies

I'm trying to feed a 7seg LEDdriver bit bashing a STP08C05 and with a



11.059M clock it takes about 180uS. Any way to speed it up, (and I am going up to 24Mhz xtal) ?


void Led7(char time) { char buff,i; bit SDI; buff=seg7[time];



for(i=0; i>1;



P1|=0x80;//clock P1&=~0x80; } }



Thanks


martin


Playing around with SDCC and counting cycles with a WCET tool, assuming a vanilla 8051 with 12 clocks per machine cycle, the fastest looping version I found is 145 us:

void Led7btx (unsigned char time) { unsigned char buff, i;

buff=seg7[time]; P1 &= ~0x20; i = 8; do { if (buff & 0x01) { P1 ^= 0x20;}

buff = buff >> 1;

P1 |= 0x80; //clock P1 &= ~0x80;

i --; } while (i != 0); }

This assumes that seg7[] is in xdata and has been modified to show the changes in segment on/off state, counting from bit 0 to bit 7 and starting from '0' state, so that P1 can be updated with an xor after being initialized to a '0' state before the loop.

Unrolling the loop in this function gives 92 us:

void Led7fx (unsigned char time) { unsigned char buff;

buff = seg7[time];

P1 &= ~0x20;

if (buff & 0x01) { P1 ^= 0x20; } // 1 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x02) { P1 ^= 0x20; } // 2 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x04) { P1 ^= 0x20; } // 3 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x08) { P1 ^= 0x20; } // 4 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x10) { P1 ^= 0x20; } // 5 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x20) { P1 ^= 0x20; } // 6 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x40) { P1 ^= 0x20; } // 7 P1 |= 0x80; P1 &= ~0x80;

if (buff & 0x80) { P1 ^= 0x20; } // 8 P1 |= 0x80; P1 &= ~0x80;

}

The SDCC code from the unrolled function looks quite tight, but I think there are some unnecessary moves from R2 into A that could be avoided in assembly language.

Please note that this code is not tested, just compiled and analysed with a cycle-counting tool.

By the way, I'm not familiar with 7-segment drivers, but I was surprised to see that the code sends 8 bits, not 7. Is that right? What is the 8th bit used for?

HTH,

Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .

Thanks,

bit 8, for the decimal point :)

martin

0) check the assembler code generated

1) try to use bit instruction to access P1 :

P1.5 = SDI; P1.7 = 1 ; // clock P1.7 = 0 ;

(you have to check how your C compiler access bits in port 1 )

2) hand write in assembler the for loop using:

DJNZ to control the loop the CARRY-FLAG to move your data between the accumulator and the port bit using shifts

the loop should be this:

datum to be send in ACC bit counter in R1

MOV R1,#8 loop: RRC A ; this move the LSB in C and shift the Acc MOV P1.5,C SETB P1.7 CLR P1.7 DJNZ R1,loop

Please, TRIPLE check if this code fragmant is right

and using bit access to P1 reduces that to 65 us:

__bit __at (0x95) P1_5; __bit __at (0x97) P1_7;

void Led7fx_bit (unsigned char time) { unsigned char buff;

buff = seg7[time];

P1_5 = 0;

if (buff & 0x01) { P1_5 ^= 1; } // 1 P1_7 = 1; P1_7 = 0;

if (buff & 0x02) { P1_5 ^= 1; } // 2 P1_7 = 1; P1_7 = 0;

if (buff & 0x04) { P1_5 ^= 1; } // 3 P1_7 = 1; P1_7 = 0;

if (buff & 0x08) { P1_5 ^= 1; } // 4 P1_7 = 1; P1_7 = 0;

if (buff & 0x10) { P1_5 ^= 1; } // 5 P1_7 = 1; P1_7 = 0;

if (buff & 0x20) { P1_5 ^= 1; } // 6 P1_7 = 1; P1_7 = 0;

if (buff & 0x40) { P1_5 ^= 1; } // 7 P1_7 = 1; P1_7 = 0;

if (buff & 0x80) { P1_5 ^= 1; } // 8 P1_7 = 1; P1_7 = 0;

}

Ah.

Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .

I'm not very good at programming, I'm just trying Niklas's approach, and thanks for the bit instruction tip

martin

Thanks, I'm reading the Raisonace documents now, _bit is different, it appears. It's a vast improvement over my original :)

martin

Correcting my own post:

To follow the SDCC manual, it is better to write "__sbit" than "__bit" in these declarations. However, it seems to make no difference in the machine code, maybe because of the "__at".

Martin, which compiler are you using? SDCC or a commercial one?

Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .

I'm using the 4k limited Raisonace compiler, freeware which is good enough for me. I am not really a programmer, I just have ideas that need a micro, so I attempt to programme

I'm making a SMPTE timecode reader, which has interrupts every 250uS, or so, so I'm trying to speed things up. There are some (bad) videos, all very short, here:

formatting link

It's going quite well.

back to the docs....

martin

oops, got 2 part numbers mixed up STP16C596 or STP16CP05 from ST micro, still waiting for the to be delivered from farnell spain

martin

I hope so. I have a mate with a small assembly shop in the uk, he's much better at soldering than I am. A bit more here

formatting link

martin

Are you making the Timecode grabber code on the PC available ??

Google can not find "STP08C05", do you have a link ??

donald

Don't know why you want it so fast? I see a potential problem. Hitting the port pins in two consecutive instructions is a no-no. The port is read-modified-write meaning the second instruction could read invalid value due to capacitance on pin.

Add a nop. Perhaps two. Read your chip spec to see what is required.

asm("nop");

Don't know why you want it so fast? I see a potential problem. Hitting the port pins in two consecutive instructions is a no-no. The port is read-modified-write meaning the second instruction could read invalid value due to capacitance on pin.

Add a nop. Perhaps two. Read your chip spec to see what is required.

asm("nop");

Don't know why you want it so fast? I see a potential problem. Hitting the port pins in two consecutive instructions is a no-no. The port is read-modified-write meaning the second instruction could read invalid value due to capacitance on pin.

Add a nop. Perhaps two. Read your chip spec to see what is required.

asm("nop");

It scopes out ok, and the base code has been running solidly for the last 2 months, on a couple of hand built stripboards

I have a datastream coming in with an interrupt every 250uS or 500uS, (possibly faster) data dependent, in Biphase encoding, I am already having to decode the binary into ascii by masking things, and I am doing everything in between the the clock pulses, just a small amount, every 8 clocks, the interrupts can't be turned off, or I loose data, or worse sync with the data stream

Each 8051 step seems to take a couple of uS, and it very quickly adds up, especially if I have to jump to #include stuff and back again

I some problems with the LCD version, as it took the LCD busy flag up to 37uS to clear, so it was just one write per clock

I used to "do video" in TV studios, so this stuff is really extremely slow, but so is the processor, and at my age I'd need at least a year to figure out the MSP430 or ATmegas,.Just trying to get AVRstudio/GCC running gave me the hiccups. I don't particularly like or dislike the

51, its what I'm used to

martin

I think your read-modify-post needs adjusting :)

martin

router locked up and hickuped. :-/

If you are stuck on 8051s, there are some crazy fast ones out there. 200mhz.

formatting link

Or pick one with high mips here.

formatting link

A: Because it fouls the order in which people normally read text. Q: Why is top-posting such a bad thing? A: Top-posting. Q: What is the most annoying thing on usenet and in e-mail?

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required