From Kicad to Digikey -> MakeDigikeyBOM Code Review: The Python Scripts

Tags

, ,

I continue my quest to document the MakeDigikeyBOM Python package I built.

The Goal

The goal of this post is to familiarize us with the structure and purpose of the MakeDigikeyBom Python package and individual modules.

Thanks to Those That Went Before

As I noted in my previous post, I could not have gotten this far this quickly without the prior work of debvisme(xesscorp).  He is the author of Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  Kicost is well worth checking out.  The GitHub location is here.  

Open Source

The MakeDigikeyBom Python project is located at this GitHub location.

Flowchart

I am self-taught when it comes to making flowcharts.  I mention this because flowcharts I make don’t conform to a standard.  This may make them more difficult for you to read.  I apologize for that.  However, I find the method I use to work for me.

Here is the flow chart of MakeDigikeyBOM at the highest level:

NewImage

 

I have built two (well, actually three) Python files:

  • __main__.py : This is where the majority of the high level command/control happens.
  • makeDigikeyBOM.py: Takes the bom2csv and JellyBeanPartNumbers files and creates a MadeDigikeyBOM.csv file or a list of errors that must be fixed in either the bom2csv or JellyBeanPartNumbers files before the MadeDigikeyBOM.csv files can be generated.
  • __init__.py: I put this in because it identifies a bunch of Python files as a Package (at least in Eclipse).  I don’t know enough about Python to use it to an advantage.

The first thing is to gather user input.  The pieces of info include:

  • The full name of the bom2csv file.  The bom2csv file was discussed in a previous post.
  • The full name of the csv file that contains the jellybean parts.  As with the bom2csv file, the jellybean parts file was discussed in a previous post.
  • The directory path where MadeDigikeyBOM.csv will be written.
  • Currently the “num_processes” field is not used.  I got this field from the Kicost Python script and thought implementing is probably a good idea.  Having this input argument is a placeholder for a potential future feature.

 Since I run Python within the Eclipse environment, I enter arguments to MakeDigikeyBOM through the debug/run configurations.  Here are the files I used:

Pasted Image 3 14 16 5 32 AM

The code in __main__.py checks to see if the bom2csv and jelly bean parts files exist.  The script exists if either file does not exist.

If the files exist and the directory to contain MadeDigikeyBOM.csv exist, the __main__.py calls into makeDigikeyBOM() which is in the makeDigikeyBOM.py file.

That’s all there is to the high level part of the code.  

What’s Next

In the next post I’ll cover the makeDIgikeyBOM.py file.

 

 

 

 

 

From Kicad to Digikey – Start of MakeDigikeyBoM Code Review – Walk Through of Block Diagram

Tags

, ,

In my previous post, I discussed my reason for creating yet another Python script to convert Kicad schematics into a BoM spreadsheet with pricing info from Digikey.  This post is a continuation.  Since the first post I am happy to say I have gotten all the goo to work and was able to use the MadeDigikeyBOM.csv to order parts from Digikey.  So far I am excited with the results.  I find them a terrific time saver (of course, learning python and getting all this to work takes A LOT more time than doing one schematic -> BoM by hand…but YIPPEE! What a learning opportunity…and I plan for plenty more schematics.

The Goal

The goal of this post is to start a code review MakeDigikeyBoM python project.  I’ll cover the block diagram I created to represent the “big picture”.

Thanks to Those That Went Before

I could not have gotten this far this quickly without the prior work of debvisme(xesscorp).  He is the author of Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  Kicost is well worth checking out.  The GitHub location is here.  The code I used the most was the script that scrapes the Digikey pages.  I learned a lot about the Kicad XML and various Python techniques from other sections of the code.

The folks who created the Beautiful Soup library for Python.  Beautiful Soup is incredibly useful/well done to parse XML files.

Open Source

The MakeDigikeyBom Python project is located at this GitHub location.

Updated Block Diagram

I like to start by doing a fly by of a block diagram.  I had done an initial block diagram in the previous post.  The block diagram evolved as the design and implementation evolved.  Here is the updated block diagram

NewImage

A

Input from a Kicad schematic.  The important component Value and PN properties are important to this process.

For example, here is an image of Ladybug Blue’s Schematic with it’s hierarchical sheets:

NewImage

Each schematic component has a PN field and Value field.  The PN field must contain one of the following:

A1

The schematic component D1 (RED_LED) with a manufacturer part number PN = XPEBRD-L1-R250-0061.  When the PN is a manufacturer or Digikey part number, the value field is not used:

NewImage

A2

The component C1 has a Jelly Bean PN = C and Value of .1u:

NewImage

When MakeDigikeyBoM modifies the <outputFrom_bom2csv>.xml file, the created <modified_outputFrom_bom2csv>.xml file replaces the PN field value to the digikey part number CS21F104XZBCNNNC.  This is the part I chose for all .1u capacitors.

 

NewImage

A3

The P5 component has None in it’s PN field value:

NewImage

A component with None in the PN field tells MakeDigikeyBom that this component is not purchased through Digikey.  The Value field is ignored.

B

Use the bom2csv plug-in to create the “BoM” XML.  The bom2csv plug-in was discussed in my previous post. The XML branch that is the most important to the DIgikey BoM creation process is the <comps> branch.  As the tag suggests, this is where the component info is found.

Here are the <comp> properties for the three types of PN discussed above.

A None <comp>

NewImage

Here, the PN = None.  The Value=BNC, but that isn’t used by the Digikey BoM process.

A Jelly Bean <comp>

NewImage

In the above, component C1 is a .1u of part type C.  The Value = .1u is used by the process.

A Manufacturer or Digikey Part Number

NewImage

As when the PN=None, the Value field is not used.  In this case, the PN number is passed directly into the screen scraping section of the Digikey process.

C

The first part of the MakeDigikeyBoM Python script takes in the output from bom2csv discussed under “B” above and creates an intermediate file that is then used by another part of the Python script.  The intermediate file is in the same XML format as the file created by bom2csv.  The properties for <comp> components that use a Jelly Bean PN have been replaced by looking up the PN / Value field in the JellyBeanPartNumbers.csv file with the part number that must be should be either the Digikey or manufacturer part.

D

For the C1 Jelly Bean <comp> listed above, the PN = C and the Value = .1u.  The Python script looks for the row in the JellyBeanPartNumbers.csv file:

NewImage

in this case, the manufacturer part number = CL21F104ZBCNNNC.  The modified bom2csv file replaces the <comp> tag for C1 with this part number:

NewImage

E

The Python script creates a URL with the PN as keyword to the Digikey web site.  The URL is pretty much what we might use when searching for this part:

url = ‘http://www.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&keywords=CL21F104ZBCNNNC” 

The html is parsed by BeautifulSoup into a fairly easy to access html tree.

There is a whole bunch of Goo in the Python script to scrape through the html and parse it out into the MadeDigikeyBoM.csv file.  If all goes well, the MadeDigikeyBoM.csv file is created.  For example:

NewImage

I realize the image is rather small…here is the row for .1u capacitors:

C13,C11,C17,C16,C3,C2,C1,C7,C6,C5,C4,C18

.1u

12

CL21F104ZBCNNNC

1276-1007-1-ND

0.1

0.031

0.0144

0.00783

792969

http://www.digikey.com/product-detail/en/samsung-electro-mechanics-america-inc/CL21F104ZBCNNNC/1276-1007-1-ND/3889093

There are 12 .1u capacitors.  The price per 1 = $.10, 10 = $.031, 100 = $.0144, and 1000 = $0.0144.  Digikey has 79,269 of these capacitors in stock.  The link to the Digikey page is included.

Challenge

The challenge is this part of the script will need to be updated when Digikey updates the web page.  This – of course – is true of any web page scraping process.

What’s Next

I’ll start going over the Python modules in the next post.  I’ve posted the Python scripts at this GitHub location.

 

 

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

From Kicad to Digikey -> Generating a BoM based on eeSchema – Overview

Tags

,

This is my latest ‘sacrificial draft’ to generate a BoM csv file with Digikey prices based on schematic files I create in Kicad.  Once I’m done with layout, creating a BoM from the components in the schematic is tedious and time consuming.  So I jump on the already heavily populated bus of folks using Python to automating the workflow going from eeSchema to ordering parts.

I will refer to this effort as MakeDigikeyBOM.py to reflect I pretty much only shop for chips on Digikey and the tool is written in Python.  Since I am fumbling about with Python for my own use and I stick to Digikey for my chip supplier, I have “hard coded” Digikey into the process.  All of this could be expanded and be made more robust.  Right now “it works good enough for me” and really is a sacrificial draft.  

Thanks to Those That Went Before

I wanted to start with saying how very grateful I am to devbisme (xesscorp) for Kicost – Python that “build(s) cost spreadsheet for a Kicad project.”  The GitHub location is here.  There is a very good chance Kicost is all you need.  It is certainly worth checking out if you use Kicad and want to automate BoM creation!  I chose to evolve Kicost to MakeDigikeyBOM.py to enhance with two features I feel are important:

  • The ability to not have to enter the part number within the schematic for jelly bean parts (capacitors, resistors,…)
  • Viewing the 1, 10, 100, 1000 unit pricing of parts.  This way I might order more parts even though I need less to lower the price per part.

The Goal

The goal of this post is to provide an overview of my MakeDigikeyBOM.py effort.  To do this, I will take a simple schematic created in Kicad:

I call this Kicad project myTestDigikeyBOMCreation.

 … i.e.: a schematic that is just a bunch of components…

and run it through MakeDigikeyBOM.py to create  a csv file that provides Digikey pricing info built by scraping the Digikey pages associated with the manufacturer part number:

Block Diagram

The Block diagram gives us a picture of the workflow I have defined to go from components within eeSchema to a csv file with the pricing info from Digikey – as shown in the image above:

BlockDiagramGoogle

Block Diagram

Components

You create your schematic by adding components – these are within the left blue circle of the block diagram.  Each component has a very important field, the PN field.  This is a custom field added to the components.  Kicad lets us add custom fields.  The Kicad documentation at this point gives direction on how to add a custom field like PN.

There are two types of components:

  • Manufacturer
  • Jelly Bean
The RED_LED component is an example of a manufacturer component:

 

The capacitor is an example of a jelly bean component:

The Value field becomes important when using a jelly bean component.  A Jelly Bean component is reconciled to a manufacturer part number using a Python script that matches the PN value (in this case ‘C”) and the Value in the value field (in this case .1u) to a row in a csv file that maps these two properties to a manufacturer’s part number. 

Jelly Bean Part Numbers

I created a Google spreadsheet that I named JellyBeanPartNumbers.  Here is an image of a few of it’s rows:

JellyBeanPartNumbers

I export the rows (which includes the header row) to a file named JellyBeanPartNumbers.csv.  This is the second blue circled area on the Block Diagram.  This csv file is used as input into the MakeDigikeyBOM.py script. 

bom2csv

The first step in the process of going from eeSchema to a BoM spreadsheet is running bom2csv.  bom2csv is a plugin for eeSchema that (at least for me!) is included with the Kicad install.  For more info on bom2csv, see the Kicad documentation on eeSchema (see this link, go to section 3.1 “Using eeSchema” then scroll down to #58 – where creating a BoM is discussed).  

bom2csv creates an XML and a csv file.  We’ll be using the XML file as input into MakeDigikeyBOM.py.  This is the file named <outputFrom_bom2csv>.csv in the above Block Diagram.  I use < filename > to represent a name that will change based on the name of the Kicad project.  In this example, the Kicad project is named myTestDigikeyBOMCreation.  The XML file that is created is named myTestDigikeyBOMCreation.xml.

We’re now ready to run MakeDigikeyBOM.py.

MakeDigikeyBOM.py

MakeDigikeyBOM.py is a bunch of Python Goo that takes in:

  • the XML file created after running bom2csv.
  • JellyBeenPartsNumber.csv.
I’ll discuss MakeDigikeyBOM.py in more detail in my next post.
 
 
Thanks for reading this far.  Please find many things to smile about. 

Using Python and a PLIST to Get pH and EC Values for a Plant into an iOS Swift App

Tags

, , , ,

The EC and pH level of a nutrient bath will be different depending on the plant type.  The Ladybug client software – at least initially an iOS app – gets the plant type from the user and then uses this info to determine the best pH level and nutrient level for the nutrient bath.  This way, the user doesn’t have to constantly look up what the pH and EC values should be.  For example, according to this table, a basil plant does best when the pH is between 5.5 and 6.5 and the EC is between 1.0-1.6mS.  This table says a tomato plant does best when the pH is between 5.5-6.5 and the EC is between 2.0-5.0.  I want to have a table/data base of plant types with the pH and EC values I need to set the nutrient bath.

The Goal

The goal of this post is to build a workflow that scrapes pH and EC values for herbs and vegetables from web sites and create a plist that can be used within an iOS app as an easy to use dictionary.  

Open Source

The files I used include:

Design Choices

  • plists or Core Data:  iOS has many ways an app can read/write a table of data.  I narrowed the choice to using either Core Data or plists.  I chose plists because the table of pH and EC values will most likely be less than 100 (although I assume I’ll be adding other plants over time) and the lookup is very simple – given a plant type, what should the pH and EC values of the nutrient bath be at?
  • Tool to scrape web pages and create plist: I chose to use the Python that is installed on my Mac’s OS X – Python 2.7 – and PyDev – the Python Eclipse plug-in.  The BeautifulSoup package makes it extremely easy to scrape web pages.

Code

Python

Scrape_pH_and_EC_into_plist.py (located at this GitHub location) scrapes:

for the pH and EC values of vegetable and herbs.  There are many sources for pH and EC values.  I am not sure which has the “best” values so I am starting with the values on these pages.  I use these because they come up near the top of Google searches for vegetable/herb pH/EC values.
 
The pH and EC values are text ranges like 5.5-6.5.  Python made it easy for me to parse these into the two numbers: 5.5 and 6.5, take the average and use that value as the “best” value for (in this case) the pH value of 6.0.
 
The plant name as well as the pH and EC values are written out into the file named pH_and_EC_values.plist .

Swift

I’m writing the Ladybug client in Swift.  I used a Playground to figure out the structure I wanted for the plist file as well as the Swift code I will use to access the pH and EC values.  I ended up deciding on a structure for entries within the plist to be:

<key>Basil</key>
     <dict>
          <key>pH</key>
          <string>6.0</string>
         <key>EC</key>
        <string>1.3</string>
     </dict>

I put a copy of the plist that is created from Scrape_pH_and_EC_into_plist.py at this GitHub location.

Here is the code I wrote in the playground to test accessing the entries in the plist:

//: Playground – noun: a place where people can play

 

import Foundation

if let path = NSBundle.mainBundle().pathForResource(“pH_and_EC_values”, ofType: “plist”) {

    print (“Path to plist: \(path)”)

    let fileManager = (NSFileManager .defaultManager())

    if fileManager.fileExistsAtPath(path) {

        if let plants = NSDictionary(contentsOfFile: path) {

            for key in plants.allKeys as! [String] {

                let plant = plants[key]

                print(“plant: \(key) pH: \(plant![“pH”]) | EC: \(plant![“EC”])”)

            }

        }

    }

}

In order to use a plist within a Playground, the plist file must be added to the Playground’s Resources folder. For example, I added a Resources folder within the Playground file I used (located at this GitHub location):

 

 

Debugging in a Playground with XCode 7

There seems to be some tweaks to displaying results in XCode 7. The tweaks confused me so I thought I’d document them here.  This will probably change in an upcoming release.

I ran across some settings that needed tweaking before the debugging experience was adequate.  Prior to changing settings, I would get very little info on what was going on.  For example: 

 

In the above example which I pulled from a Stackoverflow posting, notice how debugging just shows there are 4 items.  Viewing details just shows the last item.  To fix this, I had to hover over the popup that shows results and right click to change the view from “Latest Value” to “Value History”.

 

The other thing to do is to show the debug area by clicking the button on the far left:

 

 That’s it for now.  Thank you for reading this far.   Please find many things to smile about. 

Code Review and Error Handling: Ladybug Lite Blue

Tags

, , ,

Update (1/2-/2-16) Nordic just posted a useful article on nRF51 SDK error codes here.

I just finished a code review with Ron.  I wanted to capture a few of the recommendations Ron made.

The Goal

The goal of this post is to capture what I consider the biggest changes I will make to the existing Ladybug Lite Blue firmware as well as future coding based on Ron’s feedback.

Thanks To Those That Went Before

I was thrilled to have 1:1 time with Ron for a code review as an outcome of the Contextual Electronics course.  What a terrific opportunity to evolve my firmware programming abilities.  Ron did not disappoint. 

Open Source

The Ladybug firmware I am writing about in this blog post can be found at this github location.  Doxygen documentation is included within the Eclipse project’s Documentation/html/Search folder (see index.html).

I’d be grateful for feedback on how to improve the code. 

#define versus static const

My “NEW! IMPROVED! …Rule of Thumb:”

  • Use #define for magic numbers that are global in scope.  Use static const for variables that span functions within a .c file because:
    • #define is global in scope – which means there is a greater chance for conflicting use.  I might use a #define to name a time out period to 10 (#define TIMEOUT 10) and then use the same name within another .c file with a time out period of 20 (#define TIMEOUT 20).  Using the “static” keyword keeps the variable within the scope of the .c file.
    • static const variables are strongly typed.  I’m telling the compiler the exact data type to use for the variable.
    • the code is more readable.
Example of a magic number that is global in scope from the nRF51 SDK (ble_gap.h):

/**@brief GAP device name maximum length. */

#define BLE_GAP_DEVNAME_MAX_LEN           31

 Example where I should have used static const.  In the Ladybug_Hydro.c file I had:

/**

 * \brief mapping the FET pins to the schematic

 */

#define EC_VIN_FET0

#define EC_VOUT_FET7

I changed these to:

/**

 * \brief mapping the FET pins to the schematic

 */

static uint32_t m_EC_VIN_FET=0;

static uint32_t m_EC_VOUT_FET=7;

  • avoid making any changes to any bit of the code of an external SDK (like Nordic’s).  For example, I started changing stuff like:

#define APP_ADV_TIMEOUT_IN_SECONDS      0

to:

static uint32_t const      m_app_adv_timeout_in_seconds = 0;

I would have preferred to use a static const instead of #define however the SDK requires a precompiled value since it is used within another #define.
Note: I name variables m_<variable name> to identify variables that are scoped to a .c file (versus local to a function).  

Error Handling

I like the way the Nordic SDK supports error handling.  My code as well as SDK code are peppered with:

APP_ERROR_HANDLER(err_code);

and

APP_ERROR_CHECK(err_code);

both are #define’d in the app_error.h file of the nRF51 SDK.  These resolve into calling error routines I defined within main.c:

/**@brief Callback function for asserts in the SoftDevice.

 *

 * @details This function will be called in case of an assert in the SoftDevice.

 *

 * @warning This handler is an example only and does not fit a final product. You need to analyze

 *          how your product is supposed to react in case of Assert.

 * @warning On assert from the SoftDevice, the system can only recover on reset.

 *

 * @param[in] line_num   Line number of the failing ASSERT call.

 * @param[in] file_name  File name of the failing ASSERT call.

 */

void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)

{

  app_error_handler(DEAD_BEEF, line_num, p_file_name);

}

/**@brief Function for error handling, which is called when an error has occurred.

 *

 * @warning This handler is an example only and does not fit a final product. You need to analyze

 *          how your product is supposed to react in case of error.

 * \note I decided to use the SEGGER_RTT printing functionality.  My understanding is the SEGGER_RTT calls can be left in code with no effect

 * when there is no terminal to output.  The con of this approach is I can’t hook up a UART enabled terminal session and see what is going on without the debugger present.

 *

 * @param[in] error_code  Error code supplied to the handler.

 * @param[in] line_num    Line number where the handler is called.

 * @param[in] p_file_name Pointer to the file name.

 */

void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)

{

  // This call can be used for debug purposes during application development.

  // The SEGGER_RTT APIs will not cause a problem in production so I’m leaving them in.

  SEGGER_RTT_WriteString(0,“—>>>BUMMER!! In app_error_handler\n”);

  SEGGER_RTT_printf(0,“error code: %d (or 0X%X if assert..base for BLE = 0x3000) Line number: %d file name: “,error_code,error_code,line_num);

  SEGGER_RTT_WriteString(0,p_file_name);

  SEGGER_RTT_WriteString(0,“\n”);

  //  ble_debug_assert_handler(error_code, line_num, p_file_name);

}

For now, error checking ends up printing out information about what/where the error occurred.  This has led to quickly figuring out where the error is and an idea of why it is happening.  In the future I could see mapping these error routines to LED indicators.  I use the SEGGER_RTT APIs because they are robust and work when the code is running in both run time and debug mode. Contrast this version of printf to the serial port to what I discussed in this post.

Checking for NULL Pointers

The basic point here is to check input values of called functions.  This is simple stuff that I should just do. For example, I was not checking for NULL pointer input to functions.  For example, I would pass in  a pointer to an int16_t array:

static void get_EC_reading(int16_t *p_EC) {

and assume p_EC pointed to a valid address.  I added in a simple check:

  if (p_EC == NULL){  //Shouldn’t be passing in a null pointer given the EC Vin and Vout values are planned to be stored at this memory location.

      APP_ERROR_HANDLER(LADYBUG_ERROR_NULL_POINTER);

  }

I also added error codes unique to the Ladybug to the Ladybug_Error.h file. 

Implement Time Outs

When using the pstorage APIs to access the nRF51822’s flash, the Nordic examples use code that has the potential to hang the system if feedback from the pstorage is not given to the pstorage handler in my code.  The pstorage APIs manage access to flash when the BLE stack is running.  This allows the BLE stack to figure out when it is safe to read from and (more difficult!) write to flash.  The function ladybug_Flash_Init() in the Ladybug_Flash.c file registers the ladybug_Flash_handler() function to be called back when a flash activity has completed.  The ladybug_flash_read() and ladybug_flash_write() functions rely on the static variable m_mypstorage_wait_flag to let them know when the flash action has been completed.  These functions wait until completion.  If the ladybug_Flash_Handler() is never called, the program will hang without having an app timer set up to fire after an amount of time.  I discuss using the nRF51 SDK’s app timers in this post.  Here is the code I use to surround a flash action.  In this case within ladybug_flash_write():

 // Start the timer up again to timeout if writing to flash doesn’t happen

  start_timer();

  m_mypstorage_wait_flag = 1;

  err_code = pstorage_store(p_handle, p_bytes_to_write, num_bytes_to_write, 0);

  while(m_mypstorage_wait_flag) {  }

  APP_ERROR_CHECK(err_code);

  stop_timer();

If the timer fires, the caller’s call back function is invoked.  This returns an error code to the caller.  It is then up to the caller to act on the error code.  Here is the definition of ladybug_flash_write() showing how the call back function did_flash_action() is included within the call to ladybug_flash_write():

void ladybug_flash_write(flash_rw_t what_data_to_write, uint8_t *p_bytes_to_write,pstorage_size_t num_bytes_to_write,void(*did_flash_action)(uint32_t err_code));

I call ladybug_flash_write() in main.c.  Thus main.c also include the call back function:

/**

 * \callgraph

 * \brief call back from Ladybug_Flash.c to let us know if the flash write was successful (or not)

 * @param err_code          0 if successful

 */

void did_flash_write(uint32_t err_code) {

  if (err_code == 0) {

      SEGGER_RTT_WriteString(0,“…Flash write SUCCESS!”);

  }

  else {

      APP_ERROR_HANDLER(err_code);

  }

}

That’s it for now.   Thank you for reading this far.  Please find many things to smile about.

Ladybug Lite Blue – A Tale of Two Power Sources

After using the Ladybug Lite Blue in my nutrient baths, I’ve decided to change the hardware design from just using a coin cell battery to using a DC power source when available and switching to a coin cell battery when not available.  At some point I envision designing an outdoor version that switches between solar power and battery so I am excited to explore using multiple power sources.

The Goal

The goal of this post is to add switching between a DC and battery power source to the Ladybug Lite Blue Schematic and board layout.

Note: I will be using the acronym LBL to refer to the Ladybug Lite Blue hardware.

Thanks to Those that went Before

Thank you (as always) to  Chris Gammell of Contextual Electronics!  I came up with a design to switch between the two power sources using an op amp and a p-channel mosfet.  I showed my design to Chris who without hesitation – and I might add a lot of respect/kindness! – steered me to a much better design using Schottky diodes – which I discuss below.  In fact, Chris pointed out he had covered this a month or so ago in our Contextual Electronics course!  Shame on me for needing Chris’s nudge when he had already provided the “better” solution.  There is so much Chris is teaching us that I need to go back and figure out what else I have missed.

Thank you Afrotechmods for your excellent video on the Schottky diode.

Open Source

Kicad v4.01 files and LTSpice simulation that is discussed below can be downloaded from this github location.

The Solution

  • use a commonly available power source for DC power: USB and CR2032 3V coin cell battery.
  • use Schottky diodes along with DC power being at a higher voltage than battery to use DC power when plugged in.  

LTSpice

The LTSpice simulation is simple.  I defined a DC and battery power source.  The DC power source pulses 3.3 volts on and off.  This allows the voltage graph to show the voltage at the load when DC power is on as well as off.

Features of the Design

  • When both power sources are available, current flows through D1 (i2) and through D2 (i1).
  • The voltage rises to 3.3V – the maximum DC voltage, which is .3V more than the maximum battery voltage of 3V.
  • Diode D1 is getting a reverse current.  At this point, power is being driven by the DC source.

Benefits of Schottky Diodes

Features of a Schottky diode that makes it a good fit for this scenario include:
  • A diode’s forward voltage drop is ~ .7V.  The Schottky diode has ~ .2V forward voltage drop (this depends on variables like the amount of current).
  • Switching from allowing current to flow to not allowing current to flow happens instantly.

Schematic and Board Layout

The Kicad v4.01 schematic and board layout are available at this github location.

 

 

 

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

Source Line Debugging FRDM-KL25Z Firmware

Tags

, , , ,

In my previous post, I started out on a journey to program the FRDM-KL25Z.  I documented how I:

  • got OpenOCD talking to the FRDM-KL25Z
  • integrated OpenOCD with Eclipse
  • “got to blinky” by loading and running a binary on the FRDM-KL25Z and
  • installed the mbed library

The Goal

The goal of this post is to step through a simple C program running on the FRDM-KL25Z from within Eclipse through the OpenOCD interface to the GDB debugger.

Thanks To Those That Went Before

A special shout out to the OpenOCD mailing list (openocd-user@lists.sourceforge.net)  It amazes me that such gifted folks as Paul and Tim are there to answer my questions!  So far I have been impressed with the quality of people and their passion behind the OpenOCD effort.

  • Paul Ferster – through the OpenOCD mailing list –  yet again came to my rescue when I could not get the GDB debugger to connect to the FRDM-KL25Z.  THANK YOU.
  • Tim Wescott provided me with insights on interacting with OpenOCD as well his thoughts on documentation.  I agree with his thoughts. The one thing I might consider for the OpenOCD effort is to move from a mailing list to StackExchange/StackOverflow (I am not sure about the difference). It is my experience as a passionate learner of electronics/programming that we’ve moved from RTFM learning to asking peers via a search that lands us on StackExchange/StackOverflow.  In doing so, the community becomes the documentation.  A mailing list to me is more about a few experts answering questions.  Which doesn’t scale as well because these poor experts are taken away from improving the code base to answer questions from clueless folks (um…like me:-) ).  THANK YOU Tim.
  • Ron Sousa  of HDE for providing guidance and direction as I sorted out what he is teaching us within the embedded systems section of Contextual Electronics.

The Code

Ron has us using the FRDM_SERIAL example project that is available on mbed’s developers web site.  As I searched, I stumbled across this post which walked me through the steps to download/prepare the FRDM_SERIAL example from mbed’s developer site.  I found the post easy to follow.  Please check it out. 

 The post uses the FRDM-K64F.  But as the image above shows it is easy to select the FRDM-KL25Z.  Selecting a platform is also a simple way to see which mbed boards are supported the most.

I found this online method of getting familiar with mbed programming/building/debugging/running code on the FRDM-KL25Z to be simple and unique.  My knowledge level about mbed in the previous post assumed I would need to download the mbed sdk and create an mbed library.  And I did this.  The mbed library created running the python scripts created the mbed library: /Applications/mbed/build/mbed/TARGET_KL25Z/TOOLCHAIN_GCC_ARM/libmbed.a

The mbed library build steps I went through that were documented in this post were not necessary.  Starting off with an Exported project from the mbed developer web site brings in the libmbed.a linked for the specified chip, in my case the FRDM-KL25Z.  However, running the tests using make.py was very useful because it helped me confidently know mbed was working with the FRDM-KL25Z and familiarized me with sending/receiving data from the FRDM-KL25Z to my Mac.  As in the journey is the reward:-).  Or what I’m finding – the journey is where I actually learn stuff.

FRDM-SERIAL Project

FRDM_SERIAL is a simple mbed app.  As pointed out in the post: “You’ll see it doesn’t do much , it makes a serial connection over the USB port using Serial pc(USBTX, USBRX);it sends “Hello World” to the pcit then loops toggling the LED and sending  the loop counter to the pc.”  Here’s the code:

#include“mbed.h”

 

DigitalOut myled(LED_GREEN);

Serial pc(USBTX, USBRX);

 

int main()

{

    int i = 0;

    pc.printf(“Hello World!\n”);

 

    while (true) {

        wait(0.5f); // wait a small period of time

        pc.printf(“%d \n”, i); // print the value of variable i

        i++; // increment the variable

        myled = !myled; // toggle a led

    }

}

Prior to unzipping the FRDM_SERIAL bundle that I exported from mbed’s compiler web site, I had created an Eclipse workspace.  I briefly discussed Eclipse workspaces in this post.  I then unzipped the bundle and copied the files within a subdirectory of the workspace.

The project includes a makefile.  The makefile means we can build within Eclipse with all the dependencies and variable definitions set.  If I was to grow the project with additional code/libraries, I would consider moving the makefile into a project with a managed make file as I did for the nRF51822 projects.  Managed make is – as the name implies:-) – easier to manage within Eclipse.

Source Line Debugging

I’ve got my project set up in Eclipse with the Eclipse settings I discussed in the previous post.  Source line debugging involves integrating the latest stable version of OpenOCD within Eclipse.  I’ve got the openOCD environment variables set up:

 The debug configuration needs to be set up:

Config Options

All should be filled out except for the all important Config options.  Make sure to have a path to the KL25Z.cfg file.  Note: I’ve seen different config files on the net for the KL25Z.cfg.  It is best to stick to the one that comes with the “official” OpenOCD software.

Explained in the OpenOCD Project Setup documentation: “To use OpenOCD with your development projects, you need to do more than just connect the JTAG adapter hardware (dongle) to your development board and start the OpenOCD server. You also need to configure your OpenOCD server so that it knows about your adapter and board, and helps your work. You may also want to connect OpenOCD to GDB, possibly using Eclipse or some other GUI.”

-f <path to KL25Z.cfg>

As explained in the OpenOCD documentation under configuration basics, passing in the correct config file is super important.  

-c “init;reset halt” 

When I didn’t give these additional options, I would get the following from the gdb server:

GNU ARM Eclipse 64-bits Open On-Chip Debugger 0.9.0-00073-gdd34716 (2015-05-19-12:55)

Licensed under GNU GPL v2

For bug reports, read

http://openocd.org/doc/doxygen/bugs.html

Info : only one transport option; autoselect ‘swd’

srst_only separate srst_gates_jtag srst_open_drain connect_deassert_srst

Info : add flash_bank kinetis kl25.flash

adapter speed: 1000 kHz

srst_only separate srst_nogate srst_open_drain connect_deassert_srst

cortex_m reset_config sysresetreq

Started by GNU ARM Eclipse

Info : CMSIS-DAP: SWD  Supported

Info : CMSIS-DAP: Interface Initialised (SWD)

Info : CMSIS-DAP: FW Version = 1.0

Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1

Info : CMSIS-DAP: Interface ready

Info : clock speed 1000 kHz

Info : SWD IDCODE 0x0bc11477

Info : kl25.cpu: hardware has 2 breakpoints, 2 watchpoints

Info : MDM: Chip is unsecured. Continuing.

Info : accepting ‘gdb’ connection on tcp/3333

Warn : Cannot communicate… target not halted.

Error: auto_probe failed

Error: Connect failed. Consider setting up a gdb-attach event for the target to prepare target for GDB connect, or use ‘gdb_memory_map disable’.

Error: attempted ‘gdb’ connection rejected

The GDB Server finds the OpenOCD service running on the FRDM-KL25Z but can’t connect to it.

The “helpful hints” (i.e.: Consider setting…) were not helpful.  I could not debug this without asking the OpenOCD mailing list .  Like last time, this mailing list was quick to respond with the right solution.  

I plan to use this command string any time I set up a debug configuration for OpenOCD.

Once the command was included, The YIPPEE! moment occurred.  I was able to walk through the code as well as see the output within a CoolTerm session (I discussed using CoolTerm in the previous post):

 

 

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

 

Playing with the FRDM-KL25Z – Getting to Blinky

Tags

, ,

UPDATE (12/28/2015): Erich cleared up my confusion on what ARM processor (cortex-m0+ or cortex-m4) was used in the KL25Z.  From Erich: The KL2x (note the L) has an ARM Cortex M0+, while the K2x is indeed having a M4 core…. this post has been updated to take note of this difference.  Yet again – THANK YOU Erich!

Ron is mentoring us through embedded systems programming on using a Freedom board.  I’m excited about the opportunity to compare/contrast with what I am learning about the nRF51822.

I am using a FRDM-KL25Z board.  

The Goal

The goals of this post include:

  • Installation and verification of OpenOCD with my FRDM-KL25Z board.
  • Setting upEclipse/OpenOCD.
  • Installing the mbed SDK and running test binaries built using the mbed SDK on the FRDM-KL25Z board.

Thanks to Those That Went Before

Paul Ferster

A HUGE thank you to Paul Fertser.  While I am not exactly sure what Paul’s role is in the OpenOCD community, Paul went out of his way helping me debug an OpenOCD install on Ubuntu. We use Ubuntu in Contextual Electronics because it provides a common environment.  I got introduced to Paul after signing up for the OpenOCD mailing list.  I was desperate to figure out why OpenOCD wouldn’t run on my Ubuntu VM.  It couldn’t have been more than two minutes before Paul sent me a reply.  I’m clueless when it comes to *nix commands and had no idea what  was doing with OpenOCD.  It was the holidays, and I wanted to catch up to Ron’s Contextual Electronics videos.  After much debugging, Paul suggested we get the problem figured out on the #openOCD IRC chat channel.  To further show my ignorance, at first I had no idea what he was asking since I’ve used IRC maybe twice and immediately thought of Twitter when he put a # before a word (sad I know:-) ).  The problem ultimately turned out to be an old version of OpenOCD.  But it was more confusing than that.  I found three different versions of OpenOCD on the machine!  The Ubuntu version was outdated…and on…and…I learned A LOT about OpenOCD from Paul.  But more importantly, I met someone who kindly helped me, was very gifted in programming and all things *nix and OpenOCD, and was extremely passionate to get the OpenOCD environment “right”.  When I was discussing the experience with Paul, I shared my unhappiness with the amount of time this effort took.  I pointed out that time is the most important currency.  Paul made me rethink my feelings on time – and gave me a glimpse into how time is spent – that when stuff just will not work – that chance opportunity to meet and talk with someone who has an extremely interesting perspective, is super smart, and helpful is very important.  Thank you Paul.

Note: Given the challenges I had with Ubuntu, I moved this project to Mac OS X.  

Erich Styger

Erich Styger for his excellent series of posts on his MCU On Eclipse blog.  Often Erich has written a post on the topic I am trying to learn.  This time I found this post to be very helpful.  Thank you Erich.

Ronald Sousa

Ron teaches embedded systems programming for Contextual Electronics.  I continue to learn A LOT from Ron.  Ron’s post on committing and installing OpenOCD was extremely helpful.  Thank you Ron.

Getting To Know the FRDM-KL25Z

From this page: “The FRDM-KL25Z has been designed by Freescale in collaboration with mbed for prototyping all sorts of devices…and includes a built-in USB Flash programmer.”  From that description, it appears to me like an alternative to an Arduino…a gateway into getting deeper into programming NXP µCU …with a lot of great peripherals, OpenOCD, and mbed support.  BWA-HA-HA!!!!  (As in..You WILL see the value in dropping any other µCU and buying NXP’s SOIC…BWA-HA-HA-HA-HA ).

Details on the FRDM-KL2x series of µCU can be found here.  The User’s Guide gives a nice overview.

Block Diagran

The block diagram:

 

 

From here

Highlights the KL2X’s capabilities.  I’m looking forward to getting to know the µCU better by watching these videos.

Debug Interface

Important for this post is the debug interfaces.  This pdf document (chapter 9 – debugging) pointed out the FRDM-KL25Z implements Arm’s JTAG/SWD debugging support:

 

Like the nRF51822, the FRDM-KL25Z supports Arm’s SWD interface.  YIPPEE!…this means we’ll be able to use OpenOCD software in order to do source line debugging of FRDM-KL25Z code within Eclipse.

mbed

We’ll be using mbed software to develop firmware for the board.  I’ve been curious what mbed is all about.  What I found interesting about the development environment was the focus on a simple online IDE where code is handled within a web browser.  What a clever way to get started!  No messy IDE install.  An easy way to jump start playing with a board.  It seems to me a terrific way to have a starter IDE.

The other option for firmware development is using the mbed SDK.  This is what we’ll need to use in order to use Eclipse as the IDE.

Debugging the FRDM-KL25Z Within Eclipse 

We’ll be using OpenOCD software in order to do source line debugging of FRDM-KL25Z code within Eclipse.

The Eclipse -> OpenOCD debugging path is discussed handily by Erich Styger in  his post “OpenOCD/CMSIS-DAP Debugging with Eclipse and without an IDE”:

 

Lucky for us, the FRDM-KL25Z is supported on the latest stable release of OpenOCD (0.9).  Getting (OpenOCD) debugging working between the FRDM-KL25Z and Eclipse involve the following steps:

Step 1: Firmware

  • Update the firmware on the FRDM-KL25Z.  This was challenging for me because I use a Mac. The mbed boot loader that was loaded on my board when I got it in the mail was version 1.09.  To update firmware from 1.09 to 1.11 (the latest), I had to find a Win 7 machine.  Luckily, I have a machine I’ve kept around for 6 years!  The mbed boot firmware is located here.  Updating the boot loading firmware is confusing because what I found out there is an nbed boot loader and a non-MBed boot loader.  We are using MBed for:
    • USB drag and drop programming
    • USB Virtual COM port for serial terminal
    • CMSIS-DAP interface for programming and debugging from offline tools
    • rich SDK
    I went through the instruction on Arm’s web site.  All seemed to work:-).
     
  • Download the “Hello World!” binary onto the FRDM-KL25Z.  This is incredibly easy to do.  As stated earlier, the FRDM-KL25Z was a joint effort between mbed and Freescale.  So once the firmware was updated, the board shows up as a USB device on my Mac:

It is then just a matter of downloading the HelloWorld_KL25Z.bin file onto the FRDM-KL25Z board.  Go to here for more info.  Luckily, this “just worked” for me:-).  Although I find the continual blinking of the red light to be annoying.

Onto OpenOCD and the mbed SDK….

Step 2: OpenOCD

  • Download and install the OpenOCD binaries from here.  There are directions for the different operating systems.  WHAT A RELIEF to have stable binary distributions of the latest releases.  THANK YOU!! If I had to, I’d build everything myself.  However, it is a time saver having the Eclipse community provide this for us.  I am using OpenOCD v0.9, the most recent stable version as of this date.  Make sure to use at least 0.9!
  • Note: In case there is a need to build OpenOCD from source, this page looked promising.
  • After installing on my Mac, I changed the directory path structure to get rid of the spaces in the “GNU ARM Eclipse” directory name that was created to “GNUARMEclipse”…I find spaces in names can cause unwelcome problems that I wish to deal with.
  • Check the OpenOCD version by opening a terminal and running openocd -v .  This requires a path to the openocd.  I used the default install directory and then changed the GNU ARM Eclipse directory name as noted above, so the command I used was:

$ /Applications/GNUARMEclipse/OpenOCD/0.9.0-201505191004/bin/openocd –version

GNU ARM Eclipse 64-bits Open On-Chip Debugger 0.9.0-00073-gdd34716 (2015-05-19-12:55)

Licensed under GNU GPL v2

For bug reports, read

http://openocd.org/doc/doxygen/bugs.html

  • Check to see if OpenOCD can talk to the FRDM-KL25Z.  OpenOCD uses a configuration file for each board it supports.  Whereas the OpenOCD binary is loaded within the …/bin directory, the configuration files for the boards are located within …/scripts/board .  The configuration file for the FRDM-KL25Z is frdm-kl25z.cfg .  Making sure the board was plugged into a USB port, I ran the following from the command line:

$ /Applications/GNUARMEclipse/OpenOCD/0.9.0-201505191004/bin/openocd -f /Applications/GNUARMEclipse/OpenOCD/0.9.0-201505191004/scripts/board/frdm-kl25z.cfg

GNU ARM Eclipse 64-bits Open On-Chip Debugger 0.9.0-00073-gdd34716 (2015-05-19-12:55)

Licensed under GNU GPL v2

For bug reports, read

http://openocd.org/doc/doxygen/bugs.html

Info : only one transport option; autoselect ‘swd’

srst_only separate srst_gates_jtag srst_open_drain connect_deassert_srst

Info : add flash_bank kinetis kl25.flash

adapter speed: 1000 kHz

srst_only separate srst_nogate srst_open_drain connect_deassert_srst

cortex_m reset_config sysresetreq

Info : CMSIS-DAP: SWD  Supported

Info : CMSIS-DAP: Interface Initialised (SWD)

Info : CMSIS-DAP: FW Version = 1.0

Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1

Info : CMSIS-DAP: Interface ready

Info : clock speed 1000 kHz

Info : SWD IDCODE 0x0bc11477

Info : kl25.cpu: hardware has 2 breakpoints, 2 watchpoints

Info : MDM: Chip is unsecured. Continuing.

OOH…um…YIPPEE!!!  IT WORKED.  (side note – I originally spent way too many hours trying to get this working within Ubuntu..I mean *way* too many hours.  I was going to include details of this painful process.  However, I decided to vent a bit here and press on).
 
…pressing on to using Eclipse + OpenOCD as my IDE of choice….
  • Update Eclipse to know where the OpenOCD binary is located by following the “Update OpenOCD path” steps documented here.
  • Update Eclipse plug-ins for OpenOCD support by follow the steps outlined in “OpenOCD Debugging plug-ins documented here

 

 I already had these installed.  However, I went through the process.  A lot of updates were applied.

 And …finally… the mbed SDK

 Step 3: mbed

My attention at this point turns to what is needed to get an mbed app using the serial port of the FRDM-KL25Z to communicate with a terminal program on my mac through SSH.

The steps I took to install the mbed SDK come from here.

  • Download the mbed project from github: git clone https://github.com/mbedmicro/mbed.git
  • Create a private_settings.py file at the location noted in the web post.  Add the path to the GNU ARM GCC.  I got the path from within an Eclipse project->Properties page->C/C++ Build->Settings  under the Toolchains tab, the Toolchain path.  Mine is /usr/local/gcc-arm-none-eabi-4_9-2015q1/bin
  • I did not have the following python libraries installed on my mac so I ran:
    • sudo easy_install colorama (an overview of colorama can be found here).
    • sudo easy_install jinja2 (overview is here).
    • sudo easy_install pyserial (overview is here).
  • Run the build python script.  Python comes with OS X.  I opened a terminal window in the /Applications/mbed/workspace_tools directory (where build.py is) and ran: 

$ python build.py -m KL25Z -t GCC_ARM 

 

$ python build.py -m KL25Z -t GCC_ARM

Building library CMSIS (KL25Z, GCC_ARM)

Copy: arm_common_tables.h

Copy: arm_const_structs.h

Copy: arm_math.h

Copy: core_ca9.h

Copy: core_ca_mmu.h

Copy: core_caFunc.h

Copy: core_caInstr.h

Copy: core_cm0.h

Copy: core_cm0plus.h

Copy: core_cm3.h

Copy: core_cm4.h

Copy: core_cm4_simd.h

Copy: core_cm7.h

Copy: core_cmFunc.h

Copy: core_cmInstr.h

Copy: core_cmSimd.h

Copy: core_sc000.h

Copy: core_sc300.h

Copy: cmsis.h

Copy: cmsis_nvic.h

Copy: MKL25Z4.h

Copy: system_MKL25Z4.h

Copy: MKL25Z4.ld

Compile: startup_MKL25Z4.S

Compile: cmsis_nvic.c

Compile: system_MKL25Z4.c

Copy: startup_MKL25Z4.o

Copy: cmsis_nvic.o

Copy: system_MKL25Z4.o

Building library MBED (KL25Z, GCC_ARM)

Copy: AnalogIn.h

Copy: AnalogOut.h

Copy: BusIn.h

Copy: BusInOut.h

Copy: BusOut.h

Copy: CallChain.h

Copy: CAN.h

Copy: can_helper.h

Copy: CircularBuffer.h

Copy: CThunk.h

Copy: DigitalIn.h

Copy: DigitalInOut.h

Copy: DigitalOut.h

Copy: DirHandle.h

Copy: Ethernet.h

Copy: FileBase.h

Copy: FileHandle.h

Copy: FileLike.h

Copy: FilePath.h

Copy: FileSystemLike.h

Copy: FunctionPointer.h

Copy: I2C.h

Copy: I2CSlave.h

Copy: InterruptIn.h

Copy: InterruptManager.h

Copy: LocalFileSystem.h

Copy: LowPowerTicker.h

Copy: LowPowerTimeout.h

Copy: LowPowerTimer.h

Copy: mbed.h

Copy: mbed_assert.h

Copy: mbed_debug.h

Copy: mbed_error.h

Copy: mbed_interface.h

Copy: platform.h

Copy: PortIn.h

Copy: PortInOut.h

Copy: PortOut.h

Copy: PwmOut.h

Copy: RawSerial.h

Copy: rtc_time.h

Copy: semihost_api.h

Copy: Serial.h

Copy: SerialBase.h

Copy: SPI.h

Copy: SPISlave.h

Copy: Stream.h

Copy: Ticker.h

Copy: Timeout.h

Copy: Timer.h

Copy: TimerEvent.h

Copy: toolchain.h

Copy: Transaction.h

Copy: wait_api.h

Copy: analogin_api.h

Copy: analogout_api.h

Copy: buffer.h

Copy: can_api.h

Copy: dma_api.h

Copy: ethernet_api.h

Copy: gpio_api.h

Copy: gpio_irq_api.h

Copy: i2c_api.h

Copy: lp_ticker_api.h

Copy: pinmap.h

Copy: port_api.h

Copy: pwmout_api.h

Copy: rtc_api.h

Copy: serial_api.h

Copy: sleep_api.h

Copy: spi_api.h

Copy: ticker_api.h

Copy: us_ticker_api.h

Copy: clk_freqs.h

Copy: gpio_object.h

Copy: objects.h

Copy: PeripheralPins.h

Copy: PortNames.h

Copy: device.h

Copy: PeripheralNames.h

Copy: PinNames.h

Compile: PeripheralPins.c

Compile: gpio_irq_api.c

[Warning] gpio_irq_api.c@86: In function ‘gpio_irq_init’: ‘irq_n’ may be used uninitialized in this function [-Wmaybe-uninitialized]

[Warning] gpio_irq_api.c@100: In function ‘gpio_irq_init’: ‘vector’ may be used uninitialized in this function [-Wmaybe-uninitialized]

[Warning] gpio_irq_api.c@103: In function ‘gpio_irq_init’: ‘ch_base’ may be used uninitialized in this function [-Wmaybe-uninitialized]

Compile: mbed_overrides.c

Compile: serial_api.c

[Warning] serial_api.c@177: In function ‘serial_format’: ‘parity_enable’ may be used uninitialized in this function [-Wmaybe-uninitialized]

[Warning] serial_api.c@177: In function ‘serial_format’: ‘parity_select’ may be used uninitialized in this function [-Wmaybe-uninitialized]

Compile: spi_api.c

[Warning] spi_api.c@55: 22:0: ‘extosc_frequency’ defined but not used [-Wunused-function]

[Warning] spi_api.c@117: 22:0: ‘mcgpllfll_frequency’ defined but not used [-Wunused-function]

Compile: analogin_api.c

[Warning] analogin_api.c@55: 21:0: ‘extosc_frequency’ defined but not used [-Wunused-function]

[Warning] analogin_api.c@117: 21:0: ‘mcgpllfll_frequency’ defined but not used [-Wunused-function]

Compile: analogout_api.c

Compile: gpio_api.c

Compile: i2c_api.c

[Warning] i2c_api.c@55: 21:0: ‘extosc_frequency’ defined but not used [-Wunused-function]

[Warning] i2c_api.c@117: 21:0: ‘mcgpllfll_frequency’ defined but not used [-Wunused-function]

Compile: pinmap.c

Compile: port_api.c

Compile: pwmout_api.c

Compile: rtc_api.c

[Warning] rtc_api.c@117: 18:0: ‘mcgpllfll_frequency’ defined but not used [-Wunused-function]

Compile: sleep.c

[Warning] sleep.c@60: In function ‘deepsleep’: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]

Compile: us_ticker.c

[Warning] us_ticker.c@117: 19:0: ‘mcgpllfll_frequency’ defined but not used [-Wunused-function]

Compile: BusIn.cpp

Compile: BusInOut.cpp

Compile: BusOut.cpp

Compile: CAN.cpp

Compile: CallChain.cpp

Compile: Ethernet.cpp

Compile: FileBase.cpp

Compile: FileLike.cpp

Compile: FilePath.cpp

Compile: FileSystemLike.cpp

Compile: I2C.cpp

Compile: I2CSlave.cpp

Compile: InterruptIn.cpp

Compile: InterruptManager.cpp

Compile: LocalFileSystem.cpp

Compile: RawSerial.cpp

Compile: SPI.cpp

Compile: SPISlave.cpp

Compile: Serial.cpp

Compile: SerialBase.cpp

Compile: Stream.cpp

Compile: Ticker.cpp

Compile: Timeout.cpp

Compile: Timer.cpp

Compile: TimerEvent.cpp

Compile: assert.c

Compile: board.c

Compile: error.c

Compile: gpio.c

Compile: lp_ticker_api.c

Compile: mbed_interface.c

Compile: pinmap_common.c

Compile: retarget.cpp

Compile: rtc_time.c

Compile: semihost_api.c

Compile: ticker_api.c

Compile: us_ticker_api.c

Compile: wait_api.c

Library: libmbed.a

Copy: mbed_overrides.o

Copy: board.o

Copy: retarget.o

 

Completed in: (4.55)s

 

Build successes:

  * GCC_ARM::KL25Z

 

  • Test by running make.py.  I wanted to echo characters over a serial port, which is the 8th test.  To run this test, I needed to use a SSH application. I could use terminal.  However, I am not well versed in terminal so I downloaded and started to use coolterm.  I found coolterm to be useful so I donated $25.  I appreciate efforts such as these.  
    • after launching CoolTerm, go into options and set the Port to the USB port represented by the FRDM-KL25Z.  The USB port used by the FRDM-KL25Z can be found by starting a terminal session and typing: 

$ ls /dev/tty.*

/dev/tty.Bluetooth-Incoming-Port/dev/tty.usbmodem1452

/dev/tty.Bluetooth-Modem

    • Go into the Terminal settings dialog box and change the Key Emulation to LF and check Local Echo:

 

  • open a Terminal window and run a test.  For example, I opened a terminal window at the folder where the make.py file resides.  I ran test 8 (the echo serial test – you can get a list of the test by running make.py without parameters).  The command I used was: 

python make.py  -m KL25Z -t GCC_ARM -d /Volumes/mbed -s /dev/tty.usbmodem1452 -p 8

YIPPEE!!! Here’s the output in CoolTerm:

 That’s It For Now

The goals for this post were:
  • Installation and verification of OpenOCD with my FRDM-KL25Z board.
  • Setting upEclipse/OpenOCD.
  • Installing the mbed SDK and running test binaries built using the mbed SDK on the FRDM-KL25Z board.

I feel these goals (after many hours of…well…:-) ) were met.

My next “unknown” is to step through source code within an OpenOCD debugging session on Eclipse.

 

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

Calibrating the Ladybug’s EC Probe

Tags

,

I just passed a YIPPEE! moment…I’m able to calibrate and read pH values from a Ladybug Blue Lite using my iPad.  While the code is definitely prototype, the nRF51822 firmware talks quite well with the iOS app written in Swift.  By the way, did I mention how delightful it is to code in Swift?  I could wax on about the wonders of Playgrounds and the sheer brilliance that went into the entire iOS development environment.  But that is not what this post is all about.

I have not spent time on EC calibration. It is time I did.

The Goal

The Goal of this post is to walk through the thought process and design of how EC calibration will be done for Ladybug Blue Lite EC probes.

Thanks To Those That Went Before

  • A huge thanks to Apple for the delightful Swift language.  I get these mini explosions of excitement every time I dig deeper into Swift…like the power Swift has given enums….who woulda thought?  Well – certainly them!
  • As always, a huge and warm thanks to Chris Gammell and the team at Contextual Electronics.  I would not be able to do this stuff without Chris and the Contextual Electronics courses.

How EC is Measured  

EC is a measurement of conductivity.  EC measurements are given in Siemens/meter (or in my case µS/cm).  But an EC reading measures Siemens (µS).  A measurement of Siemens is a measurement of conductance.  The dependency relationship between Conductance (represented by G), voltage, and current is  G=I/V=1/R (since -as we all know- according to Ohm’w law: V=IR).  As I have noted in previous posts, the EC circuit measures resistance.  G is then calculated from 1/R.

To go from µS to µS/cm, the geometry of the two electrodes making up the EC probe need to be known.   A common ideal geometry for an EC probe is this one:

ECProbeDimensions

As noted hereThe conductance depends on the total concentration of ions in the solution as well as on the length and area of the solution through which the current passes.  Thus, even if the concentration of the ions remains the same, the conductance will change if the length or area of the current path changes.

What this means is the length/area of the electrodes need to be taken into account.  

EC = G*(distance between the electrodes)/(the cross-sectional area of an electrode – i.e.: each electrode is identical).  (The Distance) / (The cross-sectional area) is referred to as “K” or “the cell constant.”

Calibration

Calibration is calculating the actual K value from an ideal K value.  The ideal K value for the probe I am using = 1.  Using a calibrated EC solution of 1413µS, my probe should measure 1413µS.  But it measured 1188µS.  Since (EC measurement read) * actual K = 1413µS/cm, 1182*(actual K) = 1413 or actual K = 1.19.

What is used for the actual K value of an EC probe is the K slope.

From this post

Two Points Are Better Than One

In my earlier calculation, I used one point calibration.  While a one point calibration can be used, the K slope value will be more accurate if two EC calibration solutions are used.  This is similar to the pH calibration method in which I use a pH4 and pH7 calibration solution to calculate the probe’s variance from an ideal probe.

The Ladybug will support up to two EC calibration readings to calculate the EC probe’s K value.

 

 

OKIDOKIE…that’s it for now.  THANK YOU for reading this far.  Please find many things to smile about.  Just smile.

 

 

  

 

Using a Union and Structs to Store pH Calibration Data.

Tags

,

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

}pH_cal_t;

 

typedef  union {

  uint8_t    bytes[16];

  pH_cal_t   pH_cal;

}pH_data_t;


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;

  pH_data.pH_cal.day = 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,“%02X”,pH_data.bytes[i]);

    }

  SEGGER_RTT_WriteString(0,“\n”);

  SEGGER_RTT_WriteString(0,“\n”);

  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”,pH_data.pH_cal.day);

  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: 

04:03:02:01:A5:00:00:00:F6:FF:FF:FF:0B:14:DF:07

 

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.

Follow

Get every new post delivered to your Inbox.

Join 36 other followers