learn.parallax.com
Published on learn.parallax.com (http://learn.parallax.com)

Home > Propeller C > Propeller C Tutorials > Functions

Propeller C - Functions

Propeller C - Functions

A C-language tutorial for the 8-core Propeller microcontroller. It features the Propeller Activity Board [1]but other Propeller boards will work.

 

What it's about

A function is a little piece of reusable code designed to do a specific task.  This tutorial will show you how to use functions, pass information to them, and get information back from them. It shows you how C functions work with the Propeller's memory and multiple cores.

Before you start

  • Set up the SimpleIDE software and your Propeller board [2]
  • Update your Learn Libraries [3]
  • Try Propeller C - Start Simple [4] if you are new to the Propeller microcontroller and/or C programming.

After you finish

Once you are done here, you will be able to understand how functions are used in these tutorials' example code.  And, you will be ready to write functions to use in your own projects. You will be well-prepared for:

  • Simple Circuits [5] - blink lights, monitor pushbuttons, make beeps, and more
  • Simple Devices - coming soon!

Just follow the links below to get started!

Reusable Code Functions

Throughout the Propeller C - Start Simple [4] lessons, we put our code in the main function.  You can also add other functions to your program and call them from the main function, or even make code in one of those functions call another function.

Function Call.c

This first example has a function named hello with a printf command in its code block.  When the code running in the main method sees hello(); it jumps down to the function named hello, executes the statements in its code block, then returns to the main function. There, the program moves on to the next thing, which is a printf statement that displays “hello again!”  

  • Click the Open Project button.
  • If you aren’t already there, navigate to ...\SimpleIDE\Learn\Examples\C Intro\Basics.
  • Open Function Call.side.
  • Click the Run with Terminal and verify that the program displays “Hello from function!” first, then “Hello again from main!” second.
/*
  Function Call.c
  Send a simple hello message to the terminal, but use a function to display
  one of the messages.
*/

#include "simpletools.h"                      // Include simpletools

void hello(void);                             // Forward declaration

int main()                                    // main function
{
  pause(500);                                 // Pause 1/2 second
  hello();                                    // Call hello function
  printf("Hello again from main!\n");         // Display message
}

void hello(void)                              // Hello function
{
  printf("Hello from function!\n");           // Display hello message
  pause(500);                                 // Pause 1/2 second
}

How It Works

The void hello(void); line above the main function is called a forward declaration.  It tells the PropGCC compiler to expect to see a function named hello later in the program. 

Function call.c starts in the main function with pause(500).  After that, it sees hello(), which tells it to go find the function named hello, do whatever is in its code block, and come back when done.  The hello(); in the main function is called a function call. 

The actual hello function is the void hello(void) block of code down below the main function.  That’s where the program goes when it sees the hello() call, and it executes that one printf statement that displays the “Hello from function!” message.  After it runs out of statements to execute, the program returns to the hello call in the main function.  There, it moves on to the next statement, which is the printf command that displays “Hello again from main!”

An example of a function call


Did You Know?

In the hello function definition, the void to the left of the name means that the function does not send a value back to the function call.  The (void) to the right of the function’s name means that the function does not need to receive any values, called parameters, to do its job.  We'll look at parameters and return values in the next few lessons.

A function has a code block contained by curly braces { }.  A code block can include one or more statements that will execute when the function is called. 

Function Definition in C for the Propeller microcontroller

You can also get rid of the forward declaration by moving the entire hello function above the main function.  That way, the compiler will have seen the hello function itself before it sees the hello() function call inside main. 


Try this

The great thing about functions are that they are reusable — they can be called over and over again.   

  • Click the Save Project As button and save a copy of your project as Loop Calls Function. 
  • Modify the program using the example below.
  • Click the Run Project with Terminal button, and verify that the program displays “Hello from function!” five times before displaying "Hello again from main!"

A C statement with two functions

Your Turn

  • Use the Open Project button to reopen the original Function Call.side, then use Save Project As to make another copy with a different name.
  • Add a function named goodbye below the hello function, and add a goodbye function call to your main function.  Don't forget to add a goodbye forward declaration before the main function.
  • Test the code and make sure it works.
  • In the main function, make a for loop that repeats ten times, and put the hello() and goodbye() function calls inside it so that they both display ten times.

Function with Parameter

Many functions are designed to receive values that they need to do their jobs.  These values are called parameters. 

  • Use the Open Project button to open Function with Parameter.side.
  • Read the code.  What do you think it will do?
  • Click the Run with Terminal button, and compare the result from the Propeller with your prediction.
/*
  Function with Parameter.c 
  Call a function that displays a value passed to it with a parameter.
*/

#include "simpletools.h"                      // Include simpletools

void value(int a);                            // Function prototype

int main()                                    // main function
{
  pause(500);                                 // Pause 1/2 second
  value(6);                                   // Call value function
}

void value(int a)                             // value function
{
  printf("The value is: a = %d\n", a);        // Display a single value
}

How It Works

First we see the function definition void value(int a).  Remember, the void on the left means this function does not send back a return value to function calls.  The (int a) on the right means that it expects to receive an int value from function calls. 

In main, the function call value(6) passes the value 6 to the function.   The value function receives the value 6 stores it in the int variable named a.  Then, the value function's code block displays that value with printf("The value is: %d\n", a). 


Did You Know?

  • Local variables — The int variable a that gets declared as a parameter in the value function definition is called a local variable.  It is used only inside this function, and memory is reserved for it only while this function is running.  Your program could have other functions with their own local variables named a.  They won't interfere with each other.  
  • Multiple local variables — You can expand a function definition to receive more values by adding more parameters. Each parameter in a function definition needs a unique name.

Try this

Let's define a function named values that has two parameters. 

  • Click the Save Project As button and save your project as Functions with Parameters. 
  • Modify the program using the example below. 
  • Examine the program and predict what it will display.
  • Click the Run Project with Console button, and check what the program does against your predictions.

Did you notice that both function definitions include a parameter named a, and that they do not interfere with each other?

Your Turn

  • Write a function definition of void counter(int startVal, int endVal, int incVal)
  • Add a for loop to the function that starts counting at startVal, stops counting at endVal, and takes steps of incVal.  HINT: Your for loop should start with for(int i = startVal;...

Function with Parameters and Return

Some functions are designed to do a job and send a return value back to the function call.  For example, a function might check a pushbutton and return its state.  Or, a function might receive some values through its parameters, use them in a calculation, and return the answer — we will try this.

We will also try a neat coding technique: setting a variable as equal to a function call.  This is a quick and efficient way to call a function and get its return value into a variable.

  • Open the project Function with Parameters and Return Value.side.
  • Read the code.  What do you think it will do?
  • Click the Run with Terminal button, and compare the result from the Propeller with your prediction.
/*
  Function with Parameters and Return Value.c 
  Pass parameters to a function, let it do its job, and display the result
  it returns.
*/

#include "simpletools.h"                      // Include simpletools

int adder(int a, int b);                      // Forward declaration

int main()                                    // main function
{
  pause(500);                                 // 1/2 second pause
  int n = adder(25, 17);                      // Call adder function
  printf("adder's result is = %d", n);        // Display adder function result
}

int adder(int a, int b)                       // adder function
{
  int c = a + b;                              // Add two values
  return c;                                   // Return the result
}

How the Code Example Works

The adder function’s definition is int adder(int a, int b).  The (int a, int b) part means that a function call to adder must pass two int values.  The int at the beginning means adder will send back, or return, an int value to the function call.

Take a close look at the line inside main that sets int n equal to an adder function call.  adder(25, 17) passes those two values to the adder function's a and b parameters. There, a + b adds the values together, and the result is assigned to a local variable with int c =.  At that point, c = 42. 

Return c sends the value of c back to take the place of the original function call in main. So,  int n = adder(25, 17) evaluates to n = 42.

The next line in main, a printf statement, displays the value of n.  Your SimpleIDE Terminal will display "adder's result it 42"

 


Did You Know?

  • The function’s parameter list is not your only chance to declare local variables.  The main function's int n =... and the adder function's int c = ... are also examples of local variables. 
  • The adder function could have been even shorter.  You could replace the two lines in its code block with return a + b; no need for int c at all.

Try This

Here are some variations on the main function that use the result adder returns in different ways. 

  • Use the Save Project As button to make a copy of your project and save it into the My Projects folder.
  • Modify the code as shown below, and try to predict the results.
  • Use the Run with Terminal button to display the output. Are the actual results the same as what you predicted?

Your Turn

Try including a subtracter function. 

  • Use the Save Project As button to make a copy of your project named Adder Subtracter Functions.
  • Add a forward declaration for subtracter above main.
  • Add the subtracter function (which subtracts a from b) below the adder function.
  • Call the subtracter function from within main.

Memory Functions Can Share

So far, this tutorial has used local variables declared inside of functions.  There are advantages to using local variables, since they only use memory temporarily while the function using the variable is executing. This can be useful with microcontrollers, where memory is limited as compared to computers.

Sometimes it is necessary to have variables which more than one function can access and modify.  These shared variables are called global variables.  The multicore Propeller can execute different functions with different cores (also called cogs) at the same time.  These functions operating in parallel can use global variables to exchange information (which we will do in the next lesson).

The example program below uses a modified version of the adder function from the previous lesson, but with all local variables are replaced with global variables throughout the code.

  • Click Open Project and select Global Exchange from ...SimpleIDE\Learn\Examples\C Intro\Basics. 
  • Click the Run with Terminal button, and verify that the main function displays the result that adder stores in the global n variable.
/*
  Global Exchange.c
  Functions exchange information with global variables.
*/

#include "simpletools.h"         // Include simpletools

void adder(void);                // Forward declaration

int a, b, n;                     // Global variables

int main()                       // main function
{
  pause(1000);                   // Wait 1 s for host
  a = 96;                        // Set values of a & b
  b = 32;
  adder();                       // Call adder function
  printf("n = %d\n", n);         // Display result
}

void adder(void)                 // Adder, no parameters or return
{
  n = a + b;                     // Use values of a & b to set n
}

 

How it Works

The adder function definition void adder(void) ; does not declare parameters or a return value.

Next, a, b, and c are declared as global variables.  Since they are all the same type, int variables, they can be declared in a single statement separated by commas. 

Instead, a and b are assigned values in separate statements inside the main function, just before the adder function call.  The code jumps to the adder function, where the result of a + b is assigned to the global variable n.

Code execution then resumes on the next line in the main function, a printf statement that displays the value of n.

Since a, b, and n were all declared before the first function, they were accessible to all the functions in the program. So, there was no need to pass parameters or return values between functions.


Did You Know?

Declare & Initialize — In this example, a and b were first assigned values from within the main function. However, that could have been done right in the original declaration, like this: int a = 96, b = 32, n;

Space vs. Speed — Global variables take more memory, but using them can make code execute faster in some cases.  Setting up and releasing memory for local variables takes a little bit of time.  If your project uses lots and lots of local variables, these bits of time can add up.

Scope — The terms local and global describe a variable's scope, the context in which the variable can be used validly in a program.

BUG ALERT! 
Do not put int (or any other variable type) in front of a global variable while using it inside a function!  That would create a local variable with the same name, but only that function would use it. It might not have the same value as the same-named global function, and changes made to the local variable's value would not be stored in the global same-name function. 

 


Try This

  • Modify this program by creating a subtracter function that uses the global variables, and add some code to your main function to test it.

Multicore Example

The previous lesson showed you how to make functions share global variables.  Now,  let's try making two functions run in different Propeller cores, also called cogs, and exchange information through those global variables. 

This next example program launches the adder function into another cog.  The adder function has been modified so that it keeps on adding 1 to the global n variable every 20th of a second. 

The main function monitors the adder activity in that other cog by repeatedly displaying the value of the global n variable.  The adder function changes n 20 times-per-second, so the main function will display a new value each time through its loop even though it doesn't actually do anything to n.

  • Click the Open Project button.
  • Select Open Multicore Example from ...\SimpleIDE\Learn\Examples\C Intro\Basics.
  • Read the code. Note that the main function only sets the value of n once, but that the adder function updates it each time through its loop. 
  • Also note that the main function has a while(1) loop that displays the n variable over and over again.
  • Click the Run with Terminal button and verify that the value of n keeps changing. 
/*
  Multicore Example.c
  Launch a function into another cog (processor) and display what it does
  to the global n variable over time.
*/

#include "simpletools.h"                      // Include simpletools

void adder(void* par);                        // Forward declaration

static volatile int t, n;                     // Global vars for cogs to share
unsigned int stack[40 + 25];                  // Stack vars for other cog

int main()                                    // main function
{
  pause(1000);                                // Wait 1 s for Terminal
  t = 50;                                     // Set values of t & n
  n = 5000;

  // Launch adder function into another cog (processor).
  cogstart(&adder, NULL, stack, sizeof(stack));

  // Watch what the other cog is doing to the value of n.
  while(1)
  {
    printf("n = %d\n", n);                    // Display result
    pause(100);                               // Wait 1/10 of a second   
  }   
}

// Function that can continue on its
// own if launched into another cog.
void adder(void *par)                         // Adder keeps going on its own
{
  while(1)                                    // Endless loop
  {
    n = n + 1;                                // n + 1 each time loop repeats
    pause(t);                                 // Wait for t ms between updates
  }                           
}

How It Works

Cog 0 starts at the beginning of main, executing the pause function call and then setting the values of t and n. 

Next, cog 0 passes the memory address of the adder function. along with some other details, to a function called cogstart.  (It's part of the propeller library, which simpletools includes.)  cogstart uses that information to make the next available cog (cog 1) start executing code in the adder function. 

At this point, two cogs are executing different parts of the program.  Cog 0 moves on to start repeating the while(1) loop in the main function.   and cog 1 starts executing the while loop in the adder function.  Cog 1 updates the value of n every 50 ms because t = 50 and adder's while loop has pause(t).  Meanwhile, cog 0 checks the value of n every 100 ms and displays the value with printf.  Since cog 0 is checking more slowly than cog 1 is updating, the value of n it displays increases by 2 every time.

After the cogstart call, the adder function starts running in another cog.  Meanwhile, the code in the first cog continues onward into the main function's while(1) loop.

General Multicore Setup

From this example, we can see the general steps for setting up multicore code, for large or compact memory models (LMM or CMM):

  • Use static volatile to declare global variables for sharing between functions running in different cogs. 
    Example: static volatile int t, n;
  • Declare a stack array with 40 longs (required) + extra for local variables and calculations. Be liberal with the extra memory, and use testing to pare it down after your prototyping is done.
    Example: unsigned int stack[40 + 25];  
  • Launch a function in another cog with cogstart and the following parameters:the address of the function, an optional value (or NULL), the address of the stack array, and the size of the stack array (in bytes).
    Example: cogstart(&adder, NULL, stack, sizeof(stack));
  • The cogstart function returns the ID of the destination cog.  If you need to keep track of where a particular function is running, declare an int variable assigned to the cogstart function call. 
    Example: int cog = cogstart(&adder, NULL, stack, sizeof(stack));
     

Did You Know?

LMM & CMM  — This is an example of launching either large memory model (LMM) or compact memory model (CMM) code into another cog.  These memory models fetch machine codes (numbers that represent your program) from the Propeller chip's 32 KB main RAM, and code running in the cog processes them.

COGC & PASM — memory models There are other, higher performance options such as COGC (C that runs inside a cog) and PASM (Propeller Assembly Language).  Code for both of these types of programs get loaded into a cog's 2 KB of memory, which increases execution speed because the cog doesn't have to wait for its turn to access main ram and grab machine codes.

More on Memory Models — Additional examples and more memory model options can be found in the Propeller GCC Demos folder. 


Try This

Let's find out which cog the cogstart function launches the adder function into.

  • Try modifying the cogstart function like this:

Your Turn

Add a subtracter function to the project and launch it into a third cog. Make subtracter decrement a new global variable with the same initial value as n, repeating every t ms. Display the changing values of both variables.

  • Save the project under a new name.
  • Set up the forward declaration for the subtracter function to run in another cog.
  • Add another global variable to share with this new function.  Remember to make it static volatile.
  • Declare a stack array for subtracter, with a different name, such as otherStack.
  • Initialize your new global variable.
  • Add a new cogstart function call to launch the new subtracter function. Be sure to use the name of the new stack array you just created.
  • Write your subtracter function for use in another cog.  And, remember to use the additional global variable you created to hold the result of your subtraction operation.
  • In the main function, add code to the while(1) loop's printf statement to also display the value of the new global variable as it gets decremented by the subracter function.

SHOP IN THE PARALLAX STORE ►

Terms of Use ♦ Feedback: learn@parallax.com ♦ Copyright©Parallax Inc. 2012 (unless otherwise noted)


Source URL: http://learn.parallax.com/propeller-c-functions

Links:
[1] http://learn.parallax.com/node/653
[2] http://learn.parallax.com/node/640
[3] http://learn.parallax.com/node/658
[4] http://learn.parallax.com/node/617
[5] http://learn.parallax.com/propeller-c-simple-circuits