PSoC 6 SDK OneWire Bus (Part 5): Round out the OWB driver

Summary

This article shows the completion of the PSoC 6 SDK One Wire Bus library.  It shows the test apparatus for evaluating DS18B20 sensors.

Story

If you remember from the previous articles, I created the one wire bus library by looking at the function calls in the DS18B20 library and reverse engineering the function prototypes.  And, as I said in the earlier article, it would have been way better to just look at the David Antliff “OWB” library.  But that is not how it went down.  I wonder how much time in the world is wasted by programmer re-implementing code that already exists?

After the first four articles, I had three functions which the DS18B20 library defined, but I had not yet implemented.

I had not implemented them because I was not totally sure how they worked.  So, I decided to go back to GitHub and see what David had done originally.  When I got to the GitHub site, https://github.com/DavidAntliff/esp32-owb/blob/master/include/owb.h, there were actually quite a few functions in his owb library that I had not implemented.

Here is the list:

In this article I will create and/or copy the missing functions.  As I look through his implementation I also notice that we have some style differences that I will discuss.  In general I will say that his implementation is very good and any place that I did something different was just a matter of programming taste.

I was originally planning on this article taking you linearly through how I did the changes, but in reality I jumped around while I was doing the changes, that approach won’t work.  Here is the list of what I did:

  1. Add Doxygen Function Headers
  2. Move Logging Function to Library
  3. Change Commands to Enumerated Type
  4. Change Const Bus Pointer
  5. Pack the Structures
  6. Pass Structures as Pointers
  7. Driver Functions
  8. Test the Search
  9. Test the Parastitic Power

Doxygen Headers

I like using documentation that has been generated with Doxygen.  Specifically I like that the documentation is written “at the point of attack”.  But I have never actually used or generated it using Doxygen.  To make the documentation you need to put comments into your c-header files in the right format.  Here is an example from owb.h

In this case, David had done most of the work already and all I needed to do was copy/modify his headers in the few places where we had differences in the public interface to the library.  After that, I ran doxygen.  When I first did this I got an absolute boatload of warnings about places where I had not documented with comments.  If Hassane is reading he will say … “Really Alan didn’t write comments, imagine that”

Now I have some documentation

I will say that I wish I had a few days to really learn Doxygen as there are many many many options which I have no idea what they do.  Oh well.

Fix the Logging Function

David built the library on top of the ESP32 libraries.  This included calls to the ESP32 logging library “log.h/.c“.  All through his library he calls “ESP_LOG” like this.

When I first looked at this I decided to just do this to make the error messages go away.  This is just a trick that will use the c-preprocessor to replace the function call to “ESP32_LOGE” with NOTHING

After I sorted everything else out I went back to decide what to do.  My choices were

  1. Clone the Espressif library and “fix it”
  2. Implement the functions that David used in the OWB library
  3. Find another library

I decided to use option 3 – a logging library that I found on GitHub called “log.c” (which is a very unfortunate name when you clone it).  It is really simple and works well.  Since the Tour de France is going as I write this article I will say “chappeau rxi”.  This library is written in C99 (just normal C) and has functions which can easily replace the ESP_LOG functions.  I add it to my project with “git clone git@github.com:rxi/log.c.git”

This means that I just replace “ESP_LOGE” with “log_error”.  In reality rxi did something very nice by using a feature of the compiler to insert the file/line numbers.

This only left me with the function

Which I decided to do something cheap to solve.  The original code was:

And I replaced the two uses with:

and

I know it isn’t beautiful what I did, but it works.

Enumerated Command Type

When I examined the original source code, the one-wire commands were defined using #defines.

When I did the implementation originally I chose to make the #defines into an enumerated list.  I suppose that it doesn’t really matter.  But, by enumerating the values it lets the compiler help you in situations like a switch or a function call.

Const Bus pointer

Through out the original one wire bus library, the bus pointer is defined as const.  Like this:

But, I wanted to use the OneWireBus structure to also store some context.  By context I mean variables (which can change) but hold state for the bus.  This included the semaphore that I used to fix the delay functions.

ROM Code Structure Packed

In the original library the ROMCode is a union that allows access to individual bytes, or the actual data.

The problem is there is no guarantee that the compiler will pack the family, serial number and crc.  You should tell it to with the __PACKED macro.  I would say that I think that David got luck that there was not a bug.

C-Programming: Passing Structures as Function Arguments

In the original library David passed the rom_code structure as an argument on the stack.  But, because I started programming in the days before it was legal to pass a structure as a function argument when I did the implementation I passed a pointer.

I wrote

Which meant that he could write

but I had to write

In this case it doesn’t really matter as the structure is small.

Driver Functions

If you look at the original implementation the author has a “driver”

Which is a structure with function pointers to talk to bus.

Which meant that he did this:

In my implementation I wrote functions for those things.

I don’t really think that it helped abstract the hardware because he also did this.

Perhaps a driver with function pointers would have made the original port easier if I had started there?  But if so, it would have required more adherence to the original  architecture.

Test Search

A nice thing that came with his library was an implementation of the search feature which allows multiple devices to be attached to the bus.  To test this I added two sensors.

Then made a command in my console to run the test.

Which worked perfectly.

Parasitic Power

I would like to test the functionality of the parasitic power.  Here is a schematic from the data sheet of how it work.  But I don’t have that transistor so that will be left for another day.

What is Next?

There are several things that I should do.

  1. Fix up the libraries to use the manifest files so they are available all of the time
  2. Fix up the libraries to use the dependency scheme
  3. Test the parasitic power
  4. Test the actual DS18B20 library (the original point of this whole thing)

I have found myself in the middle of a bunch of other problems, so these things will need to happen another day.