please dont rip this site

Microchip NEW200102.TXT

~Page  http://www.piclist.org/techref/microchip/gotchas.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.microchip.com/10/lit/suppdoc/errata/index.htm
http://www.microchip.com/10/lit/suppdoc/errata/index.htm is the current Microchip errata page.


~Page http://www.piclist.org/techref/microchip/gotchas.htm
Modified by:JMN-EFP-786 
replace-to: 
<A NAME="JMN-EFP-786" HREF="http://www.microchip.com/10/lit/suppdoc/errata/index.htm" TARGET="_top">
http://www.microchip.com/10/lit/suppdoc/errata/index.htm</A> is the current Microchip errata page.
<!-- EOR -->

http://www.sxlist.com/techref/microchip/i2c-eeprom.htm
Modified by:JMN-EFP-786 
replace-to: 
</PRE>
<BODY>
<H1>
  <A HREF="index.htm">PIC</A> <A HREF="../cpus.htm">Microcontoller</A>
  <A HREF="ios.htm">Input / Output</A> <A HREF="memory.htm">Memory</A>
  <A HREF="../method/io.htm">Method</A>
</H1>
<H2>
  for <A HREF="i2c.htm">I<SUP>2</SUP>C</A> to
  <A HREF="../mem/eeproms.htm">EEPROM</A> <A HREF="memory.htm">Memory</A>s
</H2>
<H3>
  by Mike Harrison [mike at whitewing.co.uk]
</H3>
<P>
For many years I've been irritated by the relatively large amount of code
needed to talk to I2C EEPROMS, especially on c5x parts where stack depth
is limited. I swore one day I'd try to do some highly optimised code. I finally
got around to it, and 30-odd sheets of paper later, below is the result
<P>
It's primarily targetted at c5x applications, and was designed with the following
criteria & limitations in mind (based on several real applicati ons)
:
<UL>
  <LI>
    Absolute minimum code size, stack usage and register usage, in that order.
    (64 words code, 4 registers, no internal calls)
  <LI>
    Must be able to read or write one *or more* bytes to a single small (<=256
    byte) I2C eeprom, transferring data to/from an area of RAM pointed to by
    the FSR.
  <LI>
    I2C address of eeprom fixed at assemble time.
  <LI>
    Automatic retry if the eeprom is busy with a previous write.
  <LI>
    Correct I2C timing at 4MHZ.
  <LI>
    SDA and SCL will be on the same port, but no restrictions on which bits are
    used.
  <LI>
    No assumptions to be made on the state of SCL and/or SDA on entry - this
    is important where pins are shared with other funcions - SCL can often be
    re-used as the eeprom will ignore it as long as SDA is stable.
  <LI>
    No jump table schemes (as used in Microchip's code in the 12CE518 data sheet)
    to allow the code body to be moved out of page zero if required.
</UL>
<P>
The following limitation of the current code is considered acceptable for
the applications targeted : The number of bytes to read/write, and the RAM
address to read/write are likely to be fixed at assemble time, so it doesn't
matter if strange offsets etc. are required to these values, as this costs
no code space, and can be handled easily with macros.
<P>
The code will read or write up to 14 bytes per call, although the write cache
size of small eeproms will usually limit writes to 8 bytes or fewer. READ
THE DATASHEET CAREFULLY to find the cache size for the device you are using,
and be aware that this can vary between different manufacturers of the same
part, and part revisions (e.g. Microchip 24LC01 vs. 24LC01B).
<P>
The current code body uses 68 words (including return). The code used to
set-up addresses etc. is not counted as this will be different in different
applications. Three words can be saved if 'fast mode' eeproms are used (e.g.
24LC01B at 5V). 4 registers are used,(plus FSR), one of which is for the
eeprom address, which is preserved and can be eliminated if only one address
will be used. No internal CALLs are used.
<P>
Explanatory notes - the following notes describe the more subtle aspects
of the code - you don't need to understand them if you just want to use the
code 'as is', but you will if you want to modify or optimise it further!
<P>
The code runs in two 'phases' - a write phase and a read phase, the latter
only being used for read operations. Each phase begins with a start condition,
followed by the control byte.
<UL>
  <LI>
    The write phase sends the control byte, the eeprom address, and for write
    operations, the data to be written.
  <LI>
    The read phase sends the control byte and reads the bytes from the eeprom.
</UL>
<P>
The variable 'cnt' holds two counts, one per nibble, stored as negative numbers,
i.e. counting up to zero.
<UL>
  <LI>
    Bits 7-4 hold the number of bytes in the write phase
  <LI>
    Bits 3-0 hold the number of bytes in the read phase
</UL>
<P>
The flags byte is used as follows :
<UL>
  <LI>
    bit 0 'read' is set for reading bytes, cleared for writing
  <LI>
    bit 1 'addr' is set after the eeprom address has been sent, to ensure it
    only gets sent once.
  <LI>
    bit 2 'rden' is a 'read pending' flag, which causes a switch to read mode
    after the second control byte has been written
  <LI>
    bits 7..5 are used as a bit counter for the byte send/recive section.
</UL>
<P>
Using the same byte for flags and the bit count doesn't actually take any
more code - the extra cycles to increment the count it by adding 20h are
saved by not having to initialise the count - it's done when the flags are
set up.
<P>
When SCL is set high, if SDA is tri-state (input or '1' output), the SDA
output register bit may get set high (which would prevent SDA going low)
by read-modify-write bit operations on SCL. This problem is avoided by clearing
both SDA and SCL bits together with ANDWF. This will not cause SDA glitches,
as the only time this clearing will change the SDA output register state
is when SDA is tri-stated.
<P>
FSR is incremented on every byte - there's no point doing it conditionally
as all that's needed to compensate is an assembly-time offset.
<P>
Note that in a few cases you will need to add a clrwdt somewhere inside the
retry loop, depending on choice of eeprom, WDT prescale setting, and the
delay between a write and any subsequent read or write attempt. The worst-case
write time of a 24LC01B is 10mS, and the PIC's worst-case undivided watchdog
period is 9mS.
<P>
Everyone's application is different, and so there is scope for further
optimisation depending on particular requirements - here are a few suggestions
:
<UL>
  <LI>
    If only one eeprom address is needed (e.g. a single parameter block), the
    eeadr register can be replaced with a literal.
  <LI>
    If only single byte reads & writes are required, a couple of optimisations
    are possible - the INCF FSR goes, and the conditional write to INDF can be
    an unconditional write to the target register, as it doesn't matter if it
    gets written with rubbish before the actual data is read.
  <LI>
    If the routine is called from several places, some of the set-up done in
    the macros could be placed at the head of the code, depending on what parameters
    are the same for all calls.
  <LI>
    If the system timing is such that the eeprom will never be busy writing when
    an attempt to access it again is made, the 2 words of retry code can be omitted.
  <LI>
    It may be possible to simplify some of the start/stop condition code if it
    is known that other I/O activity will not affect the state of the SCL/SDA
    porta and TRIS registers between calls.
  <LI>
    The retry on busy could easily be changed to return immediately, for example
    by replacing the 'goto retry_iic' with 'retlw 1'. The calling code could
    then check W to test for success.
  <LI>
    Some of the delays (as noted in comments) can be omitted for 'fast mode'
    compatible eeproms.
</UL>
<P>
If power consumption is an issue, you may want to add a delay to the retry
loop to reduce the number of retries that will be attempted when the eeprom
is busy writing.
<P>
A 10K pullup resistor is required from SDA to Vdd. No pullup is required
on SCL as open-drain SCL drive is not required for eeprom applications.
<P>
Note that this code will not work as-is with the 12CE51x devices, and although
it could be modified, it may not be especially optimal - the CE devices don't
(all?) have a write cache, so the multi-byte write capability will not be
useful in its current form.
<PRE>

;***********************************************************************

; compact I2C eeprom access code V1.0
; (C) Mike Harrison 1998
; example code for PIC12C508
;------------------------------------------------------- workspace
cnt equ 08   	; byte count register
flags equ 09 	; flags and bit count :
read equ 0 	; 1 to read bytes, 0 to write
addr equ 1 	; 0 to send eeprom address byte
rden equ 2 	; 1 to enable read next cycle
           	; b5-7 used as bit counter

temp equ 0a  	; read/write data byte
eeadr equ 0b 	; eeprom address

iiport equ gpio  	; port address
sclbit equ 4 		; SCL port pin (no pullup required)
sdabit equ 5 		; SDA port pin (10K pullup to Vdd required)

lotris equ b'00101'	; TRIS setting with SCL and SDA outputs, other bits as required by application

hitris equ lotris+(1<<sdabit)


; calling examples :
;to read 3 bytes from eeprom addr 10..12 to registers 14..16 
; movlw 10
; movwf eeadr
; readee 3,14 

;to write 5 bytes from registers 19..1d to eeprom address 0
; clrf eeadr
; writeee 5,19


;--------------------------------------------------- calling macros

; to simplify parameter set-up, you can call the code using the following macros

readee macro bytes,address
 ; usage : readee <no. of bytes to read>, <RAM address to read to>
 
 movlw address-3 ; FSR offset due to unconditional increment
 movwf fsr
 movlw 0ef - bytes ; 2 writes (control, address) + n+1 reads (control,data) 
 call do_iic
 endm
 
writeee macro bytes,address
 ; usage : writeee <no. of bytes to write>, <RAM address to write from>

 movlw address-1 
 movwf fsr
 movlw 0e0 - (bytes <<4) ; n+2 writes (control,address,data), no reads
 call do_iic
 endm

;-----------------------------------------------------------do_iic
do_iic ; read/write byte(s) to I2C EEPROM
       ; W & FSR to be setup as follows : 
       ; read  : EF - nbytes      FSR = RAM address-1 
       ; write : E0 - (nbytes<<4) FSR = RAM address-3 
       ; eeadr holds eeprom address (preserved on exit)
       ; on exit, FSR points to the byte after the last one read/written
       ; nbytes can be up to 14, but eeprom write cache may limit this
       
 movwf cnt
retry_iic
 clrf flags ; initialise flags and bit count
phaseloop
  movlw hitris 
  tris iiport 		; ensure SDA high
  bsf iiport,sclbit  	; SCL high
  bcf iiport,sdabit 	; ensure SDA o/p reg low
  movlw lotris
  goto $+1			; ensure Tsu:sta - can be omitted in fast mode
  tris iiport 			; sda low - start condition


  movlw iiadr 			; IIC control byte (write)
  btfsc flags,rden
  movlw iiadr+1 		; .. or read control byte if read pending
  movwf temp    		; IIC control byte 
  bcf iiport,sclbit     ; scl low - code above ensures Thd:sta


byteloop        		;
								; start of byte read/write section
    movlw lotris  
    btfss flags,read 			; set SDA high (tri-state) if reading
    btfsc temp,7     			; set SDA low only if writing and data bit = 0
    movlw hitris     			; (sda o/p register bit will be low)
    tris iiport     
    goto $+1          					; wait set-up time          
    bsf iiport,sclbit 					; clock high (may set SDA o/p reg bit high)
    clc									; used later - done here for timing
    movlw 0ff^(1<<sclbit)^(1<<sdabit)  	; mask to clear SDA and SCL, "   "
    btfsc iiport,sdabit        			; test SDA input for read
    sec					      
    andwf iiport						; SCL low, SDA o/p reg bit low
    rlf temp 							; shift read data in or write data out    
    movlw 020
    addwf flags 						; increment bitcount in b5-7
    skpc
    goto byteloop						; do 8 bits
   movlw 0f0
   xorwf cnt,w				; last byte of read ? Z set if so
   movlw lotris				; ack low if reading to send ack to eeprom
   skpz					; ..but no ack on last byte of read
   btfss flags,read			;
   movlw hitris				; ack high for write to test ack from eeprom
   tris iiport
   bsf iiport,sclbit    		; clock high to get or send ack bit
   goto $+1 				; wait ack pull-up time
   movlw 0ff^(1<<sclbit)^(1<<sdabit) 	; SDA/SCL low mask, done here to add delay
   skpz					; last byte of read - skip retry  
   btfss iiport,sdabit  		; read ack bit state 
   goto no_retry_iic			
   goto retry_iic			; retry if ack high (will be forced low on reads, except last byte)
no_retry _iic
   andwf iiport				; set scl and sda o/p register bit low
  ;.....................  end of byte read/write section
   movf temp,w
   btfsc flags,read
   movwf indf 			; store data if reading
   movf indf,w			; get write data
   incf fsr 			; increment RAM pointer
   
   btfss flags,addr
   movf eeadr,w			; load eeprom address if not disabled 
   movwf temp			; byte to send next loop - address or data
   bsf flags,addr       ; disable address flag
   btfsc flags,rden		; read mode pending?
   bsf flags,read		; set read mode
   
   movlw 010
   addwf cnt			; increment byte counter in B4..7
   skpnz               
   goto done  			; both nibbles zero - all done
   skpc				; c set if b7-4 now clear - write phase done
   goto byteloop
   bsf flags,rden       ; set 'read pending' flag
   swapf cnt            ; load byte counter with read byte count
   goto phaseloop		; do second phase of command

done 
						; do stop condition				
  movlw lotris			; (SDA o/p bit will be low)
  tris iiport 			; set SDA low
  bsf iiport,sclbit		; scl high
  goto $+1				; ensure Tsu:sto
  goto $+1				; both these can be omitted for fast mode
  movlw hitris			
  tris iiport			; sda high
  retlw 0

#include	<pic.h>
// demo of Mike's optimised IIC code for eeprom access under hitech C
// (C) Mike Harrison 2001 email mike -at- whitewing.co.uk	
// Note that this doesn't seem to work when  local optimisation is enabled, as it
// appears to 'optimise' the asm code by simply ignoring it! Global optimisation seems to be OK.
// this is intended for inclusion within C source, not as a seperate 'extern' module
// It could  be converted to the latter form easily, and this would avoid the above optimisation
// problem. (If anyone does this please let me have a copy!)
// see notes on original assembler version for more details. 

// this version works under hitech C V7.86, and was tested on a PIC16C74
// if anyone who knows C better can suggest any improvements to the C side of this please let me know!


//asm macros
#define c 0
#define z 2
#define skpnc btfsc _STATUS,c
#define skpc btfss _STATUS,c
#define sec bsf _STATUS,c
#define clc bcf _STATUS,c
#define skpz btfss _STATUS,z
#define skpnz btfsc _STATUS,z
#define tris dw 0x60+
#define rp0 5
// define indf - missing from hitech 
static volatile unsigned char INDF	@ 0x00;

// eeprom port bits (PORT A)
#define sclbit 2 
#define sdabit 3
#define ee_scl _PORTA,sclbit
#define ee_sda _PORTA,sdabit
#define hitris  0x1a // PORT A TRIS for SDA high
#define lotris hitris-(1<<sdabit) 

#define iiport _PORTA
#define iiadr 0x0a0


void do_iic(char cnt,char eeadr,char fsrval)

// flags 
#define rden 2
#define addr 1
#define read 0

{
char flags;
char temp;
// the following assignments seem to stop the compiler optimising 
// out the temp vars because it thinks they are unused.
// This is required when global optimisation is enabled.
// if anyone knows a better way (i.e. one that doesn't waste ROM)
// of telling the compiler that these vars are used please let me know!
// one alternative would be to use global temp vars for temp & flags

flags=flags;
eeadr=eeadr; 
cnt=cnt;
temp=temp;
FSR=fsrval; // pointer to read/write data
#asm
do_iic ; read/write byte(s) to I2C EEPROM
       ; W & FSR to be setup as follows : 
       ; read  : cnt=EF - nbytes      FSR = RAM address-1 
       ; write : cnt=E0 - (nbytes<<4) FSR = RAM address-3 
       ; eeadr holds eeprom address (preserved on exit)
       ; on exit, FSR points to the byte after the last one read/written
       ; nbytes can be up to 14, but eeprom write cache may limit this

       
retry_iic
 clrf _do_iic$flags ; initialise flags and bit count
phaseloop
  movlw hitris 
  tris iiport 		; tris iiportensure SDA high
  bsf ee_scl  	; SCL high
  bcf ee_sda 	; ensure SDA o/p reg low
  movlw lotris
  goto $+1			; ensure Tsu:sta - can be omitted in fast mode
  tris iiport 			; sda low - start condition


  movlw iiadr 			; IIC control byte (write)
  btfsc _do_iic$flags,rden
  movlw iiadr+1 		; .. or read control byte if read pending
  movwf _do_iic$temp    		; IIC control byte 
  bcf ee_scl     ; scl low - code above ensures Thd:sta


byteloop        		;
								; start of byte read/write section
    movlw lotris  
    btfss _do_iic$flags,read 			; set SDA high (tri-state) if reading
    btfsc _do_iic$temp,7     			; set SDA low only if writing and data bit = 0
    movlw hitris     			; (sda o/p register bit will be low)
    tris iiport     
    goto $+1          					; wait set-up time          
    bsf ee_scl 					; clock high (may set SDA o/p reg bit high)
    clc									; used later - done here for timing
    movlw 0xff^(1<<sclbit)^(1<<sdabit)  	; mask to clear SDA and SCL, "   "
    btfsc ee_sda        			; test SDA input for read
    sec					      
    andwf iiport						; SCL low, SDA o/p reg bit low
    rlf _do_iic$temp 							; shift read data in or write data out    
    movlw 0x20
    addwf _do_iic$flags 						; increment bitcount in b5-7
    skpc
    goto byteloop						; do 8 bits

    movlw 0xf0
    xorwf _do_iic$cnt,w 		; =f0 (last byte of read), result used later
   
   movlw lotris				; ack low if reading to send ack to eeprom
   skpz 					; no ack on read of last byte
   btfss _do_iic$flags,read
   movlw hitris				; ack high for write to test ack from eeprom, or on last byte read
   
   tris iiport
   
   bsf ee_scl   		    ; clock high to get or send ack bit
   goto $+1 				; wait ack pull-up time
   movlw 0xff^(1<<sclbit)^(1<<sdabit) 	; SDA/SCL low mask, done here to add delay
   skpz 					; last byte of read - skip retry
   btfss ee_sda  		; read ack bit state 
   goto no_retry_iic	; no retry if ack low, or on last byte of read		
   goto retry_iic		; retry if ack high (will be forced low on reads, except last byte)
no_retry_iic

   andwf iiport				; set scl and sda o/p register bit low
  ;.....................  end of byte read/write section
   movf _do_iic$temp,w
   btfsc _do_iic$flags,read
   movwf indf 			; store data if reading
   movf indf,w			; get write data
   incf fsr 			; increment RAM pointer
   
   btfss _do_iic$flags,addr
   movf _do_iic$eeadr,w			; load eeprom address if not disabled 
   movwf _do_iic$temp			; byte to send next loop - address or data
   bsf _do_iic$flags,addr       ; disable address flag
   btfsc _do_iic$flags,rden		; read mode pending?
   bsf _do_iic$flags,read		; set read mode
   
   movlw 0x10
   addwf _do_iic$cnt			; increment byte counter in B4..7
   skpnz               
   goto done  			; both nibbles zero - all done
   skpc				; c set if b7-4 now clear - write phase done
   goto byteloop
   bsf _do_iic$flags,rden       ; set 'read pending' flag
   swapf _do_iic$cnt            ; load byte counter with read byte count
   goto phaseloop		; do second phase of command

done 
 						; do stop condition				
  movlw lotris			; (SDA o/p bit will be low)
  tris iiport 			; set SDA low
  bsf ee_scl			; scl high
  goto $+1				; ensure Tsu:sto
  goto $+1				; both these can be omitted for fast mode
  movlw hitris			
  tris iiport			; sda high
  

#endasm
 
}


//eeprom read/write routines. If only called once it would be more efficient to use macros instead
// note upper limit of 14 bytes that can be written/read at a time	
// and for writes, #bytes may be limited by eeprom cache size

void write_ee(char eeaddress,char nbytes,char source)
// call with write_ee(eeadr,#bytes,(char)&varname);
{
do_iic(0xe0-(nbytes<<4),eeaddress,source-1);
}


void read_ee(char eeaddress,char nbytes,char dest)
// call with read_ee(eeadr,#bytes,(char)&varname);
{
do_iic(0xef-nbytes,eeaddress,dest-3);
}



main()
{

long test1=0x33221100;
int test2=0x5544;
char test3=0x66;
char buffer[8];

TRISA=hitris;
ADCON1=7; // disable adc
OPTION=0b10110000;


write_ee(0x10,4,(char)&test1); // write long test1 to ee address 0x10
// data will be written LSB first, i.e. 00,11,22,33 in addresses 10..13

write_ee(0x14,2,(char)&test2); // write int test2 to ee address 0x14
write_ee(0x16,1,(char)&test3); // write char test3 to ee address 0x16

read_ee(0x10,4,(char)&test1); // read long test1 from ee address 0x10
read_ee(0x14,2,(char)&test2); // read int test2 from ee address 0x14
read_ee(0x16,1,(char)&test3); // read char test3 from ee address 0x16


read_ee(0x10,8,(char)&buffer[0]); // read 8 bytes from ee addresses 0x10..17 to buffer[0..7]
							     
do
 asm("clrwdt");
 while(1);
}


</PRE>
</BODY>



http://204.210.50.240/techref/microchip/crack.htm
Modified by:JMN-EFP-786 
replace-to: 
<H1>Cracking / Guarding PICs</H1>
<P>Its amost always harder to break copy protection on a PIC (and/or more expensive) than just hireing a programmer to duplicate the function of the original...
<P>
...and then its legal. <GRIN>

http://www.piclist.com/techref/microchip/ios.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.com/techref/microchip/rs485.htm
RS-485 (RS485)

http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.com/techref/microchip/rs485-fav.htm
RS485 Networking for intelligent house by Frank A. Vorstenbosch

http://www.piclist.com/techref/microchip/rs485-fav.htm
Modified by:JMN-EFP-786 
replace-to: 
<H1>
  <A HREF="index.htm">PIC</A> <A HREF="../cpus.htm">Microcontoller</A>
  <A HREF="ios.htm">Input / Output</A> <A HREF="../method/io.htm">Method</A>s
</H1>
  <H2><A HREF="rs485.htm">RS485</A> Networking for intelligent house by Frank A. Vorstenbosch</H2>
  <P>
...my
colleague Brian wants all of his house rewired.  Also, we have been
toying around with placing temperature sensors around our office (which
we need to prove that our airconditioning doesn't work).
<P>
After some thought about power-line RF drivers and such, we decided
on RS485-type network at a low data rate (16kbps approx).  When used
with appropriate slew-rate limited drivers (MAX487) you can have relatively
long stubs on your network.  The network is terminated on both ends
with 100R, with two 1k resistors biasing the network into a '0' state.
<P>
The temperature sensors I've built use just four active components:
a DS1621 I2C temperature sensor, a MAX487 line driver, a PIC 12C509
and a 78L05.  We're planning to use four-wire cable at home (+12V, GND
and the two differential data lines) and cat-5 network cabling in
the office.
<P>
Below is the code for the RS485 protocol that we use.  This code is
heavily macro'd, but should be readable.  If enough people show
interest then I'll put the include files needed and the rest of the
(not quite working) temperature sensor application up on my or Brian's
home page.
<P>
Frank
<P>
Note:  This source requires PC graphics to show the diagrams.
<PRE>
Note 2: JBS   - BTFSC+GOTO
        JBC   - BTFSS+GOTO
        LOOP  - DECFSZ+GOTO
        LOOPI - INCFSZ+GOTO
        STR   - MOVWF
        LD    - MOVF,W
        JZ    - SKPNZ+GOTO
        FRAME..FEND sets up a set of local registers
        etc.


; IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM;
; :                                                                     :
; :   485.I                                                             :
; :                                                                     :
; :   RS-485 home automation bus interface.                             :
; :                                                                     :
; :   Copyright 1997, Frank A. Vorstenbosch.                            :
; :                                                                     :
; HMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM<
;
; Uses:  FLAG_IDSTRING     - a flag, somewhere in a register
;        FLAG_BROADCAST    - a flag, somewhere in a register (can be same as
 FLAG_IDSTRING)
;        RxTxD             - a port pin for received and transmitted data
;        TxEN              - another port pin set high to enable transmitter

                frame 485
                byte Shifter485
                byte Counter485
                byte TempA485
                byte CRCLow485
                byte CRCHigh485
                byte Timer485
                static OurTC
                fend 485

#define Timer485        TempC485



; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3                                                                     3
; 3   Description.                                                      3
; 3                                                                     3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY

; Two twisted pairs in cable, one for data and one for power/ground.  Power is
; supplied as 9..12V as measured on the peripheral -- a transmitter may take
; approx. 120mA when using 100j terminators, or 104mA using 120j terminators
; in addition to any local power needs.
;
; The network protocol is designed to run on 4MHz 12-bit PICs at ~16kb/s in
; software.  The longest packet takes less than 23ms to send, the shortest
; packet less than 2.5ms.  CSMA is used to prevent two devices transmitting
; at the same time.

; Synchronous message format:
;
;  - Start bit (100-250us duration)
;       Peripherals try sending a start bit of 100-200us, then float the
;       line, see if the line goes back to 0, and if it does, then drive
;       it low for the remainder of the 20us, then start sending data.
;       If the line is still driven to 1, then the peripheral will back
;       off until the bus is idle for >100us, then try sending another
;       start bit.  The peripheral will try progressively longer start
;       bits up to the limit of 200us.  The host uses a 250us start bit
;       to give it priority over all peripherals (this also means that
;       most peripherals can ignore start bits <250us long).
;  - Flags byte
;       7..6 - transfer direction:
;                 00 - peripheral to host
;                 01 - peer to peer (UNIM)
;                 10 - host to peripheral
;                 11 - reserved
;       5    - reserved
;       4..0 - data length
;  - Peripheral or destination address byte or 255 for broadcast
 (Flags<7..6>=10)
;  - Optional source address byte (Flags<7..6>=01) (UNIM)
;  - Command byte (Flags<7..6>=10) or status byte (Flags<7..6>=00)
;       Command
;          0      - Are you there? (Returns up to 31 byte ID string)
;          1      - Data poll
;          2..255 - User defined commands
;       Status
;          0      - OK
;          1      - CRC error
;          2      - Command error
;          3      - Parameter error
;          4      - No (more) data
;          5..254 - User defined errors
;          255    - Data broadcast
;  - 0..31 data bytes
;  - CRC-16 over Flags, Address and Data bytes

;                        ZDDDDDDDDDDDD//DDDDDDDDDDD?    Z
; Start     line idle    3        100-250us        325us3
;       DDDDDDDDDDDDDDDDDY                         @DDDDY
;       ZDDDD?    Z
; 0-bit 325us325us3
;       Y    @DDDDY
;       ZDDDDDDDDDD?    Z
; 1-bit 3   50us   325us3
;       Y          @DDDDY
;
; The low period at the end of each byte is 50us rather than 25us, giving
; devices time to process the byte.  Thus, the byte 0x54 would be transmitted
 as:
;
; ZDDDD?    ZDDDDDDDDDD?    ZDDDD?    ZDDDDDDDDDD?    ZDDDD?    ZDDDDDDDDDD?
 ZDDDD?    ZDDDD?          Z
; 325us325us3   50us   325us325us325us3   50us   325us325us325us3   50us
 325us325us325us325us3   50us   3
; Y    @DDDDY          @DDDDY    @DDDDY          @DDDDY    @DDDDY
 @DDDDY    @DDDDY    @DDDDDDDDDDY


; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3                                                                     3
; 3   Local definitions.                                                3
; 3                                                                     3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY

                ifndef FLAG_IDSTRING
                ifndef FLAG_BROADCAST
                error   "FLAG_IDSTRING and/or FLAG_BROADCAST must be defined"
                endif
#define FLAG_IDSTRING FLAG_BROADCAST
                endif
                ifndef FLAG_BROADCAST
#define FLAG_BROADCAST FLAG_IDSTRING
                endif


; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3                                                                     3
; 3   Receive a message from the RS485 bus.                             3
; 3                                                                     3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
;
; In:   W       - Size of receive buffer
;       fsr     - pointer to first byte of receive buffer
; Act:  Receive a message from the RS485 bus.
; Out:  Receive buffer filled in with command and data bytes
;       Counter485 - Number of data bytes
;       W - error code
;              0 - no error
;              1 - message was not addressed to us
;              2 - message was too long for our buffer
;              3 - CRC error
; Regs: Shifter485, Counter485, fsr, tmp, TempA485, TempB485, TempC485
; Note: Assumes that the start bit has already been detected.
;       Uses one stack level internally, can only be called from top level

ReceiveMessage  str     Counter485

                TRACE   1,"ReceiveMessage"

                clr     CRCHigh485
                clr     CRCLow485

                jbs     RxTxD,$                     ; wait for start bit to end

                call    RM_Byte                     ; receive flags & length
 byte
                retbc   Shifter485,7,1              ; if peripheral-to-host then
 ignore it

                ld      Shifter485
                str     TempA485
                subwf   Counter485,w
                retc    2

                movlw   31
                andwf   Shifter485,w
                str     Counter485
                inc     Counter485                  ; count command as a data
 byte

                bcf     FLAG_BROADCAST              ; assume is's not a
 broadcast

                call    RM_Byte                     ; receive device ID
                call    DeviceID
                xorwf   Shifter485,w                ; is the message addressed
 to us personally?
                jz      RM_Loop

                incf    Shifter485,w                ; or is it a broadcast?
                retnz   1
                bsf     FLAG_BROADCAST

RM_Loop         call    RM_Byte                     ; receive command/data byte
                ld      Shifter485
                inc     fsr
                str     ind
                loop    Counter485,RM_Loop

                call    RM_Byte                     ; receive first CRC byte
                call    RM_Byte                     ; receive second CRC byte

                ld      TempA485
                str     Counter485

                ld      CRCHigh485
                xorwf   CRCLow485,w
                retnz   3                           ; CRC error

                movlw   31
                andwf   Counter485                  ; clear unwanted bits in the
 length byte

                retlw   0

; zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

RM_Byte         ldk     Timer485,8<<<4

RMB_Loop        jbc     RxTxD,$                     ; wait for bit to start
                clc

RMB_Inner       incfsz  Timer485                    ; time the length of the bit
                jbs     RxTxD,RMB_Inner

                ; here the low nibble of Timer485 should be 6 or 13

                btfsc   Timer485,3                  ; detect 1 bit if 9 counts
 or more
                stc
                ld      status                      ; carry is LSB of status reg
ister
                rl      Shifter485                  ; shift bit into register

                xorwf   CRCLow485,w
                clrc
                rr      CRCHigh485
                rr      CRCLow485
                andlw   1
                xorwf   CRCLow485
                movlw   0xa0
                skipz
                xorwf   CRCHigh485

                movlw   0x0f
                iorwf   Timer485
                loopi   Timer485,RMB_Loop

                retlw   0


; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3                                                                     3
; 3   Entry point to subroutines for SendMessage.                       3
; 3                                                                     3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY

SM_Byte_tmp     ld      tmp                         ; [1]
SM_Byte         str     Shifter485                  ; [1]
SM_Byte_Sh      ldk     Timer485,8<<4               ; [2]
                jp      SMB_Loop                    ; [2]


; ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD?
; 3                                                                     3
; 3   Send a message on the RS485 bus.                                  3
; 3                                                                     3
; @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY
;
; In:   W       - Number of data bytes in message
;       tmp     - Status byte
;       fsr     - pointer to first byte to transmit
; Act:  Send a message on the RS485 bus.
; Out:  W - error code
;              0 - no error
;              1 - failed to send message after 8 attempts
; Regs: Shifter485, Counter485, CRCHigh485, CRCLow485, Timer485, fsr, tmp,
 (OurTC)
; Note: Uses one stack level internally, can only be called from top level

SendMessage     str     Shifter485

                TRACE   1,"SendMessage"

                ldk     Counter485,8
                clr     CRCHigh485
                clr     CRCLow485

                clr     gpio                        ; set TxEN low
                movlw   NORMAL_TRIS                 ; float RxTxD (with pull-up)
                tris    gpio

SM_WaitIdle     movlw   30
                subwf   OurTC,w                     ; shorter delay if longer
 start bit used
                str     Timer485
SMWI_Loop       jbs     RxTxD,SM_WaitIdle           ; [2] wait for bus to be
 idle for 100..150us
                loopi   Timer485,SMWI_Loop          ; [3]

                movlw   TxEN_MASK|RxTxD_MASK

                btfss   RxTxD                       ; last chance: if activity
 on bus then don't set TxEN high
                str     gpio                        ; drive TxEN high
                jbc     TxEN,SM_WaitIdle            ; wait some more if the STR
 wasn't executed

                movlw   NORMAL_TRIS&~RxTxD_MASK     ; quickly drive RxTxD to
 high level
                tris    gpio
                movlw   NORMAL_TRIS                 ; and then float it again
                tris    gpio

                ifdef HOST
                movlw   36                          ; host uses 250us timeout
                else
                movlw   13
                addwf   OurTC,w
                addwf   OurTC,w
                endif
                str     Timer485                    ; wait for 100..200us

SM_SendStartH   call    Delay4Ticks                 ; [4]
                loop    Timer485,SM_SendStartH      ; [3]

                clr     gpio                        ; disable transmitter
                brake                               ; it takes ~2.5us for the
 MAX487 to go into read mode
                movlw   TxEN_MASK                   ; moved here to prevent
 back-to-back I/O accesses
                jbs     RxTxD,SM_BackOff            ; if RxTxD still high, then
 back off
                str     gpio                        ; enable transmitter again
                movlw   NORMAL_TRIS&~RxTxD_MASK     ; start driving RxTxD pin
 (to low state)
                tris    gpio

                call    Delay9Ticks

                ld      Shifter485
                andlw   31
                str     Counter485
                call    SM_Byte_Sh                  ; send flags & length byte

                call    Delay13Ticks
                call    DeviceID
                call    SM_Byte                     ; send our ID

                call    Delay16Ticks
                call    SM_Byte_tmp                 ; send status byte

                jbs     FLAG_IDSTRING,SM_LoopCode
                test    Counter485
                jz      SM_CRCNoData                ; [2]
                call    Delay8Ticks                 ; [8]
                jp      SMLD_Enter                  ; [2]

SM_LoopData     call    Delay12Ticks                ; [12]
SMLD_Enter      ld      ind
                inc     fsr
                call    SM_Byte                     ; send data byte
                loop    Counter485,SM_LoopData
                jp      SM_SendCRC

SM_LoopCode     brake
                movlw   31
                andwf   fsr,w
                str     tmp
                movlw   IDString
                addwf   tmp,w
                call    PCW
                inc     fsr
                call    SM_Byte                     ; send ID string byte
                loop    Counter485,SM_LoopCode
                brake

SM_SendCRC      brake
                nop
SM_CRCNoData    call    Delay8Ticks
                ld      CRCHigh485
                str     tmp
                ld      CRCLow485
                call    SM_Byte                     ; send first CRC byte
                call    Delay16Ticks
                call    SM_Byte_tmp                 ; send second CRC byte

                movlw   NORMAL_TRIS
                clr     gpio                        ; disable transmitter
                tris    gpio                        ; float RxTxD

                retlw   0                           ; return OK

; zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

SM_BackOff      incf    OurTC,w                     ; increment our timer
                andlw   7                           ; only 3 LSBs used
                str     OurTC
                decfsz  Counter485,f                ; after 8 attempts, return
 error to caller
                retlw   1
                jp      SM_WaitIdle


; DDDDD Subroutine for SendMessage DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD

SMB_Loop        bsf     RxTxD

                ld      CRCLow485
                xorwf   Shifter485,w
                clc
                rr      CRCHigh485
                rr      CRCLow485

                andlw   1
                xorwf   CRCLow485                   ; if W=0, then do nothing,
                skipz                               ; otherwise CRC^=0xa001
                movlw   0xa0
                xorwf   CRCHigh485

SMB_Wait1       inc     Timer485                    ; [1] 25us high bit for a
 '0'
                movlw   0xf0                        ; [1]
                jbc     Timer485,1,SMB_Wait1        ; [3/2]

                rl      Shifter485
                jnc     SMB_ShortBit

SMB_Wait2       inc     Timer485                    ; [1] 50us high bit for a
 '1'
                jbc     Timer485,3,SMB_Wait2        ; [3/2]
                brake
                nop

SMB_ShortBit    andwf   Timer485                    ; W=0xf0 here
                bcf     RxTxD

SMB_Wait3       inc     Timer485                    ; [1] 25us low bit
                nop                                 ; [1]
                jbc     Timer485,2,SMB_Wait3        ; [3/2]
                movlw   0x0f
                iorwf   Timer485

                loopi   Timer485,SMB_Loop
                retlw   0


; DDDDD EOF 485.I DDDDD
</PRE>
<PRE>

http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 
replace-to: 

The practical differences of 232 vs 485 are:<UL>
<LI>single-dended versus differential
<LI>sender-receiver only versus multidrop possible</UL>

Doesn't RS485 typically use a 9 bit address byte protocol for multidrop communications?
<P>
see also:<UL>
<LI>
<A HREF="http://www.chipcenter.com/circuitcellar/july99/c79bppdf.pdf">http://www.chipcenter.com/circuitcellar/july99/c79bppdf.pdf</A> 'The Art and Science of RS-485'


<LI><A HREF="http://www.embedded.com/1999/9908/">http://www.embedded.com/1999/9908/</A> "Controlling the Transmit Enable Line on RS-485 Transceivers" Aug'99 Embedded Systems Programming</UL>


http://204.210.50.240/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 
replace-to: 

<A HREF="http://www.embedinc.com/pic">Olin Lathrop</A> says: <BLOCKQUOTE>
The architectural difference between RS-232 and RS-485 is that 232 is a
bi-directional point to point link, whereas 485 is a single channel bus.
RS-232 can also carry additional signals used for flow control and modem
control.
<P>
Electrically, each 232 signal uses a single wire with symmetric voltages
about a common ground wire.  485 uses two wires to carry the single signal
differentially.  Both wires use 0 to 5 volts, with the two wires being
driven opposite.  The purpose of this is to provide noise immunity, because
much of the common mode signal can be rejected by the receiver.
<P>
{ed: Although it is not a part of the specifications, in most cases...} Both 232 and 485 use the same asynchronous encoding of individual bytes.
This is the familiar start bit, followed by data bits (usually 8), followed
by stop bits (usually 1 nowadays).  Both the transmitter and receiver have
to agree on the bit rate in advance.  All timing within a byte is relative
to the leading edge of the start bit.  The <A HREF="index.htm">PIC</A> USART module was deliberately
designed to support this encoding in its asynchronous (UART) mode.  The low
level <A HREF="index.htm">PIC</A> code is the same for both 232 and 485 because it is transmitting
and receiving bytes via the UART (or a software UART).
<P>
The big difference to the software is that only one device on a 485 bus can
transmit at a time, whereas there are separate dedicated transmit and
receive channels for the single device at the other end of a 232 link.
There must also be external hardware that enables driving the bus when
transmitting.  This hardware is usually controlled from a separate <A HREF="index.htm">PIC</A> pin,
but there are also some "automatic" schemes.
<P>
The <A HREF="../io/serial/rs485s.htm">RS-485</A> standard (well sortof, "RS" actually stands for "recommended
standard") defines how to transmit and receive bytes to/from the bus
electrically.  Issues like flow control, collision avoidance, and data
reliability are left completely as an exercise to the implementer.  In a
pure RS-485 system, these have to be dealt with in the protocol.  As you can
imagine, there are lots of ways of dealing with this, and the right choice
depends on the particular system.  The solution often envolves wrapping data
into packets, each with a checksum, and some kind of ACK/retry scheme.  So
far I've dealt with collision avoidance by having a single master with all
other bus devices being slaves that only talk when asked to by the master.
Note that this can still give the appearance to upper levels of slaves
initiating data transfer if the master polls each slave often enough (this
is also how USB works, by the way).
<P>
Each <A HREF="../io/serial/rs485s.htm">RS-485</A> system is different, and therefore probably requires a different
protocol.  You inquiry to the <A HREF="../piclist/index.htm">PIC list</A> has prompted me to put some RS-485
information on my PIC development resources web page.  This includes an
excerpt of the protocol specification for one real-world system, provided as
an example.</BLOCKQUOTE>


http://www.piclist.com/techref/microchip/rs485.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\25\113704a
PICList post "<I>RS485 code?</I>"


http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
preview-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\023715a
PICList post "<I>simple one-second timer</I>"http://www.piclist.com/techref/microchip/time.htm
Modified by: jamesnewton@geocities.com

ON 20010226@2:31:54 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
archive:-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\023715a
PICList post "<I>simple one-second timer</I>"


ON 20010226@2:33:10 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
archive:-to: http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\22\191446a
PICList post "<I>Timer Tribulations</I>"


ON 20010226@2:51:07 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to archive:http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\23\052917a
PICList post "<I>Re: [PIC] Timer Tribulations</I>" Using house mains w/o pugging in


ON 20010226@4:46:32 PM
http://www.piclist.com/techref/microchip/time.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to says
test

ON 20010227@10:51:38 AM
http://www.sxlist.com/techref/microchip/index.htm
Modified by:JMN-EFP-786 jamesnewton@efplus.com
to Interested:/techref/member/JMN-EFP-786/index.htm
JMN-EFP-786

ON 20010227@2:11:26 PM at page:
http://www.sxlist.com/techref/microchip/devprogs.htm
JMN-EFP-786 James Newton added 'Archive
http://www.piclist.org/techref/postbot.asp?by=time&id=piclist\2001\02\26\224059a
PICList post "<I>Picstart upgrade (voltage trim)</I>"'

ON 20010228@12:25:31 PM at page:
http://www.piclist.com/techref/microchip/16f84-rs232-an.htm
AK--373 Andy  Kelley added 'claim

ON 20010228@12:28:10 PM at page:
http://www.piclist.com/techref/microchip/16f84-rs232-an.htm
AK--373 Andy  Kelley edited the page





file: /Techref/microchip/new200102.txt, 46KB, , updated: 2001/3/3 14:18, local time: 2024/5/2 15:33,
TOP NEW HELP FIND: 
18.223.124.244:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://www.piclist.com/techref/microchip/new200102.txt"> PIC Microcontoller Input / Output Memory Method </A>

Did you find what you needed?

  PICList 2024 contributors:
o List host: MIT, Site host massmind.org, Top posters @none found
- Page Editors: James Newton, David Cary, and YOU!
* Roman Black of Black Robotics donates from sales of Linistep stepper controller kits.
* Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters.
* Monthly Subscribers: Gregg Rew. on-going support is MOST appreciated!
* Contributors: Richard Seriani, Sr.
 

Welcome to www.piclist.com!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .