stm32bringup/ds18b20.c

169 lines
4.4 KiB
C

/* ds18b20.c -- 1-Wire digital thermometer */
/* Copyright (c) 2020 Renaud Fivet */
#include "ds18b20.h" /* implements DS18B20 API */
#include "system.h" /* gpioa_(), usleep() */
#define DIO 13
#define input() gpioa_input( DIO)
#define output() gpioa_output( DIO)
#define bread() gpioa_read( DIO)
#define MAX_RETRIES 999
#define wait_level( lvl) \
retries = MAX_RETRIES ; \
while( bread() != lvl) \
if( retries-- == 0) \
return DS18B20_FAIL_TOUT
void ds18b20_init( void) {
input() ; /* Wire floating, HIGH by pull-up */
}
static ds18b20_retv_t initialization( void) {
/* Reset */
output() ; /* Wire LOW */
usleep( 480) ;
input() ; /* Wire floating, HIGH by pull-up */
/* Presence */
int retries ;
wait_level( HIGH) ; /* Pull-up LOW -> HIGH, T1 */
wait_level( LOW) ; /* DS18B20 asserts line to LOW, T2, T2 - T1 = 15~60us */
wait_level( HIGH) ; /* DS18B20 releases lines, Pull-up LOW -> HIGH, T3
** T3 - T2 = 60~240us */
usleep( 405) ; /* 480 = 405 + 15 + 60 */
return DS18B20_SUCCESS ;
}
static void write( unsigned char uc) {
/* Transmit byte, least significant bit first */
for( unsigned char curbit = 1 ; curbit ; curbit <<= 1) {
/* Transmit a bit takes 60us + 1us between transmit */
/* Write 1: <15us LOW */
/* Write 0: 60us LOW */
unsigned t = uc & curbit ? 13 : 60 ;
output() ; /* Wire LOW */
usleep( t) ;
input() ; /* Wire floating, HIGH by pull-up */
usleep( 61 - t) ;
}
}
static iolvl_t poll( void) {
output() ; /* Wire LOW */
usleep( 1) ;
input() ; /* Wire floating, HIGH by pull-up */
usleep( 5) ;
iolvl_t bit = bread() ;
usleep( 55) ;
return bit ;
}
static unsigned char read( unsigned char *p, int size) {
unsigned char crc = 0 ;
while( size--) {
/* Receive byte, least significant bit first */
unsigned char uc = 0 ;
for( unsigned char curbit = 1 ; curbit ; curbit <<= 1) {
/* read bit */
int v = poll() ;
if( v)
uc |= curbit ;
/* update CRC */
v ^= crc ;
crc >>= 1 ;
if( v & 1)
crc ^= 0x119 >> 1 ; /* reverse POLY = x^8 + x^5 + x^4 + 1 */
}
/* store byte */
*p++ = uc ;
}
return crc ;
}
static ds18b20_retv_t read_scratchpad( unsigned char scratchpad[]) {
ds18b20_retv_t ret = initialization() ;
if( ret != DS18B20_SUCCESS)
return ret ;
write( 0xCC) ; /* Skip ROM */
write( 0xBE) ; /* Read Scratchpad */
return read( scratchpad, 9) ? DS18B20_FAIL_CRC : DS18B20_SUCCESS ;
}
ds18b20_retv_t ds18b20_convert( void) {
ds18b20_retv_t ret ;
ret = initialization() ;
if( ret != DS18B20_SUCCESS)
return ret ;
write( 0xCC) ; /* Skip ROM */
write( 0x44) ; /* Convert T */
return DS18B20_SUCCESS ;
}
ds18b20_retv_t ds18b20_fetch( short *deciCtemp) { /* -550~1250 = -55.0~125.0 C */
ds18b20_retv_t ret ;
unsigned char vals[ 9] ; /* scratchpad */
ret = read_scratchpad( vals) ;
if( ret != DS18B20_SUCCESS)
return ret ;
*deciCtemp = *((short *) vals) * 10 / 16 ;
return DS18B20_SUCCESS ;
}
ds18b20_retv_t ds18b20_read( short *deciCtemp) { /* -550~1250 = -55.0~125.0 C */
ds18b20_retv_t ret ;
ret = ds18b20_convert() ;
if( ret != DS18B20_SUCCESS)
return ret ;
do
usleep( 4000) ;
while( poll() == LOW) ; /* up to 93.75ms for 9 bits, 750ms for 12 bits */
return ds18b20_fetch( deciCtemp) ;
}
ds18b20_retv_t ds18b20_resolution( unsigned res) { /* 9..12 bits */
ds18b20_retv_t ret ;
unsigned char vals[ 9] ; /* scratchpad */
unsigned char curres ;
/* read scratchpad */
ret = read_scratchpad( vals) ;
if( ret != DS18B20_SUCCESS)
return ret ;
/* update resolution if current value is different than requested */
res = (res - 9) & 3 ;
curres = vals[ 4] >> 5 ;
if( curres != res) {
vals[ 4] = (vals[ 4] & 0x1F) | (res << 5) ;
ret = initialization() ;
if( ret != DS18B20_SUCCESS)
return ret ;
write( 0xCC) ; /* Skip ROM */
write( 0x4E) ; /* Write Scratchpad */
write( vals[ 2]) ;
write( vals[ 3]) ;
write( vals[ 4]) ;
}
return DS18B20_SUCCESS ;
}
/* end of ds18b20.c */