Searching \ for '[PIC]: problems with interrupt driven uart, 16C63' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/ints.htm?key=interrupt
Search entire site for: 'problems with interrupt driven uart, 16C63'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]: problems with interrupt driven uart, 16C63'
2000\11\20@174659 by Michael Shiloh

flavicon
face
Hi folks,

I've become very frustrated with my inability to program a simple
buffered interrupt driven uart transmitter. I hope one of you
can figure out where my mistake is:

I'm running the following code on a 16C63.  I'm using the C2C
compiler from
http://www.geocities.com/SiliconValley/Network/3656/c2c/c.html

The key elements are:

- an 8 character circular transmit buffer
- the function "pchar" which determines if the transmitter is running; if it is,
 the new character is added to the buffer. If the transmitter isn't running,
 then the character is sent directly to the uart and transmit interrupts are
 enabled
- the transmit interrupt ISR looks to see if there are more characters in the
 buffer; if there are, the next one is transmitted. If there aren't, the
 transmit interrupt is turned off.
- buffer manipulation functions to append/remove to/from the buffer, and
 functions to tell me if the buffer is full/empty

The problem:

Any string that I pass on the first call to printf is printed fine. My guess is
this is all interrupt driven and the uart stops only at the end of this string.

I purposely inserted a pause to make sure the uart was empty, then I call
printf again.

This second call always fails, and always the same way. The second character
that would have been stored at the begining of the buffer is printed
indefinately.

I've experimented with different length strings, but the results are always the
same. I've also outputted the value of the "xxmit_remove" (the pointer
to the next char to be removed from the buffer and transmitted) to a port and
it seems to be properly counting from 0 to 7 and then starting again at 0.HH

(the include file mentioned is appended at the end)

Any help appreciated.

Thanks,
Michael

- - - - - - - - 8< - - cut here - - - ->8 - - - - - - - - - - - - -


* Configuration:
*
* With a 4 Mhz crystal
* the setting below give a serial port rate of 2400 baud
*
*/


/*
*
*
*/


/*
* Description:
*
* interrupt driven transmitter,
* using an 8 character circular transmit buffer
*
* the main() tests this by printing a string:

  printf ("\r\ntesting 1234567...");

* then pausing for a second,
* then printing a second string:

  printf ("tada\r\n");

*
* results:
*
* the first string displays with no errors
* the pause is about right
* instead of the second string, we just get the character 'g'
* forever. interestingly, 'g' is ninth character, so it is
* the first character to get written into an already used location.
* However, it should have been overwritten by the '7'
*
*/


/* Include Files */

#include <pic.h>



/* Definitions */

/* Port Directions */


/* Port A */

#define PORT_A_DIR 0x0 /* all are outputs */


/* Port B */

#define PORT_B_DIR 0x0 /* all are outputs */


/* Port C */
/* bit 2 must be set to use ccp1 as input */
/* bits 7-6 must be set for usart mode */
/* all others are outputs */

#define PORT_C_DIR 0xc4



/* global variables representing special registers */

char TXSTA@0x98;
char SPBRG@0x99;

char RCSTA@0x18;
char TXREG@0x19;
char RCREG@0x1A;

char PIR1@0x0C;
char PIE1@0x8C;

char PIR2@0x0D;
char PIE2@0x8D;

char TMR1L@0x0E;
char TMR1H@0x0F;
char T1CON@0x10;

char CCPR1L@0x15;
char CCPR1H@0x16;
char CCP1CON@0x17;


/* other global variables */

char txBuffer[8];
char xmit_remove = 0;            /* remove the next byte from xmit buffer HERE */
char xmit_append = 0;            /* append the next byte to xmit buffer HERE */

char running = FALSE;



/* functions */

/*
* returns:
*    TRUE if the transmit buffer is full
*    FALSE otherwise
*/
char SerTxBufferFull(void)
{
  char tmp;

  tmp = xmit_append + 1;
  tmp = tmp & 7;   /* faster than %8 */


  if (tmp - xmit_remove)
     return(FALSE);

  return(TRUE);
}


/*
* append the given character to the transmit buffer
* and increment the append pointer
* the buffer is NOT tested for fullness; that is the
* responsibility of the caller
*
* RETURNS:
*    nothing
*/
void SerTxBufferAppend(char c)
{

  txBuffer[xmit_append] = c;
  xmit_append++;
  xmit_append = xmit_append & 7;   /* faster than %8 */
}


/*
* remove a character from the transmit buffer
* and increment the remove pointer
* the buffer is NOT tested for emptyness; that is the
* responsibility of the caller
*
* RETURNS:
*      the character pointed to by the remove pointer
*/
char SerTxBufferRemove(void)
{
  char c;

  c = txBuffer[xmit_remove];
  txBuffer[xmit_remove] = 0;      /* indicate this has been removed */

  if (c)   /* only increment pointers if not empty */
  {
     xmit_remove++;
     xmit_remove = xmit_remove & 7;   /* faster than %8 */
  }

  return (c);
}


/*
* print the given character
*
* a simple description for a lot of work.
* this function must first determine whether the
* interrupt ISR is running or not, as if not it
* must be enabled and the character must be placed
* directly in the uart.
*
* if the ISR is running, the character is placed
* in the transmit buffer only if the buffer is not full
*
* RETURNS:
*      !OK if the transmit buffer is full
*      OK otherwise
*/
char pchar (char c)
{

  char full;
       char retval = OK;                                               /* assume everything will work        */

  disable_interrupt( GIE );         /* disable global interrupts         */

  if (running)                      /* transmitter running, add to queue */
  {

               full = SerTxBufferFull();      /* check transmit buffer for fullness */

               if (!full)
                       SerTxBufferAppend(c);
               else
                       retval = 1;                                             /* my compiler doesn't like !OK                         */
  }
  else                              /* transmitter is not running, xmit now */
  {

     TXREG = c;

     /* turn on transmit interrupts */
     set_bit( STATUS, RP0 );
     set_bit( PIE1, TXIE);         /* enable transmit interrupts */
     clear_bit( STATUS, RP0 );

     running = TRUE;               /* indicate we are running */
  }

  enable_interrupt( GIE );       /* enable global interrupts          */
       return (retval);

}

/*
* routine to print a null terminated string.
* simply call pchar until the null
*
* RETURNS:
*      nothing
*/
void printf( const char* text )
{
       char status ;
       char i = 0;
       char c;

       while( text[i] != 0 )
       {
               c = text[i];
               status = pchar( c );
               if (OK == status)
                       i++;
       }
}


void interrupt( void )
{
  char c;

  /* did timer 0 overflow? */

  if (INTCON & t0if_bitmask)
  {
     clear_bit( INTCON, T0IF );        /* clear TMR0 overflow flag */
  }

  /* did timer 1 overflow? */

  if (PIR1 & t1if_bitmask)
  {
     clear_bit( PIR1, TMR1IF );        /* clear TMR1 overflow flag */
  }

       /* capture/compare/pwm subsystem */

  if (PIR1 & ccp1if_bitmask)
  {
     clear_bit( PIR1, CCP1IF);      /* clear interrupt flag */
  }

  if (PIR1 & txif_bitmask)         /* transmit done interrupt */
  {
               /* are there more chars to transmit? */

     c = SerTxBufferRemove();        /* null signifies end of buffer */

     if (c)
     {
        TXREG = c;
     } /* remove pointer is left at next char */

     else

     {
        set_bit( STATUS, RP0 );
        clear_bit( PIE1, TXIE);         /* disable transmit interrupts */
        clear_bit( STATUS, RP0 );
        running = FALSE;
     } /* remove pointer is left pointing at this null */

  }

  if (PIR1 & rcif_bitmask)
  {
     /* nothing yet */
  }

} /* interrupt */


main()
{
  int i;

  clear_bit( STATUS, RP0 );  /* make sure we're in bank 0 */

  txBuffer[0] = 0;
  txBuffer[1] = 0;
  txBuffer[2] = 0;
  txBuffer[3] = 0;
  txBuffer[4] = 0;
  txBuffer[5] = 0;
  txBuffer[6] = 0;
  txBuffer[7] = 0;

  /* disable all interrupts */
  INTCON = 0;

  set_bit( STATUS, RP0 );  /* switch to register bank 1 */

  OPTION_REG = 0;
  PIE1 = 0;
  PIE2 = 0;


  /* initialize serial port */

  SPBRG = 25;    /* with BRGH = 0 and 4 Mhz xtal; 2400 baud  */

  clear_bit( TXSTA, BRGH );  /* low speed */
  clear_bit( TXSTA, SYNC );  /* async mode */

  set_tris_a( PORT_A_DIR );
  set_tris_b( PORT_B_DIR );
  set_tris_c( PORT_C_DIR );

  clear_bit( STATUS, RP0 );  /* switch back to register bank 0 */

  output_port_a( 0 );
  output_port_b( 0 );
  output_port_c( 0 );

       /*
        * enable interrupts and enable the uart, but do not
        * yet enable the uart transmit interrupt. this will be
        * done by pchar.
   */

  enable_interrupt( PEIE );     /* enable peripheral interrupts       */
  enable_interrupt( GIE );      /* enable global interrupts          */

  /* note that transmitter enable and interrupt bits are in bank 1 */
  set_bit( STATUS, RP0 );

       /* enable the xmitter */
  set_bit (TXSTA, TXEN);        /* enable transmitter */
  clear_bit( STATUS, RP0 );

  set_bit (RCSTA, SPEN );       /* enable serial port                */




       /* initialization complete; test the transmitter */

  printf ("\r\ntesting 1234567...");

  delay_s(1);

  printf ("tada\r\n");

  while (1)
       ;


} /* main */

- - - - - - - - 8< - - cut here - - - ->8 - - - - - - - - - - - - -
here is pic.h:


/*
* bits in the interrupt control register, INTCON.
* when written, INTCON enables or disables interrupts
* when read, INTCON flags which interrupts occurred
*
* all of the bit numbers are predifined, but I find it useful
* to define some masks
*/

#define t0if_bitmask 0x04 /* timer 0 overflow interrupt flag bitmask */
#define t1if_bitmask 0x01 /* timer 1 overflow interrupt flag bitmask */


/*
* the peripheral interrupt have separate registers for
* enables and flags
*/

/* bits in the first peripheral interrupt enable register, PIE1 */

#define TMR1IE 0x00
#define TMR2IE 0x01
#define CCP1IE 0x02
#define SSPIE 0x03
#define TXIE 0x04
#define RCIE 0x05
#define ADIE 0x06
#define PSPIE 0x07

/* bits in the first peripheral interrupt flag register, PIR1 */

#define TMR1IF 0x00
#define TMR2IF 0x01
#define CCP1IF 0x02
#define SSPIF 0x03
#define TXIF 0x04
#define RCIF 0x05
#define ADIF 0x06
#define PSPIF 0x07

#define max 0x02


/* bits in the second peripheral interrupt enable register, PIE2 */

#define CCP2IE  0x00

/* bits in the second peripheral interrupt flag register, PIR2 */

#define CCP2IF  0x00

/* masks for some of the above interrupts

#define tmr1if_bitmask 0x01  /* timer 1 overflow interrupt flag bitmask */
#define ccp1if_bitmask 0x04  /* usart transmit interrupt flag bitmask */
#define txif_bitmask   0x10 /* usart transmit interrupt flag bitmask */
#define rcif_bitmask   0x20 /* usart receive interrupt flag bitmask */

#define FALSE 0
#define TRUE 1

#define OK 0
#define ERROR !OK

/* capture/compare/pwm (CCP) mode register */

#define CAPTURE_FALLING 0x04
#define CAPTURE_RISING  0x05

--
http://www.piclist.com hint: The PICList is archived three different
ways.  See http://www.piclist.com/#archives for details.


2000\11\21@170349 by Dan Michaels

flavicon
face
Michael Shiloh wrote:
>Hi folks,
>
>I've become very frustrated with my inability to program a simple
>buffered interrupt driven uart transmitter. I hope one of you
>can figure out where my mistake is:
........


Hi Michael,

I noticed no one responded to your query - maybe because your
code is too long for anyone to want to look at, or maybe because
serial comm and C compilers have been beaten to a tiny pulp on
piclist numerous times.

I have never used a C compiler with PICs, so cannot help you there.
However, what I "would" recommend is stripping your code down to
the bare minimum, get that going, and then built it back up, one
step at a time.

First, try straight serial comm w/o interrupts. Then add in the
interrupts. Then add in the buffering stuff. Much easier to debug
the component parts individually, than to debug the entire thing
as a whole.

best regards,
- Dan Michaels
Oricom Technologies
http://www.oricomtech.com
=========================

--
http://www.piclist.com#nomail Going offline? Don't AutoReply us!
email spam_OUTlistservTakeThisOuTspammitvma.mit.edu with SET PICList DIGEST in the body


2000\11\21@204619 by Michael Shiloh

flavicon
face
Hi Dan,

Thanks for your help. I have had working, successfully, a polled
mode driver, and I tested the buffering scheme independenty. What
I haven't tested is an interrupt driven driver without the buffer.
I will test that and report back.

Thanks!
Michael

.~.    /"\    /\            Michael Shiloh
/V\    \ /   /\ \           .....mshilohKILLspamspam@spam@mediabolic.com
/( )\    X   /  \--          (415) 346-2270 x 121
^^-^^   / \  ----

On Tue, 21 Nov 2000, Dan Michaels wrote:

{Quote hidden}

--
http://www.piclist.com#nomail Going offline? Don't AutoReply us!
email .....listservKILLspamspam.....mitvma.mit.edu with SET PICList DIGEST in the body


2000\11\22@040207 by o-8859-1?Q?K=FCbek_Tony?=

flavicon
face
Hi,
noticed the lack of replys, and though maybe I'll
take a grab at it.
I can't help you with the 'c' portion ( ah maybe, but not
on the pic ).

Looking at your int handler you do not save any registers ??
At the very least you must save w and status, else you
will end up with a lot of trouble :)

Or does 'c' this automatically ? ( c2c for the pic that is ).

Then i suggest maybe using the following snippet for
a safe outside isr<->inside isr circular buffer handling.
Yes I know it's in assembler but it should not be a
problem rewriting or making inline assembler.

www.piclist.com/techref/default.asp?from=/techref/piclist/../micr
ochip/&url=16f876-hint-tk.htm


/Tony















Tony Kübek, Flintab AB            
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
E-mail: EraseMEtony.kubekspam_OUTspamTakeThisOuTflintab.com
²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²

--
http://www.piclist.com hint: To leave the PICList
piclist-unsubscribe-requestspamspam_OUTmitvma.mit.edu


2000\11\22@070654 by Ramana

flavicon
face
Hi,
Try the following

a. Initialise the Xmit_Remove and Xmit_Append after the delay back to 0.
See if th eoperation is OK. MAke sure the delay is long enough to flush
out the buffers. If it is working OK then it is a matter of buffer
operation

b. Also initilialise these 2 in the main and not leave it as global
inits. In general it would be better to init in the main routine again.
This depends on the environment (eprom/ram etc).

c. Make sure you have include the library support for interrupt
routines. These are necessary for saving and restoring context. This is
what we do in Hitec C

d. Try shorter length string of less than 8 and repeat this again to
give a clue.


rgds
ramana b v


{Original Message removed}

2000\11\23@003048 by Michael Shiloh

flavicon
face
Hello Ramana,

Thanks for your suggestions. Here are the results. I think
there is a message here but I haven't figure it out yet:

experiment 1:
       a. Initialise the Xmit_Remove and Xmit_Append after the
               delay back to 0.
       b. MAke sure the delay is long enough to flush out the
               buffers. (i made this 5 seconds)
       c. Initialise Xmit_Remove and Xmit_Append in main and not
               global inits
results: exactly the same behavior as before i.e. string
       in first printf comes out fine, delay is about right,
       then 8th character from previous string comes out forever


experiment 2:
       Try shorter length string of less than 8 and repeat
       this again to give a clue.
results: first string comes out fine, second string never
       even starts.

I'm intrigued by the results of this second experiment and
can not yet explain it. I'm still thinking about it but
would welcome any comments or ideas.

my original query and code is below


.~.    /"\    /\            Michael Shiloh
/V\    \ /   /\ \           @spam@mshilohKILLspamspammediabolic.com
/( )\    X   /  \--          (415) 346-2270 x 121
^^-^^   / \  ----

On Wed, 22 Nov 2000, Ramana wrote:

{Quote hidden}

> {Original Message removed}

2000\11\23@043425 by Ramana

flavicon
face
Hi,
The answer is like this.
a. look at pchar routine
b. in the else clause of if running add a line  SerTxBufferAppend(c)

You program should run fine.
The reason gor not starting is the moment you enable interrupts the tx
interrupt finds nothing in th ebuffer and disbles every thing

Hope this will solve your problem
rgds
ramana


{Original Message removed}

2000\11\23@151403 by Michael Shiloh

flavicon
face
> The answer is like this.
> a. look at pchar routine
> b. in the else clause of if running add a line  SerTxBufferAppend(c)
>
> You program should run fine.
> The reason gor not starting is the moment you enable interrupts the tx
> interrupt finds nothing in th ebuffer and disbles every thing

hi ramana,

thanks for taking the time to answer. i appreciate your assistance

my logic for the pchar routine is this:

1. if the uart is running, add to the buffer using SerTxBufferAppend(c).
2. if it is not running (the else clause of the "if running") then
  the uart must be started.

  the only way to start the uart is by writing to TXREG.

  In addition, the transmit interrupt must be enabled, so that once
  this character is transmitted, an interrupt will be generated which
  will cause the isr to look at the buffer to see if there is
  anything else to transmit.

  finally, the running flag must be set, so that subsequent calls
  to pchar will add to the buffer and not try to restart the uart.

  thus, i don't believe it is necessary and in fact it would be
  in error to write to the buffer.




having said all this, obviously there is a mistake someowhere in my
logic or else it would be working!

comments?

i include below just pchar() and the isr:


/*
* print the given character
*
* a simple description for a lot of work.
* this function must first determine whether the
* interrupt ISR is running or not, as if not it
* must be enabled and the character must be placed
* directly in the uart.
*
* if the ISR is running, the character is placed
* in the transmit buffer only if the buffer is not full
*
* RETURNS:
*      !OK if the transmit buffer is full
*      OK otherwise
*/
char pchar (char c)
{

       char full;
       char retval = OK;    /* assume everything will work        */

       disable_interrupt( GIE );         /* disable global interrupts         */

       if (running)                      /* transmitter running, add to queue */
       {

               full = SerTxBufferFull();      /* check transmit buffer for fullness */

               if (!full)
                       SerTxBufferAppend(c);
               else
                       retval = 1;           /* my compiler doesn't like !OK      */
       }
       else                              /* transmitter is not running, xmit now */
       {

               TXREG = c;

               /* turn on transmit interrupts */
               set_bit( STATUS, RP0 );
               set_bit( PIE1, TXIE);         /* enable transmit interrupts */
               clear_bit( STATUS, RP0 );

               running = TRUE;               /* indicate we are running */
       }

       enable_interrupt( GIE );       /* enable global interrupts          */
       return (retval);

}

void interrupt( void )
{
       char c;

       if (PIR1 & txif_bitmask)         /* transmit done interrupt */
       {
               /* are there more chars to transmit? */

               c = SerTxBufferRemove();        /* null signifies end of buffer */

               if (c)
               {
                       TXREG = c;
               } /* remove pointer is left at next char */

               else

               {
                       set_bit( STATUS, RP0 );
                       clear_bit( PIE1, TXIE);         /* disable transmit interrupts */
                       clear_bit( STATUS, RP0 );
                       running = FALSE;
               } /* remove pointer is left pointing at this null */

       }


} /* interrupt */

--
http://www.piclist.com hint: PICList Posts must start with ONE topic:
[PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads


2000\11\23@214650 by Ramana

flavicon
face
Hi,
The UART will generate interrupt once interrupts are enabled even if you
dont write into txreg.
Any way you know the problem now I think. So you can find other means of
overcoming this.
bye
ramana


{Original Message removed}

More... (looser matching)
- Last day of these posts
- In 2000 , 2001 only
- Today
- New search...