XC code examples

Started 2Feb2018, updated 7Feb2018

This page is in group Technology and is a blog note with some XMOS XC code examples. I guess that the parent note is XC is C plus X. Also see an overview at “My XMOS notes”, chapter MY OTHER NOTES WHERE XMOS MATTERS.

Fold handling

This blog note uses the Collapse-O-Matic WordPress plugin to handle text folding. In addition to expanding and closing them individually you may here:

Expand All
Collapse All

Some musts

In my opinion, bool needs to be defined.

bool

No C99

Just add this in some a global.h file (or similar name):

typedef enum {false,true} bool; // 0,1

A wild example:

bool my_bool1 = true;
bool my_bool2 = false;
   
if (my_bool1) {
    my_bool2 = false;
} if (my_bool2 == false) {
    my_bool1 = true;
} else {
    my_bool1 = !my_bool2;
    my_bool2 = false;
}

(It doesn’t look like there is any problem in having the -std=c99 defined also in this case. See below:)

Compiling C as C99 but still no _Bool

C99 has a built-in type called _Bool (read about it in Wikipediahere).

To activate C99 just add -std=c99 to XCC_FLAGS in the Makefile in xTIMEcomposer (read about it in the xTIMEcomposer user guide, from here). Then add:

#include <stdbool.h>

You must remove the bool type definition above. The stdbool.h comes with the xTIMEcomposer installation, and here is the contents:

// Copyright (c) 2008 Eli Friedman
/* Don't define bool, true, and false in C++, except as a GNU extension. */
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool, bool, false, true as a GNU extension. */
#define _Bool bool
#define bool  bool
#define false false
#define true  true
#endif

#define __bool_true_false_are_defined 1

I am surprised to see that true and false are defined with defines, and not as part of a set. I remember some ten years ago that we cooperated with a company that used the Motorola HC08; the compiler they used didn’t support enums. Maybe that’s the reason? Friedman has commented “GNU extension” in the code, maybe the answer lies there? I see that -std=gnu99 also is possible for XCC, but I get the same result.

C99 points to 1999, quite some years ago, and it’s now obsoleted for C11. There is no option for C11 in the XCC compiler.

Adding the file ref and the flags should make sense. But it doesn’t. I get this:

../src/__arduino_on_xmos_test.xc:193:5: error: use of undeclared identifer `_Bool'

This is unresolved. But I’ll query at xCore Exchange. Update: I didn’t have to, there already was a post that I just added to, see Wot no bool? started by CousinItt. The answer turned out to be that _Bool is available in ‘C99’ but not in ‘xC’, thus the header file <stdbool.h> won’t work with ‘xC’. 

A general problem with testing against “true”

In the “Wot no bool” post referred to above robertxmos points out a case where

#define FALSE 0
#define TRUE !FALSE
// Some code
if (hasItem(i) == TRUE) { /* 32bit comparison is only true if index was '0' */ }
if (hasItem(i))         { /* convert to 1bit, hence all index values are true */ }

are not equal. Read it there. He shows two problems:

  1. There is one representation of FALSE but many of TRUE, since the language does not support bool, and it internally will do logical conversions to 1 bit
  2. The example he shows uses a function that returns an index [0..(N-1)] but it’s -1 if something searched for is not found. This is standard C practice, but it’s bad practice. It invites problems. See this code:

And a code example to solve it

An example in XC where the problem shown in “Wot no bool” is not present. This compiles and runs. It’s because there is no implicit or explicit type conversions. Observe the parameter list for return values and how nice arrays may be handled in XC, like I don’t have to use any pointers in this case.  (However, there is a problem, see USE_WRONG_RETURN_LIST explained below the code)

#include <stdio.h>
#include <iso646.h> // For "not" etc

#define USE_BOOL_TYPEDEF // No difference since no type conversions done
#ifdef USE_BOOL_TYPEDEF
    typedef enum {false,true} bool; // 0,1 
#else
    #define bool unsigned // long, int, unsigned, char, bool ok 
    #define false 0
    #define true 1 // Or "not false"
#endif

typedef unsigned index_t; // long, int, unsigned, char, bool compile ok..
// #define USE_WRONG_RETURN_LIST  // ..with this defined

{index_t, bool} isItemIn (
    const char            search_for, 
    const char            text[], 
    static const unsigned len) {

    index_t  index     = 0;
    bool     found     = false;
    bool     searching = true;

    while (searching) {
        if (text[index] == search_for) {
            found     = true;
            searching = false;
        } else {
            index++;
            if (index == len) {
                searching = false;
            } else {} // No code, maybe next round
        }
    }
    return {index, found}; // According to {index_t, bool} of return list
}

int main() {
    const char text[] = {'A','B','C','D','E','F','G','H','I','J'};
    index_t  index;
    bool     found;

    {index, found} = isItemIn ('C', text, sizeof(text));
    if (found) {
        printf("C found in %u\n", index);
    } else {
        printf("C not found\n");
    }
    #ifdef USE_WRONG_RETURN_LIST
        {found, index} = isItemIn ('X', text, sizeof(text));
    #else
        {index, found} =  isItemIn ('X', text, sizeof(text));
    #endif
    if (not found) {
        printf("X not found\n");
    } else {
        printf("X found in %u\n", index);
    }
    // LOG with 
    // USE_WRONG_RETURN_LIST not defined
    // USE_BOOL_TYPEDEF or not no difference
    //   C found in 2
    //   X not found
    return 0;
}

Defining USE_WRONG_RETURN_LIST shows that the compiler will use any integer type for any definition I may have of bool. So, in this case I won’t get any help from the compiler. I may compile wrong code. I guess that’s not much worse than having any list of (..,signed,signed,..) parameter in any function, where (..,degC,degF,..) or (..,degF,degC,..) may be done wrongly. However, there is a small difference. With USE_WRONG_RETURN_LIST the compiler could have taken it if bool were understood by the compiler.

So, not even a typedef of the bool makes it a unique type to the compiler. It’s still an integer-type type.

I added this code and comment to the Wot no bool? thread. The answer from robertxmos was:

Correct, typedef should be viewed as a handy alias.
One could argue that instead of tightening a type system it does the opposite!
If you want unique types you need to reach for struct/union (class if using c++ & interface if using xC)
Even ‘enum’ is weak (unlike the ‘enum class’ in c++11)

And easier-to-get-right code to also solve it

This was triggered by the answer above.

Since interface is not for the below code, I collected the {index,found} into the struct isItemIn_return_t. I guess it’s less error prone since it’s easier to assign x.index=index than x.index=found. Even if I don’t do that, I do use it explicitly like isItemIn_return.index++. Doing it wrongly with isItemIn_return.found++ is easy to spot since I would think to increment a verb would ring a bell.

This uses the same amount of code and data as the above code. Maybe this indicates that the compiler also builds a struct for the parameter list? I kind of like it:

#include <stdio.h>
#include <iso646.h> // For "not" etc
typedef enum {false,true} bool; // 0,1

typedef unsigned index_t; // long, int, unsigned, char, bool compile ok..

typedef struct { // easier to get right than the anonymous return parameter list
    index_t index;
    bool    found;
} isItemIn_return_t;

isItemIn_return_t isItemIn (
    const char            search_for,
    const char            text[],
    static const unsigned len) {

    isItemIn_return_t isItemIn_return = {0, false}; 
    // Not type safe as {true, 0} will compile

    bool searching = true;

    while (searching) {
        if (text[isItemIn_return.index] == search_for) {
            isItemIn_return.found = true;
            searching = false;
        } else {
            isItemIn_return.index++;
            if (isItemIn_return.index == len) {
                searching = false;
            } else {} // No code, maybe next round
        }
    }
    return isItemIn_return;
}

int main() {
    const char text[] = {'A','B','C','D','E','F','G','H','I','J'};
    isItemIn_return_t isItemIn_retval;

    isItemIn_retval = isItemIn ('C', text, sizeof(text));
    if (isItemIn_retval.found) {
        printf("C found in %u\n", isItemIn_retval.index);
    } else {
        printf("C not found\n");
    }

    isItemIn_retval = isItemIn ('X', text, sizeof(text));

    if (not isItemIn_retval.found) {
        printf("X not found\n");
    } else {
        printf("X found in %u\n", isItemIn_retval.index);
    }
    // LOG with
    // USE_BOOL_TYPEDEF or not no difference
    //   C found in 2
    //   X not found
    return 0;
}

Adafruit SSD1306 on XMOS board

I have been asked about the code that makes it possible to use the SSD1306 on XMOS boards.

The Adafruit monochrome 128×32 I2C OLED graphic display is their product id 931 (here), containing module UG-2832HSWEG02 with chip SSD1306 from Univision Technology Inc. You will find Univision’s data sheets in the said url as well.

I have wrapped my code into a zip, but it is not at all a “runnable” test program. I had that in my early xTIMEcomposer version control (Git) system, but I didn’t want to publish it here because my latest code is the greatest. Instead I have just pulled some files out of my aquarium project “as is”. Observe that the broader part of the SSD1306 code have been written by Adafruit (some based on Univision’s pseudo code), and then modified by me. I probably should have made a branch on their GitHub node (here). The reason I haven’t done it is because I think it too much different. Maybe this is a recipe of how not to do things, but I’ll give it a try and publish it here. The code works and has been taking care of my fishes for some time now. Disclaimer: It may be easier to port the Cpp and C files more directly (as I explained in the chapter above) but I didn’t do that. So here are .xc files for .cpp etc.

Observe that I have used the older XMOS code [module_i2c_master] and not the newer [lib_i2c], which is more advanced.

Here’s the code, which I guarantee nothing about and have no responsibility for: here (rev3). It’s rev3 (5Feb2018) after some fixes I got from a guy who actually got his 128×64 display up and running based on this code. I had my 128×32 display up. Only a single display, the code is not general for a number of displays, too many defines of sizes etc. Should be easy to fix though. This guy has done a great job, because it’s not a “runnable” file set I have supplied, he did have to make some small incude files himself, end remove some of the aquarium code. Should you find out that I have not included something very important then please mail me. Also, should you end up with a runnable test system for f.ex. the startKIT, maybe we should join forces and do something on GitHub? This guy did, but it’s now in a product proper, not to be published.

XMOS code comments and errata

lib_spi

In https://www.xmos.com/support/libraries/lib_spi 3.0.2 User Guide (spi.pdf) the code example in chapter 2.1 should be like this (fixes in red):

// My comment:              =  OBS ports, see comment below
in  buffered port:32 p_miso =  XS1_PORT_1A;  // was out
out port p_ss[1]            = {XS1_PORT_1B};
out buffered port:32 p_sclk =  XS1_PORT_1C;  // was 22
out buffered port:32 p_mosi =  XS1_PORT_1D;
clock clk_spi               =  XS1_CLKBLK_1;
int main(void) {
  spi_master_if i_spi[1];
  par {
    spi_master(i_spi, 1, p_sclk, p_mosi, p_miso , p_ss, 1, clk_spi);
    my_application(i_spi[0]);
  }
return 0; }

I’ll be back with the ports used on the startKIT breakout board (here) and on my XCORE-200 eXplorerKIT breakout board (here and here).

Email this to someoneShare on Facebook