1-Wire

From linux-sunxi.org
Jump to navigation Jump to search

One Wire

1-Wire is a device communications bus system designed by Dallas Semiconductor that provides low-speed data, signaling, and power over a single signal. 1-Wire is similar in concept to I²C, but with lower data rates and longer range. It is typically used to communicate with small inexpensive devices such as digital thermometers and weather instruments. A network of 1-Wire devices with an associated master device is called a MicroLan.

1-Wire support for Mainline kernel

To communicate with 1-wire devices it is recommended to use w1-gpio driver as most of the Allwinner SoCs lack hardware controller (only present on A31 and A80).

Device Tree

Create an overlay for your devicetree (assuming 1-wire device is connected to PE12 pin):

/dts-v1/;
/plugin/;

&{/} {
        onewire {
        compatible = "w1-gpio";
        gpios = <&pio 4 12 16>;
        /* 4: "E" of PE12;
        12: "12" of PE12;
        16: GPIO_PULL_UP as defined in dt-bindings/gpio/gpio.h */
        status = "okay";
        };
};

Save this snippet with a name like sun50i-a64-w1-gpio-PE12.dts and compile it with:

dtc -I dts -O dtb sun50i-a64-w1-gpio-PE12.dts -o sun50i-a64-w1-gpio-PE12.dtbo

Specify the .dtbo file path in the fdtoverlays list inside the /boot/uEnv.txt file:

cat /boot/uEnv.txt
fdtoverlays=/root/sun50i-a64-w1-gpio-PE12.dtbo

Reboot and check whether it's enabled:

cat /sys/kernel/debug/pinctrl/1c20800.pinctrl/pinmux-pins |grep PE12

The pin is properly configured if you have an output like:

pin 140 (PE12): GPIO 1c20800.pinctrl:140

Linux kernel 3.4

Edit the script.fex file and set the gpio pin for 1-wire bus


[gpio_para]
gpio_used = 1
gpio_num = 67
gpio_pin_1 = port:PG03<1><default><default><1>
....
gpio_pin_66 = port:PB10<1><default><default><1>

[w1_para]
gpio = 66

Connect the data pin of devices to gpio pin PB10 and in sys folder you have

/sys/bus/w1/devices/
28-000004bfae30
28-000004c022c5

what are connect 2 DS18B20 devices

cat /sys/bus/w1/devices/28-000004bfae30/w1_slave
45 01 4b 46 7f ff 0b 10 84 : crc=84 YES
45 01 4b 46 7f ff 0b 10 84 t=20312

the temp is 20.312 °C

Linux kernel 4.14

You don't have to edit the fex-file, but the /boot/armbianEnv.txt and add the lines:

overlays=w1-gpio
param_w1_pin=PB10             # desired pin
param_w1_pin_int_pullup=1     # internal pullup-resistor: 1=on, 0=off

Connect the data pin of devices to gpio pin PB10 and proceed like Kernel 3.4 with

/sys/bus/w1/devices/
28-000004bfae30
28-000004c022c5

and

cat /sys/bus/w1/devices/28-000004bfae30/w1_slave
45 01 4b 46 7f ff 0b 10 84 : crc=84 YES
45 01 4b 46 7f ff 0b 10 84 t=20312

Read Data Sensor

BASH

simple bash script for read 1-wire temp sensor


#!/bin/bash

file="/sys/bus/w1/devices/28-000004bfae30/w1_slave"
function find(){
 [[ "$1" =~ "$2" ]] && true || false
}

while :
do
	DATE=$(date +"%d-%m-%Y-%H:%M:%S")
	#read device
	CRC=false
	while read curline; do
		#check crc
		if( find "$curline" "crc" && find "$curline" "YES" ) then
			CRC=true
			DEVICE=`echo $curline|cut -d':' -f 1`	
		fi
		if($CRC && find "$curline" "t=") then
		TEMP=`echo $curline|cut -d'=' -f 2`
		echo $DEVICE ";" $DATE ";" `echo "scale=3;$TEMP/1000"|bc -l` 
		fi
	done <$file
sleep 10
done

Python

def get_thermometer_filepath(thermometer_id: str):
    import os
    thermometer_filepath = os.path.join("/sys/bus/w1/devices/", thermometer_id, "w1_slave")
    try:
        with open(thermometer_filepath, "r"):
            pass
    except FileNotFoundError as e:
        print("Thermometer sysfs file not found: " + str(e))
        thermometer_filepath = None
    return thermometer_filepath

def get_temperature(thermometer_filepath: str):
    if thermometer_filepath:
        err = None
        try:
            with open(thermometer_filepath, "r") as w1handle:
                lines = w1handle.readlines()
                try:
                    crc = lines[0].strip().endswith("YES")
                    if crc:
                        return int(lines[1][29:].strip())/1000
                    else:
                        err = "Thermometer read CRC failed: " + thermometer_filepath
                except IndexError as e:
                    err = "Thermometer sysfs file "+thermometer_filepath+" is empty (communication unsuccessful): " + str(e)
        except FileNotFoundError as e:
            err = "Thermometer sysfs file "+thermometer_filepath+" not found: " + str(e)
        print(err)
        return -99.99
    else:
        return -99.99

Usage:

temperature = get_temperature(get_thermometer_filepath("28-000010400ca7"))