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 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


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


 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:


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:


 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”);

 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….


Automating BoM Creation


, , ,

Now that I have a better idea on the BoM creation workflow I use, I decided to automate the BoM creation process.

The (Google Script – which is Java Script) code is extremely crude.  I see it as a working prototype. While there is much (much) room for improvement, the current effort provides a framework to the direction I am heading.

Open Source

Here is an example Google Spreadsheet – BoM Parts Example.  The script I used is pasted near the bottom of this post.

An Ask

  • I don’t program in Java Script.  Also, I have no formal training or work experience in programming.  I’d appreciate any advice on script improvements.
  • I would be very grateful for a Google Script/Javascript snippet that given a part number within a Google Spreadsheet cell, can go to the distributor’s web page and get the 1, 100, 1000 piece price.  Right now I record the link to the distributor’s page, which is usually a page on  I then record the 1, 100, 1000 piece price.  I would like to improve the BoM workflow process by getting the price information from the distributor (Digikey, Mouser, etc.) at the time of BoM worksheet creation.  Because I am not familiar with the code necessary to Get the price information given a part number from a given (or more generically – across) distributor, I have a learning curve that would absorb many hours.  I would then evolve the snippet to work within the workflow and publish on GitHub.  I would make sure to give you credit within any documentation as well as within the GitHub repository.

The BoM Workflow 

Here is an image of my BoM workflow:


I use Kicad to design and layout a PCB.  The EeSchema tool is used to create the schematic.  EeSchema includes a BoM generation utility that creates a CSV file.  I import the CSV file into a Google Spreadsheet.  The Google Spreadsheet includes a script that parses through the BoM CSV and match the rows within the BoM CSV with parts in the Parts Inventory Worksheet.  The script goes on to create the Completed BoM worksheet with rows that look like:

Type Name MFG Part Quantity 1 Piece Price 1 Piece SKU 100 Piece Price 100 Piece SKU 1000 Piece Price 1000 Piece SKU  
CONNECTOR LB_COIN_CELL Link Technologies BAT-HLD-001 1 0.28 0.28 0.233 0.233 0.22875 0.22875
CAPACITOR 1u Taiyo Yuden TMK212BJ105KG-T 3 0.16 0.48 0.0523 0.1569 0.03025 0.09075
TEST POINT TESTPOINT N/A N/A 10 0 0 0 0 0 0  
CAPACITOR 47n Kemet C0805C473K5RACTU 1 0.1 0.1 0.0269 0.0269 0.0144 0.0144
CAPACITOR .1u Kemet C0805C104K5RACTU 12 0.1 1.2 0.02 0.24 0.012 0.144
LED LED Stanley Electric Co. PG1101W-TR 1 0.47 0.47 0.2169 0.2169 0.11832 0.11832
DIODE DIODE Micro Commercial Co 1N4448W-TP 4 0.14 0.56 0.0816 0.3264 0.02719 0.10876
INDUCTOR 15nH Bourns Inc. CE201210-15NJ 2 0.1 0.2 0.056 0.112 0.0416 0.0832
INDUCTOR 10uH Taiyo Yuden LBR2012T100K 2 0.1 0.2 0.0665 0.133 0.0494 0.0988
CONNECTOR LB_CONN_2 On Shore Technology OSTTE020104 1 0.38 0.38 0.2548 0.2548 0.182 0.182
CONNECTOR LB_HEADER_4 N/A N/A 1 0.2 0.2 0.2 0.2 0.2 0.2  
CONNECTOR BNC 4UCON – 1000 minimum 6542 2 0.51 1.02 0.51 1.02 0.51 1.02
RESISTOR 1K Yageo RC0805JR-071KL 7 0.1 0.7 0.0073 0.0511 0.00326 0.02282
RESISTOR 1K .5% Susumu RR1220P-102-D 1 0.11 0.11 0.0381 0.0381 0.01673 0.01673  
RESISTOR 10K Yageo C0805JR-0710KL 3 0.1 0.3 0.0073 0.0219 0.00326 0.00978
RESISTOR 22K Stackpole Electronics Inc RMCF0805JT22K0 1 0.1 0.1 0.0088 0.0088 0.0032 0.0032
RESISTOR 3M Panasonic Electronic Components ERJ-6GEYJ305V 1 0.1 0.1 0.011 0.011 0.00496 0.00496
RESISTOR 6M Yageo RC0805FR-075M9L 1 0.1 0.1 0.0099 0.0099 0.00443 0.00443
OP AMP MCP6242 Microchip Technology MCP6242-E/SN 1 0.43 0.43 0.27 0.27 0.27 0.27
BLE Module MDBT40 Raytac MDBT40-256V3 1 5 5 4.15 4.15 3.55 3.55  
OP AMP MCP6244 Microchip Technology MCP6244-E/SL 2 0.68 1.36 0.43 0.86 0.43 0.86
 Total           13.29   8.3407   7.0309  

A next step would be to integrate ordering parts with the distributor.  However, I do not do that in this prototype.

Perhaps this crude prototype is of use to you.  (if it is – please consider addressing an ask above).

The Script

The Parts BoM Example Spreadsheet is view only.  Here is the script:

function onOpen() {

  var ss = SpreadsheetApp.getActiveSpreadsheet();

  var BoMmenuEntries = [ {name: “Create BoM”, functionName: “createBOM”}];

  ss.addMenu(“Create BoM”, BoMmenuEntries);


function createBOM() {

  //I set the name of the imported CSV file that was created within Kicad’s Eeschema tool, the name of the parts inventory sheet, and the name of the built BOM as script properties.

  //See the File/Project Properties UI…NOTE: It would be better if a UI came up and asked for these names.  I’m entering the names through properties just for the prototype.

  //BOMWS = Sheet in spreadsheet that is the built BoM

  //KICADWS = Sheet that was imported from CSV file generated from Kicad’s EeSchema tool

  //PARTSWS = Sheet containing the info on each part that is listed within the CSV file

  var scriptProperties = PropertiesService.getScriptProperties();

  var KICADWS = scriptProperties.getProperty(“KICADWS”);

  if (!KICADWS) {

    var ui = SpreadsheetApp.getUi();

    ui.alert(“Can’t Complete: Did not find a sheet with the right name for the imported Kicad CSV file.”);



  var PARTWS = scriptProperties.getProperty(“PARTWS”);

  if (!PARTWS) {

    var ui = SpreadsheetApp.getUi();

    ui.alert(“Can’t Complete: Did not find a sheet with the right name for the Parts Inventory sheet.”);



  var BOMWS = scriptProperties.getProperty(“BOMWS”);

  if (!BOMWS) {

     var ui = SpreadsheetApp.getUi();

     ui.alert(“Can’t Complete: Need a name for the BoM sheet.”);

     return -1;



 ss = SpreadsheetApp.getActiveSpreadsheet();

  var cvPCBws = ss.getSheetByName(KICADWS);

  var partsws = ss.getSheetByName(PARTWS);

  var BOMws = ss.getSheetByName(BOMWS);

  //the sheet may not exist. In this case, create the sheet

  if (!BOMws) {

    BOMws = ss.insertSheet(BOMWS);



  //get the name/value and quantity rows of the parts in the cvPCBnew file

  //start at row = 1 and column = 1.  The range goes to row = # rows in cvPCBnew worksheet column = 2.

  var nPartsInDesign = cvPCBws.getLastRow();

  var values = cvPCBws.getSheetValues(1,1,nPartsInDesign,2); 

  //get the info on parts to use from the Parts Inventory worksheet

  //The Parts Inventory worksheet should have a row where the name is the same as the valueNameLookup.  I’ll loop through the rows in the worksheet and find it.

  //First, figure out how many rows are in the Parts Inventory worksheet.

  var nParts = partsws.getLastRow();

  //The PartsInventory starts with a header row.  So the actual number of parts is one less than the total number of rows in the worksheet

  var dataRangeOfNames = partsws.getRange(2,2,nParts -1);

  var partsNames = dataRangeOfNames.getValues();  

  //loop through each part in the cvPCBnew worksheet and create a row in the BoM worksheet

  //Using global variables to hold the total costs (see summing these up in the addRowToBOM function and then appending the row at the end of this function)

  onePieceSKUcost = 0;

  oneHundredPieceSKUcost = 0;

  oneThousandPieceSKUcost = 0;

  for (var i = 0;i<nPartsInDesign;i++){

    var valueNameLookup = values[i][0];

    var quantity = values [i][1];

    //locate the row in the parts Inventory worksheet that matches the value name from the worksheet created through cvPCBnew

    for (index in partsNames) {

      var currentPartName = partsNames[index].toString();

      if (currentPartName == valueNameLookup) {

        //the row was located, add it to the BoM worksheet

        //Note: the location of the row within the Parts Inventory worksheet adds 2, 1 for the Header, and another because the array starts at 0 but the worksheet rows start at 1.

        var rowInPartsInventory = +index + 2;

        //I use return to exit addRowToBOM.  If addRowToBOM fails, I return a -1 so the script will stop because of the top level return

        var err = addRowToBOM(rowInPartsInventory,quantity);

        if (err == -1) {







  //Figure out the total cost for units of 1, 100, 1000 and add the info to a row of the BoM worksheet

  var totalRow = [‘TOTAL’,”,”,”,”,”,onePieceSKUcost,”,oneHundredPieceSKUcost,”,oneThousandPieceSKUcost];


   var row = BOMws.getLastRow();

   var boldRange = BOMws.getRange(row,1,1,12);



function addRowToBOM(rowInPartsInventory,quantity) {

    var scriptProperties = PropertiesService.getScriptProperties();

    var BOMWS = scriptProperties.getProperty(“BOMWS”);

    if (!BOMWS) {

      var ui = SpreadsheetApp.getUi();

      ui.alert(“Can’t Complete: Need a name for the BoM sheet.”);

      return -1;


    var PARTWS = scriptProperties.getProperty(“PARTWS”);

    var ss = SpreadsheetApp.getActiveSpreadsheet();

    var BOMws = ss.getSheetByName(BOMWS);

    var partsws = ss.getSheetByName(PARTWS);

    //create an array in which each element is one of the cells in the row of the spreadsheet.

    //*******>The parts inventory worksheet has 9 columns.  getSheetValues(row of interest, column of interest, number of rows, number of columns)

    var partsRow = partsws.getSheetValues(rowInPartsInventory,1,1,9);

    //fill in Category, Value, MFG, MFG_Part

    var BOMRow = new Array();

    for (var i=0;i<4;i++) {

      BOMRow[i] = partsRow[0][i].toString();


    //add quantity

    BOMRow[4] = +quantity;

    //add 1 piece price

    BOMRow[5] = +partsRow[0][4];

    //add 1 piece SKU cost

    BOMRow[6] = +partsRow[0][4] * +quantity;

    onePieceSKUcost = onePieceSKUcost + BOMRow[6];

    //add 100 piece price

    BOMRow[7] = +partsRow[0][5];

    //add 100 piece SKU cost

    BOMRow[8] = +partsRow[0][5]* +quantity;

    oneHundredPieceSKUcost = oneHundredPieceSKUcost + BOMRow[8];

    //add 1000 piece price

    BOMRow[9] = +partsRow[0][6];

    //add 1000 piece SKU cost

    BOMRow[10] = +partsRow[0][6]* +quantity;

    oneThousandPieceSKUcost = oneThousandPieceSKUcost + BOMRow[10];

    //add BUY link (most likely link to Digikey page where part can be ordered)

    BOMRow[11] = partsRow[0][7];

    //add row to BoM worksheet


    return 0


function prepareBOMws(BOMws) {



    //******> ..currently 12 columns are defined

    var headerRange = BOMws.getRange(1,1,1,12);


    var headers = [“Type”,”Name”,”MFG”,”Part”,”Quantity”,”1 Piece Price”,”1 Piece SKU”,”100 Piece Price”,”100 Piece SKU”,”1,000 Piece Price”,”1,000 Piece SKU”,”Link”];


    //turn off bold

    var range = BOMws.getRange(2,1,1,12);









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

Software Debugging the Ladybug Blue Lite



I’m loving the debugging capabilities when programming the nRF51822.  A great feature of the nRF51 DK is its support for programming and debugging of external nRF51822’s – like the one that will be on the Ladybug Blue Lite.  Definitely a YIPPEE moment!! No external SWD debugger is required.  If the nRF51 DK did not include a SEGGER J-Link OB debugger chip with debug out functionality, I would have to buy a debugging probe from Segger that cost between $60 to over $1000 (link to website).  The nRF51 DK is becoming quite a bargain!

The Goal

The goal of this post is to make sure the Ladybug Blue Lite has the correct circuitry to support programming and debugging through the nRF51 DK.  I will have more confidence in the part of the schematic that handles debugging traffic.

Thanks To Those That Went Before

Mahesh Venkitachalem wrote an extremely useful post on external programming of an nRF51822 chip using the nRF51 DK.  Thank you!

Adafruit provided a great prototype nRF51 Breakout Board (the Adafruit Bluefruit LE UART Friend) as well as exceptional tutorials on using the Bluefruit.

And a grateful thanks to Chris Gammell for his Contextual Electronics course as well as his mentorship on electronics – with an emphasis on schematic design, layout, as well as how different circuits work using tools like LTSpice.

The nRF51 support and development team at Nordic for providing a really great forum – the Nordic Developer Zone – where many of my questions were answered.  Their support has proven to be quite strong.  THANK YOU!

Debugging Pins on the nRF51 DK

The nRF51-DK User’s Guide (download link) points out the connectors P19 and P20 are used in support of external debugging.  The pin outs shown in the PCA10028 schematic and PCB document (download link) has the following diagrams for the two connectors:



P19 is the standard Cortex-M 10-pin debug connector.  I don’t have one of these cables so I will use the P20 connector.  As noted by Mahesh in his post, the P20 connector uses the 2.54mm pin spacing that makes it easy to hook up with breadboard wires I already have.  Looking at the layout (image from Mahesh’s post):


Pin 8 is close to R10 and R9.  Pin 1 is closes to current measurement. 

External nRF51822

I’ll use Adafruit’s Bluefruit LE UART Friend for the external nRF51822 that I will program (or debug) to.  The back of the board expose pads for external SWD debugging:

There are four connections that must be made between an external nRF51822 and the nRF51 DK for SWD debugging:

  • Two connections are for SWD debugging traffic.  SWD debugging traffic goes over SWD (data i/o) and SWDCLK (clock).  
  • A 3V reference is required.  If the nRF51 DK detects the 3V power coming from the external nRF51822, it will target programming/debugging on the external nRF51822.
  • GND is required so that the chips share a common ground.



The Bluefruit exposes the SWD, SWC (clock), and 3V on the back.  The GND connection is exposed with the other available connections on the front.


The pin mappings from the P20 connector on the nRF51 DK and the Bluefruit are listed in the table below:

pins P20 Bluefruit
3V 3 3vo

Here is an image of the Bluefruit I used with wires I soldered on:


Here is an image of the Bluefruit connected up on a breadboard:


An an image of the wires connected to the P20 on the nRF51 DK:


Software Test

Notice the lit LED in the image of the Bluefruit on a breadboard.  To test external programming/debugging, I wrote an app for the nRF51822 that turns on and off this light.  The Eclipse project – BlinkyBlueFruit – is located at this GitHub location.

Looking at the Bluefruit LE UART Friend schematic:

Pasted Image 7 31 15 4 32 PM

pins 18 and 19 of the nRF51822 on the Bluefruit have LEDs attached.  I’ll use pin 19.  Here are the lines in main.c:

int main(void)




    // Toggle LEDs.

    while (true)








Memory Location

I’m thankful to Mahesh for pointing out checking the memory allocation for the nRF518122’s Flash and Ram in his blog post.  How much is allocated and it’s starting address are contained within the .ld file.  The .ld file comes along with each nRF51 SDK example and is part of the Make toolchain.  Where there is a Makefile there is a .ld file.  I discussed using nRF51 SDK projects in Eclipse in a previous post.

The chip that is being debugged needs to have the origin and length set correctly within the .ld file.  These values will vary based on the amount of Flash/Ram on the chip and whether a BLE software stack, like the S110 is used (link to S110 specification download).

Flash and Ram

Since I evolve my software from the SDK example, the first question is: Is there a difference in the amount of Flash and/or Ram on the nRF51822 chip used on the Bluefruit versus used on the nRF51 chip used on the nRF51 DK?

The Flash and Ram of the two chips:

  Flash Ram Source
nRF51 DK 256KB 32KB simple_adc_gcc_nrf51.ld
Bluefruit 256KB 32KB

Both the chip on the nRF51 DK and the Bluefruit include 256KB of Flash and 32KB of Ram.

Memory Without the S110 Stack – nRF51 DK

Without the S110 stack, (usually :-) ) an .ld file from the nRF51 SDK sets the Flash and Ram memory to:



  FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x40000

  RAM (rwx) :  ORIGIN = 0x20000000, LENGTH = 0x8000


I copied the above from the simple_adc_gcc_nrf51.ld file.  The amount of Flash = 0x40000 = 256KB.  The amount of Ram = 0x8000 = 32KB.

Memory With the S110 Stack – nRF51 DK

When BLE is added to the software, the values in the .ld file need to accommodate the Flash and Ram used by the BLE stack.  I use the S110 stack.  Here is a .ld file when the S110 stack is included:

FLASH (rx) : ORIGIN = 0x18000, LENGTH = 0x28000
RAM (rwx) : ORIGIN = 0x20002000, LENGTH = 0x6000

When the S110 stack is present, the Ram origin is set at 0x20002000, length = 24KB (i.e.: 0x6000 length).  Note:  Table 2 in the S110 Stack specification (link to download) states the S110 takes 8KB of Ram.  24KB + 8KB = 32KB.  That adds up nicely!

Based on what I read in Table 2, I thought the Flash origin would be 0x14000 (i.e.: 80KB for the S110 stack).  However, the example starts the Flash memory location for the app at 0x18000 – 96KB above 0x0.  Maybe this is so the S110 versions have room to grow?  Of course – I might be misinterpretting because I am not understanding something.


I set up and used the same erase/flash make commands that I had used previously (see earlier discussion of setting up the Eclipse build environment).

It worked!  I have more confidence in what connections are needed on the Ladybug Blue Lite to support SWD debugging.  A definite YIPPEE!!! moment.



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

Using a Battery with the Ladybug Blue Lite

I decided on two Ladybug Blue models – one with pumps and one without.  The one without pump measures the pH and EC.  It doesn’t require a lot of current.  I’ve decided to make a PCB I’m calling the Ladybug Blue Lite that runs off of a battery.  This way, the pH and EC can be measured wherever there is a container of nutrient bath.

But which battery?

The Goal

The goal of this post is to pick a battery topology to power remote measuring of the pH and EC of a nutrient bath.  Results can be read on a smartphone.

Thanks to Those That Went Before

I am very grateful for all I have learned from Chris Gammell and Contextual Electronics.  His mentorship style has given me the confidence to keep at electronics and embedded systems programming even though I have no background in these fields.  I look back a year and get excited thinking about how much I have learned and been able to accomplish from designing a PCB to soldering the chips on the board to figuring out expectations on how the circuits should work.

The Battery

In Chris’s Contextual Electronics course, he mentored us through two topics:

  • battery topologies to drive sensors + microntrollers + 5V motors
  • buck, boost, and buck-boost converters
During one iteration of the power section of the Ladybug Blue Lite I designed for a LiPo battery (note: I found Adafruit’s description of Lithium ion polymer and Lithium ion batteries very helpful).  The Ladybug Blue Lite included the ability to recharge the battery through a USB micro port.

LDO and DC/DC Included

Then I took a closer look at the nRF51822’s data sheet (link to download the data sheet).  And lookey-lookey!
Pasted Image 7 29 15 1 48 PM
According to Table 20 in the data sheet (link to download the data sheet):
A battery can connect directly to the nRF51822 then go through either an LDO or Buck-Boost converter provided by the nRF51822.
 As noted in the nRF51822 product specification (link to download the data sheet):
The nRF51 DC/DC buck converter transforms battery voltage to lower internal voltage with minimal powerloss. The converted voltage is then available for the linear regulator input. The DC/DC converter can be disabled when the supply voltage drops to the lower limit of the voltage range so the LDO can be used for low supply voltages. When enabled, the DC/DC converter operation is automatically suspended between radio events when only the low current regulator is needed internally.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 reference manual goes on to state (link to download):

The DC/DC converter only reduces the power consumption used by the radio, it does not affect the powerused by the Flash, System, and Peripheral.

Enabling the DC/DC converter will not turn it on, but set it in a state where it automatically gets turned on when the radio is enabled and goes off again when the radio gets disabled. This is done to avoid wasting power running the DC/DC in between the radio events where current consumption is too low.

Good to know….Importantly – the heck with including these circuits within the power design of the Ladybug Blue Lite.  This will save additional BoM costs since one of the parts I was considering for the Buck-Boost converter is the TPS63030 which currently costs $2.50 on  Not to mention the price of a LiPo battery and any connectors needed.

Not Designed for LiPo or Lithium Ion

The power supply must be between 1.8 – 3.6V (LDO) or 2.1 – 3.6V (DC/DC).  The LiPo battery I am testing with is rated at 3.7V.  After charging my DMM measures the voltage at 4.2V.  Even at 3.7V, plugging a LiPo battery directly into the chip will damage the chip.  If I were to continue down the path of a LiPo battery, I would explore using the advice given by Stefan in this Nordic Devzone post:
Since a lithium battery voltage is up to 4.2V but the supply voltage for the nRF51822 is 1.8V-3.6V, then I guess an efficient option is to have an external LDO drop the voltage down to 3.6V for the nRF51822, and have the DCDC enabled. Lithium batteries normally have voltage range of 3.0V-4.2V, so you should bypass your external LDO as your battery voltage drops below 3.6V.

Low End Voltage Requirements

That’s the high end of the power source.  What about the low end?  How much voltage is needed?  
    • VDD to the ICs:  There are only two chips to look at – the nRF51822 and the MCP6244 op amp.  The nRF51822’s minimum supply voltage is 1.8 (assuming LDO conversion).  The minimum supply voltage needed to power the MCP6244 is 1.4V.
    • there are three signals the rails of the op amp need to accommodate:
      • ph:  +/- 415 mV
      • Wien Bridge: ~ +/- 550mV
      • Gain Loop: the amplitude of the gain loop is controlled by pre-scaling the Wien Bridge wave form using a voltage divider.  Typically, the max gain for the scenarios the Ladybug was designed for (discussed in earlier posts) is 6.  If the Wien Bridge is shrunk to +/-150mV, the max amplitude of the gain loop is +/- 900mV.
    • using the on-board DC/DC (buck) converter requires a minimum of 2.1V. 
Thus the minimum voltage needed is ~ 2.1V
To be conservative, I will design for the absolute minimum voltage to be 2.4V.

Which Battery

I decided to go with what is used with the nRF51 DK – a CR2032 coin cell battery.


Looking at the data sheet for the CR2032 that came with the nRF51 DK (the Energizer CR2032), the voltage starts off at 3V:


The CR2032 provides more than enough current at 240mAh.  

Now I’ll update the design and also put together a circuit that checks the voltage level.  It certainly rings true to me that peeling an onion exposes a bag of more onions..



Thanks for reading this far.  I hope you find many things to smile about.


Switching from the ADS1015 to the nRF51822’s ADCs


, ,

The nRF51822 comes loaded with eight configurable ADC channels.  Why not take advantage of them?  I am evolving the design of the Ladybug Blue Lite to use the nRF51822’s ADCs instead of the ADS1015 + MUX.  In the previous plan, six op amps were used.  One for VGND, one for pH, and four for EC (one for Wien Bridge, one for the Gain loop, and two for rectification).  Then a MUX switched between VOUT and VIN signals.  Removing the MUX means two more op amps are needed to participate in rectification.  Now, instead of a MCP6242 and MCP6244, the Ladybug Blue Lite will use two MCP6244’s.  Another benefit is the reduction in complexity.  I see the complexity reduction to be highlighted most in the firmware.  Previous to this change, I used a timer to give about 10 seconds wait between measuring VIN and VOUT to allow the effect of switching signals to work it’s way out of the circuit.

The change to the BoM is:

Ladybug Blue Lite with ADS1015:

Total= $3.89
Ladybug Blue Lite without ADS1015:
  • no ADS1015
  • no MUX
  • exchange MCP6242 for MCP6244.  The MCP6244 costs $.68.  $.68 – $.43 = $.25
  • one additional MOSFET: $.17
Savings: $3.89 -$.25 – $.17 = $3.47 -> a significant savings!

The Goal

The goal of this post is to understand and evaluate the nRF51822’s ADC for pH and EC measurements.

Thanks to Those That Went Before

I am truly grateful to:

  • Chris Gammell – I continue to learn A LOT from his Contextual Electronics course.  Recently, the “Full Charge Ahead” section was a great introduction to designing and laying out LiPo batteries.  Chris is also an amazing mentor.
  • Ryan of Sparky’s Widgets has made it so much easier for us to sense pH and EC readings.  I started with Ryan’s schematics and design of the minipH and miniEC boards and have evolved my designs from there.  The work I am currently doing proudly stands on the shoulders of Ryan’s.  Thank you.
  • Adafruit for their attention to learning and support.  There is so much great stuff on their site!
  • OSH Park for their excellent PCB fabrication service and hiring such terrific folks that really care about the support.

What is Good Enough

I am not concerned with sampling rate.  But resolution is a factor.  The nRF51822’s maximum resolution is 10 bits.  The ADS1015 has a 12 bit resolution.  Is the loss in resolution going to negatively affect my goal of pH and nutrient adjustment?  It shouldn’t.  In an earlier post, I noted the minimum resolution for pH is 8 bit.  With EC, the VIN, VOUT, and VGND are all measured.  It should be fine for the resolution to be 10 bits.

Running a Test

To see if I can get expected results, my first test will measure VGND when the power source = 3.3V.  VGND measures 1.6V.  The test code I used (ADC_Simple) is available at this GitHub location.  It is zipped into an Eclipse project (Note: There are some hard coded paths that you would need to modify – mostly in the makefile).

ADC Configuration

The ADC HAL SDK documentation notes the following settings for the default configuration:

  • 10 bit resolution
  • 1/3 prescaling
  • internal 1200mV VREF
The 1/3 persecuting makes sense given VREF = 1200mV.  VOUT could be between 2.5-3V.  If it is at 3V, a pre-scaling of 1/3 allows the value to be correctly read (i.e.: 3000/3 -> 1000, which is below 1200mV).


VGND = 1.6V when measured with my DMM on my test setup.  Running the ADC_Simple (GitHub location) within Eclipse, the reading from the ADC with the default settings = 450.  Converting this to millivolts:
  • 10 bits = 1024 steps (0 to 1023)
  • reference = 1200mV
  • post-scale factor = 3
VGND mV = (1200mV/1023)*450*3 = 1584 mV, close enough to 1.6V.  The reading for VGND looks good enough.


VOUT = 2.5V on my test setup.
ADC reading = 700 = 1200/1023*700*3 => VOUT =  2463 mV


VIN = 1.77 on the test setup.
ADC reading = 492 = (1200/1023)*492*3 => VOUT =  1731 mV
I note aall ADC reading are slightly scaled down.  This is to be expected as noted in this post.  Since all scale down, the results for the gain even out.  That and different circuits are measuring the voltage value so it is expected there will be variability.  I see this as reasonable variability.

Calculating the Resistance

While calculating the resistance isolates how accurate the circuit is, I’m curious to know how close the measurements came to the 200Ω resistor I am using in the test setup to represent an EC probe.
Resistance = 1K (i.e.: the feedback resistor I am using)/Gain-1
These readings are relative to VGND:
  • VOUT relative to VGND = 2463 – 1584 = 879mV
  • VIN relative to VGND = 1731 – 1584 = 147mV
Gain = VOUT/VIN = 879/147 = 5.98
Resistance = 1000/4.98 = 200.8Ω…pretty darn close!
So there we have it.  I’m going ahead and update the design to use the ADCs on the nRF51822.
That’s it for now. Thank you for reading this far.  Please find many things to smile about.

Measuring EC VIN and VOUT Using a Prototype Circuit and the nRF51822



Yesterday I spent around 3 hours putting together the pH and EC circuits on a breadboard.


The pieces of the prototype circuit consist of some sections of the circuit that I milled on the Othermill, a few components on SMT-> DIP boards, and Adafruit’s ADS1015 BoB.  All…gulp…wired together….if I don’t breathe…the circuit works.

I then set up a DMM, a scope and an I2C logic analyzer to test.

I hard code the EC probe’s resistance value by using a 200Ω resistor.  To be more exact, the resistor actually measures 198Ω.  This way I’ll know if my tests can get reasonably close to the resistor value.  Recall from previous EC tests that to calculate the EC:

  • measure VIN and VOUT in order to calculate the Gain from the EC probe’s resistance.  I.e.: Gain = 1+ VOUT/VIN
  • calculate the resistance and conductance read from the EC probe:  The layout specifies a 1K feedback resistor.  So R(measured) = 1K/Gain-1 and the EC value in Siemens is 1/R(measured)

to test, I put together an Eclipse project.  The project is located at this GitHub location (the ADS1015_Test.Zip).  I decided zipping up Eclipse project at different working states is an easy way to start testing since all the include files, code, makefile, debugging options… changes are there. 


Test 1: Measure VIN and VOUT using ADS1015_Test Project

Recall VIN is the DC peak value determined from the Wien Bridge Oscillator.  VOUT is the DC peak value determined from the gain loop in the EC circuit. The VOUT is amplified by how much the EC Probe (in this case the 200Ω resistor) amplifies the VIN signal.

For this test, I will “hard code” the MUX.  


Measuring VIN

When the MUX pin = GND, the signal to the ADS1015 is the VIN.  When the MUX pin = power source (in this case I am testing with a 3.3V power source), the signal sent to the ADS1015 is VIN.

I start with the MUX pin connected to GND.



I use the debugger and open an Jlinkrttclient session within terminal.  As shown above, the value I got from the ADS1015 for VIN = 2012.  I had set the ADS1015’s resolution (also called perhaps confusingly the gan) to GAIN_FOUR, which means each LSB of the ADC = .5 mV.  So VIN = 2012*.5 = 1006mV.  Hmmm…I was expecting a value of around 200mV.  Something is not right….

Measuring VOUT

Moving the MUX pin to VDD, I rerun the test program and get VOUT = 2028.


The value of 2028*.5 = 1.014V is pretty much what I was expecting for VOUT.  


Debugging VIN

I should be seeing VIN close to 200mV and VOUT close to 1000mV.  What’s going on with VIN?  The first debug test I’ll do is to look at the values going into the ADS1015 AIN1 pin.  This is the pin for VIN and VOUT after rectification (I discuss all this in detail in previous posts.  It takes me a bit longer than I want at this point to back link to these older posts…).  So the question I am answering is: What values does the ADS1015 receive as input prior to sending them over to the nRF51822 via I2C?







Scope measurements:

  • VGND = 1.8
  • VIN = 1.92 – 1.8 = .12V
  • VOUT = 2.8 – 1.8 = 1V
The scope values are closer to what I expected.  Before I unpack the I2C traffic, I’m going to check the code.  Perhaps the data type that I use within the ADS1015 library is not the right one to return ADC values.  These need to match.  First looking at Adafruit’s Arduino library for the differential, I note the function returns an int16_t:
int16_t Adafruit_ADS1015::readADC_Differential_0_1()
In my library, I’m returning an int16_t: 
int16_t readADC_Differential_VGND(nrf_drv_twi_t const * const  p_instance,int P)
In main.c, I set the variable to receive the reading to uint16_t:
 uint16_t rawADC = readADC_Differential_VGND(&twi,1);
Changing this to int_16_t, I get the following readings:
  • VIN = 318*.5 = 159mV
  • VOUT = 318*.5 = 159mV
Sigh…this makes me think there are cached buffers holding onto the value in between readings.  The first time I started with VOUT.  The second VIN.  Coincidence?
One more time… Here is a reading for VIN:
Looking at the I2C traffic:
Packet ID Address Data Read/Write ACK/NAK
0 0x90 0x01 Write ACK
0 0x90 0xA7 Write ACK
0 0x90 0x83 Write ACK
1 0x90 0x00 Write ACK
  0x91 0x13 Read ACK
  0x91 0xC0 Read NAK

Looking at the ADS1015 data sheet (p 8 on the data sheet I’m looking at)

  • byte 1 to Address 0x90 -> ADS1015 address (see this link for how to figure out the ADS1015 address from 0x90).  Data = 0x01-> write to the config register
  • byte 2= 0xA7 = b1010 0111->MSB of what to write to the config register
  • byte 3 -> 0x83 = b1000 0011-> LSB of what to write to the config register

p. 15 of the data sheet has the map to what the config write bytes mean:


Looking at the explanation of the MSB config bytes (p. 16)

MSB = b1010 0111

  15 14 13 12 11 10 9 8
BIT 1 0 1 0 0 1 1 1
  • Single shot reading (bit 15)
  • AINp = AIN1 and AINn = AIN3 (bits 14-12)
  • programmable gain = +/1 1.024V (GAIN_FOUR) (bits 11-9)
  • Power-down single-shot device operating mode (bit 8)

so far so good.  Now onto the LSB = b1000 0011

  7 6 5 4 3 2 1 0
BIT 1 0 0 0 0 0 1 1
  • 1600SPS datarate – the default. (bits 7-5)
  • Default comparator mode (bit 4)
  • Default comparator polarity (bit 3)
  • Default latching comparator (bit 2)
  • Disable comparator (bits 1-0) – which I assume means bits 4-2 are ignored.
So the config bytes seem to be set up correctly.  Back to the I2C traffic:
  • byte 4 -> write to the ADS1015, data = 0x00 which means write to the register that contains results (the “Conversion register”)
  • byte 5 -> 0x5F – the MSB byte of the ADC reading
  • byte 6 -> 0xE0 – the LSB byte 
So the ADC reading = 0x13C0.  This isn’t the value, because the data sheet notes the Conversion register’s first 4 bits are unused (see Table 8 on p. 15):
Shifting over 4 bits,  0X13C0 -> 0x013C = 316…which is identical to what the API returned.  I decided to include the logic behind handling an ADC reading that is negative:
Values are stored in two’s complement.  This makes Adafruit’s code that reads the ADS1015 more sense:

// Read the conversion results

  uint16_t res = readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift;

  if (m_bitShift == 0)


    return (int16_t)res;




    // Shift 12-bit results right 4 bits for the ADS1015,

    // making sure we keep the sign bit intact

    if (res > 0x07FF)


      // negative number – extend the sign to 16th bit

      res |= 0xF000;


  • use a uint16_t to store the value that comes back from the ADS1015
  • check if the 12th bit is a 1 (i.e.: 0x7FF = b0111 1111 1111…anything above 0x7FF – say 0x800 – has a 1 in the most significant bit, making is a negative value.  So extend negative throughout the 16 bits and return an int16_t

After working through a few more results, I’m thinking the challenge is actually the rectifying part of the circuit.  In the prototype I take a shortcut and make a rectifier with just an opamp, diode, and cap.  I wanted to try this over the more complicated FET solution I was using.  However, I’m thinking because the MUX causes such a fluctuation between signal switching, the FET solution is what I should use.  The results I am seeing is most likely an artifact of the rectifier since the signals are switching correctly.

Well – that was a good test session.  I got a much better feel for the meaning between the I2C packets.  I also validated the API is returning the same results as what I2C is returning and the configuration settings of the ADS1015 have been set correctly.


Now I’ll rebuild the rectifier circuit to go back to the one on the Ladybug Shield.


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


Get every new post delivered to your Inbox.

Join 26 other followers