We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
The following code fragment has been running for three years on an Atmel 89c55 with no problems. Now that I have started a project using the Cypress EZ-USB FX chip I would like to move the fifo buffer from the default generic pointer in data space. #define FIFO0SIZE 10 BYTE *fifo0[FIFO0SIZE]; to xdata and increase the size using #define FIFO0SIZE 100 xdata BYTE *fifo0[FIFO0SIZE]; It compiles but continualy sends garbage out the serial port. I have tried pointer casting and changing to the large memory modle and a few other things, all with negative results. Can anyone shed some light on this problem. #define FIFO0FULL FIFO0SIZE-2 BYTE Que(new_ptr) BYTE *new_ptr; { BYTE idata Pass,i; Pass=0xff; for(i=0;i<FIFO0SIZE-1;i++){ // add new message to end of buffer if(!fifo0[i]){ // current position is empty go ahead and use it if(i>FIFO0FULL) SBuff0_Full=1; Pass=0; fifo0[i]=(BYTE xdata *) new_ptr; fifo0[i+1]=0; if(!out0_busy) TI=1; // kick start the uart break; } } return Pass; } void Serial_Port0(void) interrupt COM0_VECT { BYTE idata i; static BYTE data x=0; if(RI) { RI=0; // extract recieved byte Inkey(SBUF0); } if(TI) { TI=0; if(fifo0[0][x]) { SBUF0=(fifo0[0][x]); x++; out0_busy=1; } else out0_busy=0; // no character to send if(!fifo0[0][x]) { // end of string last character is being sent if(out0_busy) { // last character is being sent for(i=0;i<FIFO0SIZE-1;i++) { // rotate buffer if(fifo0[i]) { // if = 1 = buffer not empty fifo0[i]=fifo0[i+1]; x=0; } // if fifo0 buffer not empty else { if(i<2) SBuff0_Full=0; break; // end of buffer } } } } } }
Thank you all for your help, Andrew Neil, Dan Henry and Bob Mu. I do appreciate the time and effort you spent looking at my code and making suggestions. Dan, you are correct about ?1? the mspace casting and the loss of the Generic Pointers. It was an artifact from some of the code changes I was making while I was desperately trying to figure this out. As to ?2? the variable x is properly maintained in the hardware version. Note: This did inspire me to go back to my original system that this Serial routine was taken from and change the uC from an Atmel 89c55 to a Philips 89c51rd+ which has additional internal RAM accessed with a register bit and xdata/movx. My original code on the original hardware does work with both data and xdata buffers. Dan may be right, my problem may be related to the EZ-USB FX. Another Note. I do agree that a circular buffer is the traditional way to go. My problem was I was out of RAM. A circular buffer requires the Head and Tail pointer variable in addition to the buffer. If I used one more byte of RAM the code crashes due to Stack conflict. The original system communicated through the serial port at 300 baud to a system that did not use a UART. Instead it used a pin on a uP. Therefore not only was it a low baud rate but I had to put a delay between messages while it processed the previous message. The initial message is so long it takes about 3 minutes at 300 baud to complete the down load. All of these requirements led me to this style of serial communications. Bob you are correct about ES0 = 1. I had already made the change you first suggested and narrowed the last problem down to the if(--queued_ctr) . The problem was as long as you continue to stuff the buffer and never let it run out, the messages continue to flow. But as soon as you let queued_ctr run down to zero you never get the last message. Particularly troublesome is when you place a short message in the buffer and let a message finish before you try to send another short message you will get the old message out over and over until you stuff the buffer faster than it can be depleted. Here is the final version of the circular buffer. Note: There are a few global variables I need to maintain for other functions to use.
#define FIFOSIZE 100 xdata BYTE *fifo[FIFOSIZE]; BYTE *byte_ptr; /* Advances through message */ BYTE **tail_ptr = fifo; /* Where to enqueue next msg ptr */ BYTE **head_ptr = fifo; /* Where to dequeue next msg ptr */ BYTE queued_ctr=0; /* Count of msg's queued in FIFO */ BYTE Que(new_ptr) BYTE *new_ptr; { BYTE idata Pass; bit bdata EAstat, ESstat; EAstat=EA; EA=0; /* disable all int */ ESstat=ES; ES=0; /* turn off serial int */ Pass=0xff; if (*new_ptr != 0) { /* If the FIFO queue has room, enqueue new_ptr at * the tail. Disable serial interrupts while * accessing FIFO queue controls. */ if (queued_ctr++ < FIFOSIZE) { *tail_ptr = new_ptr; /* Advance the tail, wrapping to the start of * the FIFO array if necessary. */ if (++tail_ptr == &fifo[FIFOSIZE]) tail_ptr = fifo; if(queued_ctr>=FIFOSIZE) SBuff_Full=1; Pass = 0; } /* out0_busy is FALSE only when the transmit ISR * has nothing to transmit (e.g., after either * init or transmitting the last message's last * non-NUL byte). */ if (!out_busy) { out_busy = 1; /* Will be busy after TI is set. */ byte_ptr = *head_ptr; TI = 1; } } ES=ESstat; EA=EAstat; return Pass; } /* **************** UART I/O *********************** */ void Serial_Port0(void) interrupt 4 { BYTE b; if(RI) { RI=0; // extract received byte Inkey(SBUF); } if (TI) { TI = 0; b = *byte_ptr++; if((*byte_ptr==0)) { ES=0; Throttle(25); /* delay = 25 x DelayTick*/ /* 1/4 Sec = 25 x 10mSec */ TR0=1; /* Turn on timer 0 */ ET0=1; /* Enable Timer 0 interrupts */ } if (b) { SBUF = b; out_busy=1; } else { /* At end of message. If more messages in the * FIFO, advance the head to the next one * (wrapping if necessary) and start * transmitting from there. Otherwise, * indicate that the transmit ISR has shut * down. */ out_busy = 0; if (++head_ptr == &fifo[FIFOSIZE]) head_ptr = fifo; if (--queued_ctr) { byte_ptr = *head_ptr; SBUF = *byte_ptr++; out_busy = 1; } } } }