3

I am using a Texas Instruments CC1110, which is based on the 8051 microcontroller. I'm programming it using the IAR Embedded Workbench.

I have written a function named sendChar that sends a 8-bit char over the UART interface. Running the following code:

sendChar('H');
sendChar('e');
sendChar('l');
sendChar('l');
sendChar('o');
sendChar(' ');
sendChar('W');
sendChar('o');
sendChar('r');
sendChar('l');
sendChar('d');

Results into the expected behavior of Hello world being sent over the UART channel. But then defining the sendString function as:

void Serial::sendString(char *str) {
  unsigned int i;
  for(i = 0; i < strlen(str); i++) this->sendChar(str[i]);
}

and running the following code:

sendString("Hello world");

results in 0xFF being sent more than 100 times.

I have noticed that sending the strlen output with the sendChar function reveals that the wrong string length is being generated. For example, if I run the following code:

char str[100] = "Hello world";
sendChar(strlen(str));

I receive 101 instead of 11 as one would expect.

What am I doing wrong?

Edit


If I run the following code:

char str[100] = "Hello world";
sr.sendChar(str[1]);
sr.sendString(str);

one would expect to receive eHellow world, but instead I receive 101 dots . (0xFF).

Edit 2


Complete code:

#include <ioCC1110.h>
#include <ioCCxx10_bitdef.h>
#include <math.h>
#include <string>

void sendChar(char c);
void sendString(char *str);

void main(void) {
    CLKCON = 0; // Crystal oscillator, no pre-scaler

    U0CSR |= U0CSR_MODE; // USART0 in UART mode
    P0SEL |= BIT3 | BIT2; //P0.2 and P0.3 as peripherials

    // Baud rate = 9600 (9597)
    U0GCR |= 8;
    U0BAUD = 131;

    // Enable Rx and Tx interrupts
    IEN2 |= IEN2_UTX0IE;
    URX0IE = 1;

    while(P0_4); // Wait for P0.4
    char str[100] = "Hello world";
    sr.sendString(str);
    while(1); // Wait so main() never ends

}

void sendString(char *str) {
  while (*str) sendChar(*str++);
}

void sendChar(char c) {
  U0DBUF = c & 0xFF;
  while(!UTX0IF);
  UTX0IF = 0;
}

Edit 3


I ran a simple main:

int main( void ) {
  char str[] = "Hello world";
  CLKCON = 0; // Crystal oscillator, no pre-scaler
  P2DIR = 1; // P2.0 as output
  P2 = 0;
  char l = str[2];
  Serial sr;
  while(P0_4); 
  sr.sendString(str);
  while(1);  
}

and debugged it. Here is a screenshot of the value of the str array. enter image description here Its full of dots, as I reported previously.

Any idea on what's causing that?

jagjordi
  • 356
  • 5
  • 12
  • I suggest you find the source code of the sendChar(..) function and check what it requires. Also check what your startup C-code (crt0?) does with initializing the various program sections. – Oldfart Feb 04 '18 at 18:51
  • It's been some years, but why are you enabling interrupts based upon the flag, if your code doesn't use any interrupt events? Why bother with IEN2 or URX0IE? – jonk Feb 04 '18 at 20:01
  • I wonder if there is some problem with your compiler setup. This behaviour would be expected if string constants are not being output correctly. And usually strings are the main use of read-only data, which has a special section for it... – user253751 Feb 04 '18 at 23:51

2 Answers2

2

Use:

while (*str)
   sendChar(*str++);

You might want to add carriage returns if the string has line feeds:

while (*str)
{ if (*str==0x0A)
      sendChar(0x0d);
   sendChar(*str++);
}

Your latest debug data shows what I have been expecting all along: your string array does not get initialized. Although this is not strictly correct according to the C/C++-code, it does not surprise me. When working with micro controllers there are often limitations to what is supported by the compiler. I suspect your compiler does not support initialisation of variables on function call.

I suggested some time ago to make the string global. The reason is that most MCUs have code in the crt0.s to copy values from ROM to RAM on startup for initialized variables. The copy has to be done because you specified the string as 'changeable' thus it must reside in RAM. If you make the value

const char str[100] = ".."; 

The string is likely to be mapped to the ROM area as there is never need to change it. Check your compiler manual which should have a section on how variables are mapped depending on how you define them.

Oldfart
  • 14,212
  • 2
  • 15
  • 41
  • Thanks, but that didn't solve my problem. Please see my edit. – jagjordi Feb 04 '18 at 18:35
  • What difference between this and the asker's code will make it work? This may be more compact and slightly more efficient but I don't see how it's substantially different in operation. – user253751 Feb 04 '18 at 21:35
  • 1
    @immibiss This avoids strlen which maybe flawed if e.g. he wrote it himself. – Oldfart Feb 04 '18 at 22:18
2

I think you have more than one problem. Since you don't identify your compiler, nor how you set it up, it's going to be hard to help with precise instructions.


Let's start with problem #1.

Given your last test, it sounds to me like strlen() isn't working.

The sizeof() function, which you aren't using here, is evaluated at compile time and might have returned a large number since its job is to tell you the known size of a buffer like this.

But strlen() evaluates at run-time and should technically report the actual string length after initialization with the string. If this string is placed statically (outside of a function at the "module/file level"), then this initialization should take place prior to main() starting up (by hidden assembly code.) If this string is placed as a function-local variable, then this initialization takes place every single time the function is called (I remember the days, though, long before the first C standard arrived when such initialization was ignored.) Either way, your code should not be able to call strlen() before initialization takes place. So strlen() should always be able to "see" the string.

So either strlen() isn't working, or it is. If it isn't working, you need to find out why. If it is working, then your initialization string isn't being properly initialized (or it is being initialized with garbage or some foreign language multi-byte mess.) If that's the case, you need to track that down as well.

One thing to try, in order to verify that the string buffer is being initialized is to STOP TRYING to use string functions on it. Obviously, that is NOT WORKING for you. So now, try and dump out a few byte values as integer numbers. See what is in that buffer. Verify!!!

I'm also not entirely sure if your receiving program is getting the right number of bytes, or not. I'd like you to confirm or deny that question in my mind. I think you are saying that it is getting lots more characters. And, if your strlen() result is counting lots of characters, then it makes sense that lots of characters are being sent out. But I'd like you to talk a little more about this. Just because I might pick out something from what you add.


The other problem I see is that your receiver (whatever it is that is "getting" the characters being sent along) isn't getting the right values. This can be for several possible reasons. Since this is asynchronous communications (as I gather it), it's possible that the bit rates don't match up right between sender and receiver. Did you make sure to initialize the serial library correctly? On both ends? This could also account for different numbers of characters being sent than received, as well as the garbage you see. It's vital that you get these things matched up right.

Another possibility is that your sending library is using one stop bit and your receiving side expects two stop bits, for example.

Another possibility is that your receiving code/device/whatever cannot handle back to back characters. It has some stupid, idiotic delay inside of it that prevents it from properly parsing a continuous stream of asynchronous characters. But it can receive them one at a time, with breaks of time in between. So you get stuff that seems right when you use a separate call, each time. Because there is a LONG delay in between. But when you send out a string, the sending code just RAMS IT OUT FAST, back to back, and your receiver just gets overwhelmed and cannot keep up.


For now, that's all I can easily imagine. So try these few things earlier than later:

  1. Verify that you are initializing the asynch rate properly with the library you are using on the transmitter side.
  2. Verify that you are using the same rate properly on the receiver side.
  3. Verify that the clocks used on both sides are capable of providing those rates within the appropriate error bars for async (about 2% or less.)
  4. Verify that that the number of stop bits match up, or that the transmitting side uses MORE stop bit time than the receiving side, if they don't match.
  5. Track down what is being placed in your string buffers. Don't assume. Verify. Check the first 10 bytes. Print their byte values as integers and see what they are.
  6. Scan through the string buffer looking for a 0 byte. When you find the first 0 byte, tell us at which buffer index it occurs at.
  7. Hook up your receiving device to some other source. Verify that it can receive a continuous string without error.
  8. Tell us what compiler you are using.
jonk
  • 77,059
  • 6
  • 73
  • 185
  • 1
    I'm using the IAR Embedded Workbench. I'm not using any libraries, I made the functions myself. I'm viewing the data on an Oscilloscope so I can see exactly what bits are being sent. I think it may have to do something with the C++compiler. If I run the exact same code on a C project it works flawlessly, but in a C++ one it does not. Any ideas? – jagjordi Feb 04 '18 at 18:58
  • 1
    He said it worked with compiled characters, which excludes baud rate etc. Each error seems to involve a static string which is supposed to come from an initialized section. – Oldfart Feb 04 '18 at 18:58
  • 2
    @oldfart In cases like this, I accept very little of what the OP mentions as "true". Best to walk through some thinking. And the fact that there is a difference calling the char output one at a time vs the string output is a worry. – jonk Feb 04 '18 at 19:01
  • @jagjordi How is your C++ set up? When I use one here, I may very well find Unicode or multi-byte characters in the buffer. Or I might wind up using functions that expect them, and don't get them. Verify your buffer contents. Assume nothing. – jonk Feb 04 '18 at 19:02
  • @jagjordi Also, since these are your own functions, that's another source of problem I hadn't mentioned. We need to see exactly what you are doing. – jonk Feb 04 '18 at 19:05
  • @jagjordi I gather you are making a class and methods. Are you aware of the insertion by C++ of hidden parameters to some methods and not others (the 'this' parameter, for example.) Resolve the strlen() problem first. It should report things correctly. It is not. It's a waste of time worrying about your serial code, if strlen() itself is misbehaving. – jonk Feb 04 '18 at 19:06
  • For the moment I'm not making any class. Just C-like code compiled as C++. Please see Edit 2 for complete code. – jagjordi Feb 04 '18 at 19:17
  • I suggest you first make **char str[100] = "Hello world";** global and then check what str[1] is. If "sendChar('0');" works reliable try something like if (str[1]=='e') sendChar('1'); else sendChar('0'); You might even go using uint8_t to avoid 16 bit wide characters. – Oldfart Feb 04 '18 at 19:54
  • I tried what you suggested if (str[1]=='e') sendChar('1'); else sendChar('0'); and it sends '0'. Whats happening? I cannot understand why its not working. – jagjordi Feb 04 '18 at 23:05
  • 1
    @jagjordi If you can, dump out the buffer as integers. Can you use a printf() here and use %d or %x as the format specifier? Just print out the first 10 bytes or first 6 bytes. Something. You need some details. – jonk Feb 05 '18 at 02:35
  • See my edit please. – jagjordi Feb 05 '18 at 12:13
  • @jagjordi That tells you a lot about why things are not working, now. So place the array definition OUTSIDE of the main() function, at module/file level. Do the same check. – jonk Feb 05 '18 at 15:58
  • Placing the array definition outside main() or using const results in the same output. – jagjordi Feb 05 '18 at 18:47
  • @jagjordi Then you have a serious problem that is going to take effort to track down, I think. Initialization of an array is supposed to take place in C/C++. When you place it outside of any function, it must be properly initialized through crt0 code (usually assembly code written by the compiler folks) prior to calling main(). – jonk Feb 05 '18 at 18:54
  • @jagjordi I don't know what "sendstring" does -- never see it before. But if it is correctly dumping the contents and you are NOT seeing correct initialized values there means that there's an issue here with the compiler. Might be a switch option, for all I know. The next test here is to use strcpy() inside of main() and then dump it out. If strcpy() cannot fill the data? Then wow! Another thought crosses my mind about whether or not you have write access to the memory locations. So can you get the address of this array?? – jonk Feb 05 '18 at 18:57