Introduction:
1-Wire communication protocol is designed by Dallas Semiconductor which is now a part of Maxim Integrated. And It uses only single wire as name suggests to communicate with slave devices. It provide a very cost effective solution to interface wide variety of devices and sensors by reducing the number of interconnect wire. Even though the data rate is limited as compared to other multi-wire protocols (UART, SPI, I2C etc) but sufficient to meet the today industry requirements. Similar to I2C but using only single wires user can interface multiple sensors/devices with it. Another added feature of 1-wire is providing parasitic power supply through the same line used for 1-wire communication hence result in further reduction of wiring cost.
Details:
In this project two DS18B20 1-wire temperature sensors are used. Both these sensors are interfaced using the only 1-Wire master hardware interface of MAX32650 available at Port 1 Pin 31. The one wire master interface pin is also output pin for bit 1 of CLCD module red color. So in order to use this pin as 1-wire master we need to exclude this pin from CLCD module GPIO initialization. And one of the way of doing this is given in section below. In this project only basic features of DS18B20 sensor are used i.e reading the ROM codes and temperature values only.
Modifying the sensor configuration registers is not done in this project but anyone can do it easily by using the one wire SDK library. The difficult and lengthy part of code when working with 1-wire sensors/devices is searching and reading the ROM codes. And in MAX32650 has made programmer's life much easier by taking all these things to hardware side. And now we can do all these thing by just calling the SDK OWM_SearchROM function. All the code details along with display function is given in next section.
Code:
Sensor Initialization function can be used for multiple sensors (upto 1-wire bus max sensors limits) and number of sensors can be defined by TEMP_SENSORS macro at the beginning of the code. It will automatically search and read the ROM code of all the sensors using MAX32650 1-wire master interface.
void init_DS18B20(void) { uint8_t crc_cal; uint8_t retval = 0; uint8_t i=0; printf("\n\n Init 1-Wire Temperature Senor (DS18B2001)\n"); owm_cfg_t owm_cfg; owm_cfg.int_pu_en = 1; owm_cfg.ext_pu_mode = OWM_EXT_PU_UNUSED; owm_cfg.long_line_mode = 0; retval = OWM_Init(&owm_cfg, &sys_owm_cfg); if (retval != E_NO_ERROR){ printf("OWM init Error!\n"); } retval = OWM_Reset(); if (retval == 0){ printf("OWM Reset Error!\n"); } do{ retval = OWM_SearchROM((i==0)? 1:0, rom_code[i]); if (retval == 0){ printf("OWM No %s Device Found!\n", (i==0)? "New": "Another"); break; } crc_cal = crc_calc(rom_code[i], 7, 0x8C); if(crc_cal == rom_code[i][7]){ printf("OWM Device #%d Found with Family Code: 0x%02x | Serial Number: 0x%02x%02x%02x%02x%02x%02x | CRC:0x%02x\n", i, rom_code[i][0], rom_code[i][6], rom_code[i][5], rom_code[i][4], rom_code[i][3], rom_code[i][2], rom_code[i][1], rom_code[i][7]); } i++; }while(i<TEMP_SENSORS); }
After reading the ROM code of all the available sensors, we can read the temperature data of each sensor by using the ROM code of corresponding sensor.
void read_DS18B20(void) { uint8_t retval = 0; uint8_t cmd = 0, i=0; uint8_t crc_cal; uint8_t temp_data[9]; for (i=0; i<TEMP_SENSORS; i++){ cmd = STARTCONVO; retval = OWM_Reset(); retval = OWM_MatchROM(rom_code[i]); retval = OWM_Write(&cmd, 1); cmd = READSCRATCH; retval = OWM_Reset(); retval = OWM_MatchROM(rom_code[i]); retval = OWM_Write(&cmd, 1); retval = OWM_Read(temp_data, 9); crc_cal = crc_calc(temp_data, 8, 0x8C); if(crc_cal == temp_data[8]){ int16_t rawTemperature = (((int16_t) temp_data[TEMP_MSB]) << 11) | (((int16_t) temp_data[TEMP_LSB]) << 3); if ((rom_code[0][0] == DS18S20MODEL) && (temp_data[COUNT_PER_C] != 0)){ rawTemperature = ((rawTemperature & 0xfff0) << 3) - 32 + (((temp_data[COUNT_PER_C] - temp_data[COUNT_REMAIN]) << 7) / temp_data[COUNT_PER_C]); } temp_val[i] = (double)rawTemperature * 0.0078125; printf("Sensor #%d - RAW Temperature = 0x%04x | Temperature = %.2f\n", i, rawTemperature, temp_val[i]); } } printf("\n"); }
MAX32650 display module is configured in 8BPP mode and the Color palette used in this project is;
/** Color palette for the image. */ uint32_t palette[] = { 0x000000, // 0-Black 0xFFFFFF, // 1-White 0x0000FF, // 2-Red 0x00FF00, // 3-Lime 0xFF0000, // 4-Blue 0x00FFFF, // 5-Yellow 0xFFFF00, // 6-Cyan / Aqua 0xFF00FF, // 7-Magenta / Fuchsia 0xC0C0C0, // 8-Silver 0x808080, // 9-Gray 0x000080, // 10-Maroon 0x008080, // 11-Olive 0x008000, // 12-Green 0x800080, // 13-Purple 0x808000, // 14-Teal 0x800000, // 15-Navy 0xAE8110, // Logo Color of index 0 0x58A2DE, // Logo Color of index 1 0xF7FBF5, // Logo Color of index 2 0x6CB952, // Logo Color of index 3 0x0000FF, // Temp Color of index 0 0xF7FBF5, // Temp Color of index 1 0xF7FBF5, // Temp Color of index 2 0x666360, // Temp Color of index 3 };
The Element14 and thermometer logo images are converted to c-arrays using https://littlevgl.com/image-to-c-array and color format of "indexed 4 colores" along with "c-array" as output format is chosen to obtain the required c-array. The function to display any image c-array obtained through this method is given below.
/** * @brief Function to display 4 colored images c-array * @details The byte array can be obtained using this online * tool https://littlevgl.com/image-to-c-array. Each byte of this array * contain 4 pixels color values location in color palette. * i.e: each byte is 4x2-bits address of color palette. * @param x Image top left corner horizontal position in pixels relative to LCD top left corner * y Image top left corner vertical position in pixels relative to LCD top left corner * width Image width * height Image height * image image c-array with each byte is 4x2bit addresses of color palette * color_offset image pixels colors data location offset in color palette array * i.e: 0 - if indexed 4 colors are located at the beginning of color palette array */ void displayImage(uint16_t x, uint16_t y, uint16_t width, uint16_t heigth, uint8_t *image, uint8_t color_offset){ unsigned char *dest; unsigned int i, j, k, temp=0; uint8_t color[4]; dest = (unsigned char *)(base_addr + (((panel.width * y + x) * LOGO_BPP) >> 3)); while(width%4!=0){ width++; temp++; } k=width/4; /** Copy the image to the frame buffer */ for (j = 0; j < heigth; j++) { for (i = 0; i < k; i++) { color[0]=(image[i + k*j]>> 6 & 0x03); color[1]=(image[i + k*j]>> 4 & 0x03); color[2]=(image[i + k*j]>> 2 & 0x03); color[3]=(image[i + k*j]>> 0 & 0x03); dest[i*4] = color[0] | color_offset; if(i<(k-1) || temp<3) dest[i*4+1] = color[1] | color_offset; if(i<(k-1) || temp<2) dest[i*4+2] = color[2] | color_offset; if(i<(k-1) || temp<1) dest[i*4+3] = color[3] | color_offset; } dest += (panel.width * LOGO_BPP) >> 3; } }
Modify the following LCD GPIO pins in mxc_pins.c file as shown below: (mxc_pins.c is SDK file and in order to modify this file, first you need to uncheck the read only property of this file and also this modified code will be used by all the MAX32650 projects unless reverted back to original one)
/* ORIGINAL CODE */ //const gpio_cfg_t gpio_cfg_clcd_1 = { PORT_1, (PIN_3 | PIN_20 | PIN_23 | PIN_24 | PIN_25 | PIN_26 | PIN_27 | PIN_28 | PIN_29 | PIN_30 | PIN_31), GPIO_FUNC_ALT2, GPIO_PAD_NONE}; //const gpio_cfg_t gpio_cfg_clcd_2 = { PORT_2, (PIN_2 | PIN_3 | PIN_6 | PIN_13 | PIN_14 | PIN_15 | PIN_16 | PIN_17 | PIN_18), GPIO_FUNC_ALT2, GPIO_PAD_NONE}; /* MODIFIED CODE */ /* remove the port2 pins that can cause hardfault as mentioned in MAX32650 ERRATA sheet */ /* remove the port1 pins that is only 1-wire master hardware interface pin */ const gpio_cfg_t gpio_cfg_clcd_1 = { PORT_1, (PIN_3 | PIN_20 | PIN_23 | PIN_24 | PIN_25 | PIN_26 | PIN_27 | PIN_28 | PIN_29 | PIN_30), GPIO_FUNC_ALT2, GPIO_PAD_NONE}; const gpio_cfg_t gpio_cfg_clcd_2 = { PORT_2, (PIN_2 | PIN_3 | PIN_6 | PIN_13 | PIN_17 | PIN_18), GPIO_FUNC_ALT2, GPIO_PAD_NONE};
Optional code to calculate the CRC of DS18B20 temperature sensor data and ROM code and 0x8C is the polynomial value obtained from CRC polynomial equation given in its datasheet.
int crc_calc(uint8_t *data, uint8_t len, uint32_t polynomial) { int i, j; uint32_t temp; uint32_t crcval = 0; for (i = 0; i < len; ++i) { temp = (data[i] & 0xFF); for (j = 0; j < 8; ++j) { if ((temp ^ crcval) & 1) { crcval >>= 1; crcval ^= polynomial; } else { crcval >>= 1; } temp >>= 1; } }
Demo:
Top Comments