Returning 16-bit data in Arduino sketch vs GCC sketch

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

Hello,

 

I've just started to work on a library with AVR-GCC code, I just wanted to return a 16-bit data from a function which I was testing in Arduino sketch. It's working with the Arduino sketch but with AVR-GCC sketch it first returns only 8-bit and it waits for like 5 seconds then it continues to return the 16-bit data and display it on the Serial monitor.

 

These are the sketches:

 

1. Arduino sketch:

uint16_t tft24_read_id(void);
uint16_t tft_id;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
    tft_id = tft24_read_id();
    Serial.println(tft_id,HEX); 
    delay(500);
}

uint16_t tft24_read_id(void){
  uint16_t id=0x1211;
  return id;
}

2. AVR-GCC sketch:

uint16_t tft24_read_id(void);
uint16_t tft_id;

int main(){
Serial.begin(9600);

  while(1){
    tft_id = tft24_read_id();
    Serial.println(tft_id,HEX); 
    Serial.println();
    _delay_ms(500);
  }
}

uint16_t tft24_read_id(void){
  uint16_t id=0x1211;
  return id;
}

 

This topic has a solution.

Last Edited: Sun. Dec 30, 2018 - 08:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Arduino uses avr-gcc, so both ‘sketches’ should be near identical. For the avr-gcc one, i can only suggest you haven’t set F_CPU correctly.

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

I suspect that the 16-bit read in main() is being optimized away somehow by the compilier.  Arduino combines setup() and loop() into a   main() and then compiles this main().  But loop() as a function gets exited and then entered again with each pass through while(1) statement that the main() uses for code that repeats endlessly.  With each pass the loop() variables get reset to their defined default values or zero.  You have to declare as static all the variables in loop() that are going to be changed by loop()'s actions.

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

Kartman wrote:
Arduino uses avr-gcc, so both ‘sketches’ should be near identical. For the avr-gcc one, i can only suggest you haven’t set F_CPU correctly.

 

This is strange to me, it could be a simple problem but as always I would have no clue how to solve it. Because it's a simple code, there are no programming problems in the codes. So, because it has to do of how Arduino compiler work then that would be so difficult for me to know about.

 

The F_CPU is required in Atmel Studio, but not in Arduino IDE.

 

I tried to compile the code in Atmel Studio, but Atmel Studio obviously doesn't recognize #include <Arduino.h> library, and almost all my compiling and uploading is done with Arduino IDE. I don't know if Atmel Studio has a UART output window, I did a quick search but I think I need a JTAG tool for debugging.

 

Simonetta wrote:

I suspect that the 16-bit read in main() is being optimized away somehow by the compilier.  Arduino combines setup() and loop() into a   main() and then compiles this main().  But loop() as a function gets exited and then entered again with each pass through while(1) statement that the main() uses for code that repeats endlessly.  With each pass the loop() variables get reset to their defined default values or zero.  You have to declare as static all the variables in loop() that are going to be changed by loop()'s actions.

 

What I want is that I want the code to work in the AVR-GCC sketch in the Arduino IDE, it's working OK in the Arduino sketch.

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

Atmel Studio can compile an Arduino sketch. Have you tried this feature? Don’t ask me how to do it as I’ve not tried it and there’s plenty of info online.

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

Yes, I know the Atmel Studio compiles and support Arduino sketches, when I open the AS IDE and select new project, then Arduino sketch would appear as one of the sketches list. AS also support C++ which pretty cool. But I actually need the nice serial monitor in Arduino IDE.

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

"What I want is that I want the code to work in the AVR-GCC sketch in the Arduino IDE, it's working OK in the Arduino sketch. "

 

Huh?   The AVR-GCC sketch can not work in the Arduino IDE.  The Arduino IDE will only compile code that is the setup() and loop() format.  The AVR-GCC sketch is in main() format.

 

If you have code that works in Arduino, then you have code that works.  Code that works is code that you get paid for.  Getting paid is why people become serious programmers.

What difference does it make if the code doesn't work in somebody else's free IDE tool?   Your code works.  It works in Arduino.  So obviously, in this case, Arduino is a superior

IDE to Atmel Studio.  So continue to use Arduino and now go on now to something more important.

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

Yes, thank you. Actually, I was doing my programming as a mix of Arduino 'setup and loop' with AVR-libraries written in C installed Arduino libraries folder.

 

But members in this forum, suggested to me to use AVR-GCC sketch 'main and while' in the Arduino IDE, it worked very well and also the code size is less than the compile size of Arduino sketch.

 

Everything is OK, until yesterday when I was trying to read back 16-bit data and display it on the Serial monitor as I'm calling it with the AVR-GCC sketch, so it wasn't working as with the Arduino sketch, that's the problem.

 

As you are telling me that the AVR-GCC code is working in the Arduino IDE, yes, it's working but this one isn't really, it lags at first, then continue to read the data on the serial monitor.

 

So continue to use Arduino and now go on now to something more important.

You're right I really want to move on, anyway the problem is because only of the serial monitor lags showing the results. Otherwise, everything is OK.

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

OK, I found something really interesting in AS7! There's a terminal window, it works like a charm.

 

Now, I just better have to do my C programming in AS7, and just leave Arduino IDE for C++ projects.

 

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

I have a quick question:

 

What's the best way to redesign this function:

uint16_t get_char(void)
{
    if (rx_cnt == 0)                        // when cnt is 0, it means
        return NO_DATA;                     // that rx ISR didn't receive anything
    else if (rx_p < rx_cnt)
        return rx_buf[rx_p++] + (rx_errors << 8);
        else
        {rx_cnt = 0;rx_p = 0;}              // when read everything reset counter and pointer
}

 

Because it gives me a warning in AS7:

Severity    Code    Description    Project    File    Line
Warning        control reaches end of non-void function [-Wreturn-type] 

 

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

2. AVR-GCC sketch:

    Serial.println(tft_id,HEX); 
    Serial.println();

Where are you getting "Serial.println()" for the AVR-GCC sketch?

In the Arduino environment, that would be a heavily overloader C++ object method, and I'd be suspicious that the "AVR-GCC" version is not fully compatible in some way.  (I'm surprised that it compiles at all?)

 

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

Your question about the  warning...

 

After that last "else", there is no return statement.

 

The statement: 

control reaches end of non-void function [-Wreturn-type]

means that there is a path to the end of the function where no return is found but the kind of function (non-void, that is a return type of uint16_t in your case) that you specify REQUIRES one.
 

Jim

 

 

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

 

 

Last Edited: Tue. Dec 25, 2018 - 09:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
Where are you getting "Serial.println()" for the AVR-GCC sketch?

I'm doing my programming in Arduino IDE.

 

In the Arduino environment, that would be a heavily overloader C++ object method, and I'd be suspicious that the "AVR-GCC" version is not fully compatible in some way. 

Yes, actually I learned that Arduino sketch "setup and loop", these functions contains other init functions in Arduino.h. So yeah AVR-GCC isn't compatible with it.

 

(I'm surprised that it compiles at all?)

 Well, it worked, but I think that's because I'm calling a function within Arduino environment and the function is found but not initialized properly.

 

 

ka7ehk wrote:

After that last "else", there is no return statement.

 

means that there is a path to the end of the function where no return is found but the kind of function (non-void, that is a return type of uint16_t in your case) that you specify REQUIRES one.
 

 

Yes, even so ti has two return statements but I think it's required to put the return statement at the end of the function. I just thought of a way to rearrange the function to eliminate the warning.

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

I did it like this:

uint16_t get_char(void)
{
	uint16_t data_msg_mask=0;
    if (rx_cnt == 0)                        // when cnt is 0, it means
        return NO_DATA;                     // that rx ISR didn't receive anything
    else if (rx_p < rx_cnt)
        data_msg_mask = rx_buf[rx_p++] + (rx_errors << 8);
        else
        {rx_cnt = 0;rx_p = 0;}              // when read everything reset counter and pointer
	
	return data_msg_mask;
}

But the compiler launched a warning because the "data_msg_mask" wasn't initialized, so I had to initialize it to 0. I have other functions which have uninitialized variables and didn't launches a warning! Like this one:

 

 

ISR(USART_RX_vect)
{
    uint8_t status_mask,data_temp;
    data_temp = UDR0;
    status_mask = UCSR0A & ((1<<FE0)|(1<<DOR0)|(1<<UPE0));

    if (rx_cnt < buf_sz)
        rx_buf[rx_cnt++] = data_temp;       // just receive all with no limit
                                            // I didn't put else statement
                                            // because I didn't know what
                                            // else can be done if buffer
                                            // is full

    rx_errors |= status_mask;               // update error bits
}

Is it because it's an ISR function?

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

The obvious explanation is that you didn't load a value into the variable! The compiler figures this out. In your ISR code you always load a value into it, thus the compiler does not complain. In the get_char() function, data_msg_mask is only conditionally loaded.

 

FYI - you normally don't bother with rx errors. Higher level code should catch it. If you are worried about data integrity, then use a packet structure with a CRC or checksum.

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

wolfrose wrote:

I did it like this:

uint16_t get_char(void)
{
	uint16_t data_msg_mask=0;
    if (rx_cnt == 0)                        // when cnt is 0, it means
        return NO_DATA;                     // that rx ISR didn't receive anything
    else if (rx_p < rx_cnt)
        data_msg_mask = rx_buf[rx_p++] + (rx_errors << 8);
        else
        {rx_cnt = 0;rx_p = 0;}              // when read everything reset counter and pointer

	return data_msg_mask;
}

But the compiler launched a warning because the "data_msg_mask" wasn't initialized, so I had to initialize it to 0. I have other functions which have uninitialized variables and didn't launches a warning! Like this one:

 

 

If you don't initialize, the line I highlighted would return an unitialized value in case the "else if" is not executed. This is not something you should do, ever. So the compiler gives a warning.

Last Edited: Wed. Dec 26, 2018 - 10:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:

The obvious explanation is that you didn't load a value into the variable! The compiler figures this out. In your ISR code you always load a value into it, thus the compiler does not complain. In the get_char() function, data_msg_mask is only conditionally loaded.

 

OK, but you know what I don't get these warnings compiling the code with the Arduino IDE, AS7 is a complete IDE like MPLAB X, they compile the code with errors & warning checking. Arduino is only with errors checking.

 

But I think also is that I can control the level of code optimization like in MPLAB, I reduced the warning checking level to only check for serious code errors.

 

FYI - you normally don't bother with rx errors. Higher level code should catch it. If you are worried about data integrity, then use a packet structure with a CRC or checksum.

I should not be worried, it's just I copied this code from a UART library for Peter Fleury. But you're right like almost all the time UART works with no errors.

 

 

El Tangas wrote:
If you don't initialize, the line I highlighted would return an unitialized value in case the "else if" is not executed. This is not something you should do, ever. So the compiler gives a warning.

Yes, this is because I was compiling the code with AS7, I wasn't familiar with these warnings with Arduino IDE :) So with AS7, there should be a lot of warning checking. Like last night I was working with itoa(), so there was difference between passed variable in "uint8_t" and itoa() 2nd parameter which receives "char" so I had to cast it with "char*", the start is because itoa 1st parameter should receive only 8-bit and where "tft_id" is 16-bit and it worked.

 

int16_t tft_id=0x1122;
uint8_t ar_buf[10];

int main(void)
{
	uart_init_basic(8);
	itoa(tft_id,(char*)ar_buf,16);
    while (1) 
    {
		uart_tx_str(ar_buf);
    }

 

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

wolfrose wrote:

Yes, this is because I was compiling the code with AS7, I wasn't familiar with these warnings with Arduino IDE :)

 

This is just a matter of configuration, since the Arduino IDE and AS7 use the same compiler (avr-gcc). You can disable the warnings in AS7 but that is a bad idea. You can also enable them in the Arduino IDE preferences menu, as any more advanced user should (they are disabled by default).

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

El Tangas wrote:
This is just a matter of configuration, since the Arduino IDE and AS7 use the same compiler (avr-gcc). You can disable the warnings in AS7 but that is a bad idea. You can also enable them in the Arduino IDE preferences menu, as any more advanced user should (they are disabled by default).

 

Thanks, well, I've done almost all my programming in Arduino IDE, I go to AS7 to check something, but Arduino launches faster and the COMPILE/UPLOAD icons are easy to reach and the serial monitor, that's why I like Arduino IDE.

 

So, I guess my Arduino IDE isn't enabling the warnings and it's working ok, I just compile the code and upload it.

 

It could be a bad idea, because I think warnings would help me to optimize the code! I don't know I'm not sure, and of course help to prevent possible errors.

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

Yeah, sometimes I also use the Arduino IDE for quick tests, because it launches faster than AS7.

If you want to enable warnings, it's in files->preferences

 

Just set warnings to a level other than "none" (I set them to "all") and optionally tick the "verbose" boxes. You will get a lot of potentially useful extra info.

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

Yeah thanks :) I really haven't check the preferences more thoroughly, I enabled code folding, display line numbers and warnings to default.

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

I highly recommend setting Compiler Warnings to ALL

and fixing every single thing it complains about.

 

--Mike

 

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

Yeah that would point to me all the necessary aspects of my code. But what the difference if the code is working already and I disabled the warnings? Either fixing the warnings or leave them as is, but the code is functioning the same.

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

Yes, often the code will work fine even with warnings. But many times it won't, especially when you use undefined variables or do implicit number conversions that can give unexpected results.

Sometimes, and this is the most insidious situation, the code will work fine most of the time but will fail for specific situations. You will think everything is ok, but it isn't.

 

So it's better to fix all the warnings if possible.

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

Compilers complain about two different levels of mistake...

 

ERROR - this means that the code you have written is not valid C  and that the compiler cannot generate any machine code for it.

 

WARNING - this means that your code IS valid C, and it will generate machine code, but that there may be unintended consequences when your code runs.

 

 

You should always try to remove all WARNINGS (you have to remove all ERRORS) unless you fully understand the consequences of not doing so.

 

 

For example, I have some production code out in the field which generates the following warning...

 

Warning: E:\Product - Software\N0004xxxx\aaa.c(116): overflow is possible in 8 bit shift left, casting shifted operand to 'int' may be required

 

...generated on the following code...

 

addr = (((serial_packet[1] & 0x3f) - 1) << 2)

 

...however, by inspection, I can see that an overflow will never occur and so I can safely ignore that warning.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

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

If you know it's benign you should add the cast it suggesys to quell the warning as code should build "clean" (so the real warnings stand out when they occur)

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

In this case the snippet shown is in an ISR which needs to do its stuff and get back to main() really quickly. Every cycle counts. Not shown was the dirty great comment flagging up that it's not ideal.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I found on the Arduino forum, the solution to the problem I had when compiling an AVR-GCC sketch in Arduino IDE and printing the data on the serial monitor.

 

Actually Arduino sketch "setup & loop" contains other initialization functions than the direct AVR sketch.

 

This is the Arduino sketch:

 

/*
  main.cpp - Main loop for Arduino sketches
  Copyright (c) 2005-2013 Arduino Team.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Arduino.h>

// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }

// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }

void setupUSB() __attribute__((weak));
void setupUSB() { }

int main(void)
{
 init();

 initVariant();

#if defined(USBCON)
 USBDevice.attach();
#endif

 setup();

 for (;;) {
 loop();
 if (serialEventRun) serialEventRun();
 }

 return 0;
}

 

So, basically I had to call the function "init();", and that solved the problem. Now the serial monitor prints the results as expected.

Last Edited: Sun. Dec 30, 2018 - 08:55 AM