Back to Getting Started

Back to Examples

Board Configuration

An important part of KoliadaES is that of hardware abstraction. GPIOs and how they are set up and used represents one of the biggest differences and generate significant portability issues across SoCs. Though KoliadaES doesn't completely eliminate specific differences, it does abstract the handling and use of hardware to a common and consistent API. Of course any use of an API abstraction will consume some cycles and, though it has been optimized, and for some SoCs is assembly code, the hardware APIs will always be slightly slower than direct register read/writes. For that reason, when you need maximum i/o speed, this is still available while using KoliadaES. For example, the GPIO.REG() API will always return the direct register address of a configured GPIO which may then be used for direct i/o. Because the binding of hardware to configuration is done at 'install time' rather than 'compile time', abstraction is preserved and is completely cross-board transparent without loss of speed and flexibility.

Hardware abstraction is facilitated by maintaining a small SoC configuration database in flash. The Board Configuration tool allows you to define hardware and application configuration, including GPIO and peripheral set up details (UARTs and the like). KoliadaES runtime then uses the board configuration to manage the SoC according to specification.

This allows developers to focus on application firmware knowing that it can easily built for any SoC and run transparently on any board with the same architecture.

Setting up BoardConfig (CC8051)

Though the board config can control all aspects of hardware initialization, use and control, for this example we focus on GPIO setup.

BoardConfig manages GPIO naming through pin descriptors defined in the board config file. Each GPIO pin is abstracted as a set of (SoC specific) setup details and any number of GPIO pin names are used together to define a 'virtual' GPIO pin. A GPIO name defines a compiler term by which your application can refer to a particular GPIO, either as a string (e.g. “LED1”, or “RED_LED”) or as a macro (e.g. LED1, or RED_LED). Multiple names can be defined for any pin definition and multiple physical pins can be aggregated into one virtual pin definition.

The best way to explain this is by example and this project is an introduction to the topic. For more advanced examples of board configuration see the binary counter example here, the UART example here or the application startup example here.

Fig. 1: TOP VIEW Fig. 2: BOTTOM VIEW

Before you proceed with this tutorial, you must have Koliada visual studio plugin and Koliada toolchain setup. For more information on the setup check out Koliada Getting started. This tutorial is currently based on the TI CC2541 which uses the 8051.

Step 1

Before we continue with this tutorial on exploring the boardconfig and definitions, we can first check what the default boardconfig looks like.

Open the kesLoader.exe(the USB Board must be connected to your PC through a micro USB cable). You should see he following menu on the kesLoader start page

Fig. 3: kesLoader Start Page

If you have a previously unconfigured board, you should see something similar to the following once you hit F1 to reset the board;

Fig. 4: Default BoardConfig

The first thing to notice is that the system boot strap shows you the key details of how the system is configured. That the bootstrap system shows you the config details is, itself, a configurable option (for an example see here).

Just concerning ourselves with the GPIO pin setup, we can see we have 3 GPIO pins numbered 0-2, using SoC PINs 1_0, 1_1 & 1_5 along with some bit settings and a list of GPIO names. Before going into more detail, let's take a look at the source code for this config output;

// Pin Descriptor Table
// Pin descriptors provide portable access to pins is via the abstract (canonical) pin number
// in this table. Pins are numbered (ordered) by the order in this file. Mark unused (blank)
// entries with port id 'GPIOX'.
//
// For fastest (portable) access, use GPIO.REG() to gain direct access to the i/o register.
// You can also use the (wholly non portable) compiler pin names
//
// GPIO port names are defined by the device
//
// A single entry can describe multiple pins with same port/config (OR the bits together)
// For outputpins, REN is the init state (lo = 0, 1 = hi)
//
//                         +-------------- dir: 0 = input,   1 = output
//                         |  +----------- ies: 0 = rising,  1 = falling
//                         |  |  +-------- ren: 0 - pull,    1 - tri-state (high impedance)
//                         |  |  |  +----- inv: 0 - normal,  1 - invert
//                         |  |  |  |  +-- set: 0 = off,     1 = on
//                         |  |  |  |  |
//      pin   port   mask  |  |  |  |  |  Pin Name(s)
//   |------|------|-----|--------------|------------------------------------------
Pin: /*  0 */ PORT1, BIT0, 1, 0, 0, 0, 0, LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR
Pin: /*  1 */ PORT1, BIT1, 0, 1, 0, 0, 0, SW1
Pin: /*  2 */ PORT1, BIT5, 1, 0, 0, 0, 0, RTS
//
// End of Pin Table

The BoardConfig manages GPIO naming through a pin descriptor line. Each pin descriptor starts with the (case independent) keyword 'Pin' followed by a colon and a set of arguments. Comments are any string starting with // thru end of line and any string enclosed in /* … */ (inclusive). Typically, pin definitions will be highly SoC dependent and knowledge of the relevant datasheet sections is critical for setting up a GPIO pin correctly.

For the CC8051 series SoCs, GPIO pins are collected into ports and each port has a different set of pin capabilities (pull up/pull down, etc). Note that though the descriptor abstracts the capability, setting pullups on a pin that does not support it will be ignored (or will cause other behavior if that bit setting is overloaded with other hardware functions - _see the datasheet!_).

The first pin descriptor will set up the abstract pin '0' as BIT0 of PORT1 with direction bit set to output (1 - to drive an LED) such that this pin can be refered to in a program by any of the following names; LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE & OTA_ERROR. Note that some names are required by the runtime. In this example, the runtime expects to find an LED called 'SYSLED' and if found, uses it to indicate certain boot states. Similarly, OTA_READY, OTA_LOAD, OTA_DECODE & OTA_ERROR are used by the OTA (over the air loader) to provide basic UI functions. Here all the OTA functions are mapped to one LED, but for a board with more LEDs, there is no reason why they should not be allocated to other LEDs as appropriate.

Once the appropriate GPIO configurations are set up, the application firmware can refer to the GPIO pin using the predefined named macro (or the string name for API calls line GPIO.REG()).

Before we start using these GPIO pins(LEDS, Switches) on our application, we need to dissect and understand what each segment of these definitions mean. So, let's take a look at it.

For example, lets take the first pin definition

//                         +-------------- dir: 0 = input,   1 = output
//                         |  +----------- ies: 0 = rising,  1 = falling
//                         |  |  +-------- ren: 0 - pull,    1 - tri-state (high impedance)
//                         |  |  |  +----- inv: 0 - normal,  1 - invert
//                         |  |  |  |  +-- set: 0 = off,     1 = on
//                         |  |  |  |  |
//      pin   port   mask  |  |  |  |  |  Pin Name(s)
//   |------|------|-----|--------------|------------------------------------------
Pin: /*  0 */ PORT1, BIT0, 1, 0, 0, 0, 0, LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR

Pin- KoliadaES Board Configuration PINs. These are virtual pin numbers that reference the board configuration database encoding access to each GPIO pin. All KoliadaES APIs that refer to a GPIO pin refer to the virtual pin number defined as part of board configuration. There are no APIs that refer to either a physical SoC pin or a hardware (silicon) pin. Note that the comment /* 0 */ is provided by the developer as a reference only. it is not used in the configuration of the pin. The actual virtual number used is defined by the order the descriptors are found in the file and this virtual numbers are only used to define the pin name macros (see the generated file pindefs.h).

The above line in the board config is describing virtual (software) pin 0 (assuming it is the 0th entry in the table)

Port and mask- The manufacturer's assigned GPIO (general Purpose I/O) pin names or numbers - e.g. GPIO03 or PORT0, PIN3 (P0_3). These are manufacturer names that are used to refer to the internal silicon used for manipulating the pins and pin functions. These pins and functions are typically described in the datasheet or programmers manual. You will need to be familiar with the capabilities of the GPIO pins/ports you intend to use as this will affect the GPIO services you can leverage through KoliadaES for that pin. These names and numbers vary from chip to chip and manufacturer to manufacturer.

Hence the 0th virtual pin above is connected to manufacturer pin 1_0 (PORT1, BIT0).

Pin Characteristics- Now we set the pin characteristics (e.g. input pin or output pin, interrupts, initial logic. etc)

dir - The direction bit is set to 0 if the pin is used for input (e.g. button) or 1 if the pin is used for output (e.g. LED). In the above line it is set to 1 because it is an LED.

ies - The interrupt state bit is set to 0 for a rising edge trigger or set to 1 for falling edge. Here the LED is just an output and we do not worry about the interrupt trigger. Hence use the default 0.

ren - The ren bit is set to 0 for pull or set to 1 if tri-state. Here we set it to default 0.

inv - The invert bit which is set to 0 if normal state (toggling low with 0 and high with 1) or set to 1 if invert state (toggling low with 1 and high with 0). Here we set it to default 0.

set - The set bit which is set to 0 if initial toggle state of the pin is low(0) or set to 1 if the initial toggle state of the pin is high(1). Here we set it to 0.

Name- is used by the build configuration process as defining a common name, “LED1”, for the pin. You can define multiple common names per pin as LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR, where any such defined names must be unique to each pin.

Thus, in this way, an application program can be built that is able to run on multiple different boards with different physical attributes without changing the source code and, most importantly (for heterogeneous systems), without changing the binary. If manufacturing changes the GPIO routings for some reason (product variations, cheaper build process, etc.) you simply install the correct board config and the same binary will run without change on both boards.

Now compile the config test project from SDK/examples/TestConfig and hit 'Download to Target.

You should see the following output on your serial terminal

Fig. 5

As you can see SW1 and LED1 are configured as defaults and we can test how the LED and Switch behave.

Initially the LED1 (D1 on the PIEP CC2541 board) should be off and when the SW1 is pressed LED1 will turn on.

Now you have successfully tested the default pin setup. Let's change the pin characteristics and see what happens. For this we are going to use the example board config found in the file 'example.cfg' in the projects BoardConfig/CC8051 directory.

dir - Change the direction of the SW1 pin 1(P0_6) in the CC25xxEM.c under SDK/examples/CC25xxEM. The direction is set to 0(input) by default. Now change it to 1. Compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig. Your pin definitions should look like this

/*   0 */ PORT0, BIT3, 1, 0, 0, 0, 0, LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR
/*   1 */ PORT0, BIT6, 1, 1, 0, 0, 0, SW1
/*   2 */ PORT1, BIT5, 1, 0, 0, 0, 0, RTS

You should see that the LED will not turn on as the switch is set as an output direction pin and it does not receive the user input through the switch.

Now change the direction of the pin P0_6 back to default direction of 0,compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig and you should see pressing the button will turn the LED back on.

ies - Now Notice that the LED is turned on as soon as the SW1 is pressed(while holding) and before it is released as the SW1 ies is set for falling edge. Now lets explore ies.

Change the ies of the pin 1(P0_6) in the CC25xxEM.c under SDK/examples/CC25xxEM. The ies is set to 1(falling edge trigger) by default. Now change it to 0. Compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig. Your pin definitions should look like this

/*   0 */ {PORT0, BIT3, {1, 0, 0, 0, 0}},	/*< LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR >*/
/*   1 */ {PORT0, BIT6, {0, 0, 0, 0, 0}},	/*< SW1 >*/
/*   2 */ {PORT1, BIT5, {1, 0, 0, 0, 0}},	/*< RTS >*/

You should see that the LED will turn only after the SW1 is pressed and released(it will not turn on while pressing and holding like the falling edge trigger).

Now change the ies of the pin P0_6 back to default bit of 1,compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig and you should see pressing the button will turn the LED back on even before releasing the switch.

inv - Now let us look at inv pin. Change the inv bit of the pin 0(P0_3) (LED1)in the CC25xxEM.c under SDK/examples/CC25xxEM. The inv is set to 0 by default. Now change it to 1. Compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig. Your pin definitions should look like this

/*   0 */ {PORT0, BIT3, {1, 0, 0, 1, 0}},	/*< LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR >*/
/*   1 */ {PORT0, BIT6, {0, 1, 0, 0, 0}},	/*< SW1 >*/
/*   2 */ {PORT1, BIT5, {1, 0, 0, 0, 0}},	/*< RTS >*/

You should see that the LED will not turn on if SW1 is pressed because the GPIO.SET(LED1,1) in the testconfig function will just keep toggling the LED off as(the inve stated is inverted which toggles the LED high for 0 and toggles the LED low for 1). So now change GPIO.SET(LED1,1) to GPIO.SET(LED1,0). Now compile and download the TestConfig from SDK/examples/TestConfig. You should see the LED turn on now when the button is pressed.

Now change the inv of the pin P0_3 back to default value 0. Compile and download the CC25xxEM. Change the GPIO.SET(LED1,0) back to GPIO.SET(LED1,1). Now compile and download the TestConfig from SDK/examples/TestConfig .Now we should see the default behavior. the LED turns on when switch is pressed.

set - Now let us look at set pin. Change the set bit of the pin 0(P0_3) (LED1)in the CC25xxEM.c under SDK/examples/CC25xxEM. The set bit is set to 0 by default. Now change it to 1. Compile and download the CC25xxEM. Now download the TestConfig from SDK/examples/TestConfig. Your pin definitions should look like this

/*   0 */ {PORT0, BIT3, {1, 0, 0, 0, 1}},	/*< LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR >*/
/*   1 */ {PORT0, BIT6, {0, 1, 0, 0, 0}},	/*< SW1 >*/
/*   2 */ {PORT1, BIT5, {1, 0, 0, 0, 0}},	/*< RTS >*/

You should see that the LED will turn on as soon as the TestConfig is downloaded even without SW1 being pressed. This is because the intial toggle state is set to 1(high or ON state) on the intial configuration file CC25XXEM.c.

Now change the set of the pin P0_3 back to default value 0. Compile and download the CC25xxEM. Download the TestConfig from SDK/examples/TestConfig .Now we should see the default behavior. The LED turns on only when switch is pressed.

Now since we have explored the pin characteristics let us see what happens if we change the pin name. Change the pin name of P0_3. Chnage the name LED1 to LED2 and Compile and download the CC25xxEM. Compile and download the TestConfig from SDK/examples/TestConfig and see what happens. You should see that the LED would not light up with button press as name was changed. Now open TestConfig.c and change LED1 = GPIO.FIND(“LED1”) to LED1 = GPIO.FIND(“LED2”) and now compile and download the TestConfig from SDK/examples/TestConfig. The LED will light up with the button press.

Now since we have played around with the characteristics of the existing GPIOs, let us move on to setting up a new physical pin. For that we need to understand the CC2541 board and LED/Switch Board port mappings.

Fig. 6: CC2541 ports Fig. 7: LEDSwitch ports

Now let us change the LED1 (D1) and Switch SW1 to LED2 and SW2. How would we do that?

So we have two numbers to take into account here

1) The piep hardware board SPIP pin header number - 1 through 10.

2) The GPIO(LED/SW) or other special purpose routings which are named in the user sheet page as show above - e.g pin 5 is LED1 in LED/Switch Board header and is P0_3 in bottom header of the CC2541.

Hence if we need to control LED1 we need to map LED1 to P0_3.

Similarly pin 2 is SW1 in LED/Switch Board header and is P0_6 in bottom header of the CC2541.

Now since we want to change to LED2 and SW2 which is pin 6 and pin 3 respectively in the LED/Switch board header.

LED2 should be mapped to pin 6 in bottom header of CC2541 which P0_2 and SW2 should be mapped to pin 3 in bottom header of CC2541 which P0_7

Your pin definitions should look like this

/*   0 */ {PORT0, BIT2, {1, 0, 0, 0, 1}},	/*< LED1, SYSLED, OTA_READY, OTA_LOAD, OTA_DECODE, OTA_ERROR >*/
/*   1 */ {PORT0, BIT7, {0, 1, 0, 0, 0}},	/*< SW1 >*/
/*   2 */ {PORT1, BIT5, {1, 0, 0, 0, 0}},	/*< RTS >*/

Compile and download the CC25xxEM. Download the TestConfig from SDK/examples/TestConfig .Now we should see The LED2(D2) turns on when SW2 is pressed. SW1 or LED1 does not work now.

Now since you have successfully gone through this tutorial, try setting up more pins or try using the top header of the CC2541 and see what happens.

      Copyright © 2018-2019 Koliada, LLC
  • kes/examples/boardconfig.txt
  • Last modified: 2019/04/16 00:29
  • by venkat