View previous topic :: View next topic |
Author |
Message |
Manu59114
Joined: 22 Jan 2018 Posts: 34 Location: North of France
|
Data sent slowly with circular buffer |
Posted: Thu Sep 20, 2018 12:12 am |
|
|
Hello to all
I encounter a strange problem. When i use the circular transmit buffer, i don't understand why sometimes my data string are sent on the UART very slowly.
Code: |
void bputc2(char c)
{
short restart2;
int ni2;
restart2=t_next_in2==t_next_out2;
t_buffer2[t_next_in2]=c;
ni2=(t_next_in2+1) % T_BUFFER2_SIZE;
while(ni2==t_next_out2);
{t_next_in2=ni2
}
if(restart2)
{ enable_interrupts(int_tbe2);
}
}
#INT_TBE2
void TBE2_isr(void)
{
Flag_Int_TBE2=1;
Stop_WS2812_Stream=1;
if(t_next_in2!=t_next_out2) //
{
putc(t_buffer[t_next_out]);
fputc(t_buffer2[t_next_out2],PORT2);
t_next_out2=(t_next_out2+1) % BUFFER2_SIZE;
if(t_next_in2==t_next_out2)
{
disable_interrupts(int_tbe2);
Flag_Int_TBE2=0;
}
}
//Main.c
//Code executed at startup, not in the While(1)
delay_ms(1000);
printf(bputc2,"+++");
delay_ms(200);
printf(bputc2,"R1=9F7F7F\r");
delay_ms(200);
printf(bputc2,"R2=9F7F7F\r");
delay_ms(200);
printf(bputc2,"R3=9F7F7F\r"); |
when i replace printf(bputc2,"R3=9F7F7F\r");
with fprintf(PORT2,"R3=9F7F7F\r");
data are sent immediatly with no delay!
FYI, i need small delay between each transmission.
Have a great day!
Manu _________________ CCS + ICD3 + PIC18F46K80 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Sep 20, 2018 1:23 am |
|
|
There are several 'extreme oddities' in your posted code.....
First:
restart2=t_next_in2==t_next_out2;
This will make 'restart2', TRUE, if t_next_in2 is equal to t_next_out2, so potentially if the buffer is empty.
This then is used at the end of the routine, to enable interrupts. Possibly fair enough.
However if the buffer overflows:
while(ni2==t_next_out2);
{t_next_in2=ni2
}
Nothing is done. Look carefully. All that is executed is the ';' not the bracketed reset operation that you probably want to execute....
Wrong.... :(
So this means the first line could return TRUE if the buffer overflows as well, since the buffer is not being reset in this condition. Ugh.
Then the actual ISR only sends data if there is something in the buffer (fair enough), but if there is nothing in the buffer the interrupt is left enabled (since the test for buffer being empty is inside the test for it not being empty), so there is potentially a hang with the interrupt being continuously called. Again a major problem... :(
You need a radical re-think of how your buffer handling is being done. |
|
|
Manu59114
Joined: 22 Jan 2018 Posts: 34 Location: North of France
|
|
Posted: Thu Sep 20, 2018 4:00 am |
|
|
Thanks Ttelmah
I will re write my code! But i need to understand a part of this code.
Code: |
void bputc(char c) {
#if defined(__PCD__)
#bit U1TXIF = getenv("BIT:U1TXIF")
#endif
short restart;
int ni; |
restart=t_next_in==t_next_out; // At the beguinning, Restart == 1
t_buffer[t_next_in]=c; // send C in the Array at t_next_in
ni=(t_next_in+1) % T_BUFFER_SIZE; // ni ==0
while(ni==t_next_out); // This line is not understand...
Is it not an infinite loop?
Which part of the code will be executed if the condition is True or if the condition is false?
Code: |
t_next_in=ni;
if(restart)
#if defined(__PCD__)
U1TXIF = 1;
#else
enable_interrupts(int_tbe);
#endif
}
|
Many Thanks to all for help me!
Manu _________________ CCS + ICD3 + PIC18F46K80 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Sep 20, 2018 4:13 am |
|
|
No. Remember that 't_next_out' is updated in the interrupt.
So this will stop, if the buffer would be full after the data is added, until the interrupt sends one character.
It sounds as if you are using someone else's code, with some typing errors to make it not work correctly. Why not use ex_stisr.c which is in the compiler examples. This is correct. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Thu Sep 20, 2018 4:38 am |
|
|
Just thinking. There is another issue that applies to the code, that you may not realise. The buffer size in this code (and in the CCS example), _must_ be a 'binary multiple'. So 8, 16, 32, 64 bytes. If you use a size like (say) 20 bytes, it'll result in extreme inefficiency in the code as posted. Very important to understand. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Fri Sep 28, 2018 12:50 pm |
|
|
Just to explain the why a binary multiple (power of 2) size is faster:
The code uses the modulus operator, "%" to bound the buffer. This operation normally takes a division operation, which can be extremely slow. Even chips with hardware divide typically take 18 instruction cycles for atomic sized divisions. However, taking the modulus of a value using a binary multiple (power of 2) number, x % 256 for example, can be done without division using just an AND operation, which is normally just a single instruction cycle for atomic sized operations.
To show with the above example:
(x % 256) is equivalent to (x AND 255)
but
(x % 255) cannot be converted to an AND and must use division. |
|
|
|