Programming Techniques

Operating System

Current design removes the need for an operating system, as its presence would introduce potential failure points that are not justified in light of how few of the OS facilities would actually be required. In other words, the code we currently propose is simple enough that it can interface directly with the hardware without much trouble.

Sample Code

This is a quick piece of sample code, which we have used to verify the transfer procedure. We were able to read the resulting wave by connecting an oscilloscope to a ground terminal on the board and to pin H1-20, and thus confirm that we had successfully run a programme

#include <io.h>

/*
  Programme to create a square wave outputted through 
  the I/O port of the MCU

  Pete Hague 20/10/2009
*/

int main() {
  P1DIR=255; //Set Port 1 as an output port
  P1OUT=0;

  while (1) { //Starts an infinite loop
    P1OUT=255-P1OUT;
  }

}

General Techniques

Structure of code

Each part of the code should consist of a subroutine that performs the required function, as well as a 'main' procedure (selectable with compiler directives, see below) that allows the code to run standalone and give out meaningful test output.

Coding procedure

Code should be created such that it can, with limited modification, be tested on a desktop computer or on the development board. It is not always possible or convenient to get to the board, and thus for small incremental changes it is better to have code which can run anywhere.

This portability is to be implemented with compiler directives.

#define DEBUG

#ifdef DEBUG
#include <stdio.h>
#else
#inlcude <io.h> //Note, this is not the standard C io.h, it is a version specifically designed for the MSP430
#endif

By including or removing the line defining DEBUG, the correct library can be chosen. For a single line, this is not worth it - however it will be used again.

#ifdef DEBUG
void setsomepins ()
{
  printf("Some pins have been set\n");
}
#else
void setsomepins ()
{
  P1DIR=255;
}
#endif

This example shows, that if I/O is kept seperate from logic, it should be relatively trivial to swap between a desktop compiler and the development board during the course of programming.

In addition, it is useful to write the code such that it can be run on its own in a test mode, or compiled as a library to other files. Each file should contain the following:

#define STANDALONE

..

#ifdef STANDALONE
int main() {

//Code to trigger subroutine using test data

}
#endif

Thus, if the programme is transfered onto the board and run on its own, it can produce meaningful output to show it is working. Then, when the STANDALONE define is removed, it can be included into a larger build and be used as one of many subroutines.

Data Structures

Cosine lookup table

NB: This is not currently in use

The nature of the satellite calls for a number of trigonometric functions to be used by the microcontroller. However, without a build in floating point unit this could become very computationally expensive.

Our solution is twofold: firstly, using trigonometric identities we make sure that all our processing only involves a single function (we chose cosine) and secondly that this function be handled by a fast lookup table rather than by any difficult polynomial expansion.

The output of the cosine function ranges between 0 and 1, and in the equations we ues they are multiplied together (which also gives an output between 0 and 1) and are added together (which for a single pair gives an output between 0 and 2). This determines the structure of the numbers stored in the lookup table. The entries in the table will be 16-bit fixed-point numbers of the following layout:

Sign bit 1 bit whole part . 14 bit fractional part

Which would give an error of 1 part in 65536. The input of the cosine function would be the address at which a particular number is found, and would be formatted differently. We are only interested in the unique values of cosine beween 0 and Pi, so the format of this number will be:

2 bit whole part . 14 bit fractional part

Which has the same level of error.

The table thus describe would consist of 65536 entries, each 2 bytes wide, giving a total storage requirement of 128Kb. This is twice the size of both the RAM and flash ROM of the microcontroller, and whilst it would fit on the secondary storage easily doing so would be incredibly slow and negate any speed advantage of using a lookup table. The table must therefore be made smaller.

Our solution is to reduce the number of values available, and interpolate between them. The entries thus consist of a 16 bit value as described above, and a 16 bit increment, which is added for each bit difference between the input given and the input that corresponds to the value. The question remains, how many entries are required? Three versions of the table are currently under consideration:

Size in memory Number of values
8 Kilobytes 2048
16 Kilobytes 4096
32 Kilobytes 8192

All of them offer accuracy to within a fraction of a degree, and the choice between them is down to how much space is available in Flash ROM. Provisonally, we are going to assume an 8Kb table until we know the memory requirements of other parts of the system.

Some of the equations we are using require the inverse cosine function. This is easily enough done using the table, because it is ordered. For all values of cos x when x is between 0 and Pi, a higher value of x gives a lower value of cos x. Thus, a binary chop can be done which for the 8Kb table will find the nearest value within 11 loops.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.