EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Using Interrupt driven serial Port on 8051

Started by Makhan August 8, 2004
Hello all,

I have a very typical problem with a twist. Here goes:

I have a main loop running a piece of code. However, upon receiving
character '0' from serial port (or any 8bit code for that matter), I
want to read 8 or 16 or lets say n number of bytes from serial port.

So here is what I did, I created an updateFlag bit which gets set
whenver the true code is reached and the ISR quits. Whenever in the
main loop I reach the place for checking updateFlag, I deactivate the
ISR for Serial Port and assuming that now the serial port will act
just as normal, I run a debug code of reading a byte and outing it.
Only the serial port interrupt flag remains inactive while I am in
that function.

So the ISR goes like:

ISR_SP:
	JBC	TI, QUITY	; if TI caused it, just quit
	MOV	A, SBUF		; if '0' = 30 then update the IDATA
	ADD	A, #-30H	; else skip the update
	JNZ	QUITY
	SETB	UpdateFlag
QUITY:
	RETI			; if TX irq just returns 

and the main loop:

   while (1) 
      {
      if (UpdateFlag == 1) 
	 {
	 /*---------------------------- Debug ------------------------*/
	 EA = 0;
	 choice = GetByte();

	 choice++;

	 OutByte(choice);

	 UpdateFlag = 0;

	 EA = 1;
	 }
      
// Some functions here

My problem is this that the ISR works fine if I dont involve serial
port reading writing, that ISR would turn on or off any port correctly
upon receiving character '0'.

Similarly the GetByte and OutByte routines work fine as well when
Serial port is not on interrupt.

Its only after combining both I end up in problems, can anyone see any
potential problem in the approach?

Thanks in advance

Makhan
Makhan wrote:

> Hello all, > > I have a very typical problem with a twist. Here goes: > > I have a main loop running a piece of code. However, upon receiving > character '0' from serial port (or any 8bit code for that matter), I > want to read 8 or 16 or lets say n number of bytes from serial port. > > So here is what I did, I created an updateFlag bit which gets set > whenver the true code is reached and the ISR quits. Whenever in the > main loop I reach the place for checking updateFlag, I deactivate the > ISR for Serial Port and assuming that now the serial port will act > just as normal, I run a debug code of reading a byte and outing it. > Only the serial port interrupt flag remains inactive while I am in > that function. > > So the ISR goes like: > > ISR_SP: > JBC TI, QUITY ; if TI caused it, just quit > MOV A, SBUF ; if '0' = 30 then update the IDATA > ADD A, #-30H ; else skip the update > JNZ QUITY > SETB UpdateFlag > QUITY: > RETI ; if TX irq just returns > > and the main loop: > > while (1) > { > if (UpdateFlag == 1) > { > /*---------------------------- Debug ------------------------*/ > EA = 0; > choice = GetByte(); > > choice++; > > OutByte(choice); > > UpdateFlag = 0; > > EA = 1; > } > > // Some functions here > > My problem is this that the ISR works fine if I dont involve serial > port reading writing, that ISR would turn on or off any port correctly > upon receiving character '0'. > > Similarly the GetByte and OutByte routines work fine as well when > Serial port is not on interrupt. > > Its only after combining both I end up in problems, can anyone see any > potential problem in the approach? > > Thanks in advance > > Makhan
thou shallt never disable the interrupt on a recv serial port.
"Makhan" <makhan_rocks@hotmail.com> schreef in bericht
news:60f42c64.0408080948.35db76d2@posting.google.com...
> Hello all, > > I have a very typical problem with a twist. Here goes: > > I have a main loop running a piece of code. However, upon receiving > character '0' from serial port (or any 8bit code for that matter), I > want to read 8 or 16 or lets say n number of bytes from serial port. > > So here is what I did, I created an updateFlag bit which gets set > whenver the true code is reached and the ISR quits. Whenever in the > main loop I reach the place for checking updateFlag, I deactivate the > ISR for Serial Port and assuming that now the serial port will act > just as normal, I run a debug code of reading a byte and outing it. > Only the serial port interrupt flag remains inactive while I am in > that function. > > So the ISR goes like: > > ISR_SP: > JBC TI, QUITY ; if TI caused it, just quit > MOV A, SBUF ; if '0' = 30 then update the IDATA > ADD A, #-30H ; else skip the update > JNZ QUITY > SETB UpdateFlag > QUITY: > RETI ; if TX irq just returns > > and the main loop: > > while (1) > { > if (UpdateFlag == 1) > { > /*---------------------------- Debug ------------------------*/ > EA = 0; > choice = GetByte(); > > choice++; > > OutByte(choice); > > UpdateFlag = 0; > > EA = 1; > } > > // Some functions here > > My problem is this that the ISR works fine if I dont involve serial > port reading writing, that ISR would turn on or off any port correctly > upon receiving character '0'. > > Similarly the GetByte and OutByte routines work fine as well when > Serial port is not on interrupt. > > Its only after combining both I end up in problems, can anyone see any > potential problem in the approach? > > Thanks in advance > > Makhan
Where is the gain? Sit and wait until all those other 15 bytes arrive in the serial port? It seems that such approach is only a waste of time. Keep a 256 byte ringbuffer, and let your serial interrupt fill it. Your main loop compares a pointer/index with the one you use to fill the buffer, to check if new characters have arrived. Process those characters, and update the main pointer/index. -- Thanks, Frank. (remove 'x' and 'invalid' when replying by email)
makhan_rocks@hotmail.com (Makhan) wrote:

>So the ISR goes like: > >ISR_SP: > JBC TI, QUITY ; if TI caused it, just quit > MOV A, SBUF ; if '0' = 30 then update the IDATA > ADD A, #-30H ; else skip the update > JNZ QUITY > SETB UpdateFlag >QUITY: > RETI ; if TX irq just returns
One problem that has not been mentioned by others (at least in c.a.e.), is that your ISR does not save and restore ACC and PSW. Oops! -- Dan Henry
don't disable the IRQ function.
  when receiving a character have the IRQ
service simply put it in a recircular buffer.
using 2 pointer regs to keep track of the next
one to reed from the buffer and the next one
to write to the buffer.
    when the two pointers match this means there
is no characters in the buffer.
  when ever they don't match you read the character
from the buffer of the current next-to-pointer then
increment that pointer, when storing new characters
you simply store it using the next-to-write pointer and
then increment that pointer for the next..
  now, before storing the new incremental results of the
Next-To-write pointer you should first make sure that it
does not equal the current Next-To-Read pointer! other
wise this indicates an over flow and some form of error
should be set ..
  your buff could be a simple 16 bytes or more depending on
how much traffic your processor will take.
   lets assume its a 16 byte buffer, you do this in
math
   Next-to-read = (Next-to-read+1) and H0F; ( $0F, 0x0f etc. take your pic);
  that will create a nice wrap around buffer..
etc..


Makhan wrote:

> Hello all, > > I have a very typical problem with a twist. Here goes: > > I have a main loop running a piece of code. However, upon receiving > character '0' from serial port (or any 8bit code for that matter), I > want to read 8 or 16 or lets say n number of bytes from serial port. > > So here is what I did, I created an updateFlag bit which gets set > whenver the true code is reached and the ISR quits. Whenever in the > main loop I reach the place for checking updateFlag, I deactivate the > ISR for Serial Port and assuming that now the serial port will act > just as normal, I run a debug code of reading a byte and outing it. > Only the serial port interrupt flag remains inactive while I am in > that function. > > So the ISR goes like: > > ISR_SP: > JBC TI, QUITY ; if TI caused it, just quit > MOV A, SBUF ; if '0' = 30 then update the IDATA > ADD A, #-30H ; else skip the update > JNZ QUITY > SETB UpdateFlag > QUITY: > RETI ; if TX irq just returns > > and the main loop: > > while (1) > { > if (UpdateFlag == 1) > { > /*---------------------------- Debug ------------------------*/ > EA = 0; > choice = GetByte(); > > choice++; > > OutByte(choice); > > UpdateFlag = 0; > > EA = 1; > } > > // Some functions here > > My problem is this that the ISR works fine if I dont involve serial > port reading writing, that ISR would turn on or off any port correctly > upon receiving character '0'. > > Similarly the GetByte and OutByte routines work fine as well when > Serial port is not on interrupt. > > Its only after combining both I end up in problems, can anyone see any > potential problem in the approach? > > Thanks in advance > > Makhan
Jamie wrote:
> > don't disable the IRQ function. > when receiving a character have the IRQ > service simply put it in a recircular buffer. > using 2 pointer regs to keep track of the next > one to reed from the buffer and the next one > to write to the buffer. > when the two pointers match this means there > is no characters in the buffer.
Please don't toppost. Your answer goes after, or possibly interleaved with, appropriately snipped quoted material. i.e. remove anything not germane to your answer. You also need to resolve how to handle buffer overflow on input. For interactive use I recommend discarding the oldest char, rather than the new char. This allows a manual interrupt such as CTL-C to be noticed. -- "Churchill and Bush can both be considered wartime leaders, just as Secretariat and Mr Ed were both horses." - James Rhodes.
CBFalconer wrote:
> Jamie wrote: > >>don't disable the IRQ function. >> when receiving a character have the IRQ >>service simply put it in a recircular buffer. >>using 2 pointer regs to keep track of the next >>one to reed from the buffer and the next one >>to write to the buffer. >> when the two pointers match this means there >>is no characters in the buffer. >
> You also need to resolve how to handle buffer overflow on input. > For interactive use I recommend discarding the oldest char, rather > than the new char. This allows a manual interrupt such as CTL-C > to be noticed. >
You also need to serialize access to the buffer pointers, unless there's an atomic read-modify-write on an 8051 (which I don't know, being a PIC guy). Otherwise once in awhile your mainline code will be interrupted after reading the buffer pointer and before updating it--and when the ISR returns, the pointer will be overwritten. This sort of thing is a real headache to debug, so just follow the rule about not sharing resources between ISRs and mainline routines, and serialize the circular buffers used for the interface. That will make your programs much less flaky. Cheers, Phil Hobbs
On Mon, 09 Aug 2004 11:17:03 -0400, Phil Hobbs
<pcdhSpamMeSenseless@us.ibm.com> wrote:

> > >You also need to serialize access to the buffer pointers, unless there's an >atomic read-modify-write on an 8051 (which I don't know, being a PIC guy). >Otherwise once in awhile your mainline code will be interrupted after reading >the buffer pointer and before updating it--and when the ISR returns, the >pointer will be overwritten. This sort of thing is a real headache to debug, >so just follow the rule about not sharing resources between ISRs and mainline >routines, and serialize the circular buffers used for the interface. That >will make your programs much less flaky.
You can avoid the need for a critical region in which you lock out interrupts by proper access rules for the buffer indexes. While both the reader (main loop) and writer (ISR) can read both indexes, only the reader should modify the read index, and only the writer should modify the write index. It's also important to never write an invalid value to an index, since the other guy (really only the ISR here) can interrupt and use it. For a power of two buffer size, you can either let a byte index freely increment through all 256 values and AND it with the proper mask before using it, or you can do a wraparound test before incrementing, and set it to zero if equal to the wrap value. It isn't a good idea to increment the index and then mask it, since prior to writing back the masked value the index will be invalid. -- Jim McGinnis

Frank Bemelman wrote:

> "Makhan" <makhan_rocks@hotmail.com> schreef in bericht > news:60f42c64.0408080948.35db76d2@posting.google.com... > > Hello all, > > > > I have a very typical problem with a twist. Here goes: > > > > I have a main loop running a piece of code. However, upon receiving > > character '0' from serial port (or any 8bit code for that matter), I > > want to read 8 or 16 or lets say n number of bytes from serial port. > > > > So here is what I did, I created an updateFlag bit which gets set > > whenver the true code is reached and the ISR quits. Whenever in the > > main loop I reach the place for checking updateFlag, I deactivate the > > ISR for Serial Port and assuming that now the serial port will act > > just as normal, I run a debug code of reading a byte and outing it. > > Only the serial port interrupt flag remains inactive while I am in > > that function. > > > > So the ISR goes like: > > > > ISR_SP: > > JBC TI, QUITY ; if TI caused it, just quit > > MOV A, SBUF ; if '0' = 30 then update the IDATA > > ADD A, #-30H ; else skip the update > > JNZ QUITY > > SETB UpdateFlag > > QUITY: > > RETI ; if TX irq just returns > > > > and the main loop: > > > > while (1) > > { > > if (UpdateFlag == 1) > > { > > /*---------------------------- Debug ------------------------*/ > > EA = 0; > > choice = GetByte(); > > > > choice++; > > > > OutByte(choice); > > > > UpdateFlag = 0; > > > > EA = 1; > > } > > > > // Some functions here > > > > My problem is this that the ISR works fine if I dont involve serial > > port reading writing, that ISR would turn on or off any port correctly > > upon receiving character '0'. > > > > Similarly the GetByte and OutByte routines work fine as well when > > Serial port is not on interrupt. > > > > Its only after combining both I end up in problems, can anyone see any > > potential problem in the approach? > > > > Thanks in advance > > > > Makhan > > Where is the gain? Sit and wait until all those other 15 bytes arrive > in the serial port? It seems that such approach is only a waste of time. > > Keep a 256 byte ringbuffer, and let your serial interrupt fill it. > Your main loop compares a pointer/index with the one you use to fill > the buffer, to check if new characters have arrived. Process those > characters, and update the main pointer/index. > > -- > Thanks, Frank. > (remove 'x' and 'invalid' when replying by email)
256 may be too much for a 8051, But he definitely needs a buffer ring or otherwise.
"Neil Kurzman" <nsk@mail.asb.com> schreef in bericht
news:411853D6.F11F3A66@mail.asb.com...
> > > Frank Bemelman wrote: > > > Where is the gain? Sit and wait until all those other 15 bytes arrive > > in the serial port? It seems that such approach is only a waste of time. > > > > Keep a 256 byte ringbuffer, and let your serial interrupt fill it. > > Your main loop compares a pointer/index with the one you use to fill > > the buffer, to check if new characters have arrived. Process those > > characters, and update the main pointer/index. > > > > -- > > Thanks, Frank. > > (remove 'x' and 'invalid' when replying by email) > > 256 may be too much for a 8051, But he definitely needs a buffer ring or > otherwise.
I assumed plenty of XDATA ;) -- Thanks, Frank. (remove 'x' and 'invalid' when replying by email)

The 2024 Embedded Online Conference