oPossum 1,083 Posted August 11, 2011 Share Posted August 11, 2011 Here is a basic library for 1-wire communication. It works with CPU frequency of 1 MHz or higher. Carefully crafted assembly code is used to allow operation over a wide CPU clock frequency range. There are only two functions. One for setup and the other for all communication tasks. // one_wire.h void one_wire_setup(volatile unsigned char *dir, volatile unsigned char *in, unsigned bitmask, unsigned mhz); int owex(int data, unsigned bits); The library is initialized by a call to one_wire_setup(). The arguments specify the I/O pin and clock frequency. An example for P1.4 at 16 MHz... one_wire_setup(&P1DIR, &P1IN, 0x10, 16); The setup function can be called repeatedly to allow communication on more than one I/O pin. The owex() [One Wire EXchange] function does bus reset, tx and rx. To reset the bus and detect if any devices are present, just call it with a bit count of zero.... p = owex(0, 0); The returned value will be -1 (0xFFFF) if any devices are detected, or 0 if none are detected. To send data... owex(0xCC, 8); // Skip ROM command The returned value should match the data sent, if it does not then there is a bus problem. To receive data, use -1 (0xFFFF) for the tx data value... d = owex(-1, 8); // Get 8 bits 1 to 16 bits can be sent/received at once. This is the core code... .def owex ; int owex(int data, unsigned bit_count) .def owdport .def owiport .def owbit .def owtiming .bss owdport, 2 ; Direction port .bss owiport, 2 ; Input port .bss owbit, 2 ; Port bitmask .bss owtiming, 0 ; Timing array .bss owda, 2 ; 28 Zero .bss owdb, 2 ; 33 .bss owdc, 2 ; 39 .bss owdd, 2 ; 7 One .bss owde, 2 ; 8 .bss owdf, 2 ; 85 .bss owdg, 2 ; 500 Reset .bss owdh, 2 ; 50 .bss owdi, 2 ; 450 owex ; tst R13 ; Reset? jeq owrst ; Yes... push R11 ; Save R11, R13 push R13 ; clr R13 ; Clear bit count ; owloop ; --- Tx/Rx bit loop rra R12 ; Get tx bit jc owone ; If one... ; ; - Send and verify zero mov &owda, R15 ; nop ; mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; call #owdelay ; Delay 28 us ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; rrc R11 ; ; mov &owdb, R15 ; Delay 33 us call #owdelay ; ; mov &owdc, R15 ; mov &owdport, R14 ; Bus open bic.b &owbit, 0(R14) ; ; jmp ownext ; Delay 39 us ; owone ; - Send one and read bit mov &owdd, R15 ; tst R15 ; mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; jn owoneo ; Delay 7 us owdlyd ; sub #8, R15 ; nop ; jc owdlyd ; subc R15, PC ; nop ; nop ; nop ; owoneo ; bic.b &owbit, 0(R14) ; Bus open ; jc owones ; Delay 8 us mov &owde, R15 ; owdlye ; sub #8, R15 ; nop ; jc owdlye ; subc R15, PC ; nop ; nop ; nop ; owones ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; rrc R11 ; ; mov &owdf, R15 ; Delay 85 us ownext ; call #owdelay ; ; - Next bit inc R13 ; Increment bit count cmp R13, 0(SP) ; Compare bit count jne owloop ; Loop if not done... owrxa ; - Align rx data cmp #16, R13 ; Rx data aligned? jeq owrex ; Yes.. rra R11 ; Shift in a zero bit inc R13 ; Inc bit count jmp owrxa ; Next bit... owrex ; mov R11, R12 ; Get rx data to R12 pop R13 ; Restore R11, R13 pop R11 ; ret ; Return ; ; owrst ; - Reset and presence detect mov &owdport, R14 ; Bus low bis.b &owbit, 0(R14) ; ; mov &owdg, R15 ; Delay 500 us call #owdelay ; ; bic.b &owbit, 0(R14) ; Bus open ; mov &owdh, R15 ; Delay 50 us call #owdelay ; ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; subc R12, R12 ; ; mov &owdi, R15 ; Delay 450 us ;jmp owdelay ; and return ; owdelay ; sub #8, R15 ; nop ; jc owdelay ; subc R15, PC ; nop ; nop ; nop ; ret ; ; .end ; Demo program to read DS1820/1822 temperature sensor is included in zip file. one_wire.zip dacoffey, gyengus, larsie and 9 others 12 Quote Link to post Share on other sites
zeke 693 Posted August 11, 2011 Share Posted August 11, 2011 I think it's cool that it will work with a slow clock speed. :thumbup: Have you considered adding in more one-wire functionality? Quote Link to post Share on other sites
oPossum 1,083 Posted August 11, 2011 Author Share Posted August 11, 2011 I have bus scan and CRC written, but not yet tested. zeke 1 Quote Link to post Share on other sites
Mac 67 Posted August 13, 2011 Share Posted August 13, 2011 May I ask how to make a project out of those pieces, please? I created a project called "OneWire" and I copied the files from the zip file into the OneWire workspace folder but there doesn't appear to be a file for the "core" routines. Just not sure how you make a project with more than just a single main.c file. Sorry for the dumb question... Regards, Mike Quote Link to post Share on other sites
oPossum 1,083 Posted August 13, 2011 Author Share Posted August 13, 2011 I forgot a few files in the zip. It is fixed now. Main.c is also updated to show temperature in deg C and F. Quote Link to post Share on other sites
Mac 67 Posted August 13, 2011 Share Posted August 13, 2011 Compiles fine now. Thank you... Quote Link to post Share on other sites
Mac 67 Posted August 16, 2011 Share Posted August 16, 2011 Hi oPossum (Kevin?), Combining read/write bit "slot" functions is incredibly insightful. Bravo! After looking at the separate read and write routines on an old DS18B20 + PIC 10F200 project, combining the routines seemed embarrassingly obvious (lol). Anyway, I can't wait to try it out. Combining the routines saves eight (8) words of program memory which is pretty significant on a 10F200 with only 255 words of program memory (lol). Since you're a PIC guy too, I thought you might appreciate seeing the (untested) results; Thank you!!! Regards, Mike ; ; Ow.rwByte, send byte in WREG. send 0b11111111 to read a byte ; with read result in 'OwByte'. ; Mike McLaren, K8LH radix dec Ow.rwByte movwf OwByte ; movlw 8 ; movwf BitCtr ; rrf OwByte,W ; put b0 in Carry rwloop call Ow.rwBit ; rrf OwByte,F ; decfsz BitCtr,F ; done (all 8 bits)? goto rwloop ; no, loop, else retlw 0 ; exit ; ; Ow.rwBit (4..32 MHz clock), input = carry ('1' to read ; a bit). 'read' bit result in carry. ; radix dec Ow.rwBit movlw MaskLo ; start 60 us rw slot tris GPIO ; falling edge 0 us goto $+1 ; goto $+1 ; skpnc ; skip if bit = '0', else movlw MaskHi ; mask to release buss tris GPIO ; low pulse is 1..8 us uDlyCy (14*usecs-8) ; 14 us minus 8 cycles btfss owpin ; sample owpin at exactly 14 us clrc ; clear Carry if '0' uDlyCy (47*usecs-3) ; balance of 60 us slot movlw MaskHi ; mask to release buss tris GPIO ; read/write slot ends at 61 us retlw rombuffer ; for search rom routine ; Econiunioks and oPossum 2 Quote Link to post Share on other sites
oPossum 1,083 Posted August 17, 2011 Author Share Posted August 17, 2011 PIC code looks good. Gives me some ideas to improve MPS430 code. - Kevin (oPossum) Quote Link to post Share on other sites
oPossum 1,083 Posted August 17, 2011 Author Share Posted August 17, 2011 Here is updated one wire code that is a bit smaller. More code is shared between the zero and one tx/rx. I have also added four functions for byte/word read/write, and an export for the bus reset so it can be called directly. Core asm code... owww ; - Write word mov #16, R13 ; jmp owdx ; owrw ; - Read word mov #-1, R12 ; mov #16, R13 ; jmp owdx ; owwb ; - Write byte mov #8, R13 ; jmp owdx ; owrb ; - Read byte mov #-1, R12 ; mov #8, R13 ; ;jmp owdx ; owex ; - Exchange / Reset tst R13 ; Reset? jeq owrst ; Yes... owdx ; push R11 ; Save R11, R13 push R13 ; clr R13 ; Clear bit count ; owloop ; --- Tx/Rx bit loop mov &owdport, R14 ; rra R12 ; Get tx bit jc owone ; If one... ; ; - Send and verify zero mov &owda, R15 ; nop ; bis.b &owbit, 0(R14) ; Bus low ; jmp owdlyc ; Delay 15 us... ; ; owone ; - Send one and read bit mov &owdb, R15 ; tst R15 ; bis.b &owbit, 0(R14) ; Bus low ; jn owoneo ; Delay 7 us owdlyb ; sub #8, R15 ; nop ; jc owdlyb ; subc R15, PC ; nop ; nop ; nop ; owoneo ; bic.b &owbit, 0(R14) ; Bus open ; jc ows ; Delay 8 us mov &owdc, R15 ; owdlyc ; sub #8, R15 ; nop ; jc owdlyc ; subc R15, PC ; nop ; nop ; nop ; ows ; mov &owiport, R14 ; Sample bus mov.b @R14, R14 ; bit &owbit, R14 ; rrc R11 ; ; mov &owdd, R15 ; Delay 48 us call #owdelay ; ; mov &owde, R15 ; mov &owdport, R14 ; Bus open bic.b &owbit, 0(R14) ; ; call #owdelay ; Delay 37 us ; ; - Next bit inc R13 ; Increment bit count cmp R13, 0(SP) ; Compare bit count jne owloop ; Loop if not done... owrxa ; - Align rx data cmp #16, R13 ; Rx data aligned? jeq owrex ; Yes.. rra R11 ; Shift in a zero bit inc R13 ; Inc bit count jmp owrxa ; Next bit... owrex ; mov R11, R12 ; Put rx data in R12 pop R13 ; Restore R11, R13 pop R11 ; ret ; Return Attachment has complete asm and C code. one_wire_new.zip Wagner de Queiroz and gyengus 2 Quote Link to post Share on other sites
oPossum 1,083 Posted August 17, 2011 Author Share Posted August 17, 2011 Block read with CRC. Return will be zero if CRC is valid, or non-zero for invalid CRC. Length includes CRC. unsigned read_block(unsigned char *d, unsigned len) { unsigned crc = 0; unsigned n; for(; { crc ^= *d++ = owrb(); if(!--len) break; n = 8; do crc = (crc & 1) ? ((crc >> 1) ^ 0x8C) : (crc >> 1); while(--n); } return crc; } gyengus 1 Quote Link to post Share on other sites
Mac 67 Posted August 17, 2011 Share Posted August 17, 2011 Wow! Very similar to some of my old code; ; ; Mike McLaren's Dallas one-wire 8-bit CRC code for the DS18B20 ; ; clear the CRC variable then run each byte from the scratchpad ; read or ROM read operation through the CRC_Calc subroutine. A ; final CRC value of '0' indicates "good data". ; ; void CRC_Calc () ; { crc ^= owByte; ; for (i = 0; i < 8; i++) ; { if (crc & 1) ; crc = (crc >> 1) ^ 0x8C; ; else ; crc = crc >> 1; ; } ; } ; ; entry: owByte contains data byte ; exit: CRC contains cumulative CRC data ; CRC_Calc movlw d'8' ; |B0 movwf BitCtr ; setup bit counter |B0 movf owByte,W ; |B0 xorwf CRC,F ; |B0 movlw h'8C' ; W = x8+x5+x4+1 polynomial |B0 CRC_Next clrc ; |B0 rrf CRC,F ; |B0 skpnc ; |B0 xorwf CRC,F ; toggle b7, b3, and b2 bits |B0 decfsz BitCtr,F ; all done? yes, skip, else |B0 goto CRC_Next ; process the next IOByte bit |B0 return ; |B0 ; Could I impose on you to explain this line in your code, please? The crc ^= *d++ part makes sense but not the rest, unless... is owrb() a OneWire read byte function? Yes, that's it. I see owrb() in the previous post. Sorry! crc ^= *d++ = owrb(); Quote Link to post Share on other sites
Mac 67 Posted August 17, 2011 Share Posted August 17, 2011 Do you have any equally exciting new insights on OneWire search rom code? It's a rather messy algorithm that cost me about 50 words when I implemented it on that old PIC10F200 project (please forgive me for posting more PIC code guys); clrf LastDiscrep ; init Last Discrepency var' OwSearchNext clrf BitIndex ; BitIndex = 0 clrf LastZero ; LastZero = 0 movlw b'00000001' ; movwf BitMask ; setup rom array bit mask OwReset ; reset all 1-wire devices OwWrite(OwSearchRom) ; send "search rom" command ; movlw RomBuffer ; OwWrite() returns W = &RomBuffer movwf FSR ; FSR = &RomBuffer (0x10) GetBits OwReadBit ; read bit A rlf OwTemp,F ; F = -------A OwReadBit ; read bit B (compliment) rlf OwTemp,W ; W = ------AB rrf OwTemp,F ; put 'A' bit back into Carry andlw 0x03 ; filter out unused bits xorlw 0x03 ; AB == 11, no response? bz Restart ; yes, branch (restart), else xorlw 0x03 ; AB == 00, a discrepency? bnz SendRomBit ; no, branch, use 'A' bit, else Discrepency movf BitIndex,W ; 0..63 subwf LastDiscrep,W ; 0..63 bnc IndexGTLD ; index > last discrepency, use '0' bz SendRomBit ; index = last discrepency, use '1' IndexLTLD ; index < last discrepency, use ROM movf BitMask,W ; get ROM bit andwf INDF,W ; is ROM bit '0'? bnz SendRomBit ; no, branch with C = 1, else clrc ; set C = 0 and IndexGTLD movf BitIndex,W ; update 'LastZero' movwf LastZero ; SendRomBit movf BitMask,W ; set ROM bit to value in Carry iorwf INDF,F ; set ROM bit (unconditionally) skpc ; is bit a '1'? yes, skip, else xorwf INDF,F ; clr ROM bit OwSendCarry ; send direction/qualifier bit rlf BitMask,W ; rlf BitMask,F ; advance the bit mask skpnc ; byte boundary? no, skip, else incf FSR,F ; bump RomBuffer array address incf BitIndex,F ; bump bit index, 0..63 btfss BitIndex,6 ; BitIndex = 64? yes, skip, else goto GetBits ; do next bit movf LastZero,W ; update last discrepency movwf LastDiscrep ; a 0 indicates last DS18B20 ; Quote Link to post Share on other sites
RobG 1,892 Posted August 17, 2011 Share Posted August 17, 2011 ...please forgive me for posting more PIC code guys... You could start PICoh or PICer .com Quote Link to post Share on other sites
bluehash 1,581 Posted August 17, 2011 Share Posted August 17, 2011 (please forgive me for posting more PIC code guys) As long as it works. You could start PICoh or PICer .com :think: Quote Link to post Share on other sites
Mac 67 Posted August 17, 2011 Share Posted August 17, 2011 I apologize guys but oPossum knows PIC assembler and he may glean something useful from the code or structure that he can transfer over to the '430. Thanks for being tolerant... Cheerful regards, Mike Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.