1-Wire Communication via GPIO

Things to mention in this post:
* 1-wire Communication
* Programming DS24b33 Maxim Integrated Product 1-Wire

In this post, we are writing one-wire device communication library using HAL GPIO library.

About one-wire communication

1-Wire is a device communication bus system designed by Dallas Semiconductor Corp. that provides low-speed data, signalling, and power over a single signal.
It is used in some temperature sensors, DS24B33 card id or EEPROM like DS18B20 and many others products from Dallas.

As an example, we will consider the id of the DS24B33 Maxim product.

For 1-wire communication, the important thing is the timing of the reading and writing sequence. So, let’s analyze the reading and writing time slots.

As all you know from the mention of this post, we will use the IO output high-low and IO input GPIO features.

When going through the whole communication process from the master side, the write process requires the master to do the following things:

  • Write bit operation
  • Read bit operation

As mentioned, the timing is essential for reading and writing operations. The below code is the timing slots to perform operations.

//-----------------------------------------------------------------------------
// Set the 1-Wire timing to 'standard' (standard=1) or 'overdrive' (standard=0).

//
void OW_SetSpeed(int standard){
	// Adjust tick values depending on speed
	
	if (standard)
	{
			// Standard Speed
			A = 8  ;      // 6us  min5  - max15 us    * 30
			B = 64 ;      // 64us (65 - A)us          * 30
			C = 60 ;      // 60us min60 - max120 us   * 30
			D = 12 ;      // 10us (65 + B)us          * 30
			E = 9  ;      // 9  * 4			  * 30
			F = 55 ;      // 55 * 4			  * 30
			G = 0  ;      //                	  * 30
			H = 480;      // using in touch reset     * 30
			I = 70 ;      // using in touch reset     * 30
			J = 410;
	}
	else
	{
			// Overdrive Speed
			A = 2  ;
			B = 8  ;
			C = 8  ;
			D = 2  ;
			E = 1  ;
			F = 7  ;
			G = 2  ;
			H = 70 ;
			I = 8  ;
			J = 40 ;
	}
}

To write 1 bit we should consider the pins output logic level as an High or Low. To write zero bit :

To write logic 1 bit:

The below code represents the One Wire Write Dara Time Slot :

void OW_WriteBit(uint8_t bit)
{
	if (bit)
	{
		// Write '1' bit
		ONEWIRE_LOW(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
		ONEWIRE_DELAY(A);
		ONEWIRE_HIGH(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
		ONEWIRE_DELAY(B); // Complete the time slot and 10us recovery
	}
	else
	{
		// Write '0' bit
		ONEWIRE_LOW(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
		ONEWIRE_DELAY(C);
		ONEWIRE_HIGH(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
		ONEWIRE_DELAY(D); // Complete the time slot and 10us recovery
	}
}

To reading, make the gpio output zero after that configure the gpio as an input:

To perform the reading which code is below:

int OW_ReadBit(void)
{
	uint8_t result = 0;
	ONEWIRE_OUTPUT(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_LOW(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_DELAY(A); 
	ONEWIRE_INPUT(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_DELAY(E); // 9
	result = ONEWIRE_READ(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin); // Sample the bit value from the slave
	ONEWIRE_DELAY(F); // 55  Complete the time slot and 10us recovery

	return result;
}

After write and read slots are done, 1-wire communication sequence can start. As mentioned in the beginning of the post we will learn the device id so that we should first reset the device with reset pulse:

The reset pulse code is below:

//-----------------------------------------------------------------------------
// Generate a 1-Wire reset, return 1 if no presence detect was found,
// return 0 otherwise.
// 
//
int OW_TouchReset(void)
{
	int result;
	
	ONEWIRE_DELAY(G);
	ONEWIRE_LOW(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_DELAY(H);
	ONEWIRE_HIGH(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_INPUT(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	ONEWIRE_DELAY(I);
	result = ONEWIRE_READ(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin) ^ 0x01; // Sample for presence pulse from slave
	ONEWIRE_DELAY(J); // Complete the reset sequence recovery

	return result; // Return sample presence pulse result
}

After the reset pulse we must get the presence pulse from the slave because that is the signal, we can only understand reset pulse is worked.

After the presence pulse we should select the command. To learn device serial number we have to select Read Rom Command which is 0x33h.

To perform Read Rom command we will use the Read and Write Byte Functions which code is below:

void OW_WriteByte(uint8_t data)
{
	int loop;

	// Loop to write each bit in the byte, LS-bit first
	for (loop = 0; loop < 8; loop++)
	{
		OW_WriteBit(data & 0x01);
		// shift the data byte for the next bit
		data = data >> 1;
	}
	ONEWIRE_HIGH(KART_ID_1WIRE_S1_GPIO_Port, KART_ID_1WIRE_S1_Pin);
}
uint8_t OW_ReadByte(void)
{
	uint8_t loop, result = 1;

	for (loop = 0; loop < 8; loop++)
	{
		// if result is one, then set MS bit
		if (OW_ReadBit())
			result = result | 0x80; // b10000000

		// shift the result to get it ready for the next bit
		result = result >> 1;

	}
        result = result << 1;

	if(cmndcntr % 2 == 0  && cmndcntr < 5 )
        {
		result = result | 0x01;;
	}
	ONEWIRE_DELAY(A+E);
	return result;
}

ReadRom Function Code:

void OW_ReadRom(void)
{
	// 1-Wire reset
	uint8_t presence = OW_TouchReset();
	
	ONEWIRE_OUTPUT(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
	
	// issue the read rom command
	OW_WriteByte(ONEWIRE_CMD_READROM);  // read rom command 
	
	for (uint8_t i=0;	i<8;	i++)
	{
		 ROM_NO[i] = OW_ReadByte();
		 cmndcntr++;
	}
	
	ONEWIRE_OUTPUT(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin); 
}

In conclusion, to perform the reading serial number or card id of the DS24b33 the ReadRom Command Code should be like the below code :

int OW_ReadRomCommand(void)
{
	int rslt,i;
	OW_OneWire_Init(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);
    
#if FREERTOS
	/*
	 *	Because of the FreeRTOS context switching ONEWIRE_DELAY does not work accured.
	 *	taskENTER_CRITICAL(); used here.
	*/
	taskENTER_CRITICAL();
#endif
    
    OW_ReadRom();

	printh(" Family Code:: %02X \n Card id    :: ", ROM_NO[0]);
	// print device found
	for (i = 6; i >= 1; i--)
		 printh("%02X", ROM_NO[i]);
	
	printh("\n Crc Value  :: %02X", ROM_NO[7]);
    
#if FREERTOS

	/*
	 *	After the search completes taskEXIT_CRITICAL();
	*/
	taskEXIT_CRITICAL();
#endif
	ONEWIRE_HIGH(CARD_ID_1WIRE_S1_GPIO_Port, CARD_ID_1WIRE_S1_Pin);

	return 1;
}

You can check the GitHub Link,

Click Here For GitHub

Leave a Reply

Your email address will not be published.