Use DS18B20 Temperature Sensor module on DEBIX

2024.2.18by debix.io

Example Device: DEBIX Model A + I/O Board



Overview
·DS18B20 is a high-precision single bus digital temperature measurement chip.
·The temperature measurement range is -55 ℃ to +125 ℃, with an error of ± 0.4 ° within the range of -10 ℃ to +85 ℃.


Hardware installation

·Temperature Sensor module's VCC terminal is connected to J2 Pin2 of DEBIX Model A I/O board

·Temperature Sensor module's OUT terminal is connected to J2 Pin7 of DEBIX Model A I/O board

·Temperature Sensor module's GND terminal is connected to J2 Pin39 of DEBIX Model A I/O board


Modify the device tree imx8mp-evk.dts


1. Add the required GPIO under the iomuxc node:
pinctrl_DS18B20: DS18B20group{
            fsl,pins = <
                  MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12 0x40000
            >;
      };

2. Add DS18B20 module node under root node:

DS18B20: DS18B20 {

           compatible = "DS18B20";

           pinctrl-0  = <&pinctrl_DS18B20>;

           SW-gpios   = <&gpio1 12 GPIO_ACTIVE_LOW>;

           status = "okay";

    };


3. Compile and replace the device tree file

·Compile the device tree in the source directory: make ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- dtbs

·Copy the compiled new device tree file arch/arm64/boot/dts/freescale/imx8mp-evk.dtb to the /boot directory of DEBIX and restart DEBIX.


4. Check whether dts contains the modified device tree node.

·Run the command ls /sys/firmware/devicetree/base/DS18B20/


·Run the command cat /sys/firmware/devicetree/base/DS18B20/compatible




Write and Load DriversThe driver code is as follows:

// Simulate one wire timing using GPIO

#include <linux/init.h>

#include <linux/module.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <linux/platform_device.h>

#include <linux/device.h>

#include <linux/err.h>

#include <linux/of.h>

#include <linux/of_device.h>

#include <linux/gpio.h>

#include <linux/of_gpio.h>

#include <linux/delay.h>

#include <linux/of_irq.h>

#define GET_TEMPERATURE _IOR('R',int)

struct device_node *DS18B20_device_node;

struct property *DS18B20_node_property;

int DS18B20_gpio_index = 0;

unsigned long flags;


void DS18B20_SetGPIOInput(void){

gpio_direction_input(DS18B20_gpio_index);

}

void DS18B20_SetGPIOOutput(int value){

gpio_direction_output(DS18B20_gpio_index,value);

}

int DS18B20_GetValue(void){

return gpio_get_value(DS18B20_gpio_index);

}

void DS18B20_Rst(void){                

DS18B20_SetGPIOOutput(0);

 udelay(750);   
    DS18B20_SetGPIOOutput(1);
udelay(15);     
}
/**
 * @retval 1: found DS18B20  0: donot found DS18B20
 */ 
u8 DS18B20_Check(void){   
u8 retry=0;
DS18B20_SetGPIOInput(); 
    while (DS18B20_GetValue() && retry<200){
retry++;
udelay(1);
};  
if(retry>=200)return 1;
else retry=0;
    while (!DS18B20_GetValue() &&retry<240){
retry++;
udelay(1);
};
if(retry>=240)return 1;     
return 0;
}
u8 DS18B20_Read_Bit(void) {
    u8 data;
DS18B20_SetGPIOOutput(0);
udelay(2);
    DS18B20_SetGPIOOutput(1); 
DS18B20_SetGPIOInput(); 
udelay(12);
if(DS18B20_GetValue())data=1;
    else data=0;  
    udelay(50);           
    return data;
}
u8 DS18B20_Read_Byte(void) {        
    u8 i,j,dat;
    dat=0;
for (i=1;i<=8;i++) {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }     
    return dat;
}
void DS18B20_Write_Byte(u8 dat) {             
    u8 j;
    u8 testb;
DS18B20_SetGPIOOutput(0); 
    for (j=1;j<=8;j++) {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) {
            DS18B20_SetGPIOOutput(0); 
            udelay(2);                            
            DS18B20_SetGPIOOutput(1); 
            udelay(60);             
        }else {
            DS18B20_SetGPIOOutput(0);
            udelay(60);             
            DS18B20_SetGPIOOutput(1); 
            udelay(2);                          
        }
    }
}

void DS18B20_Start(void) {                   
    DS18B20_Rst();    
DS18B20_Check();  
    DS18B20_Write_Byte(0xcc);

    DS18B20_Write_Byte(0x44);


     
u8 DS18B20_Init(void){
  DS18B20_SetGPIOOutput(1); 
DS18B20_Rst();
return DS18B20_Check();
}  

/**
 * @note accuracy: 0.1
 * @retval temperature range[-550,1250]
 * @example return value is 223,so the temperature is 22.3
 * */
short DS18B20_Get_Temp(void){
    u8 temp;
    u8 TL,TH;
u32 tem;
    DS18B20_Start (); 
    DS18B20_Rst();
    DS18B20_Check();  
    DS18B20_Write_Byte(0xcc);
    DS18B20_Write_Byte(0xbe);     
    TL=DS18B20_Read_Byte();   
    TH=DS18B20_Read_Byte();     
    if(TH>7){
        TH=~TH;
        TL=~TL; 
        temp=0;
    }else temp=1;     
    tem=TH;
    tem<<=8;    
    tem+=TL;
//printk("temp: %d..\n",tem);
    tem= (tem * 625)/1000;
if(temp)return tem;
else return -tem;    
}
int misc_open (struct inode *inode, struct file *file){
printk("misc_open..\n");
return 0;
}
int misc_release (struct inode *inode, struct file *file){
printk("misc_release..\n");
return 0;
}
long misc_ioctl (struct file *file, unsigned int cmd, unsigned long val){
s32 tem;
switch(cmd){
case GET_TEMPERATURE:
local_irq_save(flags);
tem = DS18B20_Get_Temp();
local_irq_restore(flags);
if(put_user(tem,(int *)val)!=0){
printk("put_user err..\n");
}
break;
default:break;
}
return 0;
}

static const struct file_operations misc_fops={
.owner = THIS_MODULE,
.open = misc_open,
.release = misc_release,
.unlocked_ioctl = misc_ioctl,
};
static struct miscdevice misc_dev={


.minor = MISC_DYNAMIC_MINOR,
.name = "DS18B20",
.fops = &misc_fops
};
int DS18B20_probe(struct platform_device *pd){
int ret;
DS18B20_device_node = of_find_node_by_path("/DS18B20");
if(DS18B20_device_node == NULL){
printk("of_find_node_by_path err..\n");
return -1;
}
DS18B20_gpio_index = of_get_named_gpio(DS18B20_device_node,"SW-gpios",0);
if(DS18B20_gpio_index<0){
printk("of_get_name_gpio SW-gpios err..\n");
return -1;
}
ret = gpio_request(DS18B20_gpio_index, "SW-gpios");
if (ret<0){
printk("gpio_request SW-gpios is error \n");
return -1;
}

ret = misc_register(&misc_dev);
if(ret<0){
printk("misc_register err..\n");
return -1;
}
printk(
(DS18B20_Check())?
"DS18B20 found...\n":
"DS18B20 not found...\n");
printk("DS18B20_probe..\n");
return 0;
}
int DS18B20_remove(struct platform_device *pd){
misc_deregister(&misc_dev);
gpio_free(DS18B20_gpio_index);
printk("DS18B20_remove..\n");
return 0;
}
static const struct platform_device_id DS18B20_idtable[] = {
{.name = "DS18B20",},
{}
};
static const struct of_device_id DS18B20_data_dt_ids[] = {
{ .compatible = "DS18B20"},
{ /* sentinel */ }
};
static struct platform_driver DS18B20_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "DS18B20",
.of_match_table = of_match_ptr(DS18B20_data_dt_ids),
},
.probe = DS18B20_probe,
.remove = DS18B20_remove,
.id_table = DS18B20_idtable,
};
module_platform_driver(DS18B20_driver);
MODULE_LICENSE("GPL");



1. Run the above command to compile the driver make will get the .ko file

2. Copy the .ko file to DEBIX, run the command sudo insmod DS18B20.ko

3. Run the command sudo dmesg | tail -2 , check the driver print information:


4.  You can see that the probe function matches the device tree successfully.

Write Application Test Code

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define GET_TEMPERATURE _IOR('R',int)
int main(int argc,char *argv[]) {
    int fd;
    int Temperature;
    fd = open("/dev/DS18B20",O_RDWR);
    if(fd<0){
        printf("open err..\n");
    }
    for( ;; ){
        ioctl(fd,GET_TEMPERATURE,&Temperature);
     printf("Temperature: %d.%d\n",Temperature/10,(Temperature%10));
        sleep(1);
    }
    close(fd);
    return 0;
}
Compile the application file, run the command aarch64-none-linux-gnu-gcc app.c -o app, copy the compiled executable file to DEBIX.
Test result
·Execute the application test code, and run the command ./app.

·Touch the DS18B20 by hand, and it displays: