Hello,
appended patch adds the One-Wire primitives via MPSSE and provides a simple
test program to read out Hardware ID and temperature of 1 or 2 connected
DS18B20 one-wire devices. It uses the ASYNC api and is against current
libftdi-1.0 git.
Please comment if this is usefull and in an acceptable form.
--
Uwe Bonnes bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
>From dd3a969eba5d5688e521bfe5a9816c6ebc455b2b Mon Sep 17 00:00:00 2001
From: Uwe Bonnes <bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 25 Jun 2010 15:00:28 +0200
Subject: Implement the One-Wire primitives with the MPSSE machine, add test
program to read out DS18B20
---
examples/CMakeLists.txt | 2 +
examples/Makefile.am | 1 +
examples/ow_test.c | 125 +++++++++++++++++++
src/CMakeLists.txt | 2 +-
src/Makefile.am | 2 +-
src/ftdi.h | 24 ++++
src/ftdi_ow.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 459 insertions(+), 2 deletions(-)
create mode 100644 examples/ow_test.c
create mode 100644 src/ftdi_ow.c
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index af7f57a..6f27665 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -21,6 +21,7 @@ if (EXAMPLES)
add_executable(serial_read serial_read.c)
add_executable(baud_test baud_test.c)
add_executable(stream_test stream_test.c)
+ add_executable(ow_test ow_test.c)
# Linkage
target_link_libraries(simple ftdi)
@@ -32,6 +33,7 @@ if (EXAMPLES)
target_link_libraries(serial_read ftdi)
target_link_libraries(baud_test ftdi)
target_link_libraries(stream_test ftdi)
+ target_link_libraries(ow_test ftdi)
# libftdi++ examples
if(FTDI_BUILD_CPP)
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 820599a..45d9265 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,6 +18,7 @@ bin_PROGRAMS = simple \
find_all \
serial_read \
baud_test \
+ ow_test \
$(examples_libftdipp)
# Don't install the example files
diff --git a/examples/ow_test.c b/examples/ow_test.c
new file mode 100644
index 0000000..e0e35e0
--- /dev/null
+++ b/examples/ow_test.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include <ftdi.h>
+
+#define do_and_check(x,y,z) if (x <0) { fprintf(stderr,y); return z;}
+#define do_and_checkr(a,x,y,z) if (x <0) { \
+ fprintf(stderr,y,ftdi_get_error_string(a)); return z;}
+
+/* On the used test board, SEL_N is connected to ADBUS4,
+ and there is the possibility to connect up to two DS18B20
+ One-Wire devices*/
+
+#define MOSI 0x02
+#define OWI_EN_N 0x10
+#define TEMP_GENERAL_ERROR -1
+
+static int exitRequested = 0;
+/*
+ * sigintHandler --
+ *
+ * SIGINT handler, so we can gracefully exit when the user hits ctrl-C.
+ */
+
+static void
+sigintHandler(int signum)
+{
+ exitRequested = 1;
+ fprintf(stderr,"\n");
+}
+
+
+double get_temp(struct ftdi_context *ftdi, unsigned char *id)
+{
+ int16_t temp = 0;
+ if ((OWCommand(ftdi, OW_READ, id) == 0) &&
+ (OWReadBlock(ftdi, (unsigned char*)&temp,2) == 2))
+ {
+ if (temp == TEMP_GENERAL_ERROR)
+ {
+ fprintf(stderr, "Device 0x%08Lx disconneced\n",
+ *(unsigned long long*)id);
+ id[0] = 0;
+ }
+ }
+ return (double)temp/16.0;
+}
+
+void try_reconnect (struct ftdi_context *ftdi, unsigned char *id)
+{
+ int16_t temp;
+ if (*(unsigned long long*)id)
+ {
+ /* Try if reconnected */
+ id[0] = 0x28;
+ if ((OWCommand(ftdi, OW_READ, id)== 0) &&
+ (OWReadBlock(ftdi, (unsigned char*)&temp,2) == 2))
+ {
+ if (temp == TEMP_GENERAL_ERROR)
+ id[0] = 0;
+ else
+ fprintf(stderr, "Device 0x%08Lx reconnected\n",
+ *(unsigned long long*)id);
+
+ }
+ }
+}
+int main(int argc, char **argv)
+{
+ struct ftdi_context ftdi_a;
+ unsigned char buf[3];
+ int diff;
+ unsigned char hid_nco0[8] = {0};
+ unsigned char hid_nco1[8] = {0};
+
+ do_and_check(ftdi_init(&ftdi_a), "ftdi_init A failed\n",EXIT_FAILURE);
+ do_and_check(ftdi_set_interface(&ftdi_a, INTERFACE_A),
+ "ftdi_set_interface A failed\n", EXIT_FAILURE);
+ do_and_checkr(&ftdi_a,
+ ftdi_usb_open_desc(&ftdi_a, 0x0403, 0x6010, NULL, NULL),
+ "Can't open A on ftdi device: %s\n", EXIT_FAILURE);
+ do_and_checkr(&ftdi_a,ftdi_set_latency_timer(&ftdi_a, 2),
+ "Can't set latency A, Error %s\n",EXIT_FAILURE);
+ do_and_checkr(&ftdi_a,
+ ftdi_set_bitmode(&ftdi_a,
+ MOSI | OWI_EN_N,
+ BITMODE_MPSSE),
+ "Can't set Bitmode for Interface A: %s\n", EXIT_FAILURE);
+ do_and_checkr(&ftdi_a,ftdi_usb_purge_buffers(&ftdi_a),
+ "Cant purge buffer A: %s\n",EXIT_FAILURE);
+
+ buf[0]= SET_BITS_LOW;
+ buf[1]= MOSI;
+ buf[2]= MOSI|OWI_EN_N;
+ ftdi_write_data(&ftdi_a, buf, 3);
+
+ diff = OWRomSearch(&ftdi_a, OW_SEARCH_FIRST, hid_nco0);
+ if(diff != OW_LAST_DEVICE)
+ diff = OWRomSearch(&ftdi_a, diff, hid_nco1);
+ fprintf(stderr, "OWI0: Got ID 0x%08Lx\n", *(unsigned long long*)
hid_nco0);
+ fprintf(stderr, "OWI1: Got ID 0x%08Lx\n", *(unsigned long long*)
hid_nco1);
+
+ signal(SIGINT, sigintHandler);
+ while (!exitRequested && (OWCommand( &ftdi_a, OW_CONVERT_T, NULL) !=
EXIT_FAILURE))
+ {
+ usleep(750000);
+ if(hid_nco0[0])
+ fprintf(stderr, "OWI0: %8.4f ", get_temp(&ftdi_a, hid_nco0));
+ else
+ try_reconnect(&ftdi_a, hid_nco0);
+ if(hid_nco1[0])
+ fprintf(stderr, "OWI1: %8.4f", get_temp(&ftdi_a, hid_nco1));
+ else
+ try_reconnect(&ftdi_a, hid_nco1);
+ if(hid_nco0[0] || hid_nco1[0])
+ fprintf(stderr, "\n");
+ }
+ signal(SIGINT, SIG_DFL);
+ do_and_checkr(&ftdi_a,
+ ftdi_set_bitmode(&ftdi_a, 0, BITMODE_RESET),
+ "Can't reset Bitmode for Interface A: %s\n", EXIT_FAILURE);
+ ftdi_deinit(&ftdi_a);
+ return 0;
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a4da870..b7ba79d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -4,7 +4,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}
)
# Targets
-set(c_sources ftdi.c ftdi_stream.c)
+set(c_sources ftdi.c ftdi_stream.c ftdi_ow.c)
set(c_headers ftdi.h)
add_library(ftdi SHARED ${c_sources})
diff --git a/src/Makefile.am b/src/Makefile.am
index 9141fb9..b666382 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,6 @@
# the library search path.
lib_LTLIBRARIES = libftdi.la
-libftdi_la_SOURCES = ftdi.c ftdi_stream.c
+libftdi_la_SOURCES = ftdi.c ftdi_stream.c ftdi_ow.c
include_HEADERS = ftdi.h
# Note: If you specify a:b:c as the version in the next line,
diff --git a/src/ftdi.h b/src/ftdi.h
index 324d07b..4510c9d 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -157,6 +157,23 @@ enum ftdi_interface
#define DEPRECATED(func) func
#endif
+/* One Wire related definitions */
+#define OW_RESET_RATE 16666
+/* Minimal low time is 6 us, so use a clock of 1/6us*/
+#define OW_TRANSFER_RATE 166666
+#define OW_LAST_DEVICE 0x00
+#define OW_DATA_ERR 0xFE
+#define OW_PRESENCE_ERR 0xFF
+#define OW_SEARCH_FIRST 0xFF
+
+#define OW_READ 0xBE
+#define OW_MATCH_ROM 0x55
+#define OW_SKIP_ROM 0xCC
+#define OW_CONVERT_T 0x44 // DS1820 commands
+#define OW_READ_ROM 0x33
+#define OW_SEARCH_ROM 0xF0
+
+
struct ftdi_transfer_control
{
int completed;
@@ -403,6 +420,13 @@ extern "C"
char *ftdi_get_error_string(struct ftdi_context *ftdi);
+ unsigned char OWTouchReset(struct ftdi_context *ftdi);
+ unsigned char OWReadBit(struct ftdi_context *ftdi);
+ int OWCommand(struct ftdi_context *ftdi, unsigned char command, unsigned
char *id );
+ void OWWriteByte(struct ftdi_context *ftdi, unsigned char data);
+ int OWReadBlock(struct ftdi_context *ftdi, unsigned char *data, int len);
+ unsigned char OWRomSearch(struct ftdi_context *ftdi, unsigned char diff,
unsigned char *id);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/ftdi_ow.c b/src/ftdi_ow.c
new file mode 100644
index 0000000..b566454
--- /dev/null
+++ b/src/ftdi_ow.c
@@ -0,0 +1,305 @@
+/***************************************************************************
+ ftdi_ow.c - description
+ -------------------
+ begin : June 24 2010
+ copyright : (C) 2010 Uwe Bonnes, IKDA, TU Darmstadt
+ email : bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License *
+ * version 2.1 as published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+/* Basic Connection
+ * VCC
+ DO ------ |
+ | R
+ |\o |
+ GND/SEL_N---| --------- DI/Devices
+ |/
+
+ Use e.g. 74XX125 as driver
+
+ With SEL_N driven by a FT Pin, DO/MOSI can be shared with other devices
+ using the MPSSE serial engine. Drive SEL_N low to activate the OWI Devices.
+ Sharing DI/MISO needs more considerations, like another 74XX125 )
+
+ For One Wire Timing basics, see Maxim AN126
+ http://pdfserv.maxim-ic.com/en/an/AN126.pdf
+
+ The code is derived form code using an UART as described in
+ http://www.maxim-ic.com/app-notes/index.mvp/id/214
+ and Peter Danneger's code at
+ http://www.mikrocontroller.net/attachment/4550/1wire.zip
+*/
+#include <stdlib.h>
+
+#include "ftdi.h"
+
+/**
+ Send the reset Pulse
+
+ \param ftdi pointer to ftdi_context
+
+ \retval 0: all fine
+ \retval OW_PRESENCE_ERR: No reaction from device
+*/
+unsigned char OWTouchReset(struct ftdi_context *ftdi)
+{
+ unsigned char ibuf[2];
+ unsigned char buf[9]= {TCK_DIVISOR,
+ DIV_VALUE(OW_RESET_RATE) & 0xff,
+ (DIV_VALUE(OW_RESET_RATE) >> 8) & 0xff,
+ MPSSE_DO_READ|MPSSE_DO_WRITE |MPSSE_LSB,
+ 1,0,
+ 0,0xff, SEND_IMMEDIATE};
+
+ struct ftdi_transfer_control *tc = ftdi_read_data_submit(ftdi, ibuf, 2);
+
+ ftdi_write_data(ftdi, buf, 8);
+ if(ftdi_transfer_data_done (tc) < 0)
+ {
+ ftdi->error_str = "Unexpected error";
+ return OW_PRESENCE_ERR;
+ }
+ if (ibuf[1] != 0xff)
+ return 0;
+ else
+ return OW_PRESENCE_ERR;
+}
+
+static void OWWriteBit(struct ftdi_context *ftdi, unsigned char bit)
+{
+ unsigned char buf[8]= {TCK_DIVISOR,
+ DIV_VALUE(OW_TRANSFER_RATE) & 0xff,
+ (DIV_VALUE(OW_TRANSFER_RATE) >> 8) & 0xff,
+ MPSSE_DO_WRITE |MPSSE_LSB,1,0,0xfe,0xff};
+ if (!bit)
+ {
+ buf[6] = 0;
+ buf[7] = 0xf8;
+ }
+ ftdi_write_data(ftdi, buf, 8);
+}
+
+/**
+ Read one bit
+
+ \param ftdi pointer to ftdi_context
+
+ \retval 0: A '0' was read
+ \retval OW_DATA_ERR: Unexpected error
+ \retval 0xff: A '1' was read
+*/
+
+unsigned char OWReadBit(struct ftdi_context *ftdi)
+{
+ unsigned char ibuf[2];
+ unsigned char buf[9]= {TCK_DIVISOR,
+ DIV_VALUE(OW_TRANSFER_RATE) & 0xff,
+ (DIV_VALUE(OW_TRANSFER_RATE) >> 8) & 0xff,
+ MPSSE_DO_READ|MPSSE_DO_WRITE |MPSSE_LSB,
+ 1,0, 0xfe, 0xff, SEND_IMMEDIATE};
+ struct ftdi_transfer_control *tc = ftdi_read_data_submit(ftdi, ibuf, 2);
+ ftdi_write_data(ftdi, buf, 9);
+ if(ftdi_transfer_data_done (tc) < 0)
+ {
+ ftdi->error_str = "Unexpected error";
+ return OW_DATA_ERR;
+ }
+ if (ibuf[0] == 0xfe)
+ return 0xff;
+ else
+ return 0;
+}
+
+/**
+ Read a block of data
+
+ \param ftdi pointer to ftdi_context
+ \param buf Buffer to store data in
+ \param size Size of buffer (and data to read)
+
+ \retval -2: Couldn't alloc buffer
+ \retval -1: Unexpected error
+ \retval >0: Number of bytes read
+*/
+int OWReadBlock(struct ftdi_context *ftdi, unsigned char *buf, int size)
+{
+ unsigned char *ibuf;
+ int i, j, ret =0;
+ unsigned char result = 0;
+ struct ftdi_transfer_control *tc;
+
+ ibuf = malloc(7+4*8*size);
+ if (!ibuf)
+ return -2;
+ tc = ftdi_read_data_submit(ftdi, ibuf+7+2*8*size, 2*8*size);
+ ibuf[0] = TCK_DIVISOR;
+ ibuf[1] = DIV_VALUE(OW_TRANSFER_RATE) & 0xff;
+ ibuf[2] = (DIV_VALUE(OW_TRANSFER_RATE) >> 8) & 0xff;
+ ibuf[3] = MPSSE_DO_READ|MPSSE_DO_WRITE |MPSSE_LSB;
+ ibuf[4] = (2*8*size -1) & 0xff;
+ ibuf[5] = ((2*8*size -1)>>8) & 0xff;
+
+ for (i=0; i<size*8; i++)
+ {
+ ibuf[2*i+6] = 0xfe;
+ ibuf[2*i+7] = 0xff;
+ }
+ ibuf[6+ 2*8*size] = SEND_IMMEDIATE;
+ ftdi_write_data(ftdi, ibuf, 7+ 2*8*size );
+ if(ftdi_transfer_data_done (tc) < 0)
+ {
+ ftdi->error_str = "Unexpected error";
+ ret = -1;
+ }
+ else
+ {
+ for(j=0, i=0; i<size*8; i++)
+ {
+ result >>= 1;
+ if(ibuf[7+2*8*size +i*2] == 0xfe)
+ result |=0x80;
+ if (i%8 == 7)
+ {
+ buf[j] = result;
+ result = 0;
+ j++;
+ }
+ }
+ ret = size;
+ }
+ free(ibuf);
+ return ret;
+}
+
+/**
+ Write one byte of data
+
+ \param ftdi pointer to ftdi_context
+ \param data Data Byte to write
+
+ \retval -2: Couldn't alloc buffer
+ \retval -1: Unexpected error
+ \retval >0: Number of bytes read
+*/
+void OWWriteByte(struct ftdi_context *ftdi, unsigned char data)
+{
+ unsigned char obuf[22]= {TCK_DIVISOR,
+ DIV_VALUE(OW_TRANSFER_RATE) & 0xff,
+ (DIV_VALUE(OW_TRANSFER_RATE) >> 8) & 0xff,
+ MPSSE_DO_WRITE |MPSSE_LSB,15,0};
+ int i;
+
+ for (i=0; i<8; i++)
+ {
+ if(data & 0x01)
+ {
+ obuf[i*2+6] = 0xfe;
+ obuf[i*2+7] = 0xff;
+ }
+ else
+ {
+ obuf[i*2+6] = 0x00;
+ obuf[i*2+7] = 0xf8;
+ }
+ data >>= 1;
+ }
+ ftdi_write_data(ftdi, obuf, 22);
+}
+
+/**
+ Search for ROM IDs
+
+ \param ftdi pointer to ftdi_context
+ \param diff Result for last call to this function, start with
OW_SEARCH_FIRST
+ \param id Buffer to hold found ID
+
+ \retval OW_PRESENCE_ERR : No device found
+ \retval OW_DATA_ERR: Unknown error
+ \retval OW_LAST_DEVICE : Last device found
+ \retval else: Difference to use for next search
+
+*/
+unsigned char OWRomSearch(struct ftdi_context *ftdi,
+ unsigned char diff, unsigned char *id)
+{
+ unsigned char i,j, next_diff;
+ unsigned char b;
+
+ if (OWTouchReset(ftdi))
+ {
+ ftdi->error_str = "Unexpected error";
+ return OW_PRESENCE_ERR;
+ }
+ OWWriteByte(ftdi, OW_SEARCH_ROM);
+
+ next_diff = OW_LAST_DEVICE; // unchanged on last
device
+ i = 8 * 8; // 8 bytes
+ do{
+ j = 8; // 8 bits
+ do{
+ b = OWReadBit(ftdi); // read bit
+ if( OWReadBit(ftdi) ){ // read complement bit
+ if( b ) // 11
+ return OW_DATA_ERR; // data error
+ }else{
+ if( !b ){ // 00 = 2 devices
+ if( diff > i ||
+ ((*id & 1) && diff != i) ){
+ b = 1; // now 1
+ next_diff = i; // next pass 0
+ }
+ }
+ }
+ OWWriteBit(ftdi, b ); // write bit
+ *id >>= 1;
+ if( b ) // store bit
+ *id |= 0x80;
+ i--;
+ }while( --j );
+ id++; // next byte
+ }while( i );
+ return next_diff; // to continue search
+}
+
+/**
+ Send a One-Wire command to all or a specific device
+
+ \param ftdi pointer to ftdi_context
+ \param command Commandbyte to send
+ \param id Id of specific device or NULL for all devices
+
+ \retval OW_PRESENCE_ERR : No device found
+ \retval 0 : All fine
+
+*/
+int OWCommand(struct ftdi_context *ftdi,
+ unsigned char command, unsigned char *id )
+{
+ unsigned char i;
+ if (OWTouchReset(ftdi))
+ {
+ if (id)
+ {
+ ftdi->error_str = "Device disconnected";
+ id[0] = 0;
+ }
+ return OW_PRESENCE_ERR;
+ }
+ if( id ){
+ OWWriteByte(ftdi, OW_MATCH_ROM ); // to a single device
+ for (i=0; i<8; i++)
+ OWWriteByte(ftdi, id[i] );
+ }
+ else {
+ OWWriteByte(ftdi, OW_SKIP_ROM ); // to all devices
+ }
+ OWWriteByte(ftdi, command );
+ return 0;
+}
--
1.6.4.2
--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx
|