Speeding up a "for" loop (8051)

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

Reply to
Martin Griffith
Loading thread data ...

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
       .      @       .
Reply to
Niklas Holsti

Thanks,

bit 8, for the decimal point :)

martin

Reply to
Martin Griffith

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

Reply to
mmm

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
       .      @       .
Reply to
Niklas Holsti

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

martin

Reply to
Martin Griffith

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

martin

Reply to
Martin Griffith

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
       .      @       .
Reply to
Niklas Holsti

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

Reply to
Martin Griffith

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

martin

Reply to
Martin Griffith

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

Reply to
Martin Griffith

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

Reply to
donald

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

donald

Reply to
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");

Reply to
Moon Shine

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");

Reply to
Moon Shine

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");

Reply to
Moon Shine

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

Reply to
Martin Griffith

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

martin

Reply to
Martin Griffith

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

Reply to
Moon Shine

--
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?
Reply to
CBFalconer

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.