Getting temperature from DS18B20 with nRF5340-DK

Hello everyone,

I am experiencing issues to get temperature from DS18B20 sensor with a nRF5340 board.

The probleme I have is that the only values my code reads is 0xFF.

I am using nRF Connect SDK v2.0.0. and here is my code :

Im am using two different sources I found on internet :

I have copied this code in a file named ds18b20.c and only replaces the

nrf_delay_us(timeout);
functions by
k_sleep(K_USEC(timeout));
functions.

/**
 * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 * 
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 * 
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 * 
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */

#include <hal/nrf_gpio.h>
#include <kernel.h>

#include "ds18b20.h"

// #define DS_PIN 26
#define DS_PIN 10

// Commands
#define STARTCONVO      0x44
#define READSCRATCH     0xBE
#define WRITESCRATCH    0x4E

// Scratchpad locations
#define TEMP_LSB        0
#define TEMP_MSB        1

// Device resolution
#define TEMP_9_BIT  0x1F //  9 bit
#define TEMP_10_BIT 0x3F // 10 bit
#define TEMP_11_BIT 0x5F // 11 bit
#define TEMP_12_BIT 0x7F // 12 bit

typedef uint8_t ScratchPad[9];

/**@brief Function for sending one bit to bus.
 */
void ds18b20_send(char bit)
{
    nrf_gpio_cfg_output(DS_PIN);
    nrf_gpio_pin_clear(DS_PIN);

    k_sleep(K_USEC(5));

    if(bit==1)
    {
        nrf_gpio_pin_set(DS_PIN);
    }
    k_sleep(K_USEC(80));
    nrf_gpio_pin_set(DS_PIN);
}


/**@brief Function for reading one bit from bus.
 */
unsigned char ds18b20_read(void)
{
    unsigned char presence=0;
    nrf_gpio_cfg_output(DS_PIN);
    nrf_gpio_pin_clear(DS_PIN);

    k_sleep(K_USEC(2));

    nrf_gpio_pin_set(DS_PIN);;
    k_sleep(K_USEC(15));

    nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL);

    if(nrf_gpio_pin_read(DS_PIN))
    {
        presence = 1;
    }
    else
    {
        presence = 0;
    }
    
    return presence;
}


/**@brief Function for sending one byte to bus.
 */
void ds18b20_send_byte(char data)
{
    unsigned char i;
    unsigned char x;
    for(i=0;i<8;i++)
    {
      x = data>>i;
      x &= 0x01;
      ds18b20_send(x);
    }
    k_sleep(K_USEC(100));
}


/**@brief Function for reading one byte from bus.
 */
unsigned char ds18b20_read_byte(void)
{
    unsigned char i;
    unsigned char data = 0;
    for (i=0;i<8;i++)
    {
        if(ds18b20_read()) data|=0x01<<i;
        k_sleep(K_USEC(15));
    }
    return(data);
}


/**@brief Function for sending reset pulse.
 */
unsigned char ds18b20_reset(void)
{
    unsigned char presence;

    nrf_gpio_cfg_output(DS_PIN);
    nrf_gpio_pin_clear(DS_PIN);

    k_sleep(K_USEC(500));
    nrf_gpio_pin_set(DS_PIN);

    nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL); // usikkert p� pull her. m� sjekkes
    k_sleep(K_USEC(30));


    if(nrf_gpio_pin_read(DS_PIN) == 0)    
        presence = 1;   
    else    
        presence = 0;
    
    k_sleep(K_USEC(470));

    if(nrf_gpio_pin_read(DS_PIN) == 1)    
        presence = 1;   
    else  
        presence = 0;

    return presence;
}


/**@brief Function for reading temperature.
 */
float ds18b20_get_temp(void)
{
    unsigned char check;
    char temp1=0, temp2=0;

    check=ds18b20_reset();
    
    if(check)
    {
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(0x44);

        k_sleep(K_MSEC(600UL));

        check=ds18b20_reset();
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(0xBE);

        temp1=ds18b20_read_byte();
        temp2=ds18b20_read_byte();

        check=ds18b20_reset();

        float temp=0;
        temp=(float)(temp1+(temp2*256))/16;

        return temp;
    }
      return 0;
}


/**@brief Function for reading bit.
 */
uint8_t OneWire_read_bit(void)
{
    uint8_t r;
    nrf_gpio_cfg_output(DS_PIN);
    nrf_gpio_pin_clear(DS_PIN);
    k_sleep(K_USEC(3));
    nrf_gpio_cfg_input(DS_PIN,NRF_GPIO_PIN_NOPULL);
    k_sleep(K_USEC(10));
    r =nrf_gpio_pin_read(DS_PIN);
    k_sleep(K_USEC(53));
    return r;
}


/**@brief Function for reading.
 */
uint8_t OneWire_read()
{
    uint8_t bitMask;
    uint8_t r = 0;

    for (bitMask = 0x01; bitMask; bitMask <<= 1) {
	if ( OneWire_read_bit()) r |= bitMask;
    }
    return r;
}


/**@brief Function for reading scratchpad value
 */
void ds18b20_readScratchPad(uint8_t *scratchPad, uint8_t fields)
{
    ds18b20_reset();
    ds18b20_send_byte(0xCC);
    ds18b20_send_byte(READSCRATCH);

    for(uint8_t i=0; i < fields; i++)
    {
        scratchPad[i] = OneWire_read();
    }
    ds18b20_reset();
}


/**@brief Function for request temperature reading
 */
void ds18b20_requestTemperatures(void)
{
    ds18b20_reset();
    ds18b20_send_byte(0xCC);
    ds18b20_send_byte(STARTCONVO);
}


/**@brief Function for reading temperature method 2
 */
float ds18b20_get_temp_method_2(void)
{
    ds18b20_requestTemperatures();

    ScratchPad scratchPad;
    ds18b20_readScratchPad(scratchPad, 2);
    int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];
    float temp = 0.0625 * rawTemperature;

    return temp;
}


/**@brief Function for setting temperature resolution
 */
void ds18b20_setResolution(uint8_t resolution)
{
    ds18b20_reset();
    ds18b20_send_byte(0xCC);
    ds18b20_send_byte(WRITESCRATCH);
    // two dummy values for LOW & HIGH ALARM
    ds18b20_send_byte(0);
    ds18b20_send_byte(100);
    switch (resolution)
    {
        case 12:
            ds18b20_send_byte(TEMP_12_BIT);
            break;

        case 11:
            ds18b20_send_byte(TEMP_11_BIT);
            break;

        case 10:
            ds18b20_send_byte(TEMP_10_BIT);
            break;

        case 9:
        default:
            ds18b20_send_byte(TEMP_9_BIT);
            break;
    }
    ds18b20_reset();
}

I have rewritten this code in a file named sensor.c and changed the delay and the pin control functions.

#include <kernel.h>
#include <devicetree.h>
#include <device.h>
#include <drivers/gpio.h>

#include "ds18b20.h"

#define DQ 10

const struct device * gpio_dev;


//////////////////////////////////////////////////////////////////////////////
// OW_RESET - performs a reset on the one-wire bus and
// returns the presence detect. Reset is 480us. Presence checked
// another 70us later.
//
unsigned char ow_reset(void)
{
    unsigned char presence;

    gpio_dev = device_get_binding("GPIO_0");
    gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); //pull DQ line low

    k_sleep(K_USEC(480)); // leave it low for 480us

    gpio_pin_set(gpio_dev, DQ, 1);  // allow line to return high

    k_sleep(K_USEC(70)); // wait for presence

    gpio_pin_configure(gpio_dev, DQ, GPIO_INPUT);
    if(gpio_pin_get(gpio_dev, DQ))  // get presence signal
            presence = 1;
    else  
            presence = 0;

    k_sleep(K_USEC(410)); // wait for end of timeslot


    return(presence); // presence signal returned

} // 0=presence, 1 = no part


//////////////////////////////////////////////////////////////////////////////
// READ_BIT - reads a bit from the one-wire bus. The delay
// required for a read is 15us, so the DELAY routine won't work.
// We put our own delay function in this routine in the form of a
// for() loop.
//
unsigned char read_bit(void)
{
    unsigned char presence;

    gpio_dev = device_get_binding("GPIO_0");
    gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); // pull DQ low to start timeslot

    k_sleep(K_USEC(2));

     gpio_pin_configure(gpio_dev, DQ, GPIO_INPUT);  // then return high

    k_sleep(K_USEC(15));    // delay 15us from start of timeslot
   
    if(gpio_pin_get(gpio_dev, DQ))  // get presence signal
            presence = 1;
    else  
            presence = 0;

    return(presence); // return value of DQ line
}


//////////////////////////////////////////////////////////////////////////////
// WRITE_BIT - writes a bit to the one-wire bus, passed in bitval.
//
void write_bit(char bitval)
{
    gpio_dev = device_get_binding("GPIO_0");
    gpio_pin_configure(gpio_dev, DQ, GPIO_OUTPUT_INACTIVE); // pull DQ low to start timeslot

    k_sleep(K_USEC(5));

    if(bitval==1) gpio_pin_set(gpio_dev, DQ, 1); // return DQ high if write 1

    k_sleep(K_USEC(115)); // hold value for remainder of timeslot


    gpio_pin_set(gpio_dev, DQ, 1);
}


//////////////////////////////////////////////////////////////////////////////
// READ_BYTE - reads a byte from the one-wire bus.
//
unsigned char read_byte(void)
{
    unsigned char i;
    unsigned char value = 0;

    for (i=0;i<8;i++)
    {
        if(read_bit()) value|=0x01<<i;  // reads byte in, one byte at a time and then shifts it left
        
        k_sleep(K_USEC(103));   // wait for rest of timeslot
    }

    return(value);
}



//////////////////////////////////////////////////////////////////////////////
// WRITE_BYTE - writes a byte to the one-wire bus.
//
void write_byte(char val)
{
    unsigned char i;
    unsigned char temp;

    for (i=0; i<8; i++) // writes byte, one bit at a time
    {
        temp = val>>i; // shifts val right 'i' spaces
        temp &= 0x01; // copy that bit to temp
        write_bit(temp); // write bit in temp into
    }

    k_sleep(K_USEC(104));
}


int read_temperature(void)
{
    char get[10];
    char temp_lsb,temp_msb;
    int k;
    int temp_c;

    ow_reset();
    write_byte(0xCC); //Skip ROM
    write_byte(0x44); // Start Conversion

    k_sleep(K_USEC(600));

    ow_reset();
    write_byte(0xCC); // Skip ROM
    write_byte(0xBE); // Read Scratch Pad

    for (k=0;k<9;k++){get[k]=read_byte();}
    // printk("\n ScratchPAD DATA = %X%X%X%X%X\n",get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
    
    temp_msb = get[1]; // Sign byte + lsbit
    temp_lsb = get[0]; // Temp data plus lsb
    if (temp_msb <= 0x80){temp_lsb = (temp_lsb/2);} // shift to get whole degree
    temp_msb = temp_msb & 0x80; // mask all but the sign bit
    if (temp_msb >= 0x80) {temp_lsb = (~temp_lsb)+1;} // twos complement
    if (temp_msb >= 0x80) {temp_lsb = (temp_lsb/2);}// shift to get whole degree
    if (temp_msb >= 0x80) {temp_lsb = ((-1)*temp_lsb);} // add sign bit

    temp_c = (int)temp_lsb;

    printk( "TempC= %d degrees C\n", temp_c ); // print temp. C

    return temp_c;
}

Here is my main.c :

/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include "ds18b20.h"
#include "sensor.h"

void main(void)
{
	float fTemp1, fTemp2;
	int iTemp;


	ds18b20_setResolution(12);

	fTemp1 = ds18b20_get_temp();	// Method 1 (from sd18b20.c)
	k_sleep(K_SECONDS(1));

	fTemp2 = ds18b20_get_temp_method_2();	// Method 2 (from sd18b20.c)
	k_sleep(K_SECONDS(1));

	iTemp = read_temperature();		// Metohd 3 (from sensor.c)
	k_sleep(K_SECONDS(1));

	printk("Hello World! %s\nTemperature is :\n%d from method 1\n%d from method 2\n%d from method 3\n\n", CONFIG_BOARD, (int)fTemp1, (int)fTemp2, iTemp);

	while (1)
	{
		k_sleep(K_SECONDS(60));

		fTemp1 = ds18b20_get_temp();
		fTemp2 = ds18b20_get_temp();
		iTemp = read_temperature();

		printk("The temperature is now : \n%d from method 1\n%d from method 2\n%d from method 3\n\n", (int)fTemp1, (int)fTemp2, iTemp);
	}
	

}

Also, pics of my connections :

The problem is the same for the three methods.

What I observe is that, during the reading part, it only reads high state values (=0xFF).

I thought the problem was from the time slots of my functions. But I tried dfiferent configurations and none of them worked.

I also tried with different flags for the pin configuration (in sensor.c) : GPIO_OUTPUT, GPIO_OUTPUT_INIT_LOW, GPIO_OUTPUT_INACTIVE. With no effects.

I am strating thinking the issue comes from the hard but I can't see what I am doing wrong.

For now, I'm still thinking the problem comes from one of thoses :

  • The hard (my connections aren't correct)
  • The pin configuration (but ds18b20.c should work as I didn't touch the pin configuration in this one).
  • Maybe the k_sleep function but I woudn't understand why.

Do anyone have an idea ?

Thanks in advance for you help !

Regards,

Sulian

Parents
  • Hello Elfving,

    I looked at my signal with an oscilloscope and the issue was indeed the fault of k_sleep(K_USEC(timeout)) which couldn't apparently work with microseconds (same problem with k_usleep(timeout)).

    I have seen somewhere that upgrading the value of CONFIG_SYS_CLOCK_TICKS_PER_SEC could have helped but the default value seems to already be the highest for nRF5340 (32768).

    So I tried to use timers :

    K_TIMER_DEFINE(timer, NULL, NULL);
    
    /* Do some work */
    
    /* When a 15 usec wait is needed */
    k_timer_start(&timer, K_USEC(15), K_NO_WAIT);
    
    /* Wait the end of the timer */
    k_timer_status_sync(&timer);
    
    /* Continue the work */
    

    But it wasn't working under a hundred of microseconds nor precise.

    At this moment I didn't see the k_busy_wait function so I made my own timer function :

    void timer(uint64_t iTimeout)
    {
        uint64_t iUptime = k_uptime_ticks();
    
        while ((k_uptime_ticks() - iUptime) < k_us_to_ticks_near64(iTimeout));
        
    }

    And it works nicely.

    I tried replacing my timer function with k_busy_wait and it's still working perfectly !

    Thanks you very much Eflving !

    If someone is interesting by my code, here it is :

    (I made it board agnostic by replacing the nrf_gpio function, and the k_busy_wait functions can be replace by the timer function).

    #include <kernel.h>
    #include <drivers/gpio.h>
    
    #include "ds18b20.h"
    
    // #define DS_PIN 26
    #define DS_PIN 10
    
    // Commands
    #define STARTCONVO      0x44
    #define READSCRATCH     0xBE
    #define WRITESCRATCH    0x4E
    
    // Scratchpad locations
    #define TEMP_LSB        0
    #define TEMP_MSB        1
    
    // Device resolution
    #define TEMP_9_BIT  0x1F //  9 bit
    #define TEMP_10_BIT 0x3F // 10 bit
    #define TEMP_11_BIT 0x5F // 11 bit
    #define TEMP_12_BIT 0x7F // 12 bit
    
    typedef uint8_t ScratchPad[9];
    
    const struct device * dev;
    
    /**@brief Custome timer.
     */
    void timer(uint64_t iTimeout)
    {
        uint64_t iUptime = k_uptime_ticks();
    
        while ((k_uptime_ticks() - iUptime) < k_us_to_ticks_near64(iTimeout));
        
    }
    
    
    /**@brief Function for sending one bit to bus.
     */
    void ds18b20_send(char bit)
    {
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        
        k_busy_wait(5);
    
        if(bit==1)
            gpio_pin_set(dev, DS_PIN, 1);
        
        k_busy_wait(80);
        
        gpio_pin_set(dev, DS_PIN, 1);
    }
    
    
    /**@brief Function for reading one bit from bus.
     */
    unsigned char ds18b20_read(void)
    {
        unsigned char presence=0;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(2);
    
        gpio_pin_set(dev, DS_PIN, 1);
        k_busy_wait(15);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
    
        if(gpio_pin_get(dev, DS_PIN))
            presence = 1;
        
        else
            presence = 0;
        
        
        return presence;
    }
    
    
    /**@brief Function for sending one byte to bus.
     */
    void ds18b20_send_byte(char data)
    {
        unsigned char i;
        unsigned char x;
    
        for(i=0;i<8;i++)
        {
          x = data>>i;
          x &= 0x01;
          ds18b20_send(x);
        }
    
        k_busy_wait(100);
    }
    
    
    /**@brief Function for reading one byte from bus.
     */
    unsigned char ds18b20_read_byte(void)
    {
        unsigned char i;
        unsigned char data = 0;
    
        for (i=0;i<8;i++)
        {
            if(ds18b20_read()) data|=0x01<<i;
            k_busy_wait(15);
        }
    
        return(data);
    }
    
    
    /**@brief Function for sending reset pulse.
     */
    unsigned char ds18b20_reset(void)
    {
        unsigned char presence;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(500);
        
        gpio_pin_set(dev, DS_PIN, 1);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
        k_busy_wait(30);
    
    
        if(gpio_pin_get(dev, DS_PIN) == 0)    
            presence = 1;   
        else    
            presence = 0;
        
        k_busy_wait(470);
    
        if(gpio_pin_get(dev, DS_PIN) == 1)    
            presence = 1;   
        else  
            presence = 0;
    
        return presence;
    }
    
    
    /**@brief Function for reading temperature.
     */
    float ds18b20_get_temp(void)
    {
        unsigned char check;
        char temp1=0, temp2=0;
    
        check=ds18b20_reset();
        
        if(check)
        {
            ds18b20_send_byte(0xCC);
            ds18b20_send_byte(0x44);
    
            k_busy_wait(600);
    
            check=ds18b20_reset();
            ds18b20_send_byte(0xCC);
            ds18b20_send_byte(0xBE);
    
            temp1=ds18b20_read_byte();
            temp2=ds18b20_read_byte();
    
            check=ds18b20_reset();
    
            float temp=0;
            temp=(float)(temp1+(temp2*256))/16;
    
            return temp;
        }
          return 0;
    }
    
    
    /**@brief Function for reading bit.
     */
    uint8_t OneWire_read_bit(void)
    {
        uint8_t r;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(3);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
    
        k_busy_wait(10);
    
        r = gpio_pin_get(dev, DS_PIN);
    
        k_busy_wait(53);
    
        return r;
    }
    
    
    /**@brief Function for reading.
     */
    uint8_t OneWire_read()
    {
        uint8_t bitMask;
        uint8_t r = 0;
    
        for (bitMask = 0x01; bitMask; bitMask <<= 1)
    	    if ( OneWire_read_bit()) r |= bitMask;
        
        return r;
    }
    
    
    /**@brief Function for reading scratchpad value
     */
    void ds18b20_readScratchPad(uint8_t *scratchPad, uint8_t fields)
    {
        ds18b20_reset();
    
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(READSCRATCH);
    
        for(uint8_t i=0; i < fields; i++)
            scratchPad[i] = OneWire_read();
        
        ds18b20_reset();
    }
    
    
    /**@brief Function for request temperature reading
     */
    void ds18b20_requestTemperatures(void)
    {
        ds18b20_reset();
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(STARTCONVO);
    }
    
    
    /**@brief Function for reading temperature method 2
     */
    float ds18b20_get_temp_method_2(void)
    {
        ds18b20_requestTemperatures();
    
        ScratchPad scratchPad;
        ds18b20_readScratchPad(scratchPad, 2);
    
        int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];
        float temp = 0.0625 * rawTemperature;
    
        return temp;
    }
    
    
    /**@brief Function for setting temperature resolution
     */
    void ds18b20_setResolution(uint8_t resolution)
    {
        ds18b20_reset();
    
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(WRITESCRATCH);
        
        // two dummy values for LOW & HIGH ALARM
        ds18b20_send_byte(0);
        ds18b20_send_byte(100);
    
        switch (resolution)
        {
            case 12:
                ds18b20_send_byte(TEMP_12_BIT);
                break;
    
            case 11:
                ds18b20_send_byte(TEMP_11_BIT);
                break;
    
            case 10:
                ds18b20_send_byte(TEMP_10_BIT);
                break;
    
            case 9:
            default:
                ds18b20_send_byte(TEMP_9_BIT);
                break;
        }
    
        ds18b20_reset();
    }

    Thanks you again Elfving !

    Regards,

    Sulian

Reply
  • Hello Elfving,

    I looked at my signal with an oscilloscope and the issue was indeed the fault of k_sleep(K_USEC(timeout)) which couldn't apparently work with microseconds (same problem with k_usleep(timeout)).

    I have seen somewhere that upgrading the value of CONFIG_SYS_CLOCK_TICKS_PER_SEC could have helped but the default value seems to already be the highest for nRF5340 (32768).

    So I tried to use timers :

    K_TIMER_DEFINE(timer, NULL, NULL);
    
    /* Do some work */
    
    /* When a 15 usec wait is needed */
    k_timer_start(&timer, K_USEC(15), K_NO_WAIT);
    
    /* Wait the end of the timer */
    k_timer_status_sync(&timer);
    
    /* Continue the work */
    

    But it wasn't working under a hundred of microseconds nor precise.

    At this moment I didn't see the k_busy_wait function so I made my own timer function :

    void timer(uint64_t iTimeout)
    {
        uint64_t iUptime = k_uptime_ticks();
    
        while ((k_uptime_ticks() - iUptime) < k_us_to_ticks_near64(iTimeout));
        
    }

    And it works nicely.

    I tried replacing my timer function with k_busy_wait and it's still working perfectly !

    Thanks you very much Eflving !

    If someone is interesting by my code, here it is :

    (I made it board agnostic by replacing the nrf_gpio function, and the k_busy_wait functions can be replace by the timer function).

    #include <kernel.h>
    #include <drivers/gpio.h>
    
    #include "ds18b20.h"
    
    // #define DS_PIN 26
    #define DS_PIN 10
    
    // Commands
    #define STARTCONVO      0x44
    #define READSCRATCH     0xBE
    #define WRITESCRATCH    0x4E
    
    // Scratchpad locations
    #define TEMP_LSB        0
    #define TEMP_MSB        1
    
    // Device resolution
    #define TEMP_9_BIT  0x1F //  9 bit
    #define TEMP_10_BIT 0x3F // 10 bit
    #define TEMP_11_BIT 0x5F // 11 bit
    #define TEMP_12_BIT 0x7F // 12 bit
    
    typedef uint8_t ScratchPad[9];
    
    const struct device * dev;
    
    /**@brief Custome timer.
     */
    void timer(uint64_t iTimeout)
    {
        uint64_t iUptime = k_uptime_ticks();
    
        while ((k_uptime_ticks() - iUptime) < k_us_to_ticks_near64(iTimeout));
        
    }
    
    
    /**@brief Function for sending one bit to bus.
     */
    void ds18b20_send(char bit)
    {
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        
        k_busy_wait(5);
    
        if(bit==1)
            gpio_pin_set(dev, DS_PIN, 1);
        
        k_busy_wait(80);
        
        gpio_pin_set(dev, DS_PIN, 1);
    }
    
    
    /**@brief Function for reading one bit from bus.
     */
    unsigned char ds18b20_read(void)
    {
        unsigned char presence=0;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(2);
    
        gpio_pin_set(dev, DS_PIN, 1);
        k_busy_wait(15);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
    
        if(gpio_pin_get(dev, DS_PIN))
            presence = 1;
        
        else
            presence = 0;
        
        
        return presence;
    }
    
    
    /**@brief Function for sending one byte to bus.
     */
    void ds18b20_send_byte(char data)
    {
        unsigned char i;
        unsigned char x;
    
        for(i=0;i<8;i++)
        {
          x = data>>i;
          x &= 0x01;
          ds18b20_send(x);
        }
    
        k_busy_wait(100);
    }
    
    
    /**@brief Function for reading one byte from bus.
     */
    unsigned char ds18b20_read_byte(void)
    {
        unsigned char i;
        unsigned char data = 0;
    
        for (i=0;i<8;i++)
        {
            if(ds18b20_read()) data|=0x01<<i;
            k_busy_wait(15);
        }
    
        return(data);
    }
    
    
    /**@brief Function for sending reset pulse.
     */
    unsigned char ds18b20_reset(void)
    {
        unsigned char presence;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(500);
        
        gpio_pin_set(dev, DS_PIN, 1);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
        k_busy_wait(30);
    
    
        if(gpio_pin_get(dev, DS_PIN) == 0)    
            presence = 1;   
        else    
            presence = 0;
        
        k_busy_wait(470);
    
        if(gpio_pin_get(dev, DS_PIN) == 1)    
            presence = 1;   
        else  
            presence = 0;
    
        return presence;
    }
    
    
    /**@brief Function for reading temperature.
     */
    float ds18b20_get_temp(void)
    {
        unsigned char check;
        char temp1=0, temp2=0;
    
        check=ds18b20_reset();
        
        if(check)
        {
            ds18b20_send_byte(0xCC);
            ds18b20_send_byte(0x44);
    
            k_busy_wait(600);
    
            check=ds18b20_reset();
            ds18b20_send_byte(0xCC);
            ds18b20_send_byte(0xBE);
    
            temp1=ds18b20_read_byte();
            temp2=ds18b20_read_byte();
    
            check=ds18b20_reset();
    
            float temp=0;
            temp=(float)(temp1+(temp2*256))/16;
    
            return temp;
        }
          return 0;
    }
    
    
    /**@brief Function for reading bit.
     */
    uint8_t OneWire_read_bit(void)
    {
        uint8_t r;
    
        dev = device_get_binding("GPIO_0");
        gpio_pin_configure(dev, DS_PIN, GPIO_OUTPUT_INACTIVE);
    
        k_busy_wait(3);
    
        gpio_pin_configure(dev, DS_PIN, GPIO_INPUT);
    
        k_busy_wait(10);
    
        r = gpio_pin_get(dev, DS_PIN);
    
        k_busy_wait(53);
    
        return r;
    }
    
    
    /**@brief Function for reading.
     */
    uint8_t OneWire_read()
    {
        uint8_t bitMask;
        uint8_t r = 0;
    
        for (bitMask = 0x01; bitMask; bitMask <<= 1)
    	    if ( OneWire_read_bit()) r |= bitMask;
        
        return r;
    }
    
    
    /**@brief Function for reading scratchpad value
     */
    void ds18b20_readScratchPad(uint8_t *scratchPad, uint8_t fields)
    {
        ds18b20_reset();
    
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(READSCRATCH);
    
        for(uint8_t i=0; i < fields; i++)
            scratchPad[i] = OneWire_read();
        
        ds18b20_reset();
    }
    
    
    /**@brief Function for request temperature reading
     */
    void ds18b20_requestTemperatures(void)
    {
        ds18b20_reset();
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(STARTCONVO);
    }
    
    
    /**@brief Function for reading temperature method 2
     */
    float ds18b20_get_temp_method_2(void)
    {
        ds18b20_requestTemperatures();
    
        ScratchPad scratchPad;
        ds18b20_readScratchPad(scratchPad, 2);
    
        int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];
        float temp = 0.0625 * rawTemperature;
    
        return temp;
    }
    
    
    /**@brief Function for setting temperature resolution
     */
    void ds18b20_setResolution(uint8_t resolution)
    {
        ds18b20_reset();
    
        ds18b20_send_byte(0xCC);
        ds18b20_send_byte(WRITESCRATCH);
        
        // two dummy values for LOW & HIGH ALARM
        ds18b20_send_byte(0);
        ds18b20_send_byte(100);
    
        switch (resolution)
        {
            case 12:
                ds18b20_send_byte(TEMP_12_BIT);
                break;
    
            case 11:
                ds18b20_send_byte(TEMP_11_BIT);
                break;
    
            case 10:
                ds18b20_send_byte(TEMP_10_BIT);
                break;
    
            case 9:
            default:
                ds18b20_send_byte(TEMP_9_BIT);
                break;
        }
    
        ds18b20_reset();
    }

    Thanks you again Elfving !

    Regards,

    Sulian

Children
Related