Using a Union and Structs to Store pH Calibration Data.



I need to store information about pH calibration within the Ladybug Blue Lite’s (LBL) nRF51822 Flash.  The values I store include:

  • a word for the write check. The write check is a known value the program checks to check if the values for the pH calibration have been stored before – or if the values written are corrupted (this assumes if the write check bytes are corrupted, the bytes holding the pH calibration info is also corrupted).  The value I will use is 0x01020304
  • a word for the pH 4 millivolts read when the probe is in the pH 4 calibration solution.  This should be +/- 415 mV.  I cover why in earlier posts on the pH circuit….As well as why calibrating the probe to the LBL circuits is important….
  • a word for the pH 7 millivolts read when the probe is in the pH 7 calibration solution.  This also should be +/- 415 mV.
  • a word to hold the date the calibration was taken.  pH probes should be regularly checked.  By storing the calibration date, the smartphone can notify the hydro farmer it is time to calibrate.

Unions are a wonderful way to map a bunch-o-bytes to the same memory location as formatted values.  Examples where this is useful is storing data to Flash as well as sending data over a connection (e.g.: BLE).

Thanks to Those That Went Before

Ron Sousa provided us with excellent videos within the embedded section of Contextual Electronics that gave me a much more practical view on when to use a Union in firmware.

The Goal

I am sure twiddling data structures is very familiar to most of you.  I struggle with setting up Unions and Structs in a way that makes it easiest to access bytes based on different views.  The goal of this post is to highlight how a Union (plus structs) can provide easier access to the two most common views: 1) a bunch of sequential bytes that need to go from one place to the other (e.g.: RAM to Flash, a micro controller to a Smartphone…) 2) data types (like a pH value) that map to bytes in memory that most likely need to be swapped in some fashion to go from a bunch of bytes to an int32_t (for example) pH value.

The Data Structure for pH Calibration

Measuring the pH means using a pH probe (and circuitry like that on the LBL) that will not give the “ideal” values.  Calculating the pH means mapping mV values to pH values where the ideal step (slope) between two pH values is 59.16mV.  Most likely a pH probe will not get exactly 0 mV for pH 7 or 3*59.16 (lower pH values register positive voltage values, pH 4 is 3 away from pH 7) = 177.5mV for pH 4.  Once the actual values of a pH probe’s reading when the probe is emerged in a calibration solution, the slope measurement of 59.16 = (177.5 – 0)/(7-4) = 177.5/3 = 59.16 mV can be adjusted so subsequent pH measurements when in the nutrient bath can accommodate for the difference in slope.  For example, I measured a pH of 165 mV for pH4 and -10 mV for pH 10.   The slope is: (165 – -10)/(7-4) = 175/3 = 58.3 mV.

Here are the Union and struct typedefs I use:

typedef  struct {

  uint32_t   write_check;

  int32_t    pH4;

  int32_t    pH7;

  uint8_t    month;//eg: 1 for January, 12 for December

  uint8_t    day;//eg: 30 for the 30th day of the month

  uint16_t   year;//eg: 2015



typedef  union {

  uint8_t    bytes[16];

  pH_cal_t   pH_cal;


Here is part of the test code I wrote:

  pH_data.pH_cal.write_check = 0x01020304;

  pH_data.pH_cal.pH4 = 165;

  pH_data.pH_cal.pH7 = -10; = 20;

  pH_data.pH_cal.month = 11;

  pH_data.pH_cal.year = 2015;

  pstorage_wait_handle = block_0_handle.block_id; //Specify which pstorage handle to wait for.

  pstorage_wait_flag = 1;

  pstorage_store(&block_0_handle, pH_data.bytes, 16, 0);

  while(pstorage_wait_flag) { power_manage(); }

  SEGGER_RTT_WriteString(0,“data written:\n”);

  for (int i = 0; i < 16; i++)


      if (i > 0) SEGGER_RTT_WriteString(0,“:”);





  SEGGER_RTT_printf(0,“write_check: %0X\n”,pH_data.pH_cal.write_check);

  SEGGER_RTT_printf(0,“pH 4 calibration: %d\n”,pH_data.pH_cal.pH4);

  SEGGER_RTT_printf(0,“pH 7 calibration: %d\n”,pH_data.pH_cal.pH7);

  SEGGER_RTT_printf(0,“day             : %d\n”,;

  SEGGER_RTT_printf(0,“month           : %d\n”,pH_data.pH_cal.month);

  SEGGER_RTT_printf(0,“year            : %d\n”,pH_data.pH_cal.year);

The code uses the nRF51’s persistent storage manager (pstorage) APIs to read and write from flash.  There turned out to be some “gotchas” reading and writing to flash that took away my enthusiasm to talk directly to the NVMC registers.  I’ll probably cover my flash read/write exploration in a future post.

Here is what is printed out to the terminal screen: 



write_check: 1020304

pH 4 calibration: 165

pH 7 calibration: -10

day             : 20

month           : 11

year            : 2015

The side by side comparison of the pH_data.bytes view of the data and the pH_data.pH_cal view helped me better see how the bytes are internally stored versus how the program’s data type interpret them.  For example, pH 4 calibration is 4 millivolts.  It is the second word with a LSB of 0xA5 followed by 0’s for the other three bytes.  The int32_t representation is 0x000000A5 = 165.

Using Unions and structs to go between different data views – the view the micro controller’s storage has on the data versus a data type’s interpretation of the bytes that are stored – made it much easier to understand what the bytes are all about.



That’s it for now.  Thanks for reading this far.

The Ladybug Blue Lite is Measuring pH/EC and sending Results to an iPhone!


, , ,

A YIPPEE!! day for me.  I received the Ladybug Blue Lite Beta 2 PCBs from OSH Park yesterday.  Today I tested reading pH and EC values.

It worked!  It worked!…well, results were the exact values but they were within an acceptable range.  Particular given the pH probe is an inexpensive probe I got from eBay about a year ago.  Since pH probes “go bad”, I am not surprised results were a bit off from what the model predicts.

It is such a great feeling.  BLE, pH, EC…working on a small PCB!  Off the Arduino and shields!  I plan to use this one to help me grow tomatoes this winter.

Here are the measurements I read from the AINs:


The probe was placed in the pH 4 and then pH 10 calibration solution.

  VGND(mV) AIN(mV) pH (mV) pH
pH 4 1455 1620 165 4.2
pH 10 1455 1314 -141 9.4

I discuss calculating the pH in earlier posts.  The first thing is to calculate the mV reading from the AIN.  The AIN is not a differential reading so there are two AINs for pH measurements.  One is the virtual ground (VGND) used to move the rails of the op amp to accommodate the AC waveform of the pH reading.  The other is the pH measurement (above virtual ground).

For pH 4, the pH in mV = 1620 – 1455 = 165 mV. pH =  7 – 165/59.16 = 4.2

For pH 10, the pH = 1314 – 1455 = -141 mV. pH = 7 – (-141/59.16) = 9.4

If I decide to use this probe, I would calibrate readings to be on the slope of the line for the 4.2 and 9.4 readings.


I placed the EC probe into a 1000TDS/2mS calibration solution.

VGND(mV) EC VIN (mV) EC VOUT (mV) Gain Resistance(Ω) EC (mS)
1455 1650 2085 3.2 448.3 2.2

Gain = Vout/Vin = (2085-1455)/(1650-1455) = 3.2.  Resistance = 1000/(3.2-1) = 448.3Ω.  EC = 1/448.3 = 2.2mS.  Pretty darn close!


Off to finish the firmware and iOS app…


Thanks for reading this far.  Please find many things to smile about.

Why I am not a fan of ARM’s Semihosting feature



I figured out why my nRF51822 applications loaded just fine on the debugger and not on a power cycle / pin reset.  ….just in case this happens to you…


The quick answer: if you are using Eclipse and the GNU ARM toolchain, check to see if the link option:


is one of the linker options.  If it is, semihosting has been enabled and the binary will not load unless a debugger is present.


What the heck is semihosting? I liked Erich Styger’s definition the best: Semihosting is a technique to do printf() debugging through an active debug connection. So instead using a physical connection like RS-232 or USB CDC, the connection to the host machine is through the debugger.

Seems that semihosting is something concocted by Arm…Looking at this page from Arm, “if you are compiling for an ARMv6-M or ARMv7-M, for example a Cortex-M1 or Cortex-M3 processor, semihosting is implemented using the BKPT instruction.”  The nRF51822 uses the cortex-m0, which is based on the ARMv6-M architecture.

As noted on this page from Arm, The specific instruction sent by the binary to invoke semihosting is:


It turns out my .hex files all had the BKPT 0xAB command somewhere near the beginning of the file.  As the .hex was loaded and run, the cortex-m0 ran across the BKPT 0xAB and then waited patiently for the debugger to start communicating with it.  Since I hadn’t attached a debugger, “waiting patiently” turned into not running my nRF51822 app.

I found this out by exploring the .hex file with jlinkexe.  After loading the binary onto the chip, I opened a terminal window and started jlinkexe:

 jlinkexe -device nRF51422_xxAC

Once in the jlink utility, I executed the go command:


and (I think) the step command:



now the code sits at the breakpoint….

After reading Erich’s post on semihosting with the GNU ARM Eclipse Debug plugins, it turned out that yes indeed, the C template I had started with in Eclipse had included the —specs=rdimon.specs  !  Once this option had been removed, the binaries ran after a power cycle without the debugger.  YIPPEE!

I also removed the debugger settings Erich pointed out.

Determining the Revision, FLASH and RAM size of the nRF51822



Philip in the comments noted the current version of the nRF51 Compatibility Matrix (discussed below) can be downloaded here.  THANK YOU Philip!

End of Update

I just got another rev of the Ladybug Lite (LBL) PCB from OSH Park….excuse me for one second….YIPPEE!!!!….

The first thing I did was to solder a MDBT40 nRF51822 module (discussed in a previous post). I also soldered on the header pins that connect to the SWD pins on the MDBT40.  So now I can “talk” to the MDBT40 on this rev of the LBL PCB by using the nRF51 DK’s debug out (discussed in a previous post).

The MDBT40 has the nRF51822 inside.  Because of this, I can’t get to the markings on the chip that could identify the amount of RAM, Flash, and hardware identification into.

So how was I going to figure out the chip revision?  How much RAM / Flash is on it?  

The Goal

The goal of this post is to use the JLinkEXE SEGGER utility on my Mac to figure out the revision, amount of RAM and amount of Flash on the MDBT40 module I soldered onto the LBL Alpha 5 board.

Thanks to Those That Went Before

Lucky for me, Ron Sousa has been covering accessing micro controllers through registers in our Contextual Electronics Embedded course.  Armed with the confidence to not only read a data sheet but figure out what to do :-)…

It’s All About the FICR

I found the Factory Information Configuration Registers (FICR) described in chapter 7 of the nRF51_Series_Reference_manual v3.0.pdf.

The FICR’s base address is 0x1000 0000.  From the base address, there are several registers that can be used to ask the nRF51822 how much RAM, Flash, and the chip revision.

The challenge I was having is interpreting Table 13 in the nRF51_Series_Reference lists the registers.   Perhaps my lack of background working with micro controller firmware makes it difficult for me to interpret the very brief descriptions……however, some of the naming was promising such as CODESIZE and SIZERAMBLOCKS and NUMRAMBLOCKS.  

How do I take the values in these registers and turn them into the amount of RAM and Flash?

A nice thing about the Nordic’s nRF51 SDK is there are A LOT of helper APIs that help me figure out how to interact with the nRF51822’s registers.  In this case, there is the .c and .h nrf_ic_info files.  Looking at the nrf_ic_info.h file:

/**@brief Enum identifying the IC revision as described in the nRF51 Series Compatibility Matrix. */



    IC_REVISION_NRF51_REV1,    /**< IC Revision 1. */

    IC_REVISION_NRF51_REV2,    /**< IC Revision 2. */

    IC_REVISION_NRF51_REV3,    /**< IC Revision 3. */

    IC_REVISION_NRF51_UNKNOWN  /**< IC Revision unknown. */

} nrf_ic_revision_t;


 /**@brief IC information struct containing the IC revision, RAM size, and FLASH size. */



    nrf_ic_revision_t ic_revision;    /**< IC revision. */

    uint16_t          ram_size;       /**< RAM size in kB (16 = 16 kB RAM). */

    uint16_t          flash_size;     /**< FLASH size in kB (256 = 256 kB FLASH). */

} nrf_ic_info_t;



/**@brief  Function for returning information about the IC revision, the RAM size, and the FLASH size.


 * @param[out]  p_ic_info  Struct containing IC revision, RAM size, and FLASH size.

and then at the function that uses these typedefs:

void nrf_ic_info_get(nrf_ic_info_t * p_ic_info)


    uint32_t ic_data;


    ic_data = (((*((uint32_t volatile *)0xF0000FE8)) & 0x000000F0) >> 4);


    p_ic_info->ram_size = (uint16_t) NRF_FICR->NUMRAMBLOCK * (NRF_FICR->SIZERAMBLOCKS / 1024);

    p_ic_info->flash_size = (uint16_t) NRF_FICR->CODESIZE;

    switch (ic_data)


        /** IC revision 1 */

        case 1:

            p_ic_info->ic_revision = IC_REVISION_NRF51_REV1;



        /** IC revision 2 */

        case 4:

            p_ic_info->ic_revision = IC_REVISION_NRF51_REV2;



        /** IC revision 3 */

        case 7:

            /* fall through */

        case 8:

            /* fall through */

        case 9:

            p_ic_info->ic_revision = IC_REVISION_NRF51_REV3;




            p_ic_info->ic_revision = IC_REVISION_NRF51_UNKNOWN;



the ic_data seems like “gobbly gook” to me.  I found it more informative to check out the tables in the nRF51_Series_Compatibility_Matrix_v1.1.pdf (download link) against what is stored for the hardware ID in the NRF_FICR->CONFIGID register (which I’ll use below).

Figure out Flash/RAM/Revision


I then figured out the RAM/Flash/Revision for the MDBT40 nRF51822 module on the latest LBL:

Amount of RAM = NRF_FICR->NUMRAMBLOCK * (NRF_FICR->SIZERAMBLOCKS / 1024);  /**< RAM size in kB (16 = 16 kB RAM). */

Amount of Flash = NRF_FICR->CODESIZE  /**< FLASH size in kB (256 = 256 kB FLASH). */ 

Start JLinkExe

Hooking up the SWD cables on the LBL to the nRF51 DK’s P19 debug out port:


 From a terminal window on the Mac, I started jlinkexe: 

jlinkexe -device nRF51822

nRF51822 on the LBL Alpha 5

and looked at the contents of the NRF_FICR->CODESIZE register. The nRF51 Series Reference Manual gives the register offset of the CODESIZE register as 0x0014.

J-Link>mem32 10000014,1

10000014 = 00000100 

and 0x100 = 256.  This means the nRF51822 on the LBL has 256KB of Flash.

 NRF_FICR->NUMRAMBLOCK’s register offset is 0x0034:

J-Link>mem32 10000034,1

10000034 = 00000002

NRF_FICR->SIZERAMBLOCKS’s register offset is 0x0038:


J-Link>mem32 10000038,1


10000038 = 00002000  0x2000 = 8192)

The amount of RAM = 2 * (8192/1024) = 16KB

Revision is in NRF_FICR->CONFIGID

J-Link>mem32 1000005C,1

1000005C = FFFF0072

 the last four bytes – in this case 0x0072 give the revision number of the chip.  Table 2 in the nRF51_Series_Compatibility_Matrix_v1.1.pdf (downloaded from this link) notes 72 = revision 3, packet variant QF AA in a QFN48 package.  Revision 3 has three package variants: QF AA, QF AB, QF AC.  The difference is in the amount of Flash and Ram.  The QF AA – which is the one I am using in this build of the LBL PCB- has  256K Flash, 16KB RAM.  The one that I have ordered – which has the same amount of Flash and Ram as the nRF51 chip on the nRF51 DK – is the QF AC.  The QF AC is a FN-48 package containing 256K Flash and 32K Ram.

nRF51822 on the nRF51 DK

looking at the same register contents on the nRF51 DK:


RAM = 4 * (8192/1024) = 32KB, Flash = 256KB.  The CONFIGID – 86 – is not listed in a table of the nRF_Series_Compatibility_Matrix_v1.1.pdf.  The closest is 85 – which is a QF AC nRF51422 which is a QFN48 package containing 256K Flash and 32K Ram.  Given what Nordic advertises about the chip on the nRF51 DK, I make a leap and assume the identification of 85 and 86 are the same.



That was fun!  Please find many things to smile about.



Using a Property Get/Set nRF51822 UI To turn on an LED

My eyes were open to the benefits of using the EmbSysRegView plug-in through Ron Sousa’s embedded systems video in our Contextual Electronics course.



Ron showed us how to program the USART of a STM32F030x.  We’re using this micro controller in our project.  It is proving to be a powerful learning experience to compare the STM32F030x to the nRF51822.  They both use the Arm cortex-mo but the peripherals are very different.  The obvious difference being the nRF51822 does a terrific job servicing BLE.  Even on what I think of as “core” features like GPIO are implemented differently.  In addition, the documentation approach is different.  Yet the lessons learned are directly transferable.

The Goal

The goal of this post is to turn on and off the LBL LED using a get/set property editor within Eclipse.

Thanks To Those That Went Before

  • Thanks to Ron Sousa for his terrific instruction within the Embedded Systems section of Contextual Electronics.  Ron has “been there, done that” providing insight into coding and what to think about when programming Embedded Systems.  Ron has been extremely supportive and responsive.  THANK YOU.
  • I am continually grateful to Chris Gammell for founding and running Contextual Electronics as well as being an exceptional mentor.  As Chris likes to say, signing up for Contextual Electronics signed me up to be an apprentice of Chris’s.  It still amazes me to have gone from never seeing a solder gun or hearing about Ohm’s law to building PCBs that do stuff I want to use!
  • The Nordic support team is AWESOME.  There hasn’t been a challenge they haven’t willingly helped me with and provided excellent guidance in a very polite manner.  For this post I am especially thankful to Vidar Berg and Aryan.

Open Source

The LED_TEST Eclipse (managed make) project that I used is available in this GitHub repository.

The SVD File

Get/Set property viewers for Arm cortex-m micro controllers read a CMSIS-SVD file.  This is an XML formatted file that as Arm notes in their introduction to SVD: The CMSIS System View Description format(CMSIS-SVD) formalizes the description of the system contained in ARM Cortex-M processor-based microcontrollers, in particular, the memory mapped registers of peripherals. The detail contained in system view descriptions is comparable to the data in device reference manuals. The information ranges from high level functional descriptions of a peripheral all the way down to the definition and purpose of an individual bit field in a memory mapped register.

An SVD viewer will be a tremendous help in learning how to program the nRF51822.

I have come across two SVD viewers:

  • EmbSysRegView
  • The Perspective Viewer


EmbSysRegView seems to be the popular way to get/set properties within Eclipse.  It is what is shown in the above image.  EmbSysRegView is an Eclipse plug-in.   From the EmbSysRegView web siteEMBedded SYStems REGister VIEW is an Eclipse Plugin which is designed for monitoring and modifying memory values of embedded devices. Therefore it offers a structured display of the special functions registers (SFR). 

EmbSysRegView Does Not Play Nice the nRF51822

Getting/setting register bits worked well for Ron when he used EmbSysRegView to view the STM32F030x SVD file.

When using EmbSysRegView with the nRF51822, register values were read-only.  I could monitor register changes as I twiddled bits, but the goal of using EmbSysRegView to turn the LBL’s LED on/off is not possible.

I asked why I couldn’t set registry properties with EmbSysRegView on the Nordic DevZone.   The reason is most likely what Aryan pointed out: Embsys also uses SVD file that comes with SDK and it looks like there is some format difference…(this could be a problem with the format of the SVD file or an interpretation problems with the EmbSysRegView).  My guess it is a problem with how EmbSysRegView is interpreting the nRF51822’s SVD file because I was able to set register properties using the Peripherals View.

The Peripherals View

Luckily, Vidar Berg pointed out The Peripherals View is another Eclipse plug-in that provides a property get/set UI to an SVD file.

Getting to the Peripherals View requires specifying the device within the C/C++ build’s settings:

The Peripherals view relies on Packs to distribute device information (in the form of CMSIS-SVD files).  Packs are installed into the Eclipse IDE using the Eclipse Packs Manager plug-in.  Once the Packs Manager is installed, I updated the software, and installed v8.0.3 of the nRF_DeviceFamilyPack for the nRF51 Series.



If the pack is not in the Packs list, from Vidar BergThe packs are kept up to date at which is where the pack system will look for updates using these URLs at Although I do not expect SVD file to be updated unless new peripherals were to be added in HW.  Just checked the SVD from SDK 5.2.0 and it is still the same as the one in SDK 9.0.0. The SVD file is working with Keil, IAR and the peripheral viewever in Eclipse, so it appears to only be a problem between our .xml file and embsys.

The one I am using is located here.

Blink The LED

Now it’s time for fun.  Instead of just the data sheets/documentation for the nRF51822, I can poke around with the registers.  This will give me a firmer grasp on how to program GPIO pins.

The LED_TEST Eclipse project includes two very simple functions, led_Init(LED_pin); and led_Toggle(LED_pin);.  Here’s the call graph for main.c that Doxygen created:


led_Init() calls the nRF51 SDK’s helper function nrf_gpio_cfg_output().  led_Toggle() calls nrf_gpio_pin_toggle().  

Configure the GPIO Pin

The LED is attached to pin 13.  The nrf_gpio_cfg_ouput() helper function takes out some of the guess work around configuring a GPIO pin for output.  It sets bits in the NRF_GPIO->PIN_CNF[13] register:




What I like about this view is it gives me a more “hands on” approach to configuring a GPIO pin.  I see from the code the nRF51 SDK has defined a gob of macros to aid in the readability.  The macros are in the nRF51_bitfields.h file that comes with the nRF51 SDK.  Stuff like GPIO_PIN_CNF_DIR_Output and it’s closely related GPIO_PIN_CNF_DIR_Input make it much easier to correctly set the pin for output.  Which bit in the PIN_CNF[13] 32 bit register is handled by define macros such as GPIO_PIN_CNF_DIR_Pos.  

Setting the GPIO pin with Pull-Up or Pull-Down

Ooh – and I had no idea that I could set the PULL bits (3-2) to be either PULL UP or PULL DOWN.  To be fair, I would have if I had set a GPIO for reading using the APIs found in nrf_gpio.h.  After all, void nrf_gpio_cfg_input(uint32_t pin_number, nrf_gpio_pin_pull_t pull_config); would have forced me to look at nrf_gpio_pull_t and found out about the different PULL states.

I played around with different PULL states using pin 8.  Taking DMM measurements, when the PULL-UP (bits 3:2 set to 11) was set, the voltage on the pin measured the same as the power source (3.3V).  When the PULL-DOWN (bits 3:2 set to 01) was set, the pin was set to GND.


There’s some functionality that I don’t understand – even after reading the documentation :-)…such as DRIVE, INPUT, SENSE….with these – I don’t know if that is TMI at this point or I’ll be spending days debugging something because I don’t understand every bit…hmmm…I struggle with when to move on when learning something new!


The nrf_gpio.h sets a pin to high using:

NRF_GPIO->OUTSET = (1UL << pin_number);

YIPPEE!!! The LED turned on:

To turn off the LED, set the appropriate bit of the GPIO’s OUTCLR register to 1:

NRF_GPIO->OUTCLR = (1UL << pin_number);

I can go to the Perspective View and set this bit in the same way I set the OUTSET register’s bit to 1 and the light turns off.

That was exciting. I now have a powerful tool to use when writing firmware for an Arm cortex-m.

One issue I did run into was in the UI for the Perspective View. There were several times when I attempted to change a bit value and it didn’t take, or the text saying if it had changed was incorrect. I attribute this to the UI. Eventually I could get what I wanted to work and tell it worked because the bit values shown were correct even if the text was incorrect.

Thank you for reading this far. Please find many things to smile about.

FINALLY…the Ladybug Blue Lite Can Blink


Whoa.  I have just spent an excessively long time…so long I have lost count of the days….attempting to blink an LED on the Ladybug Blue Lite (LBL) A2 PCB.  I can now say…YIPPEE!  the LED light will now blink.  This blog post is the story of the (mind) numbing path I stumbled up to blinking the LED on the (LBL) Alpha 2 PCB.

This was the first time I would be trying out a micro controller that I soldered onto a PCB.  Well, actually I am using a BLE module. Instead of using the nRF51822 chip directly, I decided to use the MDBT40 BLE module from Raytac.  I don’t know anything about BLE radios so it is best to leave it to a chip integrator that has been certified.

Thanks to Those That Went Before

  • THANK YOU to Ron Sousa for the course he is running as part of Contextual Electronics.  If he had not focused our attention and practice on a “similar” ARM Cortex-m0 SOIC – an STM32 micro controller,  I doubt if I would have been able to figure out/understand how the NVMC registers worked and how to write to them (I discuss this below.  It was a key part of the debugging process)
  • THANK YOU to folks like Erik Midtown on the Nordic DevZone blog for posting very helpful info.  Like this.

Open Source

The LED_TEST Eclipse project is available at this GitHub location.  The Ladybug Lite kicad schematics and layout are available at this GitHub location.

Flash Programming

I don’t know why the term “flash programming” bothers me.  Perhaps because of the results I get when Googling “flash programming.”  Whatever. Somehow I must get the bits that make up the executable of the LED_TEST binary copied onto the nRF51822 that the MDB40T encapsulates.

The Programer 

The programmer sends bits back and forth between my Mac and the micro controller.  A terrific feature of the nRF51 DK is it’s Debug out support.  Debug out support allows me to flash program and debug programs on external nRF51822’s – like the LBL.  YIPPEE! I don’t need an additional programmer/debugger like SEGGER’s J-LINK.

My Brief Intro To SWD

When I was growing up, my family lived in non-English speaking countries.  Most of the conversational language I picked up came from listening and observing.  I find observing a wire protocol to be daunting since it is at a lower level than say asking for a drink of water.  So my first search was for SWD documentation.


The language/protocol “spoken” between the debugger and the nRF51822 chip within the MDB40T is the very popular two wire protocol Serial Wire Debug (SWD).  Arm’s specification can be downloaded here if you signed up for an account.  I also included the specification in the Specifications folder of the LBL GitHub repository.

Another SWD reference I found surprisingly useful was the reference manual for the STM32F0xxxx .  I also included this document in the Specifications folder.  I was surprised by how well the document condensed down what was needed for me to start understanding what the heck would be spoken between the debugger and the nRF51822.  I was introduced to this reference manual by Ron Sousa in his embedded systems course within Contextual Electronics.

Protocol Analysis 

Lucky for us, the Saleae logic analyzer can decompose SWD traffic.   A change log on Salae’s web site noted the version of the Logic UI I needed to run on my Mac was at least version 1.2.2.  The most recent version is identified as 1.1.5.  Saleae has a beta version (1.2.3 as of this post) available here.  I updated to the beta version to use the SWD protocol analyzer.  A caveat:  Given the records I reviewed and compared with the SWD documentation, I believe there are mistakes in some of the bit interpretations.  I say “I believe” versus “there are” because I reached a saturation point  and moved on once I got an idea on why I could not initially program the LBL.

The Schematic

The other thing I looked at – not carefully enough at first – was the schematic as it related to debug-out and debug-in and the MDBT40 reference design.  The nRF51-DK Hardware Files 1_1_0 2 (also in GitHub) shows the pinouts of P20:

The nRF51-DK User Guid v1_0.pdf (also in GitHub) talks about debug output in section 5.10.  There are two connectors on the board – P19 and P20 – that can be hooked up to external nRF51822’s.  I chose to use the P20 because the P19 requires a cable/connector I do not have.  I used standard male shield header pins for the P20

Debugging Flash Programming

I’m finally ready to debug why flash programming doesn’t work

Check Connectivity

I actually didn’t do this first…the first thing I did was to go down debugging the SWD protocol.  That was not the right thing to do.  Always check connectivity first!

And there it was.  The circled pins are the pins on the BLE module exposed for SWDIO and SWCLK traffic.  On the first soldering go around, I was too light with the amount of solder paste.  Note the SWDIO and SWCLK pins weren’t connected to the pads:


Applying more solder:


While I am unskilled at reading SWD traffic, the packets pointed to a lack of connection because the host can’t connect to the nRF51822’s access port.  As in – knock, knock, knock…no one is answering.

Type R/W AP/DP Register Request byte ACK WData
Operation read AccessPort DRW 0b 1011 1111 OK 0b 1111 1011 1111 1111 0110 1111 1110 1110
Operation read AccessPort RAZ_WI 0b 1011 0111 OK 0b 1111 1111 0111 0111 1101 1111 1101 1101
Operation read AccessPort RAZ_WI 0b 1011 0111 OK 0b 1110 0111 1111 1111 1011 1111 1101 1101
Operation read AccessPort RAZ_WI 0b 1011 0111 OK 0b 0100 1111 1110 1111 1101 1111 1101 1101

but still… flash programming STILL failed…

Running JLinkEXE

Instead of JLink running through the GDBServer, I tried connecting using JLink Commander in a terminal window.  The JLink Commander executable is called JLinkEXE on the Mac.  It got installed and the PATH system variable updated on my Mac when I installed all the Eclipse goo which I discussed in previous posts, like this one.

To start the connection, I typed in:

jlinkexe -device nrf51422_xxac


The problem was the device name was incorrect.  I had gotten the device name from earlier Eclipse builds that worked on Adafruit’s Bluefruit LE friend as well as the nRF51 DK.  Unfortunately, these devices could still be flash programmed with the nrf5142_xxac device name.

It turns out the current MDBT40 modules I have include 16kB RAM instead of 32kB RAM:

  • nRF51422_xxAA:  256kB of Flash and 16kB of RAM
  • nRF51422_xxAC: 256kB of Flash and 32kB of RAM
so the device name for the sample I am currently using should be nRF51422_xxAA.  I have recently ordered MDBT40’s with 32kB RAM.
It turns out, if I had updated the device name within the debug configuration, flash programming and debugging would have worked:



 Typing JLinkEXE ? in a terminal window showed a list of commands.  I’ve included a partial list below:

Available commands are:


f          Firmware info

h          halt

g          go

Sleep      Waits the given time (in milliseconds). Syntax: Sleep <delay>

s          Single step the target chip

st         Show hardware status

hwinfo     Show hardware info

mem        Read memory. Syntax: mem  [<Zone>:]<Addr>, <NumBytes> (hex)

mem8       Read  8-bit items. Syntax: mem8  [<Zone>:]<Addr>, <NumBytes> (hex)

mem16      Read 16-bit items. Syntax: mem16 [<Zone>:]<Addr>, <NumItems> (hex)

mem32      Read 32-bit items. Syntax: mem32 [<Zone>:]<Addr>, <NumItems> (hex)

w1         Write  8-bit items. Syntax: w1 [<Zone>:]<Addr>, <Data> (hex)

w2         Write 16-bit items. Syntax: w2 [<Zone>:]<Addr>, <Data> (hex)

w4         Write 32-bit items. Syntax: w4 [<Zone>:]<Addr>, <Data> (hex)

erase      Erase internal flash of selected device. Syntax: Erase

I tried:


and then:

J-Link>loadfile LED_TEST.hex

The return from both was an error that talked about

“No matching RAMcode found.”  


Info: J-Link: Flash download: Restarting flash programming due to program error (possibly skipped erasure of half-way erased sector). Info: J-Link: Flash download: Skip optimizations disabled for second try. Error while programming flash: Programming failed.

Looking at a Nordic DevZone post under the section Troubleshooting tips I saw that I could try erasing the flash by writing directly to the registers.  Besides, this gave me an opportunity to better understand how to program to the registers:

J-Link>w4 4001e504 2
J-Link>w4 4001e50c 1

From above, w4 is the command to JLinkExe to write a 32 bit chunk-o-data to an address.  In the case of the first command, the address is 0x4001e504.

The Functional Description 6.1 section (in the nRF51_Series_Reference_manual v3.0.pdf) notes: “Before a write can be performed the NVM must be enabled for writing in CONFIG.WEN.  Similarly, before an erase can be performed the NVM must be enabled for erasing in CONFIG.EEN.”

Looking at the documentation on the NVMC (Non-Volatile Memory Controller) in the nRF51_Series_Reference_manual v3.0.pdf (also on GitHub) – Section 6, the base register for the NVMC peripheral is 0x4001E00.  

OK, I’m in the right “ball park.”

Going to Table 4, the Config register is 0x504.  The first write is to the Config register of the NVMC peripheral.  A 2 is written.  Looking at Table 6:Config setting 0x504 to 2 enables erase.

Now that erase is enabled, time erase all.  0x50c does an erase all which is documented in Table 9: ERASEALL.  a 1 written to this memory address starts a chip erase.  

And YIPPEE! This worked.  Checking some of the bytes of memory with this command:

J-Link>mem32 0,20

 returned 0xFF 0xFF….. flash was erased.

Running J-Link erase and loadfile

I could continue this route – basically programming the erase and loadfile functionality using registers commands- but…why am I getting “No matching RAMcode found” when I tried the erase or loadfile commands?  How am I going to load and debug from within Eclipse?

Oh – wait – RAMcode is J-Link’s error info for a device’s code to handle these functions.  Apparently everyone (except me?) is familiar with the term “RAMcode.”  In hindsight, what it is makes sense but at the time I thought running in a circle flailing my arms up and down was the definition.  Oh.  Well…and that is how I concluded to try a different device name.  I tried the device name used in the “Automating Tasks by Modifying the Makefiles” section of the Nordic DevZone post:

JLinkEXE -device nrf51822

and… wait for it… YIPPEE!!! it worked!  

What seems to happen is the device is actually nrf51822_xxAA instead of nrf5182_xxAC.


Now while this experience was mind number, I found blundering through figuring this out to be satisfying in the sense that my determination out maneuvered my lack of skill/knowlege.  I was determined to figure this out.  I did.  I’m happy about that.




That’s it for now.  Please find many things to smile about.

Designing Ladybug Blue Lite for the nRF51822 BLE Module




I’m iterating on the design of the Ladybug Blue Lite (LBL).  The LBL measures pH and EC of a nutrient bath (used for hydroponics).  Measurements are sent to an iOS app over BLE.

Instead of using the nRF51822 chip directly, I decided to use the MDBT40 BLE module from Raytac.  I don’t know anything about BLE radios so it is best to leave it to a chip integrator that has been certified.

The Goal

The goal of this post is to provide an overview of the schematic I used around the MDBT40 BLE module.  There was stuff I didn’t understand/didn’t get right that I muddled through with the help of “those that went before” (see below).

Thanks To Those That Went Before

  • THANK YOU to Nordic support!  I am finding Nordic support – the company behind the nRF51822 – to be EXCELLENT.  A HUGE shout out to Ketil Aas-Johansen.  Ketil was able to clarify design mistakes I had made.  He even checked out my schematic and Gerbers to make sure I got the design right with respect to the MDBT40.
  • Another shout out to Martin Børs-Lind for the excellent (and kind!) answer he provided to my question about the AVDD.  The code example he gives for enabling/disabling the DC/DC converter as well as turning on/off the BLE radio was extremely helpful.
  • THANK YOU to Adafruit for their Bluefruit LE UART Friend and their excellent support forum.  They have incredibly sharp folks (like ktownsend) who seems to be pivotal in the design and build not only of the hardware but firmware for the Bluefruits.  Thank you for being so amazingly helpful.  I totally recommend buying from Adafruit.  Particularly if you are like me – learning about electronics.
  • Chris Gammell’s excellent Contextual Electronics course and exceptional mentoring has taken me far in my currently two year journey learning electronics.  While every day I delight in finding out stuff I didn’t know or – even more enchanting – totally misunderstood! – Not knowing/misunderstanding is better to take when there is a path to understanding which I feel Chris’s efforts have given me.
  • I am incredibly grateful to the skilled folks who share their knowledge on forums and blog posts.  It amazes me how much easier it is to figure stuff out than it used to be!

Open Source

The schematic and layout Kicad files are located in this GitHub repository.


Here’s the current schematic for the MDBT40 on the LBL:


Simple, right?  Yes.  But I still managed to misunderstand some aspects…

Mistake 1: My Interpretation of AVDD

In a previous post, I interpreted the Analog voltage to supply power to the other ICs (like the op amps) on the board.  Wrong.  AVDD provides power to the BLE radio.  This is EXACTLY what the nRF51822 product spec says it does, from Table 1 Pin functions:

My Misunderstanding

I believe the reason I got confused was what I got out of reading the Power management section (3.4) of the nRF51822_PS v3.1.pdf.  This section starts out by stating:

nRF51 supports three different power supply alternatives:

  • Internal LDO setup
  • DC/DC converter setup
  • Low voltage mode setup

Oh how nice I thought….this chip does everthing…voltage comes in from the CR2032 battery and the nRF51 cleans it up for the rest of the circuit to use.

Um….No.  What is perhaps obvious to you – but not me at the time – was this section was saying….when the BLE radio is transmitting or receiving, the radio’s power supply (AVDD) can be set up to use one of three different  voltage regulators.

A challenge I faced was / is being overwhelmed by the documentation.  As pointed out by Martin Børs-Lind in his answer to my question on the Nordic DevZone, the information about how the different regulators work is nicely covered in Figure 9 of the nRF51_Series_reverence_manual v3.0.pdf.  Because the “goo” behind interacting with BLE is kept from me via the SoftDevice 110 stack, I was unaware of:




The radio_test example in the nRF51 SDK does use these.

My Current Understanding of the Radio’s Power Source

Perhaps yet another obvious statement.  The Radio uses the AVDD power source when it is transmitting or receiving packets over BLE.

The simplest is the radio LDO setup.  Note: there are other LDOs for system and peripheral as well as flash power.  This is the configuration in the schematic above.  I ended up using the LDO because it was the simpler than using the DC/DC Converter.  A ~ 3V power source feeds into the AVDD. An internal LDO voltage regulator provides the expected power to the BLE radio.

The DC/DC buck converter sounded like the way to go as noted in of the spec:

This feature is particularly useful for applications using battery technologies with nominal cell voltages higher than the minimum supply voltage with DC/DC enabled. The reduction in supply voltage level from a high voltage to a low voltage reduces the peak power drain from the battery. Used with a 3 V coin-cell battery, the peak current drawn from the battery is reduced by approximately 25%.

The things that need to be there for the DC/DC converter to work:

  • an inductor and capacitor wired between the VDD and AVDD pins.  Here is an example from the MDBT40 specification:
  • the DCDEN register needs to be enabled (through firmware).
Figure 8 in the nRF51_Series_reference_manual v3.0.pdf is a great visual of the radio LDO regulator:

Figure 9 is an equally great visual of the radio DC/DC converter:

The other thing the images point out is the LDO regulators for the power needs of flash and the system.  A separate topic on its own merits!

Figure 10 gives a visual of using a low voltage mode for powering the radio:

In this mode, an outside power source can be used to provide power to the radio.  I’m not sure if the MDB40T supports this mode since there is a DEC2 but no exposed DEC1?  I don’t plan to use this mode so I won’t investigate more right now.

Mistake 2: Confusion On Pin Outs

I didn’t understand what the MDB40T included above the nRF51822 – besides the BLE radio.  For example, a requirement for the nRF51822’s radio to work is a crystal on the XC1/XC2 pins of the nRF51822:

The MDB40T does not expose these pins.  However, all their reference circuits included a crystal on XL1 and LX2 (see the MDB40T reference circuit above).  This made me think the crystal on XL1/XL2 was required, which is not true.  The crystal on XC1/XC2 is provided by the MDB40T.

On The Other Hand

On the other hand, the MDB40T reference circuits all include a resistor on SWDCLK:

As Ketil pointed out to me: “The pull down resistor was only needed in the very first revision of the nRF51822. It’s been on-chip for quite a while now so you shouldn’t need it.

Also I have gotten in the habit of sprinkling a bypass cap on any VDD.  Yet the MDB40T reference circuits include a 1uF bypass cap on AVDD but not VDD.  Ketil also clarified this for me: “There are 100 nF caps close to all VDD and AVDD pins on the module and these takes care of HF noise. But somewhere in your design you should have a larger cap, 1 µF is fine here. You can have 1 µF caps on all VDD pins if you like, no problem.”

Lessons Learned

  • While RTFM definitely applies, I find it impossible to believe I will understand something so new without making the type of design mistakes I made above.
  • I hope what I have learned will translate to other micro controllers.  This makes me even more excited to design, build and program around the STM chip we’re using in Contextual Electronics.
  • Nordic and Adafruit support are top notch.  I will continue buying their products whenever possible.
Thanks for reading this far.  Please find many things to smile about.







Using Doxygen Within Eclipse to Document Projects



I appreciate documenting my code mostly because I forget how I wrote it – and sometimes worse – why I wrote it.  An added benefit is if the documentation is well thought out, it greatly helps me figure out which way I should go within the variety of options to create code for the task at hand.  I don’t mean the kind of comment that I run across all too often:

//open the gate

void openTheGate(){


A comment that repeats the name of the function.  What a waste of time and space! Certainly, the name of the function is super important to documentation.  However the name should work with more context to understand why a program was written the way it is and why that function is needed.

In our embedded systems section of Contextual Electronics, Ron showed us how he uses Doxygen and Graphviz to document code.  I like having the documentation within the same location as the source.

Thanks to Those That Went Before

I found this post by Erich Styger to be exceptionally helpful in understanding what was going on.  Thank you Erich for your well written advice.

Thanks to Ron Sousa (@OpticalWorm) for showing us how to use Doxygen and Graphviz.  I clearly saw the value after Ron walked us through one of his projects that had been “Doxygenated.”

The Goal

The goal of this post is to add documentation to an Eclipse project (running on Mac OS X 10.10) – LED_TEST.  LED_TEST is a very simple project I will be using to test the LED I have laid out on the LadybugBlueLite PCB.

Open Source

I provided example Eclipse projects that use the NRF51 SDK in this GitHub repository.  I peppered the source with Doxygen commands.  Each contain a Documentation folder where you can view Doxygen’s output (open up the index.html file).  The examples are located here in this GitHub repository.

The Steps

The steps include:

Install Doxygen 

Doxygen can be installed from this link.  I downloaded Doxygen-1.8.10.dmg (56.0MB).  I copied into the Applications folder.

Install GraphViz

As pointed out in this postGraphviz is open source software to create graphs using the dot language. Dot code can be used with Doxygen.  I downloaded Graphviz from here.  From what I can tell, the only thing used is the dot command line tool.  Dot seems to work with either of the versions.  I’m not completely sure because I was fiddling around trying to get graphical views to work within Doxygen.  I’m pretty sure (but not positive) my challenge was not in the version of graphviz.

Install Eclox

Eclox is an Eclipse plug-in that I found out about from this post.  When I looked at the Eclox home page, I was greeted with a concerning message:

Important Notice !
Since December the 1st of 2009, the development and the maintenance of eclox are discontinued ! See Getting Involved to get information about development resources.

Despite the notice, I am throwing caution to the wind and going ahead with Eclox.  Risky, I know, but…I optimistically believe the gain will be worth the risk.

Plug-ins are installed by going to Help->Install New Software…


 Choose Add from the Install dialog box:

 Add the Eclox repository:




Configure Eclox to use Doxygen

Time to tell Eclox where the Doxygen executable is located.  This step is a little tricky.  Go to Eclipse’s Preferences page

click the Add.. button.

Tricky part: Assuming you did like I did and copied into the /Applications folder, the location of the Doxygen binary is located within within the /Applications/ .  If you are not familiar with OS X application bundles, this wikipedia article may be helpful.

You know you have been successful if you see the version number.

Create a Doxyfile

Each Project needs a Doxyfile.  As noted in the Doxygen documentation: [The doxyfile] configuration file is a free-form ASCII text file with a structure that is similar to that of a Makefile, with the default name Doxyfile. It is parsed by doxygen.  Eclox adds a wizard to create one.  Go to File -> New -> Other -> doxyfile .

A doxyfile has been created within the LED_TEST project:

Modify the Doxyfile

The easiest way to modify the Doxyfile is through the Doxyfile UI.  Double clicking on the LED_TEST.doxyfile  brings up the Doxyfile editor

Using the Doxyfile Editor

I used the settings above.  However, I needed to set a few more properties before I could get the Diagrams to be generated.  The additional properties can be set by going to the properties in the Advanced Tab.  The Advanced Tab is located at the bottom of the editor.


 Hurdle: Don’t forget DOT_PATH .  Without it defined, Doxygen can’t find the dot utility provided by the GraphViz install.

Tip: When in the Advanced tab searching for a variable, go into the Custom Settings Tab and enter a search term like “DOT” to narrow down the properties to the ones you want.

I modified the following:

DOT_PATH = /usr/local/bin





You may want to modify some or none of the above.  Perhaps splash around and find out what works for your project.

Add Doxygen Statements to your Source

Here is my simple main.c source with Doxygen statements:


 *  \file main.c

 *  \brief Test if the led on the Ladybug Blue Lite is working

 *  Author: Margaret Johnson






 * \brief the Ladybug Blue Lite schematic identifies gpio pin 24 as the LED pin


#define LED_pin  24


 * \callgraph

 * \brief Toggle the Ladybug Blue Lite’s LED


int main(void){








TRICKY: I could not consistently generate call graphs UNLESS I included the \callgraph Doxygen command in the function’s description.

USEFUL: Eclipse makes it easy to enter Doxygen commands.  Start a line with /** then hit enter.

Run Doxygen

Eclox adds a toolbar button (image from this awesome post):

 press the button to generate documentation for the opened project (or choose the project).  A whole bunch of documentation files will be placed within the folder defined as the Output Directory in the Doxygen Editor step above.  I set my Output Directory for this project to Documentation.

Double click on the index.html file to open the documentation within Eclipse.

Documentation Created With Doxygen 


Here is an image of the documentation that was created by Doxygen as well as the graph by the Dot utility (from Graphviz):

From here I can jump to the source documentation (note “line 17” and “main.c” are in blue).  Also, there is a call graph that makes it much easier to follow what is going on. 

While I am new to Doxygen and Graphviz (the Dot utility), so far I am finding many positive reasons to consistently use as part of my programming process.  The call graphs have been a great way to sift through the NRF51 SDK and gain a better understanding of what the libraries are up to as well as what code I should look at more closely.



Thanks for reading this far.  Please find many things to smile about.




Using Eclipse for nRF51 Development: Getting off Makefile and into Managed Make


UPDATE November, 2015

Guess what I found?  We can export the include file paths and CFLAGS and then import them into another workspace.  Wow – what a time saver!

There are two ways to get to this dialog box:

  • File/Export…
  • Properties->C/C++ General->Paths and Symbols->Export Settings button (keep the tab on Includes)

Thanks To Those That Went Before 


 Thanks to Chris Gammell’s Contextual Electronics course, I got to see the advantage of using the CDT’s managed make feature over using Eclipse with a standalone makefile.  Basically, as I discussed in this post, to use the nRF51 SDK with Eclipse, I modify makefiles that came with examples from the nRF51 SDK.  I was going to continue along this path.  After all, I just want to build, program the nRF51822, and debug.  Do I really need to become a Make expert?  Probably not.  But I do see an advantage in simplifying the toolchain since now Eclipse is handling these tasks.

The Goal

The goal is to build and debug the Blinky nRF51 SDK example within a Eclipse managed make project.  Note: there are a few more “things” that need to be done to use with the BLE soft device stack.  I’ll probably cover that in my next post.

Why Bother

An Eclipse project with managed make is much better integrated into the Eclipse environment.  There are many advantages.  The obvious one is I don’t have to maintain two build environments – the info Eclipse needs and then constantly updating the makefile.  Also, once I got the hang of the Nordic makefiles, I noticed many similarities that I could put into a managed make and then reuse.

It would be best if Nordic created templates that can be used to start a “Hello World nRF51, no BLE” and “Hello World nRF51, SOFTDEVICE110” (etc. on the remaining soft devices).  However, this is – unfortunately – not available.

Thanks To Those That Went Before

Thanks to Chris Gammell for including an Embedded Systems section within Contextual Electronics.  The combination of learning on my own and while going through projects with more skilled instructors is very valuable in scoping what I need to learn to successfully apply to my projects.

I am thrilled Chris Gammell’s Contextual Electronics has started modules on Embedded Systems.  Chris found excellent folks – Ronald Sousa and Eric Hankinson – to be our instructors.  Incredible to me, they were able to set up a virtual environment that transcends whether we are on a Mac, Windows, or other operating system.  We can then work together within an identical environment.  It is truly impressive how they set the environment up.  

Thanks to Doug Schaefer for co-leading the Eclipse CDT project.  Eclipse is a very rich IDE for embedded systems.  It amazes me how much care, time, and effort Doug and other folks on the Eclipse team spend to make it easier/better to develop code for SOICs like the nRF51822.

Thanks to Vidar Berg (Nordic employee) for posting a very helpful post: “Development with GCC and Eclipse

The Steps

Without more discussion, I’m documenting the steps…heck, it only took me two days to figure out (down from a week that it took me to figure out the stuff I covered in this post :-) ).  I am assuming you have enough familiarity with Eclipse (or can Google to find out) to know what I am referring to within the steps. Click on the images to view a larger/more readable image.

1. Install Eclipse with the right gnu arm toolchain goo.  I covered how I did this here.  

2. Create a new C Project.


3. Choose the Hello World ARM C Project


After entering a project name and choosing next, the Basic Settings dialog box is displayed:

 I delete the Linker semi-hosting options based on what I learned about semi-hosting (see this post).

 4. Go into the project’s property page C/C++ Build->Settings->Tool Settings  (I think I cover doing this in detail in this post) and set the target processor to cortex-m0


5. In this step I started mapping what was going on in the Blinky makefile into the build property pages.  The easiest way for me was to load the Blinky makefile into a text viewing project – I used TextEdit on my Mac.   The Blinky makefile comes with the Blinky example within the PCA10028 /blank/armgcc folder.

6. Note the CFLAGS:


The first one identifies the chip.  The second two are used by the code interacting with the nRF51 DK, where the CFLAG BSP_DEFINES_ONLY is used when the LEDs are used.

Other CFLAGS that I have used when BLE is included:


7. Go to same Tool Settings properties page as in the earlier step and click on the Preprocessor property under Cross ARM C Compiler.  Add these defined symbols.



8. Now let CDT know about the location of the include files. The makefile lists the following include paths:

INC_PATHS = -I$(abspath ../../../../../../components/toolchain/gcc)
INC_PATHS += -I$(abspath ../../../../../../components/toolchain)
INC_PATHS += -I$(abspath ../../..)
INC_PATHS += -I$(abspath ../../../../../bsp)
INC_PATHS += -I$(abspath ../../../../../../components/device)
INC_PATHS += -I$(abspath ../../../../../../components/drivers_nrf/hal)

 I added the include paths into the includes property page using the ${workspace_loc} environment variable to simplify entering the path info.


9. Checking the Optimization property page, I noted the “default” was C11, but the blinky makefile used C99, so I changed the language standard to C99.  I am not skilled enough in what issues would arise if I had left it with the default.  I did this to mimic the makefile.


10. The Linker script – blinky_gcc_nrf51.ld – needs to be incorporated into the build.  Copy the script over to the Eclipse project folder.  It will then show up in Eclipse’s Project Explorer.  Go to the Linker properties page.  Add the file to the script files list. I did this by looking at the environment variables and noting ${ProjDirPath} expands to the Eclipse Project folder:

UPDATE: instead of hard coding to the name of the script file (in this case blinky_gcc_nrf51.ld), use the ProjName build variable. So the -T entry is ${ProjDirPath}/${ProjName}.ld

Here’s the property page to enter Linker script location info:


Here is the contents of the bliny_gcc_nrf51.ld that I have:

/* Linker script to configure memory regions. */

GROUP(-lgcc -lc -lnosys)

FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x40000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x8000

INCLUDE “gcc_nrf51_common.ld”

note the script includes gcc_nrf51_common.ld.  To resolve this reference, go into the Libraries property page and add a path under the -L entries:

 11. set the map file location:

12. Add the system files. Copy the files: ..\components\toolchain\system_nrf51.c, ..\components\toolchain\system_nrf51.h, and ..\components\toolchain\gcc\gcc_startup_nrf51.s into the project folder.   Then (and this seems weird to me), I had to upper case the s on the gcc_startup_nrf51 assembly file, i.e.: rename to gcc_startup_nrf51.S .

Eclipse needs to be told to look in the project folder.  To do this, go to the property page at C/C++ General ->Paths and Symbols->Source Location and add the project location to the build path:


13. Go to file manager and delete main.c in the src folder of the workspace.  Copy the main.c from the blinky example.

14.  Go to Run-> Debug Configurations…   and double click the GDB SEGGER J-Link Debug configuration to create a debug instance for the project.

Run Debug.  



And that’s it.  It should be working. :-)

Sometimes Debugging Doesn’t Work

 I tried repeating the above steps a few times.  Occasionally, I couldn’t get into line level debugging of main.c.  I wondered if it was similar to the problem I had earlier with Build Variables so I added step 11 above (put the full path to the map file location).  As I learn more I’ll update this post.




Thanks for reading this far.

Please find many things to smile about.





Using the nRF51822’s Application Timer


, , , ,

There will be many times when I will want to fire off timer events.  I’m used to doing this at a level that is closer to “get back to me after one second five times.”  Where the one second and five times can easily be changed.  It’s so simple…I don’t need to understand anything about how the software gets this magic to happen.

I found getting a timer to fire off every second for five times required me to learn more about how the nRF51822’s clock + software drivers work.

The Goal

The goal of this post is to understand how to set up a timed event using the nRF51 DK and SDK.

Thanks To Those That Went Before

I like to take a moment to share my gratitude for the people who have provided me with the knowledge I needed to figure out what I wrote about in a post.

  • Chris Gammell – continues to be an excellent mentor.  I continue to take his Contextual Electronics course.  I am extremely grateful for the skills I have learned since starting his course in January of 2014.
  • The Nordic developers who tirelessly answer our questions on their DevZone.  It is VERY difficult to provide the level of respectful and useful support that comes from this team.  THANK YOU.

Open Source

  • The nRF51 Eclipse project (for Max OS X) for using the app_timer APIs is located at this GitHub repository.  Note: because it took me a bit of head knocking to get the Eclipse + nRF51 environment working on my Mac I wrote a post on how to get this environment up and running.

Choosing an API for Timed Events

Goldilocks had three bears.  The nRF51 appears to have three timer APIs that can be used to implement timed events.  Which approach should I take?

  • the APIs of app_timer.c – these are used in the BLE example apps.  After trying all methods, I ended up using the app_timer APIs.  The app_timer apis sit on top of the nRF51822’s RTC (Real Time Counter) APIs, providing a queue so that multiple timers can be set up on one of the RTC instances.  
  • the RTC APIs.  As noted in the nRF51 Series Reference ManualThe [Real Time Counter] is a 24 bit low-frequency clock with frequency prescaling and tick, compare, and overflow events.  There are two RTC instances available.
  • the hardware timer APIs.

The Hardware Timer

The timer example in the nRF51 SDK (timer_example) illustrates using a hardware timer to call an ISR every 1/2 a second.  This made me think the hardware timer was the way to go if I wanted a timer to fire off every second.  Using the hardware timer is simple and perhaps makes sense.  As noted to me by a Nordic developer:  If you are not concerned about power usage (maybe because you are experimenting or making a prototype) then you can just use TIMER1 and TIMER2 and do not get concerned about the HFCLK.



The hardware timers use a high frequency clock source – either an external crystal or internal oscillator (see the Reference Manual for more detail).  While there are three timers – TIMER0, TIMER1, and TIMER2, buried within the reference manual for the BLE stack, TIMER0 is blocked for it’s use.

Power Hog

What’s more,  as noted in this Nordic DevZone postIf you use TIMER1 or TIMER2 then those will keep HFCLK enabled in sleep modes making your power go up…Any of the modules in the system that use HFCLK when started and not stopped before going to sleep will keep the HFCLK enabled. For example, if you enable and start Timer1 and then call sd_app_evt_wait(), then Timer1 will be on and it will keep the HFCLK on.

Given my newbie knowledge approach to these timers, there is a good chance I am missing other reasons why using the hardware timers is not the way to go for the scenario I seek.


On to the Real Time Counter.  As noted in the nRF52 SDK documentation, “The RTC will run off the LFCLK.”  There are two RTC instances, RTC0 and RTC1.  The app_timer APIs use RTC1.  The BLE stack (called “the SoftDevice” – link to the S110 documentation) uses RTC0.  So if you plan to use the SoftDevice, the only available RTC instance is RTC1.  Or – said another way – if you use the Application Timer apis and the BLE SoftDevice stack there aren’t any RTC instances available.


Similar to the HFCLK, the Low Frequency Clock source can be set to use either an external crystal or internal oscillator.  Even though I have been warned by Elicia in Making Embedded Systems : “Many small microcontrollers use an internal RC oscillator as their clock source. Although these make life easier for the hardware designer, their accuracy leaves a lot to be desired. Considerable drift can accumulate over time, and this can lead to errors in communication and some real-time applications.”  I decided I’d go with what is included until I can justify the addition of an external oscillator.  The Ladybug Blue timer scenarios use timed events to give spacing between ADC readings and not for maintaining a time or synchronization.

Power Saver

 this Nordic DevZone post notes: you can use RTC in system on low power mode. In this mode it’ll consume around 3uA = ION + IRTC + IX32k.

Another Nordic DevZone post notes a bit more detail: In system off mode, all clock sources and peripherals on the chip are turned off, and the only wakeup source is reset and pin change (for those that have this enabled)..Depending on whether you use a 32 kHz crystal or the internal RC oscillator, this gives a total consumption of I_on + I _RTC + I_X32k, typical 2.3 + 0.2 + 0.4 = 2.9 µA or i_on + I_RTC + I_RC32k = 2.3 + 0.2 + 0.8 = 3.3 µA

Repeating Timed Events

I was testing the  RTC nRF51 SDK example. While tick events fired regularly, I could not get the compare events to repeatedly fire.  While I do point out this is a “RTFC” where C = Code moment, I asked why this was happening on the Nordic DevZone.  Stefan kindly answered (and provided code): The internal event handler of the rtc driver, i.e. the nrf_drv_rtc_int_handler, handles the RTC0 peripheral interupt and then calls the registered event handler of the application. If you look into the nrf_drv_rtc_int_handler, you see that interrupts for any COMPARE[x] events are disabled, while TICK and OVERFLOW interrupts are not disabled. If you avoid disabling the COMPARE[x] interrupts, then the COMPARE[0] interrupt will be recurrent after you clear the RTC0 counter. (see the post for the code)

The app_timer (Application Timer) APIs

Given what I have learned, the app_timer APIs are most suitable to meet my needs.  Because:

  • they are an abstraction above the RTC APIs – the Ladybug Blue timer events would be shielded from the uses of the hardware and RTC timers.
  • they are easy to use.
  • many of the BLE examples use the app_timer APIs.  The use case of these examples are similar to the Ladybug Blue scenarios.
If you look at the main.c after downloading the file and unzipping, notice how the main() routine:
  • Initializes the low frequency clock and the app_timer queue:

static void timers_init(void)


  //initialize the low frequency cloc

  uint32_t err_code = nrf_drv_clock_init(NULL);



  // Initialize timer module.



  // Create timers.

  err_code = app_timer_create(&m_timer_id,






  • start the timer(s):

static void timers_start(void)


  uint32_t err_code;

  // Start application timers.

  err_code = app_timer_start(m_timer_id, TIMER_TICKS, NULL);



  • handle the callback:

static void timeout_handler(void * p_context)


  //  UNUSED_PARAMETER(p_context);

  SEGGER_RTT_WriteString (0, “–> in timeout handler\n”);

  • stop the timer(s):

  uint32_t err_code;

  err_code = app_timer_stop(m_timer_id);



 Simple.  It took me awhile to get this working since I kept forgetting to initialize the low frequency clock source.


One variable that needs to be set is the value of the nRF51’s PRESCALER register.

From wikipediaThe prescaler takes the basic timer clock frequency (which may be the CPU clock frequency or may be some higher or lower frequency) and divides it by some value before feeding it to the timer.  

Another way to say this – the PRESCALER lumps the ticks into a grouping so that timed events can happen at larger time periods before an overflow occurs.

The  nRF52 SDK documentation has a nice visualization for when the PRESCALER is set to 1:


Tick events happen every time the clock ticks. Counter events happen after (tick*(prescalar+1)) ticks.  We’re interested in counter events.

The  nRF52 SDK documentation has the following table:


From this Nordic DevZone post

  • I noted at the beginning of this post the RTC (and hence app_timer which sits on top of RTC1) uses a 24 bit counter.  Thus the maximum value that can be held is 0xFFFFFF.
  • The clock source is the low frequency RC oscillator which runs at 32,768 HZ.
  • When the PRESCALER is 0, the maximum time before an overflow occurs is 0XFFFFFF/32768 seconds = 512 seconds.
  • The PRESCALER is a 12 bit register so the prescalar value can go from 0 to 212-1 = 4095.  The longest amount of time that can pass before the RTC overflows is then 512 s *(4095+1) = 582.542 hours.
  • When the PRESCALER is 0, the counter and ticks are the same, so the counter resolution = 1/32768 = 30.5µs.
  • When the PRESCALER is 4095 the counter resolution = 1/(32768/4095) = 125ms.  (i.e.: as the wikipedia article noted, take the clock frequency and divide it by the PRESCALER to get the counter frequency.  1/f = time resolution).


For averaging ADC sampling (of ~100 at a frequency of 5HZ), overflow won’t be a problem and a PRESCALER value of 0 can be used.

For background pH and EC measurement timed events, there will be overflow since I plan to sample continually.  Luckily for me, the app_timer APIs handle overflow for me!

Time Drift

This Nordic DevZone post discusses the low frequency clock accuracy.  “PPM” is thrown around a bit, but I was only familiar with this term as it related to chemistry.  For example, the amount of nutrients I might give a plant is usually given in either Siemens or Parts Per Million (PPM).  This document from the site says: Long term stability is usually expressed in parts per million or ppm. A typical specification of 10 ppm means that over a 1 ms interval the clock period can change by 10 ns: Dt=1ms*(10/1,000,000) =10 ns.

In the DevZone post, Ole and Stefan tell us: The…RC oscillator…has an accuracy of 250 ppm when calibrated.  In a 1 second interval, the clock can drift 1 second *(250/1,000,000) = 250µs.  Ole and Stefan go on to point out:  The only thing you can choose through this enum for the RC is the calibration interval. As given in the nRF51822 PS, the accuracy is specified when the temperature is relatively stable, and it is calibrated every 4 seconds, so this is the calibration interval that should be used for most (all?) applications.  When the RC is calibrated, the 16 MHz clock must run while calibration is ongoing, which causes an increase in the average current consumption of about 6-7 µA with a 4 s interval…

I might not understand this correctly…my interpretation:  When the PRESCALER is 0, the time elapsed before overflow is 512s.  Given the 250µs drift/s, the clock will drift 512*.00025 = .128s.  When the PRESCALER is 4095, the time elapsed before overflow is 2097152s, the clock drift will be 2097152s*.00025 ~= 524s or ~8.73 minutes.

Until proven otherwise, I do not see clock accuracy as being important for pH and EC measurements since it is more important to have a length of time between measurements that ensures stable readings. 


Whew.  That’s it for now.  Ooh…YIPPEE!! I got boards back from OSHPark….a bit of soldering and hopefully I’ll be able to run these tests on the Ladybug Blue Alpha 1 board….



Get every new post delivered to your Inbox.

Join 28 other followers