Skip to content

Commit

Permalink
Improve DS1820 driver (#1382)
Browse files Browse the repository at this point in the history
* feat: Improve DS1820 driver

New features:
* Handle all types of DS1820 tempature sensors by detecting the family of the sensor and calculating the temperature accordingly
* Clean up some log prints
* Set the channel value with current temperature
* Set the period of the conversion interval with an optional first parameter
* Start the conversion instantly and not wait for multiple of the conversion period

* rework: Change DS1820 logging to be more consistent

- Output logging to `LOG_FEATURE_SENSOR` and not `CFG` as it would be expected
- Created a macro `DS1820_LOG` to simplify logging statements.
- Use the macro in various places throughout the driver

* refactor: Remove unused crc code and improve DS1820 logging

Co-authored-by: MaxineMuster <146550015+MaxineMuster@users.noreply.github.com>

---------

Co-authored-by: MaxineMuster <146550015+MaxineMuster@users.noreply.github.com>
  • Loading branch information
Lenart12 and MaxineMuster authored Oct 17, 2024
1 parent 968ebc1 commit ad816b7
Showing 1 changed file with 89 additions and 61 deletions.
150 changes: 89 additions & 61 deletions src/driver/drv_ds1820_simple.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ static int Pin;
static int t=-127;
static int errcount=0;
static int lastconv; // secondsElapsed on last successfull reading
static uint8_t ds18_family = 0;
static int ds18_conversionPeriod = 0;

#define DS1820_LOG(x, fmt, ...) addLogAdv(LOG_##x, LOG_FEATURE_SENSOR, "DS1820[%i] - " fmt, Pin, ##__VA_ARGS__)

// usleep adopted from DHT driver

Expand Down Expand Up @@ -311,25 +314,6 @@ int OWTouchByte(int Pin, int data)
return result;
}




uint8_t OWcrc( uint8_t *data, uint8_t len)
{
uint8_t crc = 0;

while (len--) {
uint8_t inb = *data++;
for (uint8_t i = 8; i; i--) {
uint8_t mix = (crc ^ inb) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inb >>= 1;
}
}
return crc;
}

// quicker CRC with lookup table
// based on code found here: https://community.st.com/t5/stm32-mcus-security/use-stm32-crc-to-compare-ds18b20-crc/m-p/333749/highlight/true#M4690
// Dallas 1-Wire CRC Test App -
Expand All @@ -356,8 +340,11 @@ int DS1820_getTemp() {
return t;
}


void DS1820_driver_Init(){};
// startDriver DS1820 [conversionPeriod (seconds) - default 15]
void DS1820_driver_Init(){
ds18_conversionPeriod = Tokenizer_GetArgIntegerDefault(1, 15);
lastconv=0;
};


void DS1820_AppendInformationToHTTPIndexPage(http_request_t *request)
Expand All @@ -366,7 +353,38 @@ void DS1820_AppendInformationToHTTPIndexPage(http_request_t *request)
hprintf255(request, "<h5>DS1820 Temperature: %.2f C (read %i secs ago)</h5>",(float)t/100, g_secondsElapsed-lastconv);
}

int DS1820_DiscoverFamily() {
if (!OWReset(Pin)) {
DS1820_LOG(DEBUG, "Discover Reset failed");
return 0;
}

// Read ROM
uint8_t ROM[8];
OWWriteByte(Pin, 0x33);
for (int i = 0; i < 8; i++) {
ROM[i] = OWReadByte(Pin);
}

// Check CRC
uint8_t crc = Crc8CQuick(ROM, 7);
if (crc != ROM[7]) {
// This might mean bad signal integrity or multiple 1-wire devices on the bus
DS1820_LOG(DEBUG, "Discover CRC failed (CRC=%x != calculated:%x)", ROM[7], crc);
return 0;
}

// Check family
uint8_t family = ROM[0];
if (family == 0x10 || family == 0x28) {
ds18_family = family;
DS1820_LOG(INFO, "Discover Family - discovered %x", family);
return 1;
} else {
DS1820_LOG(DEBUG, "Discover Family %x not supported", family);
return 0;
}
}

void DS1820_OnEverySecond() {

Expand All @@ -379,58 +397,61 @@ void DS1820_OnEverySecond() {
// if (dsread == 1 && g_secondsElapsed % 5 == 2) {
// better if we don't use parasitic power, we can check if conversion is ready
if (dsread == 1 && DS1820TConversionDone(Pin) == 1) {

uint8_t Low=0,High=0,negative=0;
int Val,Tc;

if (OWReset(Pin) == 0) addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Reset failed",Pin);
if (OWReset(Pin) == 0) {
DS1820_LOG(ERROR, "Read Reset failed");
return;
}
OWWriteByte(Pin,0xCC);
OWWriteByte(Pin,0xBE);

for (int i = 0; i < 9; i++)
{
scratchpad[i] = OWReadByte(Pin);//read Scratchpad Memory of DS
}
// crc= OWcrc(scratchpad, 8);
{
scratchpad[i] = OWReadByte(Pin);//read Scratchpad Memory of DS
}
crc= Crc8CQuick(scratchpad, 8);
if (crc != scratchpad[8])
{
errcount++;
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Read CRC=%x != calculated:%x (errcount=%i)\r\n",scratchpad[8],crc,errcount);
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Scratchpad Data Read: %x %x %x %x %x %x %x %x %x \r\n",scratchpad[0],scratchpad[1],scratchpad[2],scratchpad[3],scratchpad[4],scratchpad[5],scratchpad[6],scratchpad[7],scratchpad[8]);

DS1820_LOG(ERROR, "Read CRC=%x != calculated:%x (errcount=%i)", scratchpad[8], crc, errcount);
DS1820_LOG(ERROR, "Scratchpad Data Read: %x %x %x %x %x %x %x %x %x",
scratchpad[0], scratchpad[1], scratchpad[2], scratchpad[3], scratchpad[4],
scratchpad[5], scratchpad[6], scratchpad[7], scratchpad[8]);

if (errcount > 5) dsread=0; // retry afer 5 failures
}
else
{
Low = scratchpad[0];
High = scratchpad[1];
int16_t raw = (scratchpad[1] << 8) | scratchpad[0];

if (ds18_family == 0x10) { // DS18S20 or old DS1820
int16_t dT = 128 * (scratchpad[7] - scratchpad[6]);
dT /= scratchpad[7];
raw = 64 * (raw & 0xFFFE) - 32 + dT;
DS1820_LOG(DEBUG, "family=%x, raw=%i, count_remain=%i, count_per_c=%i, dT=%i", ds18_family, raw, scratchpad[6], scratchpad[7], dT);
} else { // DS18B20
uint8_t cfg = scratchpad[4] & 0x60;
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
raw = raw << 3; // multiply by 8
DS1820_LOG(DEBUG, "family=%x, raw=%i, cfg=%x (%i bit resolution)", ds18_family, raw, cfg, 9+(cfg)/32) ;
}

// Raw is t * 128
t = (raw / 128) * 100; // Whole degrees
int frac = (raw % 128) * 100 / 128; // Fractional degrees
t += t > 0 ? frac : -frac;

Val = (High << 8) + Low; // combine bytes to integer
negative = (High >= 8); // negative temperature
if (negative)
{
Val = (Val ^ 0xffff) + 1;
}
// Temperature is returned in multiples of 1/16 °C
// we want a simple way to display e.g. xx.yy °C, so just multiply with 100 and we get xxyy
// --> the last two digits will be the fractional part (Val%100)
// --> the whole part of temperature is (int)Val/100
// so we want 100/16 = 6.25 times the value (the sign to be able to show negative temperatures is in "factor")
Tc = (6 * Val) + Val / 4 ;
t = negative ? -1 : 1 * Tc ;
dsread=0;
lastconv=g_secondsElapsed;
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - Pin=%i temp=%s%i.%02i \r\n",Pin, negative ? "-" : "+", (int)Tc/100 , (int)Tc%100);
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - High=%i Low=%i Val=%i Tc=%i -- Read CRC=%x - calculated:%x \r\n",High, Low, Val,Tc,scratchpad[8],crc);
CHANNEL_Set(g_cfg.pins.channels[Pin], t, CHANNEL_SET_FLAG_SILENT);
DS1820_LOG(INFO, "Temp=%i.%02i", (int)t/100 , (int)t%100);
}
}
else if (g_secondsElapsed % 15 == 0) { // every 15 seconds
// ask for "conversion"

if (OWReset(Pin) == 0){
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - Pin=%i -- Reset failed",Pin);
else if (dsread == 0 && (g_secondsElapsed % ds18_conversionPeriod == 0 || lastconv == 0)) {
if (OWReset(Pin) == 0) {
lastconv=-1; // reset lastconv to avoid immediate retry
DS1820_LOG(ERROR, "Reset failed");

// if device is not found, maybe "usleep" is not working as expected
// lets do usleepds() with numbers 50.000 and 100.00
Expand All @@ -441,27 +462,34 @@ void DS1820_OnEverySecond() {
usleepds(tempsleep);
int duration = (int)(portTICK_RATE_MS*xTaskGetTickCount()-actTick);

addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - usleepds(%i) took %i ms ",tempsleep,duration);


DS1820_LOG(DEBUG, "usleepds(%i) took %i ms ", tempsleep, duration);

tempsleep=100000;
actTick=portTICK_RATE_MS*xTaskGetTickCount();
usleepds(tempsleep);
duration = (int)(portTICK_RATE_MS*xTaskGetTickCount()-actTick);

addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "DS1820 - usleepds(%i) took %i ms ",tempsleep,duration);
DS1820_LOG(DEBUG, "usleepds(%i) took %i ms ", tempsleep, duration);

if (duration < 95 || duration > 105){
// calc a new factor for usleepds
addLogAdv(LOG_ERROR, LOG_FEATURE_CFG, "usleepds duration divergates - proposed factor to adjust usleepds %f ",(float)100/duration);
DS1820_LOG(ERROR, "usleepds duration divergates - proposed factor to adjust usleepds %f ",(float)100/duration);
}

}
else {
if (ds18_family == 0) {
int discovered = DS1820_DiscoverFamily();
if (!discovered) {
lastconv=-1; // reset lastconv to avoid immediate retry
DS1820_LOG(ERROR, "Family not discovered");
return;
}
}

OWWriteByte(Pin,0xCC);
OWWriteByte(Pin,0x44);
addLogAdv(LOG_INFO, LOG_FEATURE_CFG, "DS1820 - asked for conversion - Pin %i",Pin);
DS1820_LOG(INFO, "Starting conversion");
dsread=1;
errcount=0;
}
Expand Down

0 comments on commit ad816b7

Please sign in to comment.