Corruption of fixed char strings in USART output

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good day all,

I am having an issue that I don't understand. As part of my simple state machine I have a help if you press h, but if this help information gets too big the text becomes truncated and corrupted, not only of help, but most other outputs to usart, in the extreme case the thing just fails to run.

What am I doing wrong? (in relation to this question 9)

Hope this is the right forum and I given enough code:

usart.c:
/* usart enable send/recv mode: 8N1 @ 57600 */
void init_usart() {
    UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
    UCSR0C = (1 << UCSZ00) | (1 << UCSZ01);
    UBRR0 = F_CPU / 16 / BAUDE_RATE - 1;
}

/* write a single byte to the usart */
void send_char(uint8_t byte) {
    while (~UCSR0A & (1 << UDRE0));
    UDR0 = byte;
}


/* write a null-terminated string to the usart */
void send_string(const char *s) {
    while (*s) {
        send_char(*s++);
    }
}

void send_newline() {
    send_char('\r');
    send_char('\n');
}

and

command.c:
void handle_line(const char* line) {
    char *endptr = 0;

    //Check whether rest of line is a number and if so proceed to logic
    uint32_t argument_value = strtoul(line+1, &endptr, 10);
    if (*endptr == '\0') {
        command_from_serial(line[0], argument_value, &program);
    }
}

/* The Giant mess that is the commands from serial */
void command_from_serial(char commandname, uint32_t commandvalue, struct Program *program) {
    
    
    struct Inputs *inputs = &program->inputs;
    struct Settings *settings = &program->settings;
    
    switch(commandname) {
        //Help!
        case 'h': //Disable logging
//             send_string("Help! Available commands."); send_newline();
            send_string("Commands are case sensetive letters followed by a number (commandvalue) with no space"); send_newline();
            send_string("Default commandvalue is 0 if not given"); 
            send_newline();
            send_char('\t'); send_string("L: X "); send_char('\t');
            send_char('\t'); send_string("S: X "); send_char('\t');
            send_char('\t'); send_string("F: X "); send_char('\t');
            send_char('\t'); send_string("H: X "); send_newline();
            send_char('\t'); send_string("P: X "); send_char('\t');
            send_char('\t'); send_string("f: X "); send_char('\t');
            send_char('\t'); send_string("b: X "); send_char('\t');
            
            send_char('\t'); send_string("t: X "); send_newline();
            send_char('\t'); send_string("T: X "); send_char('\t');
            
            send_char('\t'); send_string("Y: X "); send_char('\t');
            send_char('\t'); send_string("y: X "); send_char('\t');
            send_char('\t'); send_string("U: X "); send_newline();
            send_char('\t'); send_string("u: X "); send_char('\t');
            
            
            send_char('\t'); send_string("M: X "); send_char('\t');
            send_char('\t'); send_string("m: X "); send_char('\t');
            send_char('\t'); send_string("J: X "); send_newline();
            send_char('\t'); send_string("N: X "); send_char('\t');
            send_char('\t'); send_string("n: X "); send_char('\t');
            send_char('\t'); send_string("G: X "); send_char('\t');
            send_char('\t'); send_string("g: X "); send_newline();
            
            send_char('\t'); send_string("s: X "); send_char('\t');
            send_char('\t'); send_string("d: X "); send_char('\t');
            
            send_char('\t'); send_string("C: X "); send_char('\t');
            send_char('\t'); send_string("O: X "); send_newline();
            send_char('\t'); send_string("o: X "); send_newline();
           break;

THis is the short version that mostly works, any more text in place of the X's causes corruption on USAART output and ine the extreeme lockup of the device. The case statement is veeeery long with so many damn options!

main.c:
       
        //USART
        while (num_in_serial_buffer()) { //check whether there is anything on the serial buffer, if there is, look at it
            handle_single_char_from_serial();
        }
        

OMG what can I do please oh gurus?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
what can I do
Tell us what clock frequency you are using and what kind of oscillator. ie it may have NOTHING to do with the code.

This looks suspicious

    while (~UCSR0A & (1 << UDRE0)); 

try

	while (!(UCSR0A & (1<<UDRE0)));

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Sat. Mar 1, 2014 - 06:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What are you using as clock source? Is it the internal oscillator or an external resonator/crystal?

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What do your build tools say about the total size of the data segment, compared to the amount of RAM actually present on the chip? Strings happen in RAM, and it's really easy to use more than you have. 2K of RAM in a m328 is only one "screenful" on an old 24x80 terminal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is on arduino Nano which I think uses external 16MHz crystal oscillator.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Strings happen in RAM,
...or not depending on whether one is using PROGMEM. :wink:

Of course in this case they do.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you do the math, you cannot achieve exactly 57600 baud rate with 16MHz oscillator, you have more than 2% error and even AVR datasheets recommend the error to be smaller than 2% for reliable communications.

You have two choises, either lower baud rate to something like 38400 which has only 0.16% error at 16MHz, or use U2X feature to get 57600 with about 0.8% error at 16MHz.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you all for your advice!
some reason the whole project is failing periodically in weird ways... oh dear. So learning about PROGMEM (and onboard EEPROM) ironically I re-typsed all of Deans turorials for various reason but didnt read them... stupid! They are good! Will use a lower baude, and not sure if the change to the while command has caused all my usart weirdness... Hopefully it will like me today.

BTW my bad I 'imagined' that the progmen thing would be done automatically for unchanging text strings. Better put them _all_ in progmem manually. IS there a preferred way? Dean shows a few.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

IS there a preferred way?

Well for one thing PROGMEM is effectively deprecated by __flash if you use a >=4.7 compiler.