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.
Hello,
I'm using the XC164CS-32, 40 MHz, and I'm experiencing some problems with the ASC0 port where it seems that its not synchronizing with the program I wrote in C#. The application I wrote will send out at least 6 ASCII characters, but no more than 9.
#define TIMEOUT_100MS 31250 #define EBCMOD0_SETTING 0x1820 #define EBCMOD1_SETTING 0x003F #define FCONCS1_SETTING 0x0031u #define TCONCS1_SETTING 0x0181u #define ADDRSEL1_SETTING 0xB000u #define PORT1_HIGH_DIRECTION_SETTINGS 0x0F #define PORT1_LOW_DIRECTION_SETTINGS 0xFF #define PORT3_DIRECTION_SETTINGS 0xB620 #define PORT4_DIRECTION_SETTINGS 0x00FC #define PORT9_DIRECTION_SETTINGS 0x0001 #define SYS_RDY P1H_P0
void main(void) { char temp_string[9] = "\0"; char label[3] = ""; int i = 0; ASC0_FDV = 0x003B; /* load ASC0 fractional divider register */ ASC0_BG = 0x000E; /* load ASC0 baud rate time reload register */ ASC0_CON = 0x88D1; /* load ASC0 control register */ DP1L = PORT1_LOW_DIRECTION_SETTINGS; DP1H = PORT1_HIGH_DIRECTION_SETTINGS; ALTSEL0P3 = 0x2720; ASC0_TIC = 0x01B9u; ASC0_RIC = 0x01F9; DP3 = 0xB620; P3_P10 = 1; P1H_P3 = 0; /* Disable the loopback relays */ ASC0_RXFCON = 0x0607; ASC0_RXFCON = 0x0605; GPT12E_T3CON_T3R = 1; /* Start the timer T3 */ printf ("Initialized\n"); setup(); update();
while (1) { if (GPT12E_T3 > TIMEOUT_100_MS) { GPT12E_T3 = 0; /* Reset the timer */ update(); }
// if ( (ASC0_FSTAT & 0x0F) != 0) if ( (ASC0_FSTAT & 0x0F) > 6) { gets(temp_string, 9); if (strcmp(temp_string, "status") == 0) printstat(); else if (strlen(temp_string) < 8) { printf("sync error. purging RX buffer...\n\n"); for (i = 0; i < 100; i++) ASC0_RBUF = 0x0; ASC0_RXFCON = 0x0607; ASC0_RXFCON = 0x0605; }
else { label[0] = temp_string[6]; label[1] = temp_string[7]; label[2] = '\0'; printf("\nInput: %s \n", temp_string); printf("\nhex label: %s \n",label); if (strcmp(label,"38") == 0) { // some code } if (strcmp(label,"72") == 0) { // some code } if (strcmp(label,"8A") == 0) { // some code } strcpy(label,""); ASC0_RXFCON = 0x0607; ASC0_RXFCON = 0x0605; } } }
My problem lies in the following IF statement:
if (ASC0_FSTAT & 0x000F) != 0)
For some strange reason, it's not getting the first two characters that I send to it via RS232 and it seems to be some kind of synchronization problem.
I thought I would change the situation by replacing the != 0, but when I try making it greater than 6 (> 6), it will hang and will no received data is coming in.
Does any one see a problem and can help me out?
Steve
You say that the PC program will send up to 9 ASCII characters. Is that including a terminating zero? Your receive buffer does not have room for 9 characters and a terminating zero.
You call
gets(temp_string, 9);
But gets() does not have a parameter for the size of the buffer. It just looks like char* gets(char *s) and is one of the functions that should _never_ be used, since it doesn't have any buffer-overflow protection.
You are printing temp_string, and evaluating its length with:
else if (strlen(temp_string) < 8)
and
printf("\nInput: %s \n", temp_string);
How have you made sure that temp_string is zero-terminated?
You say that the following change makes your program hang. But have you found any documentation in your datasheets that the change is allowed and valid?
// if ( (ASC0_FSTAT & 0x0F) != 0) if ( (ASC0_FSTAT & 0x0F) > 6)
Hi there!
Thanks for the response! I'll try to answer much as I can about this program.
What I am sending is 8 ASCII characters with a "\n". It's basically an ASCII hexadecimal representation for 32 bits that I need to send, then later on, it will be converted in the format I need in the IF statments that I left as "// some code".
I don't need it to be fancy with the serial port, which is why I'm using the standard I/O library "stdio.h". There's part of the according to the help file for gets(char *, len) in Keil:
char *gets (
char *string, /* string to read */
unsigned int len); /* max characters to read */
Description: The gets function calls the getchar function to read a line of characters into string. The line consists of all characters up to and including the first newline character ('\n'). The newline character is replaced by a null character ('\0') in string.
The len argument specifies the maximum number of characters that may be read. If len characters are read before a newline is encountered, the gets function terminates string with a null character and returns.
and in my C# program I wrote, I have this:
port.WriteLine(output);
which output is a text string and the default writeline is "\n".
Since I'm using the standard I/O (stdio.h) library, it should automatically change the "\n" to "\0".
I'm not sure about the ASC0_FSTAT, but it seems to be able to modify, through the "xc16x.h" file this line, I found this:
sfr ASC0_FSTAT = 0xF0BA; //FIFO Status Register
which gives me the impression that it CAN be written to, however, I am not doing so in this case. All I am doing is checking to see if the FIFO Status register -- which is for both transmit and receive buffers -- has any data in it. I'm trying to do a bitwise AND on it to mask out the transmit FIFO buffer, which is on bits 11 to 8. I'm only concerned with bits 3 to 0 which indicates the receive FIFO buffer. Hence why I am doing (ASC0_FSTAT & 0x0F).
As to why I have that if statement whereas the length is less than 8, the label I am using needs to be 8 characters long, and it's in hexadecimal format, at a total of 32 bits, MINIMUM. That's why I have it rejected if I cannot get the entire 32 bits across on the serial.
I've put those printf statements in there for debugging and evaluation purposes only so I get an idea how the Infineon chip is receiving the data.
I hope that I've explained it a bit.
It seems to me that it might be a problem with the clock cycle which is could lead me to believe there lies the problem with the receive FIFO buffer missing out on the first one or two characters being transmitted to the Infineon. What I am at a loss is trying to find the hardware control like CTS/RTS signals, which seems to be absent with this processor. If it's suppose to be UART chip, then how come it wasn't added on there, or am I missing something about the hardware control part on this chip?
-- Steve
Don't use gets, at least not with the FIFO enabled. It echoes all charaters it gets and clears the reveive interrupt flag after reading each character, which messes up the FIFO operation.
You have receive and transmit interrupts enabled. Who knows what happens if you also have interrupts globally enabled in PSW.
Sauli
Hi Sauli,
Thanks for that suggestion. I didn't realize that it puts function was echoing the characters back on the serial and that helped somewhat. I've changed it to this instead:
count = 0; while ( (c = _getkey()) != '\n' && (count < 11) ) { temp_string[count] = c; count ++; } temp_string[count] = '\0';
It still seems a bit of a hiccup at times receiving data but I've put in a delay time at the beginning to allow the chip to warm up first. That seems to help, but I still once in a while get a transmission error and still the word is getting rejected.
The other problem I'm noticing is that while it's trying to use the printf functions to send back data on the serial, it tends to hang and I have to reset the processor, either by power off or just simply using the wiggler and re-loading the program.
I've checked on the Processor Status Word register, and it seems we're not using it. However, I really do need the ASC0_TIC and ASC0_RIC, otherwise nothing will get processed with the UART.
Am I missing something on the transmission interrupts which could be the reason why the printf statments hang on the Infineon?
Have you changed the size of temp_string so that it can fit 12 characters?
Hi Per,
I have changed temp_string to 15, just in case. I'm playing a bit by adding whitespaces before sending the ASCII characters in order to get better control of synchronization on the RS232. It seems to help somwehat and I've writen up code to eliminate the whitespaces like this:
while (temp_string[0] == ' ') { for (i = 0; i < strlen(temp_string); i++) temp_string[i] = temp_string[i+1]; temp_string[i+1] = '\0'; }
I'm still facing the problem with the printf statement hanging on the RS232 which no one here can figure out why.
Don't use _getkey. It is the function gets calls to read one character. You have eliminated the echoing of the characters but _getkey still clears the receive interrupt flag, which should not be done when using the receive FIFO.
Don't use printf either (or putchar which printf calls). They do things you don't expect, like check and read a received character when they see a '\r' or '\n'.
If your application really is such that you don't have to do anything else while waiting for a message from the PC or sending a message to the PC, I recommend polling the serial interface directly yourself, both when receiving and sending. Instead of using printf you can use sprintf, which does exactly and only what it is expected to do.
Sauli,
Talk about limiting on what can be done on the serial port!
Are you suggesting something like this?
while (((char)ASC0_RBUF != '\n') && (count < 11) ) { // read the buffer?? temp_string[count] = (char)ASC0_RBUF; // clear the buffer?? ASC0_RXFCON = 0x0607; count++; } temp_string[count] = '\0';
but then that causes a problem because it will NEVER get the rest of the data from the RS232 stream and it's like filling up the first character and ignoring the rest.
How would you then write something up like this using the FIFO buffer to get the received data?
Curiously, do you know the size for the Receive buffer?
Check the datasheet about the registers for the serial port.
You do not read out a character just to check if there is a character. If there is, then your while loop will loose that character.
There are specific flags to check if there are one or more characters available to read, and if there is room to insert at least one more character to send. Use them, when polling the serial port.
And skip the space characters. Just refuse to insert them in your buffer, since you would just have to spend time throwing them away later. If you want to know how many space characters you have received before the actul data, you can count the number of spaces thrown away since the previous newline character was received.
By the way, your chip does not need to be "warmed up". All it needs is enough time for the crystal to get a stable frequency, and that any used PLL gets time to lock into the correct frequency. Depending on hardware, that takes milliseconds up to maybe a second.
You really should figure it out yourself, but you can try out these to prove yourself that the serial interface actually does work. It took me a few minutes to write them and I certainly have not tested them, not even compiled. From experience I know that it is all too easy to put in a mistake in the most simple piece of code.
unsigned int receive_line( char *buf, unsigned int bufsize) { unsigned int count; /* Cannot read anything into a nonexistent or zero sized buffer. */ if( ( buf == NULL) || (bufsize == 0)) { return 0; } /* Must have space for the terminating NUL. */ bufsize--; /* Read no more characters than fits in the buffer. */ for( count = 0; count < bufsize; count++) { /* Wait for a character. */ while( (ASC0_FSTAT & 0x0F) == 0) { ; } /* Read it to the buffer. */ buf[ count] = ASC0_RBUF; /* If newline, we are done. Newline is not saved. */ if( buf[ count] == '\n') { break; } } /* Terminate the line. */ buf[ count] = '\0'; /* Return number of characters read. */ return count; }
void send_line( char *buf) { /* Cannot send anything from a nonexistent buffer. */ if( buf != NULL) { /* While not end of string.. */ while( *buf != '\0') { /* Wait for room in the transmit FIFO. */ while( (ASC0_FSTAT & 0xF00) == 0x800) { ; } /* Send the character. */ ASC0_TBUF = *buf++; } } }
After you have these working, you could start figuring out how to do it with interrupts. Sooner or later you will want to do something useful with the time wasted in these two routines.