Hello,
I have the EVB51JM128 board and was running the AN2883 (SCI application) no problem. I tested my hardware with the CMX lite USB mass storage program. Ever since, when I want to run the same AN2883 program it prints garbage on tera term. The reception part is still working fine; when i type in any character I can see the MCU receiving it. But when I want to print any character on the tera term it prints Garbage. Would anyone have any idea?
Solved! Go to Solution.
TomE,
You were right. The Bus_Clock divisor I had was generating 20164.923 bps which was +5.03% higher than the baud rate on my terminal. I changed the divisor (From 0x0D to 0x0E in my SCIConfig()) to generate a 18724.571 bps; this is only -2.5% lower than my com port baud rate (19200). Now, it works. I just don't know why it was working with my original setting before. I formatted my computer and installed the new version of the CW since then.
Anyway, problem solved.
Thanks for the advice.
Farhood,
The first guess would be a baud-rate problem with either Teraterm or the UART being set to different baud rates,
or something has changed in the CPU clocking.
You say the receiver is working. Is it receiving the correct characters?
Can you send characters one at a time by dumping them (from the debugger) into the transmitter?
Check 7/8/9 data bits, parity off/on/odd/even and the numbr of stop bits.
The best thing to do is to see what is being transmitted with an oscilloscope, then measure the bit times and the transmitted data format.
I think something has changed in the CPU clocking. After numerous hours of analyzing it here is what I am experiencing:
1. The baud rates are the same for fact.
2 The MCU can receive any characters I type in through my keyboard with NO PROBLEM.
3. I can transmit the same character I type in with no problem. I see it popping up on my Tera Term terminal.
4. When I want to print a bunch of character, the Tx just goes crazy. I get just garabage data. (e.g. when I go in a FOR LOOP or try to print out say 4 characters)
5. If I delay the Tx sequence (delay the time I write to SCID) things work a little better but I still get nonsense transmission.
The only thing I can think of right now, may be that the Processor Expert Initialization is causing something. I was using the CW Trial version before. In that version I only used the Device Initialization and everything worked. Now I have the CW standard version and the Processor Expert keeps running instead. I have no idea what initialization PE does that cause the TRANSMISSION mechanism go corrupt. Very frustrating. Any idea?
OK. When I delay the SCID write by the following function, it prints out properly.
"void delay(int i){
main code...
SCI1D='a';
delay(7000);
SCI1D='b';
delay(7000);.....
"
Now, I have no idea which source clock I need to change to get this working. Your first hint was right correct TomE. Any more hints?
You can't write the next byte out until the previous byte has left the transmitter.
By adding a hard delay between successive writes you're making this seem to work, but the wrong way completely.
Read the chapter on the UART. In the Status Register you'll find three status bits.
The "Receiver Ready" bit says the UART has received a character. Don't read the data register until this is set.
The "Transmitter Ready" bit is set when there's room for another character. Do not write the next byte until this has set.
The "Transmitter Empty" says that all data has been transmitted, in case you need to know that exact timing for some reason.
In anything but "toy" programs, characters are received into and sent from software-managed memory buffers using interrupts.
Freescale should have some simple sample code for using UARTs somewhere on its site. Hunt for those, or some old app,notes.
TomE,
I guess I did not explain my problem correctly. My program was running the AN2883 without any problem. AN2883, thoroughly explains the SCI module and gives a code example in the end. I had modified the code on this app note according to my MCU specs and was running it WITHOUT any problem before. I have to say that I was using the CW special edition before. Every time I ran the CW, the "Device Initialization" ran first. Recently, I installed the CW standard edition and every time i run my program, the "Processor Expert" runs first. My problem is that the SAME code was running PROPERLY before is NOT running properly now. I have a feeling that the "Processor Expert" is initialization some clock some where that is causing this mess. As for your recent suggestions:
1. I do know that I can't write a byte out until the previous one has left. This is done by reading the "Transmitter Data Ready" status bit.
2. I do know that I am cheating by adding a software delay and is not correct.
3. I even tried my program by reading the "Transmitter Complete Flag" status bit before write the second byte.
4. I guess the only reason the Rx is working fine is because the MCU is not receiving the data fast enough. Maybe if receives data as fast as I am trying to print data (Tx situation) it will act the same.
TomE, I greatly appreciate you taking your time and following up on my concerns. I am just very frustrated.
Your code sample had you not checking the transmit ready flags.
Have you followed my previous advice:
> The best thing to do is to see what is being transmitted with an oscilloscope,
> then measure the bit times and the transmitted data format.
That still applies.
By adding delays you are adding gaps between the serial characters. If that fixes the problem then there could be two causes.
1 - The BYTES are too short. If the SCI is sending a start bit, seven data bits and a stop bit, but Teraterm is programmed to receive 8 bits then that would explain the problem. Change it to 7 bits and see what happens.
But from your explanation that isn't very likely. You should still double-check the programming to find out exactly what data length you've programmed the chip to in both cases.
2 - The BITS are too short. The Baud rate clock might be approx 5% faster in the non-working case. RS232 communication can handle an absolute maximum of +-5% clock speed variation, and a practical maximum of 2-3%. If you add manual gaps between the bytes (as you're doing with the waits) it can tolerate a little bit more.
But you're groping in the dark. Both of these situations could be seen instantly with an oscilloscope. It is an essential piece of kit for microcontroller development. If you don't have one, find someone who has and borrow it.
TomE,
I am not able to get my hands on any oscilloscope, but I have a STRONG feeling that 5% limitation you mention is correct. When I try to fix the Baud rate divisor in the "Device Initialization" Box to "0x0D", it gives me a 20164.923 Baud rate. I am suppose to get 19200 bps. That's actually 5.03% higher than the baud rate on my computer com port. Do you have any idea how to reduce my baud rate on the MCU side so I can generator a proper baud rate? I am attaching my code just in case you were wonder....
unsigned char SCIConfig(void){
SCI1BDH = 0x00; /*an SCI clock modulo of 4MHz*/
SCI1BDL = 0x0D; /*Configure baud rate at 19200 bps with*/
SCI1C1 = 0x00; /*8 data bits, no parity*/
SCI1C2 = 0x2C; /*Enable Tx, Rx, and RDRF interrupt*/
if (SCI1S1 & 0x80){ /*Poll TDRE flag*/
return ERROR_OK; /*TDRE set, return OK*/
}
else{ return ERROR_ERROR; /*TDRE clear, return ERROR*/
}
}
..main()...
{
.......
for (;{
if(SCIIniTx == START_CYCLE){
SCIIniTx = WAIT_CYCLE;
SCIStringp=SCIString; /*Set pointer to character string*/
SCITx(*SCIStringp + Stringcase);/*Send first byte of string*/
}
}
}
in the MCU_init.c file, the SCIIsr function:
__interrupt void SCI1Isr(void)
{
if (SCI1S1 & 0x80){ /*If transmission flag is set*/
SCI1S1;
if(*(SCIStringp++) != '\0'){
if(*SCIStringp > 0xD){ //Avoid to change CR and LF characters
SCI1D=*SCIStringp + Stringcase;
}
else{
SCI1D=*SCIStringp;
}
}
else{
SCIIniTx=START_CYCLE; /*Start new transmission cycle*/
SCI1C2 &= 0x7F; /*Disable TDRE interrupt*/
}
}
if(SCI1S1 & 0x20){ /*If reception flag is set*/
SCI1S1;
if(SCI1D == 'U' || SCI1D == 'u'){
Stringcase = 0x00; /*Uppercase the character string*/
}
else if(SCI1D == 'L' || SCI1D == 'l'){
Stringcase = 0x20; /*Lowercase the character string*/
}
}
return;
}
sorry about the typos and picture there. My keyboard acted funny.
Anyways, do you have any idea how to bring down the baud rate from my MCU side? Maybe the bus clock is acting funny...
TomE,
You were right. The Bus_Clock divisor I had was generating 20164.923 bps which was +5.03% higher than the baud rate on my terminal. I changed the divisor (From 0x0D to 0x0E in my SCIConfig()) to generate a 18724.571 bps; this is only -2.5% lower than my com port baud rate (19200). Now, it works. I just don't know why it was working with my original setting before. I formatted my computer and installed the new version of the CW since then.
Anyway, problem solved.
Thanks for the advice.
Farhood,
> this is only -2.5% lower than my com port baud rate
I've been looking for a definitive specification of how far out the baud rate is allowed to be.
The following:
http://ics.nxp.com/support/documents/interface/pdf/an10386.pdf
says "theoretical maximum error is 5% assuming 16 times oversampling and perfect ...".
That is the abxolute limit. The reason for it is that the receiver waits for ths start bit, then waits HALF a bit (to get the bit-centre) and then samples the line at one-receiver-baud-rate-bit intervals. It samples 10 bits - the start, 8 data and one stop. The first bit is sampled at time "0.5" in bits. The last one should sample at time 10.5, but if the transmitter is 5% fast it will be sending the beginning of bit 11 at that time, the receiver will now be out of sync, miss the next start bit and it fails. That's where the 5% comes from. But that's the ABSOLUTE limit assuming no noise, no signal distortion, no sampling times, and all of these mean the real working value is LESS than 5%.
The following states "Most users of RS-232 serial communication agree that any baud rate error over 3% is likely to cause
communication errors...":
http://pdfserv.maxim-ic.com/en/an/AN137.pdf
That's not "3% error from the exact value", that's "3% difference between the receiver and transmitter". if both ends are 2.5% out in opposite directions then they're are 5% out relative to each other and it won't work. If you're only ever going to connect to a "perfect device" on the other end of your cable then you can consume the entire error budget. If you box is going to connect to "anything" then the other box may have taken the entire budget, so you shouldn't.
Is a PC perfect? PCs have never been spot on. They're designed to run faster than specified - usually 115,402 baud for 115,200 because their baud-rate clock is (14.318MHz * 114) / (17 * 52). That's a tiny error, but does matter in some corner cases. Here's the derivation (and yes, that's me again from 11 years ago :-):
http://groups.google.com.au/group/comp.sys.m68k/msg/f892c289795152e2
Wow, that's quite useful. Thanks. One question out of curiosity though. According to the manual in order to clear the Tx data ready flag and allow another Tx, one needs to read the status register SCIS1 first then write to SCID. Or if one needs to receive data in streams, one needs to read SCI1S1 register fist then read the contents of the SCID. This is required in order to clear the Rx Data ready flag bit so another reception takes place. Now, would you think the following code is acceptable?
if (SCI1S1 & SCI1S1_RDRF_MASK) then myData=SCI1D;
Or do we have to do the following:
if (SCI1S1 & SCI1S1_RDRF_MASK) then { SCI1S1;
myData=SCI1D;
}
Same goes for Tx.
The manual saysTo clear RDRF, read SCIxS1 with RDRF set and then read the SCI data register (SCIxD)."
> if (SCI1S1 & SCI1S1_RDRF_MASK) then myData=SCI1D;
The above does exactly what the manual says. You have read SCI1S1 and found the RDRF bit set, so you've done the first bit and so can then write SCI1D.
Aren't you going to use interrupts?
well, I was using interrupts before. Now, I am using the usb-mass-storage example from CMX USB stack, and it doesn't look like it is using interrupts. I really want to use the interrupts but I haven't figured it out yet. In the example, it basically uses software for this driver. It's in the uart folder of that examples.
I don't know how I can configure the MCU so it picks up the ISR function when necessary in the "USB-MASS-STORAGE" example. Before, I was configuring the SCI module on the "Device Initialization" window in the CW IDE and then run the "Generate Code" option from it. This way the CW would create a file called MCUinit.c which includes a function definition of my ISR function. I then wrote the code in there and....
If you have any idea in how to configure the MCU SCI module (in the usb-mass-storage example) so the compiler knows where to look for the ISR function let me know please.
cheers,
Farhood,
Read the interrupt controller chapter. Compare what it tells you with the code your "automatic code generation" creates.
I'm using the MCF5329 and it has an overly complicated interrupt controller that needs a lot of setting up. The MCF51xx (from the manual I'm looking at) has SCI1 hard-wired to interrupt vectors 82, 83 and 84. The address of your interrupt service routine has to be loaded into the correct vector.
How that is done is up to your tools and development environment. They all abstract this basic work in different ways (they're only trying to help you :smileyhappy:. I have no idea what CW does so I can't help you with this, we're using CodeSourcery and Make here, very basic stuff that doesn't get in the way.
As I suggested to another contributor to this forum, it might be better to ask CW-related questions in the CW forum instead of here.