/** * @file module_one_wire.c * @author Juraj Dudak * @date 16 January, 2015 * @version 1.0 * * @brief Implementacia funkcii pre 1-Wire zbernicu. * */ //---------------------------------------------------------------------- // Include & define //---------------------------------------------------------------------- #include "one_wire.h" #define TRUE 0x01 // konstanty v kniznici 1-wire #define FALSE 0x00 /** @addtogroup Firmware * @{ */ /** @addtogroup Implementácia_MultiSlave * @{ */ /** @defgroup OneWire_modul * @brief Implementácia komunikácie na zbernici 1-wire * @{ */ //---------------------------------------------------------------------- // Lokalne premenne //---------------------------------------------------------------------- /** * SW driver pre zbernicu 1-wire. Obsahuje dátový buffer, časové konštanty, * príznaky komunikácie a stavové premenné. */ oneWireDriver_typeDef oneWireDrv; /** Definícia pinov pre ovládanie zbernice 1-wire*/ oneWirePin_typeDef oneWirePins; /** globalna hodnota CRC */ uint8_t crc8_ow; /** Tabuľka pre výpočet súčtu CRC8 */ static const uint8_t dscrc_table[] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255, 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185, 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115, 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22, 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 }; //-------------------------------------------------------------------------- // Implementacia low-level funkcii pre STM32 //-------------------------------------------------------------------------- /** * Nastavi pin pre 1W ako vstupný. * Aktuálne je podporovaná rýchla zmena len pre STM32F0x * Opis registrov: http://www.hertaville.com/stm32f0-gpio-tutorial-part-1.html */ __attribute__((optimize("O1"))) static void setPinIn(){ #ifdef STM32F0 #define PIN_IN_USE_IN uint32_t temp = oneWirePins.port->MODER; CLEAR_BIT(temp, GPIO_MODER_MODER0 << (oneWirePins.pin_ow_moder_bit)); SET_BIT(temp, (0) << (oneWirePins.pin_ow_moder_bit)); oneWirePins.port->MODER = temp; #endif // STM32F0 #ifdef STM32L0 #define PIN_IN_USE_IN uint32_t temp = oneWirePins.port->MODER; CLEAR_BIT(temp, GPIO_MODER_MODE0 << (oneWirePins.pin_ow_moder_bit)); SET_BIT(temp, (0) << (oneWirePins.pin_ow_moder_bit)); oneWirePins.port->MODER = temp; #endif // STM32L0 #ifndef PIN_IN_USE_IN #error aktualne MCU nie je podporovane #endif // PIN_IN_USE_IN } /** * Nastavi pin pre 1W ako výstupný. * Aktuálne je podporovaná rýchla zmena len pre STM32F0x * Opis registrov: http://www.hertaville.com/stm32f0-gpio-tutorial-part-1.html */ __attribute__((optimize("O1"))) static void setPinOut() { #ifdef STM32F0 #define PIN_IN_USE_IN uint32_t temp = oneWirePins.port->MODER; CLEAR_BIT(temp, GPIO_MODER_MODER0 << (oneWirePins.pin_ow_moder_bit)); SET_BIT(temp, (1) << (oneWirePins.pin_ow_moder_bit)); oneWirePins.port->MODER = temp; #endif // STM32F0 #ifdef STM32L0 #define PIN_IN_USE_IN uint32_t temp = oneWirePins.port->MODER; CLEAR_BIT(temp, GPIO_MODER_MODE0 << (oneWirePins.pin_ow_moder_bit)); SET_BIT(temp, (1) << (oneWirePins.pin_ow_moder_bit)); oneWirePins.port->MODER = temp; #endif // STM32L0 #ifndef PIN_IN_USE_IN #error aktualne MCU nie je podporovane #endif // STM32F0 } //---------------------------------------------------------------------- // Implementacia high-level funkcii podla Maxim, AN187 //---------------------------------------------------------------------- /** * @brief Inicializacia drivera zbernice 1-wire * - Nastavia sa časové konštanty na preddefinované hodnoty. * - Nastavia sa piny pre zbernicu One-wire * * @param timer časovač použirý an generovanie: * - blokujúcej pauzy v ráde us * @param GPIOx port pre piny * @param GPIO_Pin pin pre zápis na zbernicu pre zápis/čítanie * @return none */ void oneWire_init(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin ) { oneWireDrv.one_wire_timing_settings = OW_SETTING_NORMAL; oneWirePins.port = GPIOx; oneWirePins.pin_ow = GPIO_Pin; uint16_t tmp = oneWirePins.pin_ow; oneWirePins.pin_ow_moder_bit = 0; while(tmp){ oneWirePins.pin_ow_moder_bit++; tmp>>=1; } oneWirePins.pin_ow_moder_bit--; oneWirePins.pin_ow_moder_bit*=2; setPinOut(); OW_SET_HI; *(oneWireDrv.ROM_NO) = (uint32_t)0; *(oneWireDrv.ROM_NO+4) = (uint32_t)0; } /** * Vráti pointer na ROM_NO. * @retval pointer na ROM_NO */ uint8_t *oneWire_getROM() { return oneWireDrv.ROM_NO; } /** * @brief Find the 'first' devices on the 1-Wire bus * @param none * @retval TRUE - device found, ROM number in ROM_NO buffer * FALSE - no device present */ uint8_t owFirst() { // reset the search state oneWireDrv.LastDiscrepancy = 0; oneWireDrv.LastDeviceFlag = FALSE; oneWireDrv.LastFamilyDiscrepancy = 0; return owSearch(); } /** * @brief Find the 'next' devices on the 1-Wire bus * @param none * @retval : TRUE - device found, ROM number in ROM_NO buffer * FALSE : device not found, end of search */ uint8_t owNext() { return owSearch(); } void owSelect_ROM(const uint8_t rom[8]) { uint8_t i; owWriteByte(OW_CMD_MATCH_ROM, OW_STRONG_OFF); // Choose ROM for (i = 0; i < 8; i++) { owWriteByte(rom[i], OW_STRONG_OFF); } } void owSelect() { OW_DIS_INTERRUPTS; uint8_t i; if (owReset()) { owWriteByte(OW_CMD_MATCH_ROM, OW_STRONG_OFF); for(i=0; i<8; i++) { owWriteByte(oneWireDrv.ROM_NO[i], OW_STRONG_OFF); } } OW_ENA_INTERRUPTS; } /** * Skopíruje obsah ROM. * @param mem_page pole bytov[8], kde bude uložený obsah ROM_NO */ void owGetROM(uint8_t *mem_page) { memcpy(mem_page, oneWireDrv.ROM_NO, 8); } /** * @brief Perform the 1-Wire Search Algorithm on the 1-Wire bus * using the existing search state. * @param none * @retval : TRUE - device found, ROM number in ROM_NO buffer * FALSE : device not found, end of search */ uint8_t owSearch() { OW_DIS_INTERRUPTS; uint32_t id_bit_number; uint32_t last_zero, rom_byte_number, search_result; uint32_t id_bit, cmp_id_bit; uint8_t rom_byte_mask, search_direction; // initialize for search id_bit_number = 1; last_zero = 0; rom_byte_number = 0; rom_byte_mask = 1; search_result = 0; crc8_ow = 0; // if the last call was not the last one if (oneWireDrv.LastDeviceFlag == FALSE) { // 1-Wire reset if (!owReset()) { // reset the search oneWireDrv.LastDiscrepancy = 0; oneWireDrv.LastDeviceFlag = FALSE; oneWireDrv.LastFamilyDiscrepancy = 0; OW_ENA_INTERRUPTS; return FALSE; } // issue the search command owWriteByte(OW_CMD_SEARCH_ROM, OW_STRONG_OFF); // loop to do the search do { // read a bit and its complement id_bit = owReadBit(); cmp_id_bit = owReadBit(); // check for no devices on 1-wire if ((id_bit == 1) && (cmp_id_bit == 1)) { break; } else { // all devices coupled have 0 or 1 if (id_bit != cmp_id_bit) { search_direction = id_bit; // bit write value for search } else { // if this discrepancy if before the Last Discrepancy // on a previous next then pick the same as last time if (id_bit_number < oneWireDrv.LastDiscrepancy) search_direction = ((oneWireDrv.ROM_NO[rom_byte_number] & rom_byte_mask) > 0); else // if equal to last pick 1, if not then pick 0 search_direction = (id_bit_number == oneWireDrv.LastDiscrepancy); // if 0 was picked then record its position in LastZero if (search_direction == 0) { last_zero = id_bit_number; // check for Last discrepancy in family if (last_zero < 9) oneWireDrv.LastFamilyDiscrepancy = last_zero; } } // set or clear the bit in the ROM byte rom_byte_number // with mask rom_byte_mask if (search_direction == 1) oneWireDrv.ROM_NO[rom_byte_number] |= rom_byte_mask; else oneWireDrv.ROM_NO[rom_byte_number] &= ~rom_byte_mask; // serial number search direction write bit owWriteBit(&search_direction); // increment the byte counter id_bit_number // and shift the mask rom_byte_mask id_bit_number++; rom_byte_mask <<= 1; // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask if (rom_byte_mask == 0) { owCrc8(oneWireDrv.ROM_NO[rom_byte_number]); // accumulate the CRC rom_byte_number++; rom_byte_mask = 1; } } } while (rom_byte_number < 8); // loop until through all ROM bytes 0-7 // if the search was successful then if (!((id_bit_number < 65) || (crc8_ow != 0))) { // search successful so set LastDiscrepancy,LastDeviceFlag,search_result oneWireDrv.LastDiscrepancy = last_zero; // check for last device if (oneWireDrv.LastDiscrepancy == 0) oneWireDrv.LastDeviceFlag = TRUE; search_result = TRUE; } } // if no device found then reset counters so next 'search' will be like a first if (!search_result || !oneWireDrv.ROM_NO[0]) { oneWireDrv.LastDiscrepancy = 0; oneWireDrv.LastDeviceFlag = FALSE; oneWireDrv.LastFamilyDiscrepancy = 0; search_result = FALSE; } if(search_result){ // owSelect(); } OW_ENA_INTERRUPTS; return search_result; } /** * @brief Verify the device with the ROM number in ROM_NO buffer is present. * @param none * @return : TRUE : device verified present * FALSE : device not present */ uint8_t owVerify() { OW_DIS_INTERRUPTS; unsigned char rom_backup[8]; int i, rslt, ld_backup, ldf_backup, lfd_backup; // keep a backup copy of the current state for (i = 0; i < 8; i++) rom_backup[i] = oneWireDrv.ROM_NO[i]; ld_backup = oneWireDrv.LastDiscrepancy; ldf_backup = oneWireDrv.LastDeviceFlag; lfd_backup = oneWireDrv.LastFamilyDiscrepancy; // set search to find the same device oneWireDrv.LastDiscrepancy = 64; oneWireDrv.LastDeviceFlag = FALSE; if (owSearch()) { // check if same device found rslt = TRUE; for (i = 0; i < 8; i++) { if (rom_backup[i] != oneWireDrv.ROM_NO[i]) { rslt = FALSE; break; } } } else rslt = FALSE; // restore the search state for (i = 0; i < 8; i++){ oneWireDrv.ROM_NO[i] = rom_backup[i]; } oneWireDrv.LastDiscrepancy = ld_backup; oneWireDrv.LastDeviceFlag = ldf_backup; oneWireDrv.LastFamilyDiscrepancy = lfd_backup; if(rslt == TRUE) { owSelect(); } OW_ENA_INTERRUPTS; // return the result of the verify return rslt; } /** * @brief Setup the search to find the device type 'family_code' on the next call * to owNext() if it is present. * @param none * @retval : none */ void owTargetSetup(uint8_t family_code) { // set the search state to find SearchFamily type devices oneWireDrv.ROM_NO[0] = family_code; oneWireDrv.ROM_NO[1] = 0; oneWireDrv.ROM_NO[2] = 0; oneWireDrv.ROM_NO[3] = 0; oneWireDrv.ROM_NO[4] = 0; oneWireDrv.ROM_NO[5] = 0; oneWireDrv.ROM_NO[6] = 0; oneWireDrv.ROM_NO[7] = 0; oneWireDrv.LastDiscrepancy = 64; oneWireDrv.LastFamilyDiscrepancy = 0; oneWireDrv.LastDeviceFlag = FALSE; } /** * @brief Setup the search to skip the current device type on the next call * to owNeOW_LOWxt(). * @param none * @retval : none */ void owFamilySkipSetup(void) { // set the Last discrepancy to last family discrepancy oneWireDrv.LastDiscrepancy = oneWireDrv.LastFamilyDiscrepancy; oneWireDrv.LastFamilyDiscrepancy = 0; // check for end of list if (oneWireDrv.LastDiscrepancy == 0) oneWireDrv.LastDeviceFlag = TRUE; } /** * @brief Setup new ROM number * @param array with new ROM number * @retval : none */ void owSetRom(uint8_t *array) { *oneWireDrv.ROM_NO = *array; *(oneWireDrv.ROM_NO +4 )= *(array+4); } /** * @brief Calculate the CRC8 of the byte value provided with the * current global 'crc8' value. * @param byte value * @retval : current global crc8 value */ uint8_t owCrc8(uint8_t value) { crc8_ow = dscrc_table[crc8_ow ^ value]; return crc8_ow; } /** * @brief Reset 1-wire zbernice s detekciou pritomnosti zariadenia * @param none * @retval : TRUE - device present * FALSE - no device present */ uint8_t __attribute__((optimize("O3"))) owReset(void) { uint8_t state; OW_GPIO_PULSE(OW_RESET_MEASTER, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_SET_HI; setPinIn(); OW_DELAY_US(OW_RESET_PRESENCE, MCU_FREQUENCY, 1); //TODO set offset state = (oneWirePins.port->IDR & oneWirePins.pin_ow ) != 0; //setPinOut(); OW_DELAY_US(OW_RESET_DELAY, MCU_FREQUENCY, 40); //TODO set offset setPinOut(); //Toto som presunul až za oneskorenie, pretože to spôsobovalo nechcené pulzy return !state; } /** * @brief Vyslanie 8-bitov na zbernicu 1-wire * @param byte_value 1W príkaz * @param strong príznak, či sa má po poslednom bite dať zbernica do stavu STRONG. * povolené hodnoty: @arg OW_STRONG_OFF - zbernica bude v stave RESISTIVE, * @arg OW_STRONG_ON zbernica bude v stave STRONG * @retval : none */ void __attribute__((optimize("O1"))) owWriteByte(uint8_t byte_value, uint8_t strong) { owWriteBit(&byte_value); owWriteBit(&byte_value); owWriteBit(&byte_value); owWriteBit(&byte_value); owWriteBit(&byte_value); owWriteBit(&byte_value); owWriteBit(&byte_value); //owWriteBit(&byte_value); #if USE_STRONG == 1 if(strong == OW_STRONG_ON){ owWriteBitStrong(byte_value>>7); }else{ if(byte_value & 0x01){ // zapis bit=1 OW_GPIO_PULSE(OW_WRITE_ONE, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_ONE_DELAY + OW_WRITE_DELAY, 1, MCU_FREQUENCY, 29, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 19, pretože zohľadňuje volanie aj obsluhu funkcie } else{ // zapis bit=0 OW_GPIO_PULSE(OW_WRITE_ZERO, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_DELAY, 1, MCU_FREQUENCY, 30, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 21, pretože zohľadňuje volanie aj obsluhu funkcie } } #else if(byte_value & 0x01){ // zapis bit=1 OW_GPIO_PULSE(OW_WRITE_ONE, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_ONE_DELAY + OW_WRITE_DELAY, 1, MCU_FREQUENCY, 29, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 19, pretože zohľadňuje volanie aj obsluhu funkcie } else{ // zapis bit=0 OW_GPIO_PULSE(OW_WRITE_ZERO, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_DELAY, 1, MCU_FREQUENCY, 30, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 21, pretože zohľadňuje volanie aj obsluhu funkcie } #endif } /** * Na zbernicu 1-wire zapíše 1 bit. Po zápise nastaví zbernicu * do stavu STRONG. * @param bit_value - bit, ktorý sa bude zapisovať. */ void owWriteBitStrong(uint8_t bit_value) { if(bit_value & 0x01){ // zapis bit=1 OW_GPIO_PULSE(OW_WRITE_ONE, 1, MCU_FREQUENCY, 15, oneWirePins.port, oneWirePins.pin_ow); //TODO offset je stanovený od oka v tomto prípade } else{ // zapis bit=0 OW_GPIO_PULSE(OW_WRITE_ZERO, 0, MCU_FREQUENCY, 17, oneWirePins.port, oneWirePins.pin_ow); //TODO offset je stanovený od oka v tomto prípade } } /** * @brief Vyslanie 1 bitu na zbernicu 1-wire * @param data, akceptovany je LSB * @retval : none */ void __attribute__((optimize("Ofast"))) owWriteBit(uint8_t* bit_value) { if(*bit_value & 0x01){ // zapis bit=1 OW_GPIO_PULSE(OW_WRITE_ONE, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_ONE_DELAY + OW_WRITE_DELAY, 1, MCU_FREQUENCY, 19, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 19, pretože zohľadňuje volanie aj obsluhu funkcie } else{ // zapis bit=0 OW_GPIO_PULSE(OW_WRITE_ZERO, 0, MCU_FREQUENCY, 1, oneWirePins.port, oneWirePins.pin_ow); OW_GPIO_PULSE(OW_WRITE_DELAY, 1, MCU_FREQUENCY, 21, oneWirePins.port, oneWirePins.pin_ow); //Offset je nastavený na 21, pretože zohľadňuje volanie aj obsluhu funkcie } *bit_value >>= 1; } /** * @brief Nacitanie 1 bitu zo zbernicu 1-wire * @param none * @retval : nacitana hodnota 0/1 */ uint8_t owReadBit(void) { uint8_t state=0x00; OW_GPIO_PULSE(OW_READ_PULSE, 0, MCU_FREQUENCY, 7, oneWirePins.port, oneWirePins.pin_ow); //TODO set offset //OW_SET_HI; setPinIn(); OW_SET_HI; //Toto som presunul až za oneskorenie, pretože to spôsobovalo nechcené pulzy OW_DELAY_US(OW_READ_PRESENCE, MCU_FREQUENCY, 1); //TODO set offset state = (oneWirePins.port->IDR & oneWirePins.pin_ow ) != 0; //setPinOut(); //OW_SET_HI; OW_DELAY_US(OW_READ_DELAY, MCU_FREQUENCY, 1); //TODO set offset setPinOut(); //Toto som presunul až za oneskorenie, pretože to spôsobovalo nechcené pulzy OW_DELAY_US(OW_BOOSTER, MCU_FREQUENCY, 36); //TODO set offset return state; } /** * @brief Nacitanie 1 byte zo zbernice 1-wire * @param none * @retval nacitana hodnota 8-bit hodnota */ uint8_t owReadByte(void) { uint8_t value; value = (owReadBit()); // LSB first value |= (owReadBit()<<1); value |= (owReadBit()<<2); value |= (owReadBit()<<3); value |= (owReadBit()<<4); value |= (owReadBit()<<5); value |= (owReadBit()<<6); value |= (owReadBit()<<7); return value; } /** * @} */ /** * @} */ /** * @} */