Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Thread

Help needed:- what's the quickest way to store 256 bytes of data?

Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by thekenhunt

I have an application which needs to store 256 bytes of data. My
current (C) solution is way too slow. Could anyone point me to the
fastest way to go about reading a fixe number of bytes into an
array/memory location using assembler? ie how can I replace the loop
below most efficiently.

char mydata[256];
void myloop()
    {
    for(d=256;d;d--) mydata[d]=PIND;
    }

many thanks

Ken

Re: Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by kernels_nz

Hi Ken,

Im a C user myself, so I can only think of 3 possible answers. . . 

1. Try using a higher clock speed.

2. if you had :

   mydata[0] = PIND;
   mydata[1] = PIND;
   mydata[2] = PIND;
          .
          .
          .
   mydata[255] = PIND;

all written out the hard way like that, it would be slightly faster,
because the "for" loop condition would not be checked every time, it
would of course occupy much more code space, and be considered
terrible programming.

I dont believe that assembler can do it much faster than option 2 tho.

3. Look around and see if there are any flash memory ICs that have 8
bit parallel data in, and a line that only need to be clocked to save
that data to the next address in memory, then read it out at your
leasure. (Dont personally know of any IC like this, maybe someone else
has used something like this ?)

Cheers
Hein B
Auckland, New Zealand.

 
--- In AVR-Chat@yahoogroups.com, "thekenhunt" <kenhunt@...> wrote:
Show quoted textHide quoted text
>
> I have an application which needs to store 256 bytes of data. My
> current (C) solution is way too slow. Could anyone point me to the
> fastest way to go about reading a fixe number of bytes into an
> array/memory location using assembler? ie how can I replace the loop
> below most efficiently.
> 
> char mydata[256];
> void myloop()
>     {
>     for(d=256;d;d--) mydata[d]=PIND;
>     }
> 
> many thanks
> 
> Ken
>

Re: [AVR-Chat] Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by John Samperi

At 04:26 AM 14/02/2006, you wrote:
>fastest way to go about reading a fixe number of bytes into an
>array/memory location using assembler?
>
>char mydata[256];
>void myloop()
>     {
>     for(d=256;d;d--) mydata[d]=PIND;
>     }

ldi     xl,low(mydata)
ldi     xh,high(mydata) ;use x as pointer
clr     counter         ;use any 8 bit register

cpy_loop:
in      data_reg,pind   ;use any 8 bit register for data
st      x+,data_reg     ;save data with post increment
dec     counter
brne    cpy_loop        ;exit when 8 bit counter reaches 0 again

Regards

John Samperi

********************************************************
Ampertronics Pty. Ltd.
11 Brokenwood Place Baulkham Hills, NSW 2153 AUSTRALIA
Tel. (02) 9674-6495       Fax (02) 9674-8745
Email: john@ampertronics.com.au
Website  http://www.ampertronics.com.au
*Electronic Design * Custom Products * Contract Assembly
********************************************************

Re: Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by thekenhunt

John
  Many thanks for the reply - Just tested it out and it works a treat.

cheers

Ken


--- In AVR-Chat@yahoogroups.com, John Samperi <samperi@...> wrote:
Show quoted textHide quoted text
>
> At 04:26 AM 14/02/2006, you wrote:
> >fastest way to go about reading a fixe number of bytes into an
> >array/memory location using assembler?
> >
> >char mydata[256];
> >void myloop()
> >     {
> >     for(d=256;d;d--) mydata[d]=PIND;
> >     }
> 
> ldi     xl,low(mydata)
> ldi     xh,high(mydata) ;use x as pointer
> clr     counter         ;use any 8 bit register
> 
> cpy_loop:
> in      data_reg,pind   ;use any 8 bit register for data
> st      x+,data_reg     ;save data with post increment
> dec     counter
> brne    cpy_loop        ;exit when 8 bit counter reaches 0 again
> 
> Regards
> 
> John Samperi
> 
> ********************************************************
> Ampertronics Pty. Ltd.
> 11 Brokenwood Place Baulkham Hills, NSW 2153 AUSTRALIA
> Tel. (02) 9674-6495       Fax (02) 9674-8745
> Email: john@...
> Website  http://www.ampertronics.com.au
> *Electronic Design * Custom Products * Contract Assembly
> ********************************************************
>

Re: Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by thekenhunt

Ned
  Many thanks for the feedback. I think 3 cycles/byte is about as good
as it gets.. 8o) 

cheers

Ken

--- In AVR-Chat@yahoogroups.com, Ned Konz <bikenomad@...> wrote:
Show quoted textHide quoted text
>
> 
> On Feb 13, 2006, at 9:26 AM, thekenhunt wrote:
> 
> > I have an application which needs to store 256 bytes of data. My
> > current (C) solution is way too slow. Could anyone point me to the
> > fastest way to go about reading a fixe number of bytes into an
> > array/memory location using assembler? ie how can I replace the loop
> > below most efficiently.
> >
> > char mydata[256];
> > void myloop()
> >     {
> >     for(d=256;d;d--) mydata[d]=PIND;
> >     }
> >
> 
> Well, the first byte you're storing is past the end of mydata[],
> and you're storing from the end to the beginning.
> 
> Assuming that you wanted to store entirely inside mydata[],
> this is the output from gcc 4.0.2 with -O2:
> 
>     7:test3.c       **** void myloop(void)
>     8:test3.c       **** {
>    74                .LM0:
>    75                /* prologue: frame size=0 */
>    76                /* prologue end (size=0) */
>    77 0000 E0E0              ldi r30,lo8(mydata+255)
>    78 0002 F0E0              ldi r31,hi8(mydata+255)
>    79                .L2:
>    80                .LBB2:
>     9:test3.c       ****     for(unsigned char d=255;d;d--)
>    10:test3.c       ****         mydata[d]=PIND;
>    82                .LM1:
>    83 0004 80B3              in r24,48-0x20
>    84 0006 8083              st Z,r24
>    85 0008 3197              sbiw r30,1
>    87                .LM2:
>    88 000a 80E0              ldi r24,hi8(mydata)
>    89 000c E030              cpi r30,lo8(mydata)
>    90 000e F807              cpc r31,r24
>    91 0010 C9F7              brne .L2
> 
> That would be 1+2+2+1+1+2 = 9 cycles / byte
> 
> And using a pre-decremented pointer helps a little bit:
> 
> 
>     7:test3.c       **** void myloop(void)
>     8:test3.c       **** {
>    74                .LM0:
>    75                /* prologue: frame size=0 */
>    76                /* prologue end (size=0) */
>    77 0000 E0E0              ldi r30,lo8(mydata+256)
>    78 0002 F0E0              ldi r31,hi8(mydata+256)
>    79                .L2:
>     9:test3.c       ****     char* p=mydata+256;
>    10:test3.c       ****
>    11:test3.c       ****     do
>    12:test3.c       ****     {
>    13:test3.c       ****         *--p=PIND;
>    81                .LM1:
>    82 0004 80B3              in r24,48-0x20
>    83 0006 8293              st -Z,r24
>    14:test3.c       ****     }
>    15:test3.c       ****     while (p >= mydata);
>    85                .LM2:
>    86 0008 80E0              ldi r24,hi8(mydata)
>    87 000a E030              cpi r30,lo8(mydata)
>    88 000c F807              cpc r31,r24
>    89 000e D0F7              brsh .L2
> 
> For 1+2+1+1+1+2 = 8 cycles/byte
> 
> Of course, you could always unroll the loop:
> 
>     7:test3.c       **** void myloop(void)
>     8:test3.c       **** {
>    74                .LM0:
>    75                /* prologue: frame size=0 */
>    76                /* prologue end (size=0) */
>     9:test3.c       ****     mydata[255] = PIND;
>    78                .LM1:
>    79 0000 80B3              in r24,48-0x20
>    80 0002 8093 0000         sts mydata+255,r24
>    10:test3.c       ****     mydata[254] = PIND;
>    82                .LM2:
>    83 0006 80B3              in r24,48-0x20
>    84 0008 8093 0000         sts mydata+254,r24
>    11:test3.c       ****     mydata[253] = PIND;
>    86                .LM3:
>    87 000c 80B3              in r24,48-0x20
>    88 000e 8093 0000         sts mydata+253,r24
> 
> I can't imagine it getting much faster than that.
> 
> That would be 3 cycles / byte
> * 256 = 768 cycles for 256 bytes.
> 
> It's also 768 words (1536 bytes) of code, but you wanted fast...
> 
> -- 
> Ned Konz
> ned@...
>

Re: [AVR-Chat] Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-13 by Ned Konz

On Feb 13, 2006, at 9:26 AM, thekenhunt wrote:

> I have an application which needs to store 256 bytes of data. My
> current (C) solution is way too slow. Could anyone point me to the
> fastest way to go about reading a fixe number of bytes into an
> array/memory location using assembler? ie how can I replace the loop
> below most efficiently.
>
> char mydata[256];
> void myloop()
>     {
>     for(d=256;d;d--) mydata[d]=PIND;
>     }
>

Well, the first byte you're storing is past the end of mydata[],
and you're storing from the end to the beginning.

Assuming that you wanted to store entirely inside mydata[],
this is the output from gcc 4.0.2 with -O2:

    7:test3.c       **** void myloop(void)
    8:test3.c       **** {
   74                .LM0:
   75                /* prologue: frame size=0 */
   76                /* prologue end (size=0) */
   77 0000 E0E0              ldi r30,lo8(mydata+255)
   78 0002 F0E0              ldi r31,hi8(mydata+255)
   79                .L2:
   80                .LBB2:
    9:test3.c       ****     for(unsigned char d=255;d;d--)
   10:test3.c       ****         mydata[d]=PIND;
   82                .LM1:
   83 0004 80B3              in r24,48-0x20
   84 0006 8083              st Z,r24
   85 0008 3197              sbiw r30,1
   87                .LM2:
   88 000a 80E0              ldi r24,hi8(mydata)
   89 000c E030              cpi r30,lo8(mydata)
   90 000e F807              cpc r31,r24
   91 0010 C9F7              brne .L2

That would be 1+2+2+1+1+2 = 9 cycles / byte

And using a pre-decremented pointer helps a little bit:


    7:test3.c       **** void myloop(void)
    8:test3.c       **** {
   74                .LM0:
   75                /* prologue: frame size=0 */
   76                /* prologue end (size=0) */
   77 0000 E0E0              ldi r30,lo8(mydata+256)
   78 0002 F0E0              ldi r31,hi8(mydata+256)
   79                .L2:
    9:test3.c       ****     char* p=mydata+256;
   10:test3.c       ****
   11:test3.c       ****     do
   12:test3.c       ****     {
   13:test3.c       ****         *--p=PIND;
   81                .LM1:
   82 0004 80B3              in r24,48-0x20
   83 0006 8293              st -Z,r24
   14:test3.c       ****     }
   15:test3.c       ****     while (p >= mydata);
   85                .LM2:
   86 0008 80E0              ldi r24,hi8(mydata)
   87 000a E030              cpi r30,lo8(mydata)
   88 000c F807              cpc r31,r24
   89 000e D0F7              brsh .L2

For 1+2+1+1+1+2 = 8 cycles/byte

Of course, you could always unroll the loop:

    7:test3.c       **** void myloop(void)
    8:test3.c       **** {
   74                .LM0:
   75                /* prologue: frame size=0 */
   76                /* prologue end (size=0) */
    9:test3.c       ****     mydata[255] = PIND;
   78                .LM1:
   79 0000 80B3              in r24,48-0x20
   80 0002 8093 0000         sts mydata+255,r24
   10:test3.c       ****     mydata[254] = PIND;
   82                .LM2:
   83 0006 80B3              in r24,48-0x20
   84 0008 8093 0000         sts mydata+254,r24
   11:test3.c       ****     mydata[253] = PIND;
   86                .LM3:
   87 000c 80B3              in r24,48-0x20
   88 000e 8093 0000         sts mydata+253,r24

I can't imagine it getting much faster than that.

That would be 3 cycles / byte
* 256 = 768 cycles for 256 bytes.

It's also 768 words (1536 bytes) of code, but you wanted fast...

-- 
Ned Konz
ned@bike-nomad.com

Re: [AVR-Chat] Re: Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-14 by Ned Konz

On Feb 13, 2006, at 11:31 AM, kernels_nz wrote:

> 2. if you had :
>
>    mydata[0] = PIND;
>    mydata[1] = PIND;
>    mydata[2] = PIND;
>           .
>           .
>           .
>    mydata[255] = PIND;
>
> all written out the hard way like that, it would be slightly faster,
> because the "for" loop condition would not be checked every time, it
> would of course occupy much more code space, and be considered
> terrible programming.

Yes, but there's still a middle way, which is partial unrolling:

#define ATONCE 8
uint8_t mydata[256];

void myloop(void)
{
     uint8_t *p = mydata;
     for (uint8_t counter = sizeof(mydata) / ATONCE; counter--; p +=  
ATONCE)
     {
         p[0] = PIND;
         p[1] = PIND;
         p[2] = PIND;
         p[3] = PIND;
         p[4] = PIND;
         p[5] = PIND;
         p[6] = PIND;
         p[7] = PIND;
     }
}


which results in (with avr-gcc 4.0 and -O2):

    9:test3.c       **** void myloop(void)
   10:test3.c       **** {
   74               	.LM0:
   75               	/* prologue: frame size=0 */
   76               	/* prologue end (size=0) */
   77 0000 E0E0      		ldi r30,lo8(mydata)
   78 0002 F0E0      		ldi r31,hi8(mydata)
   79               	.L2:
   80               	.LBB2:
   11:test3.c       ****     uint8_t *p = mydata;
   12:test3.c       ****     for (uint8_t counter = sizeof(mydata) /  
ATONCE; counter--; p += ATONCE)
   13:test3.c       ****     {
   14:test3.c       ****         p[0] = PIND;
   82               	.LM1:
   83 0004 80B3      		in r24,48-0x20
   84 0006 8083      		st Z,r24
   15:test3.c       ****         p[1] = PIND;
   86               	.LM2:
   87 0008 80B3      		in r24,48-0x20
   88 000a 8183      		std Z+1,r24
   16:test3.c       ****         p[2] = PIND;
   90               	.LM3:
   91 000c 80B3      		in r24,48-0x20
   92 000e 8283      		std Z+2,r24

... etc ...

   21:test3.c       ****         p[7] = PIND;
110               	.LM8:
111 0020 80B3      		in r24,48-0x20
112 0022 8783      		std Z+7,r24
114               	.LM9:
115 0024 3896      		adiw r30,8  ; 2
116 0026 80E0      		ldi r24,hi8(mydata+256)  ; 1
117 0028 E030      		cpi r30,lo8(mydata+256)  ; 1
118 002a F807      		cpc r31,r24 ; 1
119 002c 59F7      		brne .L2 ; 2

As a result, you amortize the cost of lines 115-119 (7 cycles) over 8  
bytes of transfer.
For a cost/byte transferred of 3+7/8 cycles.

-- 
Ned Konz
ned@bike-nomad.com

Re: [AVR-Chat] Re: Help needed:- what's the quickest way to store 256 bytes of data?

2006-02-14 by Peter Harrison

And there is Duff's device (Google is your friend here) for the more 
general case where the count is neither 8 bits nor a multiple of 8:

    count = 256;
    uint8_t *to = mydata;
    register int n = (count + 7) / 8;      /* count > 0 assumed */

    switch (count % 8)
    {
    case 0:        do {  *to++ = PIND;
    case 7:              *to++ = PIND;
    case 6:              *to++ = PIND;
    case 5:              *to++ = PIND;
    case 4:              *to++ = PIND;
    case 3:              *to++ = PIND;
    case 2:              *to++ = PIND;
    case 1:              *to++ = PIND;
                       } while (--n > 0);
    }

Which compiles, with GCC3.4.5 and -Os, to give:

    count = 256;
    uint8_t *to = mydata;
  136:	e2 e6       	ldi	r30, 0x62	; 98
  138:	f0 e0       	ldi	r31, 0x00	; 0
    register int n = (count + 7) / 8;      /* count > 0 assumed */
  13a:	20 e2       	ldi	r18, 0x20	; 32
  13c:	30 e0       	ldi	r19, 0x00	; 0

    switch (count % 8)
    {
    case 0:        do {  *to++ = PIND;
  13e:	80 b3       	in	r24, 0x10	; 16
  140:	81 93       	st	Z+, r24
    case 7:              *to++ = PIND;
  142:	80 b3       	in	r24, 0x10	; 16
  144:	81 93       	st	Z+, r24
    case 6:              *to++ = PIND;
  146:	80 b3       	in	r24, 0x10	; 16
  148:	81 93       	st	Z+, r24
    case 5:              *to++ = PIND;
  14a:	80 b3       	in	r24, 0x10	; 16
  14c:	81 93       	st	Z+, r24
    case 4:              *to++ = PIND;
  14e:	80 b3       	in	r24, 0x10	; 16
  150:	81 93       	st	Z+, r24
    case 3:              *to++ = PIND;
  152:	80 b3       	in	r24, 0x10	; 16
  154:	81 93       	st	Z+, r24
    case 2:              *to++ = PIND;
  156:	80 b3       	in	r24, 0x10	; 16
  158:	81 93       	st	Z+, r24
    case 1:              *to++ = PIND;
  15a:	80 b3       	in	r24, 0x10	; 16
  15c:	81 93       	st	Z+, r24
                       } while (--n > 0);
  15e:	21 50       	subi	r18, 0x01	; 1
  160:	30 40       	sbci	r19, 0x00	; 0
  162:	12 16       	cp	r1, r18
  164:	13 06       	cpc	r1, r19
  166:	5c f3       	brlt	.-42     	; 0x13e <myloop+0x6c>
  168:	08 95       	ret

I have to dash to work so I have not checked the cycle count and such 
but it looks pretty good to me.

Pete Harrison

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.