CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

block of bytes transmission, array is the only way?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Amin



Joined: 19 Feb 2004
Posts: 15

View user's profile Send private message

block of bytes transmission, array is the only way?
PostPosted: Fri Mar 10, 2006 11:02 pm     Reply with quote

Hi

I trying to send 16 bytes over the serial port. I have an array of 16 cells and the ISR increment the index and grabs the byte and sends it for transmission until it reaches the end when it stops the cycle.



I am wondering if there is any faster way? Array handling seems like a slow way of doing it.



THANKS
_________________
McMaster Solar Car Project
http://www.solarcar.mcmaster.ca
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Sat Mar 11, 2006 5:15 am     Reply with quote

The slowest thing in transmitting anything over a serial line is the actual transmission of the data itself. If you don't want to wait for the transmission to finish the most common solution is to move the transmission away from your main process. Write the data to a large enough buffer and than have an interrupt driven routine transmit the data in the background.
An implementation example of this approach is EX_STISR.C in the examples directory, or search this forum for the keywords 'circular buffer'.
Ttelmah
Guest







PostPosted: Sat Mar 11, 2006 9:54 am     Reply with quote

Array handling is 'slow', but we are talking 'slow' in computer terms here. Typically perhaps 30 machine cycles to access a byte (will depend on the size of the element, and the processsor involved). A circular buffer will impose the same 'sloth'. Any other process will involve this same overhead.
I have posted warnings about the 'sloth' of array accesses in the past, but here dealing with operations, where people have multiple array accesses in one ISR, perhaps unneccessarily. You can reduce the 'work' slightly, by declaring the access variable as a int pointer, and just incrementing this for each access, up to the size of the array. Advantage here is that the address does not need to be recalculated on each interrupt.
Nothing else is going to be 'faster', for accessing a block of data. It is the internal overhead involved in using indirect addressing of the RAM, which causes the rest of the sloth, and this is inherent in the processor architecture.

Best Wishes
Amin



Joined: 19 Feb 2004
Posts: 15

View user's profile Send private message

PostPosted: Sat Mar 11, 2006 2:13 pm     Reply with quote

thanks guys,

Ttelmah,

That really sounds like a better solution because of that lack of address calculation each time.
You think you could give me some lead there, how to use an INT or char as pointer?

When I say slow, it is not in comparison with my 2400bps serial communication. But the I mean in term of processor time.

ckielstra,
When you say let the ISR handle it in the background, the problem is this background processing is time from the mainloop, there is a single cpu anyways.
_________________
McMaster Solar Car Project
http://www.solarcar.mcmaster.ca
Ttelmah
Guest







PostPosted: Sat Mar 11, 2006 3:12 pm     Reply with quote

You don't 'use an int or char as a pointer'. You just use a pointer to an int.
If (for instance), your data is sitting in memory declared as a structure, or an array of int 16's, then declare a pointer, and a size.
So if the structure is called 'fred', then just declare:
Code:

int * ptr;
int ctr;
int size;

//Then in the initialsation code:

ptr=&fred;
size=sizeof(fred);
ctr=size;

Then to getthe byte in the ISR:

val=*ptr++;
if (--ctr==0) {
   //here you have finished. To reset:
   ctr=size;
   fred-=size;
}


This way, the ISR address moves forwards by one byte, no matter what 'size' the actual data elements are (because ptr is an integer pointer).
The 'count', is done by simply decrementing a counter, equal to the number of bytes in the entire structure, and resetting when this reaches zero. This way the count is a single byte operation, using the fast '==0' test, which the compiler wll automatically do in the single dec/test instruction.

Best Wishes
Ttelmah
Guest







PostPosted: Sat Mar 11, 2006 3:14 pm     Reply with quote

Make the last line 'val-=size', not fred....

Best Wishes
Ttelmah
Guest







PostPosted: Sat Mar 11, 2006 3:16 pm     Reply with quote

Aaargh. My typing is going to pot.
ptr-=size;
God, I am gladI don't type that wrongly too often!...

Best Wishes
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Mar 12, 2006 1:52 pm     Reply with quote

Quote:

I am trying to send 16 bytes over the serial port. I have an array of 16
cells and the ISR incerement the index and grabs the byte and sends it
for tranmission until it reaches the end when it stops the cycle.
I am wondering if there is any faster way? Array handling seems like a
slow way of doing it.


I made a small test program to look at your problem. This program
uses the UART Tx interrupt to send 16 bytes from a buffer to the PC.
Code:

#include <16F877.H>
#device *=16
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#define MAX_INDEX 15
char buffer[MAX_INDEX +2] = {"0123456789ABCDEF"};
int8 index;

#int_tbe
void tbe_isr(void)
{
char c;

c = buffer[index];

putc(c);

index++;

if(index > MAX_INDEX)
   disable_interrupts(INT_TBE);

}

//===============================
void main()
{

index = 0;
enable_interrupts(INT_TBE);
enable_interrupts(GLOBAL);

while(1);
}


I looked at the .LST file, and it doesn't use many instructions to fetch
a byte from the array. It only takes 6 instructions, as shown in bold
below. So I'm not sure why you're concerned about this. The thing
that uses the most time is the interrupt dispatcher. It takes over 50
instructions just to get in and out of the isr. That's not including the
isr code.
Quote:

.................... #int_tbe
.................... void tbe_isr(void)
.................... {
.................... char c;
....................
.................... c = buffer[index];
0035: MOVLW 29
0036: ADDWF 3A,W
0037: MOVWF 04
0038: BCF 03.7
0039: MOVF 00,W
003A: MOVWF 3B

....................
.................... putc(c);
003B: MOVF 3B,W
003C: BTFSS 0C.4
003D: GOTO 03C
003E: MOVWF 19
....................
.................... index++;
003F: INCF 3A,F
....................
.................... if(index > MAX_INDEX)
0040: MOVF 3A,W
0041: SUBLW 0F
0042: BTFSC 03.0
0043: GOTO 047
.................... disable_interrupts(INT_TBE);
0044: BSF 03.5
0045: BCF 0C.4
0046: BCF 03.5
....................
.................... }
....................
....................
//===============================
0047: BCF 0C.4
0048: BCF 0A.3
0049: BCF 0A.4
004A: GOTO 01F
Amin



Joined: 19 Feb 2004
Posts: 15

View user's profile Send private message

PostPosted: Sun Mar 12, 2006 2:05 pm     Reply with quote

PCM Programmer,

thanks for the try. I never really looked at the dispatcher's default code. Mostly because I thought it would just right from the vector to the start my code.
I might have to just do something other than using CCS IRQ handlers.


Ttelman,

I haven't got a chance to try the pointer way, and I made a simple change (taken from your post) and that was to make my index to decrement from SIZE to zero as opposed to zero to size and that reduced the code size by 19 INSTR!!!! thanks

EDIT:
I goofed up, the 19 count decrease happened because I had index=0 as opposed to index==0!
and I will try the pointer business soon.
_________________
McMaster Solar Car Project
http://www.solarcar.mcmaster.ca
Amin



Joined: 19 Feb 2004
Posts: 15

View user's profile Send private message

PostPosted: Mon Mar 13, 2006 12:06 am     Reply with quote

Ttelmah wrote:
Aaargh. My typing is going to pot.
ptr-=size;
God, I am gladI don't type that wrongly too often!...

Best Wishes


you mean CTR or PTR?

My understanding is that the counter should be decremented ?
_________________
McMaster Solar Car Project
http://www.solarcar.mcmaster.ca
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Mar 13, 2006 3:23 am     Reply with quote

I compared both implementations for a PIC18F458, PCWH v3.245.

1) Using index:
Code:
....................   c = buffer[index];
009C:  CLRF   03
009E:  MOVF   2A,W
00A0:  ADDLW  19
00A2:  MOVWF  FE9
00A4:  MOVLW  00
00A6:  ADDWFC 03,W
00A8:  MOVWF  FEA
00AA:  MOVFF  FEF,2F
....................   index++;
00AE:  INCF   2A,F


2: Using pointer, short notation:
Code:
....................   val = *ptr++;
00C0:  MOVFF  2C,03
00C4:  MOVF   2B,W
00C6:  INCF   2B,F
00C8:  BTFSC  FD8.2
00CA:  INCF   2C,F
00CC:  MOVWF  FE9
00CE:  MOVFF  03,FEA
00D2:  MOVFF  FEF,30
Slower because of the post increment the ptr must be saved.

3: Using pointer, long notation:
Code:
.................... val = *ptr;
00D6:  MOVFF  2B,FE9
00DA:  MOVFF  2C,FEA
00DE:  MOVFF  FEF,30
.................... ptr++;
00E2:  INCF   2B,F
00E4:  BTFSC  FD8.2
00E6:  INCF   2C,F



1) 9 instructions, 10 clock cycles, 20 bytes.
2) 8 instructions, 11 clock cycles, 22 bytes.
3) 6 instructions, 9 clock cycles, 18 bytes

Conclusion:
Using pointers is 1 clock cycle faster than index based addressing but only when you take care of the notation. To me the increased difficulty in code readability doesn't outweigh the tiny performance gain.
Ttelmah
Guest







PostPosted: Mon Mar 13, 2006 5:07 am     Reply with quote

It is important here to distinguish between simple arrays, and larger forms. A integer array, with a one byte index, is pretty good. The problems appear with larger arrays, involving me complex data sizes, where the array fetch, has to involve multiplying the index, by the element size, and for multi-dimensional arrays, by the row size as well. This is why I am quite 'happy' about the array fetch for normal buffer handling. As I said, my 'worry' about arrays, comes in places, where people are using multiple arrays inside an ISR, where I have seen twenty or thirty extra instruction times being involved, for this type of work..

My suggestion, was not to use the ptr form, as a replacement for normal buffer handling (the savings are gnerally too small to be worthwhile), but as a method of transmitting data, sitting in something like a complex structure, where the pointer form, allows this to be handled as if it was in a simple array (an alternative is a union to an integer array, but this then involves redeclaring the variables, if they are used elsewhere).

The times given by Ckielstra are 'interesting', since I looked at these times some while ago, and the differences where then rather more marked. Improvements have obviously happened to the optimiser.

Best Wishes
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Mon Mar 13, 2006 8:01 am     Reply with quote

I guess it would be better when Amin explains a bit more of the troubles he is experiencing. We are now trying to optimize array access while we have very little info; What does the array look like? Why is timing so critical? How is it possible that reversing the loop from counting up to down counting gives a 19 byte reduction? I never get more than about 4 instructions reduction. etc.

Transmitting at 2400bps means the interrupt routine will only be entered 300 times per second. Assume the processor is running at 4MHz, 1 million instructions/second, and that we can save 100 instructions (which is a lot). Than this will give a performance increase of 3%. Nice, but not huge. Very likely there are other more effective targets for increasing performance.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group