PSoC 6 SDK OneWire Bus (Part 2) : Implement Read & Write

Summary

In this article I will explain how to implement (badly) the one wire bus read & write functions using the PSoC 6 SDK.  This is one of many articles that are part of a series discussing the implementation:

Article
PSoC 6 SDK OneWire Bus (Part 1) : Build Basic Project
PSoC 6 SDK OneWire Bus (Part 2) : Implement Read & Write
PSoC 6 SDK OneWire Bus (Part 3) : Remove Busy Wait & Debug
PSoC 6 SDK OneWire Bus (Part 4): But, Can it Read the Temperature?
PSoC 6 SDK OneWire Bus (Part 5): Round out the OWB Driver

Story

In the previous article, I built a test framework inside of a PSoC 6 FreeRTOS project.  This includes a command line shell which will enable me to execute functions based on typed commands.  This means I can use the CLI shell to debug my interface.  To get going testing, I bought a DS18B20 temperature sensor from Mouser.

Then wired it like this:

Here is a picture of the test jig.  It looks like I used 4200 ohms instead of 4400 ohms, oh well it seems to work.

Init

Init seems like a good place to start.  To have a one wire bus you need to have a GPIO to read/drive.  So, that will be the only argument to the initialization function.  In the implementation I will use a common semaphore to handle blocking functions (line 13).  On lines 15-17 I initialize a timer to handle the requirements of reset, read and writes (more on this later).  At the end on line 20 I initialize the GPIO.

In the usrcmd.c I need to add includes for the new stuff.

The next step is to add the “init” command to usrcmd.c  This is accomplished by adding a function header for usrcmd_init and adding it to the table of legal commands.

Then you need to add the usrcmd_init function to call the owb init.

Now test it.  All good.

Reset

In order to reset the bus you follow this process

  1. Pull down the bus for trstl=480uS
  2. Let the bus go back to 1 (remember that it is restive pull-up)
  3. Wait another trsth=480uS
  4. If there is a slave device on the bus it will pull down the bus at some point to indicate a “presence detect”

From the data sheet you can see that the low& high times = 480uS.  At some point during the high period the slave will pull the bus down for 15->60uS

In order to implement the reset I will modify the owb.c file.  To meet the timing requirements I will use a cyhal_timer.  The cyhal_timer is implemented in the Cypress PDL at a Cy_TCPWM_Timer which is then implemented in the hardware as a timer counter.  In this configuration the timer has:

  • A Counter (an up or down counter)
  • A Compare (a register which can be compared with the counter to trigger events)
  • A Period (a register which is compared to the counter to reset the counter back to 0).   This event is also called the “terminal count”

For this implementation I will setup a timer with

  1. Input clock 1Mz (aka 1uS per count)
  2. An up counter
  3. Starts at 0
  4. Compare value = 480 (means trigger an interrupt at 480uS)
  5. Period = 960 (means trigger an interrupt at 480uS)
  6. One shot (stop counting when you get to period (aka Terminal Count))

The code will

  1. Configure the timer (line 41-52)
  2. Pull a 0 onto the bus (line 54)
  3. Start the timer (line 56)
  4. At the compare value 480uS reset the bus to 1 using the event handler (line 20) and setup the GPIO trigger a fall event interrupt (line 21-22)
  5. At the period release the semaphore (27-30)
  6. After the compare value if the GPIO pulls down, use the GPIO interrupt to record the presence of a device (line 10)

Once I have the owb_init code I add the init command to usrcmd.c.

When I run it, I get this nice picture from the oscilliscope.

Write

In the ds18b20.c file I see that the author has three functions of interest.  In the implementation owb_write_bytes will call owb_write byte and owb_write_byte will call owb_write bit.

The one wire protocol has the following steps.

In order to write a “0” you need to

  1. Pull down the bus (write a 0)
  2. Wait 60uS
  3. Write a 1
  4. Wait 1uS (to allow the next “slot” to start

In order to write a “1” you need to

  1. Pull down the bus (write a 0)
  2. Wait 1 uS
  3. Write a 1
  4. Wait 60uS (to allow the next “slot” to start)

Notice that the minimum write slot is 60uS and the maximum is 120uS.  Here is a picture from the data sheet.

For the first implementation of owb_write_bit I will use a simple “CyDelayUs”  to implement the delays (this is a bad idea, but is a ‘cheap’ way to get going).

The write byte function just loops through the 8-bit and uses the owb_write_bit function.  Notice that it is least significant bit first.

And write_bytes (multiple) just loops through the buffer calling the write_byte function.

Now that I have the three write functions I will add a new command to usrcmd.c  This function lets the user type a command like “wbyte a1” where he/she can input a 2-character hex command.  Yes, I use the sscanf function which is unsafe… but cheap for a test rig.

When I program and launch the project I end up here.

OK that is easy enough to fix, I just ran out of stack in the ntshell thread.

Now when I run it I am off to the races.

Here is an example of “wbyte ff”

What about “owb_write_rom_code”?  I don’t know what it does, but Ill figure it out as I integrate the rest of the library.

Read

When I examine the ds18b20.c file I find these three read functions, which mirror the write functions.

To read a bit you follow a a very similar process to the write.

  1. Write a 0 on the bus
  2. Wait 1uS
  3. Write a 1 on the bus (release the bus)
  4. Wait 5uS
  5. Read (the slave will pull a 0 or a 1 onto the bus)
  6. Wait 55uS to the end of the slot

Here is a picture

The code uses a really bad busy-wait delay (but it is a good starting place to figure out what is happening)

To read a byte, just read 8 bits using the owb_read_bit function

To read an array of bytes, use a loop of read_byte

Now that you have a read and a write, update the usrcmd.c to add a “rbyte” command to the CLI

When I program the kit I can send a 0x33 (which will make the sensor respond more on this later), then read the first byte of the ROM

When you look at the scope picture (from right to left) you can see 10110110 which sure enough is B6.  The thin gaps are 1’s and the wide gaps are 0’s

In the next article Ill deal with the stupid CyDelay’s