Hi There,
I am working on a little microcontroller application and i want to
receive bytes from UART 1(rs232) and pass them on to UART2 with as
little buffering as possible.
I have an interrupt function that kicks in when I can receive a byte
and I do this:
// buffer was allocated with calloc(1,1)
if(realloc(buffer,++buffersz)!=NULL){
if(buffersz){
fprintf(DEBUG,"NoBrcv %Ld %c 0x%x\r\n",Brcv, ch, ch);
buffer[buffersz-1]=ch;
}else
fprintf(DEBUG,"ERROR: invalid buffer size(%Ld), cant receive data!
\r\n",buffersz);
} else{
fprintf(DEBUG,"Out of memory, allocated %Ld Bytes\r\n",buffersz);
if (buffersz%1024==0){
fprintf(DEBUG, "%LdKB allocated\r\n",buffersz/1024);
}
}
and then in my main, i have a loop to send the data out and i do it
like this:
while(RC1IE || buffersz>1){
if(buffersz)
{
fputc(buffer[0],MCU1);
if(realloc(buffer,--buffersz)!=NULL){
fprintf(DEBUG, "ERROR:Failed to shrink buffer %Ld!\r\n",
buffersz);
}
}
}
But that doesn't quite seem to work correctly. I think I 'm messing my
array up with my realloc() calls. Any suggestions are appreciated!
Thank you!
BTW: I'm using the CCS compiler version 4.119
Hi There,
I am working on a little microcontroller application and i want to
receive bytes from UART 1(rs232) and pass them on to UART2 with as
little buffering as possible.
I have an interrupt function that kicks in when I can receive a byte
and I do this:
// buffer was allocated with calloc(1,1)
if(realloc(buffer,++buffersz)!=NULL){
if(buffersz){
fprintf(DEBUG,"NoBrcv %Ld %c 0x%x\r\n",Brcv, ch, ch);
buffer[buffersz-1]=ch;
}else
fprintf(DEBUG,"ERROR: invalid buffer size(%Ld), cant receive data!
\r\n",buffersz);
} else{
fprintf(DEBUG,"Out of memory, allocated %Ld Bytes\r\n",buffersz);
if (buffersz%1024==0){
fprintf(DEBUG, "%LdKB allocated\r\n",buffersz/1024);
}
}
and then in my main, i have a loop to send the data out and i do it
like this:
while(RC1IE || buffersz>1){
if(buffersz)
{
fputc(buffer[0],MCU1);
if(realloc(buffer,--buffersz)!=NULL){
fprintf(DEBUG, "ERROR:Failed to shrink buffer %Ld!\r\n",
buffersz);
}
}
}
But that doesn't quite seem to work correctly. I think I 'm messing my
array up with my realloc() calls. Any suggestions are appreciated!
Thank you!
BTW: I'm using the CCS compiler version 4.119
Just a couple of points to consider in addition to these other posts.
Typically you want your interrupt functions to be in and out as fast
as possible, to avoid the interrupt in an interrupt debacle. I've
only used one MCU and its library support does not have dynamic
memory, but I imagine that doing a realloc of any kind is a bad idea
in an interrupt. Functions of the printf are very bad for similar
reasons. In an interrupt, I typically set a bitflag that the main
while loop detects that moves the character into some non-volatile
declared circular buffer to ensure that the interrupt is ready for the
next ping. I might need to move it to a separate holding character
depending on how slow main responds to other events. If your app has
to update an 128x64 pixel LCD display, read an array of 5 temperature/
humidity sensors at a rate of once a second, respond to serial
commands, handle a 3-button menu interface, and store data to EEPROM,
you obviously can't shove all this into the interrupt handler.
In your scenario, if the response to each of your events is fast,
little work needs to be done. If your MCU app is just mirroring
serial port traffic at the same rate, there's very little if any
buffering that I would think needs to be done. A single character
buffer may be all that is needed, or if the app is busy and lag from
processing other events is severe, a small fixed size buffer can cache
the collected characters until the main program can catch up. If it's
burst traffic, then you just have to cache enough space to store
characters to allow main to finish processing its current event before
sending the accumulated data. If your throughput is constant and
hovers near the max baud rate, then one needs to be quite a bit more
careful.
One thing that really helps me is using an oscilloscope and toggling a
pin to measure time periods within the program. It can help give you
an idea of how much time a particular task takes. You set the pin
high at the start of your event, and set it low at the end, and you
can measure the time while the pulse is high to estimate the time
needed to process your event. This is useful to ensure that the speed
of your event handling exceeds the rate of input.
If you have synchronous events, like taking a temperature sensor
measurement at a rate of once a second, you can use a timer interrupt
to update a global clock with millisecond precision and use timeouts
to signal when events happen. If you have a clock with millisecond
precision that you increment based on a hardware timer, you need to be
wary when reading or writing the clock variables.
Here's a code snippet that demonstrates how I interact with an
interrupt to maintain a millisecond clock. I cut out most of the
fluff, and hopefully you can see the main points.
\code snippet
/* Timer0 interrupt service routine that increments a counter. */
void interrupt isr( void );
/* The TMR0 counter bias. */
#define TMR0_BIAS 6
/* The PIC18F system clock. */
volatile long int tmr0_s;
volatile int tmr0_tick;
/* Get the PIC time in seconds. */
time_t gettime_s( time_t* t );
void gettime( c_time_value_t* tv );
....
void gettime( c_time_value_t* tv )
{
if ( tv )
{
TMR0IE = 0;
tv->sec = tmr0_s;
tv->usec = (long int)tmr0_tick * 1000;
TMR0IE = 1;
}
}
time_t gettime_s( time_t* t )
{
time_t tv;
TMR0IE = 0;
tv = tmr0_s;
TMR0IE = 1;
if ( t ) {
*t = tv;
}
return tv;
}
void interrupt isr( void )
{
if( (TMR0IE) && (TMR0IF) && (TMR0IP) )
{
/*
* The output pins RB6 and RB7 are toggled to measure to overhead
* of the ISR implementation. They demonstrate one method to
* measure code execution time using an oscilloscope.
*/
RB6 ^= 1;
TMR0 = TMR0_BIAS; /* 0.375 ns (3 inst) */
TMR0IF=0; /* 0.125 ns (1 inst) */
++tmr0_tick; /* 0.500 ns (4 inst) */
if ( tmr0_tick == C_TICKS_PER_SECOND ) /* 0.750 ns (6 inst) */
{
++tmr0_s; /* 0.750 ns (6 inst) */
tmr0_tick = 0; /* 0.500 ns (4 inst) */
}
RB7 ^= 1; /* 0.125 ns (1 inst) */
}
}
\endcode
Note the disabling of timer interrupt in gettime 'TMR0IE = 0;',
followed by updating the timestamp to the global clock, then re-
enabling the interrupt. Note that when I disable the interrupt in
gettime 'TMR0IE = 0', it's possible that during the time I update the
timestamp 'tv->sec = tmr0_s; tv->usec = (long int)tmr0_tick * 1000;',
the 1ms timer interrupt could have triggered. The interrupt won't
happen until I re-enable the interrupt at 'TMR0IE = 1', which can
introduce a little bit of jitter. As an aside, this was running on a
chip configured with a clock speed of 32MHz or 8MIPS (millions of
instructions per second), so the jitter effect is negligible in my
application. If the clock speed is slower, or the data rates approach
clock speed limitations, it can be problematic.
Also, in the ISR, I toggle pins RB6 and RB7 to generate square waves
so I can actually see whether my hardware timer is set correctly, and
whether my clock has any cumulative skew (to make sure that any jitter
effects are not cumulative).
Hope it helps.
Best regards,
John D.