ds18b20 library error for SAMR34 Xplained Pro

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone. I am using the board SAM R34 Xplained Pro and sensor ds18b20. For this to work and read the temperature I need to create a oneWire library to use the sensor, and I think I am almost there, but I cannot seem to make it work. The code I have written is using asf.h, and is thought for the particular case of: the ds18b20 with External Supply, only one sensor and an external pullup of 4.7KΩ. I guess I could make the pin pullup and retrieve the external one, but I am sticking to the documentation.

 

The error I am facing is that the reading pin is getting the value 1 constantly, and so every byte read is 255, which is not correct. Here is a picture of my connection. I am using Pin PA06 for the data pin:

 

Connection between SAM R34 Xplained Pro and ds18b20 sensor

 

I have tried this same wiring using an Mega2560 and I am able to read using the arduino libraries, so it is not a sensor issue.

 

Also, I have based myself on some code on other discussions, but I have not find one that could make me realize my error, so I apologize if there is, I am pretty new to all this.

 

I attach the code of both the .h and .c

 

This is the code for my oneWire.h:

 

#ifndef _oneWire_H
#define _oneWire_H

#include "asf.h"

/**********************************************************************/
//ONEWIRE --> TEMPERATURE SENSOR DS18B20
//Note:
//The code is implemented to:
//   -Power the DS18B20 with an External supply
//   -Only one sensor
//	 -External 4.7K  PullUp resistance
/**********************************************************************/

/**********************************************************************/
//DS18B20 TEMPERATURE SENSOR - COMMAND DESCRIPTION
/**********************************************************************/
#define CONVER_TEMP 0x44
#define READ_SCRATCH 0xBE
#define SKIP_ROM 0xCC
#define READ_ROM 0x33

/**********************************************************************/
//PIN DEFINITION
/**********************************************************************/
#define PIN_ONEWIRE  PIN_PA06
#define INPUT        PORT_PIN_DIR_INPUT
#define OUTPUT       PORT_PIN_DIR_OUTPUT
#define PULL_SETTING PORT_PIN_PULL_NONE

/**********************************************************************/
//      DECLARATION OF FUNCTIONS
/**********************************************************************/

//Function to initialize GPIO (pin P0.31)
void initOneWire (void);

//read from pin
unsigned char read_pin(void);

//This function is required for starting all the communications
/*All communication with the DS18B20 begins with an initialization sequence that consists of a reset pulse
from the master followed by a presence pulse from the DS18B20.
When the DS18B20 sends the presence pulse in response to the reset, it is indicating to the master that it is on
the bus and ready to operate.*/

uint8_t resetWire(void);

//Send command to convert temp and read temperature data in Celsius
float OnewireReadTemp(void);
void OnewireSendConvertTempCommand(void);     //only send command to convert temp
float OnewireReceivedTemp(void);           //only received temp (necessary to send command previously)

//This funciton is internally used by OneWireReadTemp() function.
//The temperature data is stored as a 16-bit sign-extended two's complement number in the temperature register. If the
//DS18B20 is configured for 12-bit resolution (by default), all bits in the temperature register will contain valid data
float complement2_12bitsResolution (uint16_t);

//put gpio pin as an input
void goInput(void);

//put gpio pin as an out
void goOutput(void);

//send command
void SendCMD(uint8_t);

//read data
int ReadBit(void);
int ReadByte(void);

//this functions are not used
//not sure if they work properly
void ReadSerialNumber(void);
int iBSPACMonewireComputeCRC (const unsigned char *, int);
#endif

 

Here the oneWire.c:

 

#include "oneWire.h"
#include "string.h"

struct port_config pin_conf;

void initOneWire(void)
{
	//Init GPIO for communication
	//I don´t know if I should try this

	//PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.DRVSTR = PORT_PINCFG_DRVSTR_Pos;
	//PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.PULLEN = PORT_PINCFG_PULLEN_Pos;
	//PORT->Group[0].PINCFG[PIN_ONEWIRE].bit.INEN   = PORT_PINCFG_INEN_Pos;
	//PORT->Group[0].DIRSET.bit.DIRSET = (1 << PIN_ONEWIRE);

	//Init GPIO for communication

	port_get_config_defaults(&pin_conf);

	pin_conf.input_pull = PULL_SETTING;
	pin_conf.direction  = INPUT;

	port_pin_set_config(PIN_ONEWIRE, &pin_conf);

	OnewireSendConvertTempCommand();
}

unsigned char read_pin(void){
	unsigned char read_data = 0;                                                 // variable for status of pin, 8 bits            // Make Probe_Pin an input by putting 1 on TRIS
	//read_data = PORT->Group[0].IN.bit.IN & (1<<PIN_ONEWIRE);
	port_pin_get_input_level(PIN_ONEWIRE);
	return (read_data);
}

uint8_t resetWire(void){

	/*During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus
	low for a minimum of 480µs. The bus master then releases the bus and goes into receive mode (RX).
	When the bus is released, the 5k? pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects
	this rising edge, it waits 15µs to 60µs and then transmits a presence pulse by pulling the 1-Wire bus low
	for 60µs to 240µs.*/

	goOutput();
	delay_us(480);
	goInput();
	delay_us(140);
	if(!read_pin()) //The ds18b20 pulls the bus low
	{
		delay_us(350);
		return;
	}
	else //If not, wait and try again
	{
		delay_us(500);
		resetWire();
	}

}

void OnewireSendConvertTempCommand(void){

	//Send command to convert the temperature
	resetWire();
	SendCMD(SKIP_ROM);
	SendCMD(CONVER_TEMP);
}

float OnewireReceivedTemp (void)
{
	uint16_t rawTemp;

	//wait until receive 1 (conversion done!)
	while(!ReadBit());

	//Read the temperature
	resetWire()
	SendCMD(SKIP_ROM);
	SendCMD(READ_SCRATCH);

	rawTemp = ReadByte();
	rawTemp |= (ReadByte() << 8);

	return complement2_12bitsResolution(rawTemp);
}

float OnewireReadTemp(void){
	/*
	After the Convert T command and the DS18B20 will respond by transmitting
	0 while the temperature conversion is in progress and 1 when the conversion is done.
	If the DS18B20 is powered with parasite power, this notification technique cannot
	be used since the bus must be pulled high by a strong pullup during the entire temperature conversion.
	Necessary to wait until the 750 ms ( max temperature conversion time for 12-bits resolution)
	We are powering by external supply
	*/

	OnewireSendConvertTempCommand();
	return OnewireReceivedTemp();
}

float complement2_12bitsResolution (uint16_t rawData)
{
	float temp;
	//correct the sign (complemento a 2 - 12 bits the resolución)
	if ((rawData & 0x8000)>0)    //negative
	{
		temp = ((rawData ^ 0xffff) + 1) * -1;
	}
	else    //positive
	{
		temp=(float)rawData;
	}

	return (temp / 16.0);
}

void goInput (void)
{
	port_get_config_defaults(&pin_conf);

	pin_conf.input_pull = PULL_SETTING;
	pin_conf.direction  = INPUT;

	port_pin_set_config(PIN_ONEWIRE, &pin_conf);
	//PORT->Group[0].DIRCLR.bit.DIRCLR = (1 << PIN_ONEWIRE); //Another way?
}

void goOutput(void){
	port_get_config_defaults(&pin_conf);

	pin_conf.input_pull = PULL_SETTING;
	pin_conf.direction  = OUTPUT;

	port_pin_set_config(PIN_ONEWIRE, &pin_conf);

	//PORT->Group[0].DIRSET.bit.DIRSET = (1 << PIN_ONEWIRE); ////Another way?
}

/*Note for writing and reading data:
All write/read time slots must be a minimum of 60µs in duration with a minimum of a 1µs recovery
time between individual write slots.*/

void SendCMD (uint8_t command)
{
	for (int i = 0; i < 8; i++) {
		goOutput();
		if (command & 0x01) {
			delay_us(10);
			goInput();
			delay_us(60);
		}
		else {
			delay_us(60);
			goInput();
			delay_us(10);
		}
		command >>= 1;
	}
}

int ReadBit (void){
	int inputState;

	goOutput();
	delay_us(6);
	goInput();
	delay_us(9);
	//inputState=  ((PORT->Group[0].IN.bit.IN>>PIN_ONEWIRE) & 0x01); // This could work as well?
	inputState = port_pin_get_input_level(PIN_ONEWIRE);
	//Another way?:
	//Get the value set in the 13th bit and shift it to get 1 or 0
	//input = (PORT->Group[0].IN.bit.IN>>PIN_ONEWIRE) & 1UL;
	delay_us(55);
	return inputState;
}

int ReadByte (void){
	int byte = 0;
	int bit = 1;

	do {
		if (ReadBit()) {
			byte |= bit;
		}
		bit <<= 1;
	} while (0x100 != bit);
	return byte;
}

//not checked
void ReadSerialNumber(void){
	uint8_t serialNumber[8];
	uint8_t id[6];
	int rv = -1;

	resetWire();
	SendCMD(READ_ROM);

	do {
		resetWire();
		SendCMD(READ_ROM);
		for (uint16_t i = 0; i < sizeof(serialNumber); ++i) {
			serialNumber[i] = ReadByte();
		}
		rv = 0;
	} while (0);

	if (rv==0) {
		if (0 != iBSPACMonewireComputeCRC(serialNumber, sizeof(serialNumber))) {
			rv = -1;
			} else {
			for (uint16_t i = 0; i < sizeof(id); ++i) {
				id[i] = serialNumber[sizeof(serialNumber) - 2 - i];
			}
		}
	}
	delay_ms(100);
}

//not checked
int iBSPACMonewireComputeCRC (const unsigned char * romp,int len){
	static const unsigned char OW_CRC_POLY = 0x8c;
	unsigned char crc = 0;

	while (0 < len--) {
		int bi;
		crc ^= *romp++;
		for (bi = 0; bi < 8; ++bi) {
			if (crc & 1) {
				crc = (crc >> 1) ^ OW_CRC_POLY;
			}
			else {
				crc >>= 1;
			}
		}
	}

	return (int)crc;
}

 

And just in case, my main.c (Not included the functions for initializing the console or so, just the oneWire use):

#include "asf.h"
#include "stdio_serial.h"
#include "conf_uart_serial.h"
#include "oneWire.h"

int main(void)
	{
		system_init();

		/*Configure UART console.*/
		configure_console();

		/*Initialize the delay driver*/
		delay_init();

		/* Output example information */
		puts(STRING_HEADER);

		initOneWire();

		/*main loop*/
		while(1){
			OnewireSendConvertTempCommand();
			//ReadSerialNumber();
			temperature = OnewireReadTemp();
		}
	}

Any more useful information that I code have missed please let me know and I will attach it as soon as possible.

 

Than you in advance for your time.

 

 

This topic has a solution.
Last Edited: Tue. Oct 13, 2020 - 10:25 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AEduardo wrote:
The error I am facing is that the reading pin is getting the value 1 constantly

Is your SAMR34 permanently driving the data line high?

 

The 1-WireTM slave needs to be able to pull the line low.

 

Essential information for working with the Maxim (formerly Dallas) 1-WireTM bus:

 

https://www.avrfreaks.net/commen...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey awneil, thanks for answering.

 

awneil wrote:

Is your SAMR34 permanently driving the data line high?

 

I have read the documentation and I think I understand how oneWire works, I based myself both on the codes they provide at their page and some I could find in the forums here.

I did set the pin on the SAMR34 without internal pullup so I could use the value recommended in the documentation (4.7K) because I was facing this error earlier. Can I have a data line driven high constantly even after doing this? Is there a way I can check if it is the SAM driving it high?

 

Sorry if this are stupid questions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


AEduardo wrote:
Can I have a data line driven high constantly even after doing this?

You need to study the  SAMR34  datasheet to see exactly what options it has for its output structures.

 

What you need is an open-drain output; not all microcontrollers give this directly so, again, RTFM for the SAMR34  for specific details ...

 

Is there a way I can check if it is the SAM driving it high?

disconnect the sensor, and connect another 4k7 resistor to ground:

 

 

Vout shout be half the supply voltage

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AEduardo wrote:
I guess I could make the pin pullup and retrieve the external one

I doubt it.

 

The DS18B20 datasheet tells you that it needs to be "approximately 5kΩ";  a microcontroller's internal pullup is likely to have a much higher resistance than that - so is unlikely to be suitable.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Fri. Oct 2, 2020 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Thank you awneil,

 

awneil wrote:

You need to study the  SAMR34  datasheet to see exactly what options it has for its output structures.

 

What you need is an open-drain output; not all microcontrollers give this directly so, again, RTFM for the SAMR34  for specific details ...

 

I have read the User Guide for now but I will need to find more information.

open-drain is supported by the SAMR34, but not all pins do, so maybe that is the issue.

 

Edit: After reading the "port.h" inside atmel studio it looks like it is actually not supported. 

 

awneil wrote:

 

disconnect the sensor, and connect another 4k7 resistor to ground:

 

Vout shout be half the supply voltage

 

As for this, I have tried it out and looks like I have an oscillating Vout going from 2.3 V to almost 3.1V so that means it is not working properly.

The supply is 3.3V

I will try and check how to make it open drain in the software

Last Edited: Fri. Oct 2, 2020 - 01:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
read_pin

always returns 0. Should have

read_data = port_pin_get_input_level(PIN_ONEWIRE);

right?

 

Also resetWire is recursive, not a good idea.

Open drain in software is what you have, i.e., the pin is an output to get a 0 on the wire and an input to get a 1 from the pullup resistor.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lajon wrote:
an input to get a 1 from the pullup resistor.

or a 0 if the DS18b20 is pulling low

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Lajon, thank you for answering.

 

Lajon wrote:

read_pin

always returns 0. Should have

read_data = port_pin_get_input_level(PIN_ONEWIRE);

right?

 

You are totally right.That is a big mistake I made in that read pin function... Sorry about that.

 

Lajon wrote:

Also resetWire is recursive, not a good idea.

 

And yes it was, I have changed it to a do-while now to still have this repetition but avoiding recursion. Thank you so much for the comment!

 

New read_pin() is as follows:

 

unsigned char read_pin(void){
	unsigned char read_data = port_pin_get_input_level(PIN_ONEWIRE);
	return (read_data);
}

And resetWire():

 

void resetWire(void){

	/*During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus
	low for a minimum of 480µs. The bus master then releases the bus and goes into receive mode (RX).
	When the bus is released, the 5k? pull up resistor pulls the 1-Wire bus high. When the DS18B20 detects
	this rising edge, it waits 15µs to 60µs and then transmits a presence pulse by pulling the 1-Wire bus low
	for 60µs to 240µs.*/
	bool presence_pulse = 0;
	do{
		goOutput();
		delay_us(480);
		goInput();
		delay_us(140);
		presence_pulse = !(read_pin());
		if(presence_pulse) //The ds18b20 did pull the bus low
		{
			delay_us(350); //wait for timing and then the do-while will exit
		}
		else //If not, wait and try again
		{
			delay_us(500); //wait and try again since presence pulse is 0
		}
	} while(!presence_pulse);
}

Lajon wrote:

Open drain in software is what you have, i.e., the pin is an output to get a 0 on the wire and an input to get a 1 from the pullup resistor.

 

Oh, alright I get it now, I thought the configuration of the pin needed to be changed as well since I saw a PORT_ODRAIN field in the port.h file. It is not supported anyway so I would not be able to use it.

Last Edited: Sat. Oct 3, 2020 - 02:11 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone, I finally found the issue.

 

It was related with the timing in the functions. I adjusted it using the pointer access to the pins for faster operation and incremented the CPU speed.

 

Now everything works fine. Thank you for your help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, I'm pretty new in this kind of programming, can you tell me how did you resolve this problem of CPU speed?

thanks in advance. Sorry for my english.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it's 3 months ago but, since  esoriano841 has woken the thread up:

AEduardo wrote:
It was related with the timing in the functions. I adjusted it using the pointer access to the pins for faster operation and incremented the CPU speed.

That sounds a bit unlikely: although 1-WireTM does require timings to be reasonably precise, it isn't particularly fast.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...