View previous topic :: View next topic |
Author |
Message |
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
Different speed for different ports |
Posted: Tue Mar 20, 2012 9:18 am |
|
|
Hello,
I noticed something very unusual for me. I wrote a software write serial function. I notice there is a speed difference between pin_Do vs pin_D7.
Although, I checked the asm and the code being generated does seem correct.
Pin_A0, Pin_B0, Pin_C0, Pin_D0 are all faster than Pin_A7, Pin_B7, Pin_C7 and Pin_D7.
Could the method of referencing the BIT within the BYTE be the speed issue? Or does the hardware have different latency on higher port bits than lower port bits?
Also, is it possible to modify a port for input/output on a per BIT basis when using Fast I/O? For example, can I set Pin_D6 to Input without having to re-modify the other bits within the port for that TRIS?
Code: |
#bit bit1 = c.0
#bit bit2 = c.1
#bit bit3 = c.2
#bit bit4 = c.3
#bit bit5 = c.4
#bit bit6 = c.5
#bit bit7 = c.6
#bit bit8 = c.7
disable_interrupts(GLOBAL);
output_low(port); // start bit
delay_us(delay);
output_bit(port, bit1);
delay_us(delay);
output_bit(port, bit2);
delay_us(delay);
output_bit(port, bit3);
delay_us(delay);
output_bit(port, bit4);
delay_us(delay);
output_bit(port, bit5);
delay_us(delay);
output_bit(port, bit6);
delay_us(delay);
output_bit(port, bit7);
delay_us(delay);
output_bit(port, bit8);
delay_us(delay);
output_high(port); // stop
delay_us(delay);
enable_interrupts(GLOBAL);
|
|
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Tue Mar 20, 2012 11:43 am |
|
|
Hello, also ..
I think i see how to set the tris direction without modifying the entire port... I can use Output_Float (for input) and Output_Drive (for output)?
I notice that Output_Float() works great when i pass in a variable respresenting the port... However, Output_Drive() has a bug that requires a constant. |
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Tue Mar 20, 2012 12:42 pm |
|
|
I data logged a 12.8us timer turning on and off 20 i/o with fast and general and in the main thread counted from 0 to 800000.
With fast i/o it took 4.5400 seconds
With general purpose it took 4.5425 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 20, 2012 2:18 pm |
|
|
If you want help, you need to post a complete test program. For example
in your code, you don't tell show the declaration of 'port'. You also don't
tell us your PIC, or your oscillator frequency.
This thread discusses how to speed up software SPI loop code:
http://www.ccsinfo.com/forum/viewtopic.php?t=46142
Notice that the program I posted is a complete test program. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Mar 20, 2012 2:26 pm |
|
|
RBuilder wrote: | With fast i/o it took 4.5400 seconds
With general purpose it took 4.5425 | I don't understand your method of measurement, but a difference of 0.055% is insignificant. This difference is well within normal error margins for measurements, for example a temperature difference would explain it.
Off topic: I hate it that often a thread hasn't been responded to for more than an hour, and then just the five minutes it takes me to read the post and type an answer somebody posts the same answer I was going to send. |
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Tue Mar 20, 2012 4:50 pm |
|
|
PCM programmer wrote: | If you want help, you need to post a complete test program. For example
in your code, you don't tell show the declaration of 'port'. You also don't
tell us your PIC, or your oscillator frequency.
This thread discusses how to speed up software SPI loop code:
http://www.ccsinfo.com/forum/viewtopic.php?t=46142
Notice that the program I posted is a complete test program. |
Okie dokie. It's a 18f4685 @ 40 mhz (H4)
The rest of the code is too long so i'll just summarize again.
If i output_high(pin_a0), it is faster than if i output_high(pin_a7). Do you know why?
It appears all ports behave the same way. The lower the bit on the port responds faster than the higher bits.
Ckielstra, the 0.055% is actually a HUGE difference because at a 12.8us timer, that's quite a few clock cycles |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 20, 2012 4:53 pm |
|
|
What's your CCS compiler version ? It's a 4-digit number given at the
top of the .LST file, which will be in your project directory after a
successful compilation. Examples of version numbers:
http://www.ccsinfo.com/devices.php?page=versioninfo |
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Tue Mar 20, 2012 5:03 pm |
|
|
PCM programmer wrote: | What's your CCS compiler version ? It's a 4-digit number given at the
top of the .LST file, which will be in your project directory after a
successful compilation. Examples of version numbers:
http://www.ccsinfo.com/devices.php?page=versioninfo |
4.105
I took a screenshot of the oscilliscoped output. I have no where to store the image though.
I set the delays for Pin_d0 to bit bash 9600 baud serial from that real basic code i printed earlier. The delay i used comes out to be absolutely PERFECT timing for Pin_d0 @ 9600 .. The width of each pulse is exactly 0.104ms..
But then I do the exact same code but switch to Pin_d7 and the width of each pulse is now 0.106ms
That's a huge difference - and it's consistent. And even stranger, the same code on Pin_d3 (which is half way) is 0.105ms
LOL, it's totally confusing me. I didn't know there was a physical latency on the hardware based on the bit of the port.
Edit: PS I am using Fast I/O also. There are no timers running in the background, as you can see from my above code, i disable them. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 20, 2012 5:22 pm |
|
|
Quote: | I have no where to store the image though.
|
http://www.imageshack.us
Then post a link to it. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Mar 20, 2012 6:50 pm |
|
|
Unexplained #bit and other VAR defines aside ---
is this not a a very primitive way to try to output a serial baudot code bit stream ?? ie: generate software rs232 style bit bang output ??
and the complaint, if I decode it right - is that the poster believes
the delay_us function works differently when used on different pins??
There is so much concealed that its hard to have much of an idea of what, if anything - might be wrong - other than surely, at least the basic concept behind this listing. I sure need a define for
c
PORT
DELAY
to even begin to know what could be at issue.
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 21, 2012 12:49 am |
|
|
RBuilder wrote: | Ckielstra, the 0.055% is actually a HUGE difference because at a 12.8us timer, that's quite a few clock cycles | I disagree. A small percentage error remains small, whatever your clock is. That's why a percentage is such a nice way of indicating value differences.
0.055% speed error equals to 1 instruction difference out of every 1818 instructions.
Unless, of course, I am misunderstanding your test method. Reading your test method again it is not clear to me what you are measuring and how you do it.
One minor suggestion in your code is to not to define bit1 as c.0. In electronics it is common practice to start numbering bits from 0. An other person reading your code could get confused from this (at least I did). |
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Wed Mar 21, 2012 12:58 am |
|
|
asmboy wrote: | Unexplained #bit and other VAR defines aside ---
is this not a a very primitive way to try to output a serial baudot code bit stream ?? ie: generate software rs232 style bit bang output ??
and the complaint, if I decode it right - is that the poster believes
the delay_us function works differently when used on different pins??
There is so much concealed that its hard to have much of an idea of what, if anything - might be wrong - other than surely, at least the basic concept behind this listing. I sure need a define for
c
PORT
DELAY
to even begin to know what could be at issue.
|
okay here
hook up an oscilliscope to your pic. run this code and look at the length of time of the low pulse.
Code: |
void blah() {
int16 port = pin_d0;
int delay = 100;
while (true) {
output_bit(port, 1);
delay_us(delay);
output_bit(port, 0);
delay_us(delay);
output_bit(port, 1);
delay_us(delay);
}
}
|
now run this and look at the length of time of the low pulse.
Code: |
void blah() {
int16 port = pin_d7;
int delay = 100;
while (true) {
output_bit(port, 1);
delay_us(delay);
output_bit(port, 0);
delay_us(delay);
output_bit(port, 1);
delay_us(delay);
}
}
|
now see? the same code on the same port and different bits results in two different speeds. i never accused the delay of being different because that would be completely silly
the higher the bit of that port, the more latency there is. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Mar 21, 2012 3:14 am |
|
|
You are confusing things by even having the delay there.
All you need to show what you are talking about, is:
Code: |
int16 pin_no;
int8 count;
do {
pin_no=PIN_D0;
for (count=0;count<100;count++) {
output_bit(pin_no,1);
output_bit(pin_no,0);
}
pin_no=PIN_D7;
for (count=0;count<100;count++) {
output_bit(pin_no,1);
output_bit(pin_no,0);
}
} while (TRUE);
|
The answer is 'yes'. Of course it'll take different time.
Even if you wrote it directly in assembler, it would. There is no inbuilt instruction in the PIC, to access a bit by a number stored in a variable. So the compiler has to convert the bit number into a mask, using rotation, and the further up the byte the bit is, the more rotations are needed, so the more time.
You need to rethink what you are actually trying to do.
If (for instance), you are using a variable because you want the same code to talk to two port bits, then just use a single bit variable as a flag, and use two hard coded output instructions.
So:
Code: |
#define USE_PIN_D7 (1)
#define USE_PIN_D0 (0)
#define OUTPUTHIGH_TO_PIN(x) if(x) output_high(PIN_D7); else output_high(PIN_D0)
#define OUTPUTLOW_TO_PIN(x) if(x) output_low(PIN_D7); else output_low(PIN_D0)
int1 pin_flag;
int8 count;
do {
pin_flag=USE_PIN_D7;
for (count=0;count<100;count++) {
OUTPUTHIGH_TO_PIN(pin_flag);
OUTPUTLOW_TO_PIN(pin_flag);
}
pin_flag=USE_PIN_D0;
for (count=0;count<100;count++) {
OUTPUTHIGH_TO_PIN(pin_flag);
OUTPUTLOW_TO_PIN(pin_flag);
}
} while (TRUE);
|
Realistically, if timing is critical, one also has to ask if software is the right tool for what you are trying to do. This is what things like hardware UART's, and timers are for. If you perform the timings using a hardware timer, then varying latencies in the bit accesses have no effect.
Another alternative, is to perform the masking yourself. If you look at many standard examples for doing bit accesses, people generate the mask _once_ when the code is called, and then just perform a bytewide access using this mask when needed, so the timings remain constant.
This is a case of needing to understand the abilities and limitations of the hardware you are using, and working within these.
Best Wishes |
|
|
RBuilder
Joined: 27 Oct 2011 Posts: 10
|
|
Posted: Wed Mar 21, 2012 5:20 pm |
|
|
Great that is a nice response. Thanks for taking the time.
The thing is, this actually comes from a timer experience also. output_high(pin_d7) is slower than output_high(pin_d0) even when in a timer, and even when it's the only thing in the timer.
When i scope the pulse widths, they're identical in pin_d0 and pin_a0 and pin_b0. Then when I do the same with pin_d7, pin_a7, pin_b7, the time are equally the same but higher than lower bits of the same ports.
I've even tried using assembler instead of CCS. And they're the same also (i.e. BCF 0xF8C.7, BSF 0xF8C.7) is slower vs (i.e. BCF 0xF8C.0, BSF 0xF8C.0)
It seems that higher bits of a port respond slower by a few microseconds. I'm surprised no one else has experienced it. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Mar 21, 2012 5:24 pm |
|
|
Quote: | output_high(pin_d7) is slower than output_high(pin_d0) even when in a timer |
You should be able to post a super-short compilable test program so
we can test this. |
|
|
|