Author Topic: Passing a pointer (Atmel Studio 6 and Xmega)  (Read 10906 times)

0 Members and 1 Guest are viewing this topic.

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Passing a pointer (Atmel Studio 6 and Xmega)
« on: July 28, 2013, 09:18:23 am »
I'm trying to convert some C++ code to use in Atmel Studio 6 with an Xmega.

So far I've got all of it working apart from one function:

Code: [Select]
void LCD_PRINT(char *st, uint8_t x, uint8_t y)
{
   uint8_t stl, i;
   stl = strlen(st);
   x=((disp_y_size+1)-(stl*cfont.x_size))/2;
   for (i=0; i<stl; i++)
   PrintChar(*st++, x + (i*(cfont.x_size)), y);
}

How do I pass a string (which could be either constant or a variable) to this function?
 

Offline Bored@Work

  • Super Contributor
  • ***
  • Posts: 3932
  • Country: 00
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #1 on: July 28, 2013, 10:15:31 am »
Strings are char pointers in C. So you just pass the string, what's the problem?

If your string / char pointer is located in progmem you need to rewrite the function to access progmem instead of *st++.
I delete PMs unread. If you have something to say, say it in public.
For all else: Profile->[Modify Profile]Buddies/Ignore List->Edit Ignore List
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #2 on: July 28, 2013, 10:35:46 am »
After a bit more investigation, it turns out it's actually another function (called from the print one) that's causing the error.  I had commented it out in the code show above as I wanted to show the bare minimum.  Whoops.  The code in question was for rotated text and I'll investigate that once I get the non-rotated text working.

Part of the problem is I only know a little C code and I'm porting this from a C++ (Arduino) TFT library.  I'm now stuck on how to get the font data working with it, so that will keep me frustrated for many more hours.   :(
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #3 on: July 28, 2013, 11:48:56 pm »
I'm trying to convert some [arduino] C++ code to [plain C]
Code: [Select]
void LCD_PRINT(char *st, uint8_t x, uint8_t y)How do I pass a string (which could be either constant or a variable) to this function?
Beware that C++/Arduino code has two kinds of "strings."

1) Standard C style strings - pointers to arrays of characters (which is what your included function is using):
Code: [Select]
char * myStringVar = "this is a C string in a variabel";
LCD_PRINT(myStringVar, 0, 0);
LCD_PRINT("this is a string constant", 0, 0);

2) Members of the C++ "String" (note capitalization) class.  These are dynamically allocated and garbage-collected, and "variable length":
Code: [Select]
String myCPPString = "This will become a C++ String variable";
myCPPString += "\nI can easily modify it";
Serial.print(myCPPString); // C++ will no how to treat this differently than a C string
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #4 on: July 29, 2013, 12:03:42 am »
More fun today as I threw away the Atmel ASF and started again with a "standard" project.  This may also be a cause of issues.   |O
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #5 on: July 29, 2013, 12:32:05 am »
I'm a little confused on how to correctly use include files in Atmel Studio.  There is some conflicting advice out there.

Say I have my main.c file with the main loop, etc.  I also have another file with the LCD routines in it.  Let's call that lcd.c for now.

I gather that I should also have a header file called lcd.h with the prototypes for the functions inside the lcd.c file.

So, main.c has an entry #include "lcd.h" so that it can call the LCD routines.  How do lcd.h and lcd.c then include one or the other?

It seems to me that lcd.c needs to see it's prototypes, but where do the various include <avr/io> includes go?.
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9889
  • Country: nz
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #6 on: July 29, 2013, 01:14:47 am »
Im still learning C (like every other C programmer heh)
So i could be doing this totally wrong, but here's how i do it in Atmel Studio
I put the <avr/io.h> <avr/interrupt.h> etc. in whatever c file needs them,
etc, i might isolate all the i/o code to one file, then #include <avr/io.h> only needs to be in that file.
(io.h is probably a bad example but yeah, you get the idea)

[File - main.c]
Code: [Select]
#include <avr/wdt.h>  // my watchdog is reset from main so it needs this here
#include "osd_spi.h"      // osd library for SPI coms
#include "variables.h"     // this is just a list of extern variables (so they're global to all files)

// global variables
uint8_t i=0;

void main()
{
   init();   
   while(1)   
   {
      wdt_reset();   
      SPI_write(VM0 ,123);   
   }
}


[File - osd_spi.h]
Code: [Select]
#define VM0 0x00
#define VM1 0x01
void SPI_write(char cAddress, char cData);


[File - osd_spi.c]
Code: [Select]
#include <avr/io.h>  // file needs i/o access
#include "osd_spi.h"  // declarations and defines
#include "variables.h" // list of variables that are going to be global between units.

void SPI_write(char cAddress, char cData)
{
    // stuff
    i=10;
}

[File - variables.h]
Code: [Select]
extern uint8_t i;  // allows i variable to be used across units when variable.h included
« Last Edit: July 29, 2013, 06:07:27 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #7 on: July 29, 2013, 02:27:55 am »
Quote
It seems to me that lcd.c needs to see it's prototypes
Yes.  lcd.h would include all the prototypes for the lcd code, and you'd #include it from both lcd.c (as forward reference/prototype definitions) and from main.c (as external references.)

Fortunately, "extern" in C can be used on prototypes as well (the function doesn't have to actually be external.)

Various principles of software lifecycle maintenance say that you should divide up lcd.h into it's API (those pieces that are relevant to to external modules that will call LCD functions), and the internal parts (like the primitive LCD display commands) that are only used INTERNAL to the LCD code itself.  That's a good idea, and something to think about...

Quote
but where do the various include <avr/io> includes go?
Everywhere they are needed.  Typically, that means nearly everywhere.  In theory, if main.c contains
Code: [Select]
#include <avr/io.h>
#include "lcd.h"
then lcd.h does not need to also #include io.h.  But it should, if it references anything from io.h; include files should not generally count on other standard include files having been included, and .h files are laid out so that they can be included multiple times without causing problems, and without too much loss of efficiency.  lcd.h might get away without including io.h, if it sticks purely to LCD-related things.   But lcd.c almost certainly will need to include io.h as well.
(there's a principle that says .h files should all compile cleanly, by themselves.  Another good idea.)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #8 on: July 29, 2013, 02:47:20 am »
Thanks guys.  That helps a lot.

From the above can I deduce that C supports private and public procedures?

For example, there are low level LCD routines that I don't want to be visible from the main code.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #9 on: July 29, 2013, 02:54:27 am »
Of a sort.

Any function not declared "static" will be usable externally, but only if declared before the code you try to use it in. The name is still used and cannot be used again without pissing off the linker. Functions declared "static" are only visible within the current compilation unit (the C source file and anything it pulls in as an include) and do not pollute the namespace - use these for your low-level routines. Sadly there's no way (that I can think of) to make private functions that can be used across multiple units without playing around with the linker (just use a name prefix for this).
No longer active here - try the IRC channel if you just can't be without me :)
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4196
  • Country: us
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #10 on: July 29, 2013, 03:13:44 am »
Quote
Of a sort.
Indeed.  The trick is to implement policies and discipline that give you most of the advantages of true private/public functions, using the somewhat primitive capabilities that are present in C.

Quote
There's no way to make private functions that can be used across multiple units
Tables of function pointers.  And structures that contain them.  The argument for C over C++ is that C allows you to implement most of the good parts of C++, anyway.  So for example, you could interface to your LCD via avr-libc's stdio facility ( http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html ), where lcd.c could do:
Code: [Select]
extern FILE *lcd = &lcdfile;
FILE lcdfile = FDEV_SETUP_STREAM(lcd_putchar, NULL,
                                             _FDEV_SETUP_WRITE);
and then access it via fprintf(lcd, "this is a string"); and similar, while keeping lcd_putchar() entirely "private" (name-wise.)  (not necessarily the best way to access an LCD, since it's somewhat random-access compare to a pure stream device.  But possible.)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #11 on: July 29, 2013, 03:29:24 am »
Hmmm... I added static to the front of each routine that I wanted to be private, but they are all still visible from the main unit.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #12 on: July 29, 2013, 03:35:08 am »
How is your code structured?
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #13 on: July 29, 2013, 03:37:42 am »
Main unit includes lcd.h unit.  The lcd.h unit includes lcd.c unit.  Prototypes for the "private" routines are in lcd.c unit.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #14 on: July 29, 2013, 03:54:20 am »
Don't include the C file from the H file. Remember that an include is literally a copy/paste, so now the LCD routines are inside main.c. You want to do it the other way around, include the H file from both C files. Combining the two C files should be done by compiler configuration, not by include.
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #15 on: July 29, 2013, 04:35:50 am »
So...

lcd.h has nothing ?

lcd.c has #include lcd.c ?

main.c also has #include lcd.h ?

And what gets added to the project besides main.c ?
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #16 on: July 29, 2013, 04:41:04 am »
lcd.h has the declarations (not definitions) of the functions that you want to be public, as well as any data types (structs, etc) and useful macros (like perhaps the screen size).

lcd.c has the definitions of all the LCD functions, public and private.

All C files from which you want to use the LCD functions (including lcd.c itself) include lcd.h.

Never #include anything that has ".c" as an extension.

I'm not familiar with Atmel Studio so I couldn't tell you how to get it to compile everything (maybe it automatically compiles any C files in the project).
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline AlfBaz

  • Super Contributor
  • ***
  • Posts: 2183
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #17 on: July 29, 2013, 04:47:54 am »
Usually the IDE will pass all of the C files through the compiler which generates an object file for each C file. The linker then joins them all together.

If you don't have lcd.c in your project but it still works then it's most probably because lcd.o is part of a precompiled object library installed with the IDE.
The pain with this scenario is that some vendors will give you the libraries and relevant include files but no C source files
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #18 on: July 29, 2013, 04:50:53 am »
I'm not using any canned LCD routines, just my own.

If the .h file has the definitions for the functions in the .c file, does the .c file only have the actual functions ?
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #19 on: July 29, 2013, 04:54:08 am »
Yes.

Be careful with terminology. This is a declaration:

Code: [Select]
int main (int argc, char *argv[]);

This is a definition:

Code: [Select]
int main (int argc, char *argv[])
{
    printf ("Hello, world!\n");
    return 0;
}
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #20 on: July 29, 2013, 05:40:25 am »
Actually, I should make use of the inbuilt C functions wherever possible.  Seeing that my current function takes x/y coordinates as well as the string, is that possible?
 
The following users thanked this post: David_

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #21 on: July 29, 2013, 05:51:32 am »
Not that I can think of. That function could be a bit neater, though, in which case you might not object to using it:

Code: [Select]
// Reserve all-caps for macros
// "const" helps ensure you don't try to modify the string by mistake, you'll get a compiler error if you do
void lcd_print (const char *st, uint8_t x, uint8_t y)
{
   uint8_t i;
// No need to count the string's length twice. strlen() just looks for a NUL character at the end, which you
// can do in your loop
//   stl = strlen(st);
   x=((disp_y_size+1)-(stl*cfont.x_size))/2; // What about this line? Why are you setting X when it's been passed in?
   for (i=0; st[i]; i++) // Go until st[i] is no longer nonzero (NUL is zero)
       PrintChar(st[i], x + (i*(cfont.x_size)), y); // Indent for clarity
}

So we have:
Code: [Select]
void lcd_print (const char *st, uint8_t x, uint8_t y)
{
   uint8_t i;
   x=((disp_y_size+1)-(stl*cfont.x_size))/2; // Still not sure what's going on here
   for (i=0; st[i]; i++) // Go until st[i] is no longer nonzero (NUL is zero)
       PrintChar(st[i], x + (i*(cfont.x_size)), y);
}

Which is a perfectly serviceable C function in just three lines plus variable declaration.

Alternately, you might investigate writing an LCD output backend for the built-in IO functions like printf(). It's not hard, but it depends on the implementation and I don't know Atmel's C library. You can use a simple cursor in that case and include a set_cursor() function.

Edit: I noticed your other use of stl. Hold on, might need a bit of an adjustment...
How does PrintChar() work - what are the parameters supposed to be? I'm not sure what the x variable is supposed to be.
« Last Edit: July 29, 2013, 06:11:14 am by c4757p »
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline David_AVDTopic starter

  • Super Contributor
  • ***
  • Posts: 2797
  • Country: au
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #22 on: July 29, 2013, 06:55:14 am »
It's a graphic LCD, so no cursor as such, just x and y coordinates of where to start the output.

The variable x gets adjusted in the real version of the code to account for left/right/centre justification.

I'll see if I can clean it up some more.
 

Offline c4757p

  • Super Contributor
  • ***
  • Posts: 7799
  • Country: us
  • adieu
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #23 on: July 29, 2013, 06:56:48 am »
But for simplicity, it may be helpful to break up the graphical LCD into a fixed character grid. You can still overlay that on whatever graphics you are also displaying.

If you don't want that, what you can do is have local character grids - specify x,y and width,height, then have a cursor within that grid. This makes it easy to fill up a text box, for instance.
« Last Edit: July 29, 2013, 06:59:04 am by c4757p »
No longer active here - try the IRC channel if you just can't be without me :)
 

Offline Kremmen

  • Super Contributor
  • ***
  • Posts: 1289
  • Country: fi
Re: Passing a pointer (Atmel Studio 6 and Xmega)
« Reply #24 on: July 29, 2013, 07:00:48 am »
This may count as a stupid question, but why do you wish to convert C++ code to C (assuming you do - it appeared that way in some of your earlier posts)? AVR Studio and Atmel Studio are perfectly capable of compiling say Arduino libraries practically unmodified (ignoring any possible HW changes if you are not actually using an Arduino). Also mixing C and C++ code is not an issue so you can write whichever you prefer.
Regarding .h and .c/.cpp files the logic is actually dead simple. The preprocessor will replace each #include with the text in the file referenced, exactly as it appears in the file. For any case where you invoke an external procedure or function in a compilation unit (source file), there must be some way to present the prototype of that procedure or function (i.e. its declaration) to the compiler. You can do it by typing the declaration as part of the source file itself but that is cumbersome and error prone. Enter the header file. Write the declaration once in a header and #include it everywhere it needs to go. To guard against multiple inclusion, use the #ifndef pragma to bracket the text (examples to be found in all "standard" header files). That way multiple overlapping #includes are ignored and everything works as expected.
Nothing sings like a kilovolt.
Dr W. Bishop
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf