No Description

adbio.asm 37KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. list P = 16F88, n = 66, c=132, N=60
  2. include "p16f88.inc"
  3. include "adb.inc"
  4. org 000h
  5. goto Start
  6. chktmr macro timer, pin
  7. local next
  8. tstf timer
  9. skpnz
  10. goto next
  11. decfsz timer, f
  12. goto next
  13. movlw 1<<pin
  14. xorwf PortAShadow,w
  15. movwf PortAShadow
  16. movwf ADBIOPortA
  17. next
  18. endm
  19. ; --------------------------------------------------------------------------
  20. ; Interrupt Handler
  21. ; --------------------------------------------------------------------------
  22. org 004h
  23. movwf SaveW
  24. swapf STATUS,W
  25. movwf SaveStatus
  26. banksel bank1
  27. btfss PIR1, TMR1IF
  28. goto IntDone
  29. bcf PIR1, TMR1IF
  30. banksel bank0
  31. movlw d'60'
  32. movwf TMR1H ; preset for timer1 MSB register
  33. movlw d'190'
  34. movwf TMR1L ; preset for timer1 LSB register
  35. banksel bank1
  36. bsf PIE1, TMR1IE
  37. banksel bank0
  38. chktmr A1Timer, ADBIOPinA1
  39. chktmr A2Timer, ADBIOPinA2
  40. chktmr A3Timer, ADBIOPinA3
  41. chktmr A4Timer, ADBIOPinA4
  42. IntDone
  43. swapf SaveStatus, W
  44. movwf STATUS
  45. swapf SaveW,F
  46. swapf SaveW,W
  47. movf STATUS, w
  48. movwf SaveStatus
  49. retfie
  50. include "adb.asm" ; ADB Sub-Routines - these must be included
  51. ; here to ensure being in the first
  52. ; half of the memory page when called.
  53. ; --------------------------------------------------------------------------
  54. ; Start
  55. ; --------------------------------------------------------------------------
  56. ; The original ADB I/O has two pins attached to the bus. this code only uses
  57. ; one of them, the other is configured as an input so it can be safely igno-
  58. ; red. In the future, I want to reconfigure the code so that the CCP feature
  59. ; of TMR1 on RA4 is used to for receive, while the tristate of RB0 is used
  60. ; for transmit.
  61. ; --------------------------------------------------------------------------
  62. Start
  63. banksel bank1
  64. bsf TRISA, ADBPin ; Make ADB pin an input
  65. bsf TRISB, ADBAltPin ; Make alternate ADB pin an input
  66. bsf TRISB, ADBIOIDH
  67. bsf TRISB, ADBIOIDL
  68. banksel bank0
  69. bcf PORTA, ADBPin ; Port will go low when tris'd as an
  70. ; output. ADB is open collector, so
  71. ; 0 = pin configured as outputting low
  72. ; 1 = pin configured as input allowing
  73. ; bus to float high
  74. clrf PortAShadow
  75. clrf PortBShadow
  76. clrf UnitID ; Get unit ID from jumpers
  77. btfsc PORTB, ADBIOIDH
  78. bsf UnitID, 7
  79. btfsc PORTB, ADBIOIDL
  80. bsf UnitID, 6
  81. ; Timer1 Registers Prescaler= 4 - TMR1 Preset = 15550 - Freq = 10.00 Hz - Period = 0.099972 seconds
  82. bsf T1CON, T1CKPS1 ; bits 5-4 Prescaler Rate Select bits
  83. bcf T1CON, T1CKPS0 ; bit 4
  84. bsf T1CON, T1OSCEN ; bit 3 Timer1 Oscillator Enable Control bit 1 = on
  85. bsf T1CON, NOT_T1SYNC ; bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
  86. bcf T1CON, TMR1CS ; bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
  87. bsf T1CON, TMR1ON ; bit 0 enables timer
  88. movlw d'60'
  89. movwf TMR1H ; preset for timer1 MSB register
  90. movlw d'190'
  91. movwf TMR1L ; preset for timer1 LSB register
  92. ; Interrupt Registers
  93. banksel bank1
  94. bsf PIE1, TMR1IE
  95. banksel bank0
  96. bsf INTCON, GIE ; bit7 global interrupt enable
  97. bsf INTCON, PEIE ; bit6 Peripheral Interrupt Enable bit...1 = Enables all unmasked peripheral interrupts
  98. ; --------------------------------------------------------------------------
  99. ; Reset
  100. ; --------------------------------------------------------------------------
  101. ; This is run at power-up time, but Reset is also called when the ADB host
  102. ; issues a bus-wide reset instruction.
  103. ; --------------------------------------------------------------------------
  104. Reset btfss PORTA, ADBPin
  105. goto Reset ; Wait until the 3ms reset pulse completes
  106. clrf TmpReg1
  107. clrf TmpReg2
  108. clrf RegNum
  109. clrf RAMaddr
  110. clrf Flags1
  111. clrf Flags2
  112. clrf BitCounter
  113. clrf Reg0a ; Clear ADB Storage Data Register Variables
  114. clrf Reg0b
  115. clrf Reg1a
  116. clrf Reg1b
  117. clrf Reg2a
  118. clrf Reg2b
  119. clrf A1Timer
  120. clrf A2Timer
  121. clrf A3Timer
  122. clrf A4Timer
  123. ; TODO: Adjust address based off of unit ID setting
  124. movlw DefaultAddr ; Register 3 has special Default Data set at Reset:
  125. movwf DeviceAddr
  126. movwf Reg3a ; load Register 3a with Default Device Address
  127. bsf Reg3a, Srq_Bit ; allow Service Requests of Host
  128. bsf Reg3a, ExpEvnt ; include the Exceptional Event bit as default
  129. ; *** NOTE: at this time, this Device doesn't
  130. ; process for Exceptional Events
  131. movlw DefaultID
  132. movwf Reg3b ; load Register 3b with Default Device Handler ID
  133. ; --------------------------------------------------------------------------
  134. ;*** LOOK FOR ATTENTION OR RESET *** (AttnSig) ***
  135. ; Look for the line being low, when it is, see if the line went high.
  136. ; During that time, allow the 2nd Application Task to be performed for a
  137. ; limited amount of time, then return to Attn Signal
  138. ; if the line went high, did it go high within the 776-824 usec range?
  139. ; if so, go on to get the Command
  140. ; if not, goto the Reset routine
  141. ; IN DETAIL:
  142. ; look at the line
  143. ; if the line is not yet low,
  144. ; loop until it goes low, & clear the RTCC
  145. ; Loop with Minimum Time: check the time
  146. ; if the time is less than the Attention Minimum usecs,
  147. ; check whether the line has gone high,
  148. ; if the line has not gone high,
  149. ; loop again checking the time
  150. ; if the line has gone high,
  151. ; check whether the Min. usecs have passed
  152. ; if not, Abort; too little time went by.
  153. ; if so, go on to look for the Sync signal
  154. ; Loop with Maximum Time: load the Maximum Time Variable & check the time
  155. ; if the time is less than the Attention Maximum usecs,
  156. ; check whether the line has gone high,
  157. ; if the line has not gone high,
  158. ; loop again checking the time
  159. ; if the line has gone high before Max. Attention usecs have passed,
  160. ; go on to look for the Sync signal
  161. ; if the time is greater than the Attention Maximum usecs,
  162. ; abort to Reset
  163. ; --------------------------------------------------------------------------
  164. AttnSig banksel TMR0
  165. movf TMR0, w ; Look for Attn between ATT_MIN - ATT_MAX usecs
  166. btfss Flags1, F1Cllsn ; this is a good time to use the RTCC and
  167. xorwf Random, F ; Pseudo-Random Address
  168. btfsc PORTA, ADBPin ; See if the line went low
  169. goto AttnSig ; Loop to AttnSig until the line goes low
  170. call PreScale8 ; Switch prescaler to RTCC for > 250 usec count
  171. ; during Attn Signal
  172. movlw ATT_MIN
  173. movwf TimeVar ; use TimeVar to subtract from ATT_MIN usecs
  174. CleanUp clrf CmdByte ; Clear the Command Byte
  175. clrf TmpReg1 ; Clear the temporary Data registers
  176. clrf TmpReg2 ; NOTE: No need to clear variable register 'Random'
  177. clrf RegNum ; clear the current Register Number register
  178. clrf RAMaddr ; clear the register holding the RAM Address of
  179. ; the first byte of where Data is stored
  180. clrf PortTalkBytes+0
  181. clrf PortTalkBytes+1
  182. clrf PortTalkBytes+2
  183. clrf PortTalkBytes+3
  184. clrf PortTalkBytes+4
  185. bsf Flags1, F1Attn ; Set this bit to indicate to the 2nd Task that
  186. ; it should Return to the AttnMin routine
  187. bcf Flags1, F1Stop ; Data-Stop-Bit-is-being-sent
  188. bcf Flags1, F1Lstn ; Listen
  189. bcf Flags1, F1Rcvd1 ; Received-1st-Byte
  190. bcf Flags2, F2DRcvd ; Received listen data
  191. AttnMin banksel bank0
  192. movf TMR0, W ; Check the time, then check the line
  193. subwf TimeVar, W ; See if more than ATT_MIN usecs have passed
  194. btfss STATUS, C ; if not, check the line
  195. goto AttnMax ; if so, go check time/line again in AttnMax
  196. btfss PORTA, ADBPin ; Check for line being high & if so, check time
  197. goto AttnMin ; if line is still low, loop again
  198. movf TMR0, W ; if line is high, see if time is in range
  199. subwf TimeVar, W ; by checking whether Carry bit is
  200. btfss STATUS, C ; set after subtraction
  201. goto AttnSig ; If time <= Min, look for Attn Signal again
  202. goto SyncSig ; If time > Min, go get Sync signal
  203. AttnMax banksel TMR0
  204. movlw ATT_MAX ; Load the TimeVariable to check for the maximum
  205. movwf TimeVar ; amount of time for Attn Signal
  206. AttnTmp movf TMR0, W ; Check the time, then check the line
  207. subwf TimeVar, W ; See if more than ATT_MAX usecs have passed
  208. btfss STATUS, C ; if not, check the line
  209. goto Reset ; if so, Abort to Reset; too much time has passed
  210. btfss PORTA, ADBPin ; Check for the line to going high
  211. goto AttnTmp ; if the line isn't high, loop AttnMax again
  212. clrf TMR0 ; if the went high, go get the Sync signal
  213. ; --------------------------------------------------------------------------
  214. ;*** LOOK FOR SYNC SIGNAL *** (`) ***
  215. ; This routine checks the timing between the rising edge of the Attention
  216. ; Signal & a falling edge indicating the start of the 1st Command bit.
  217. ; At the end of the Attn Signal routine, the line went high, and
  218. ; the RTCC was cleared.
  219. ; Check the RTCC,
  220. ; if the 72 usec limit is exceeded,
  221. ; abort to the Attn Signal
  222. ; if the 72 usec limit is not exceed,
  223. ; check the line
  224. ; if the line went low (as the first bit of the Command),
  225. ; go on to get the 8 Command Bits
  226. ; if the line is still high,
  227. ; loop to check the RTCC again
  228. ; --------------------------------------------------------------------------
  229. SyncSig call PreScale2 ; Get the Sync Signal which follows the Attn Signal
  230. banksel TimeVar
  231. movlw ADBSYNC ; Turn off prescaler; timing counts are < 255 usecs
  232. movwf TimeVar ; and load the timing the for the Sync Signal
  233. SyncTmp movf TMR0, w
  234. subwf TimeVar, w ; See if more than SYNC usecs have passed
  235. btfss STATUS, C ; if not, go check the line
  236. goto AttnSig ; if so, Abort to Attn Signal
  237. btfsc PORTA, ADBPin ; Check for the line to go low
  238. goto SyncTmp ; if the line is still high, loop again
  239. clrf TMR0 ; if low, clear RTCC & go on to get the Command
  240. ; --------------------------------------------------------------------------
  241. ;*** GET THE COMMAND: 8 BITS & STOP BIT *** (Command) ***
  242. ; The Sync Signal was detected when the line went low after approximately
  243. ; 70 usecs. This low line is the first bit of the Command. This
  244. ; routine recieves 8 bits, followed by a '1' Stop bit.
  245. ; IN DETAIL:
  246. ; initialize a counter for counting down as the bits come in
  247. ; call Get_Bit to receive each bit, MSB first, & rotate it into the CmdByte
  248. ; register, where the Command Byte is stored.
  249. ; After returning from GetBit, decrement the counter.
  250. ; when all 8 bits have been received, clear the RTCC (to allow looking for
  251. ; the Stop bit, or holding down the line for an SRQ), and go on to
  252. ; Interpret the Command.
  253. ; In GetBit, get the time,
  254. ; if the time is greater than 72 usecs,
  255. ; abort to the Attn Signal
  256. ; if the time is less than 72 usecs,
  257. ; check if the line went high
  258. ; if line is still low,
  259. ; loop to check the time again
  260. ; if the line went high,
  261. ; determine whether the line went high before or after 50 usecs
  262. ; if the line went high before 50 usecs, rotate a 1 bit into CmdByte reg.
  263. ; if the line went high after 50 usecs, rotate a 0 bit into CmdByte reg.
  264. ; after getting a bit, check if the line went low (the start of the next bit)
  265. ; if the max. Cell Bit time (104 usecs) is exceeded, abort to Attn Signal
  266. ; when the line goes low, clear the RTCC and return to get another bit or
  267. ; interpret the Command if all 8 bits have been been received
  268. ; --------------------------------------------------------------------------
  269. Command
  270. assume bank0
  271. movlw 8 ; Get the 8 Command Bits - 1st bit already started,
  272. movwf BitCounter ; so count down from 8 to 0
  273. movlw CmdByte ; rotate bits into CmdByte
  274. movwf FSR ; used by Get_Bit
  275. CmdLoop
  276. movlw MAX_BIT ; Get & rotate a 1 or 0 bit into CmdByte, or
  277. movwf TimeVar ; see if the maximum time is exceeded & abort
  278. bcf STATUS, C ; clear Carry bit to ensure it won't wrap around
  279. rlf CmdByte, F ; rotate in the last bit
  280. call Get_Bit ; and get another one
  281. decfsz BitCounter, F ; keep looping until 8 bits are received & rotated
  282. goto CmdLoop ; when the Command has been received, interpret it
  283. ; We have all the bits, decode the command
  284. call DecodeCmd ; populates ReqAddress, ReqCommand and ReqReg
  285. movf ReqAddress, w
  286. xorwf DeviceAddr, w
  287. skpnz ; is this out address?
  288. goto StopBitLoop ; yes, get the stop bit then handle the command
  289. ; no, maybe it's a global command
  290. btfsc ReqCommand, cmdReset ; is it a reset?
  291. goto Reset
  292. btfsc Flags2, F2Srq ; do we need to send an SRQ?
  293. call SendSrq
  294. goto AttnSig ; all done, wait for another byte
  295. StopBitLoop
  296. movlw MAX_BIT ; load the maximum time for a bit low time
  297. movwf TimeVar ;
  298. subwf TimeVar, W ; See if more than the max. # of usecs have passed
  299. btfss STATUS, C ; if not, go check for the line to go high
  300. goto AttnSig ; if so, abort to the Attn Signal
  301. btfss PORTA, ADBPin ; Check for the line to go high
  302. goto StopBitLoop ; if the line is still low, loop CmdStop again
  303. clrf TMR0 ; if high, clear RTCC as the beginning of the Tlt
  304. ; and go on to interpret Command as Talk,
  305. ; Listen, or Flush.
  306. ; route the command
  307. btfsc ReqCommand, cmdTalk
  308. goto Talk
  309. btfsc ReqCommand, cmdListen
  310. goto Listen
  311. btfsc ReqCommand, cmdFlush
  312. goto Flush
  313. goto AttnSig ; All done, wait for another byte
  314. ; --------------------------------------------------------------------------
  315. ;*** SEND DATA TO THE HOST *** (Talk; calls Tlt, LineLow, LineHi) ***
  316. ; Data is sent to Host from ADB Data Registers using indirect addressing.
  317. ; (The RTCC was cleared in CmmdChk, and timing for Tlt began there)
  318. ; Call the Tlt (Stop to Start Time), which waits for the middle of the Tlt,
  319. ; when the Tlt returns, send a '1' Start Bit,
  320. ; load the first byte of the Data Register into temporary register,
  321. ; send the 1st 8 bits,
  322. ; load the second byte of the Data Register into temporary register,
  323. ; send the 2nd 8 bits,
  324. ; and send a '0' Stop Bit
  325. ; if at anytime during the Tlt, LineLow, or LineHi the ADB line is
  326. ; inappropriately high or low, the routine aborts to the Collision routine.
  327. ; The Collision routine only sets a flag if this is a Talk Reg. 3 Command,
  328. ; indicating a Collision occurred when sending Data for Reg. 3, and goes
  329. ; to get the Attention Signal.
  330. ; Using temporary registers assures the Data doesn't get cleared until
  331. ; all of it has been sent.
  332. Talk
  333. movlw 0x02
  334. movwf ByteCounter
  335. movf RAMaddr, W
  336. ; adjust source register and ByteCounter for register 1 & 2
  337. chkReg0
  338. ; Register 0
  339. btfss ReqReg, reqReg0
  340. goto chkReg1
  341. movlw 0x02
  342. movwf ByteCounter
  343. movlw RAMaddr
  344. movwf FSR
  345. goto talkCont
  346. chkReg1
  347. ; Register 1 = Read Port A
  348. btfss ReqReg, reqReg1
  349. goto chkReg2
  350. call ReadPortA
  351. movlw 0x05
  352. movwf ByteCounter
  353. movlw PortTalkBytes
  354. movwf FSR
  355. goto talkCont
  356. chkReg2
  357. ; Register 2 = Read Port B
  358. btfss ReqReg, reqReg2
  359. goto chkReg3
  360. call ReadPortB
  361. movlw 0x05
  362. movwf ByteCounter
  363. movlw PortTalkBytes
  364. movwf FSR
  365. goto talkCont
  366. chkReg3
  367. ; Register 3 = Status & Device Information
  368. btfss ReqReg, reqReg3
  369. goto talkCont
  370. movf TMR0, W ; The Address sent to the Host for a Talk Reg. 3
  371. xorwf Random, W ; Command must be random to avoid collisions with
  372. andlw 0x03 ; other Device Addresses during initialization
  373. btfsc UnitID, 7 ; copy unit ID in to upper two bits of temporary address
  374. iorlw b'00000010'
  375. btfsc UnitID, 6
  376. iorlw b'00000001'
  377. movwf TmpReg1
  378. movf Reg3a, W
  379. andlw 0xF0
  380. iorwf TmpReg1, F
  381. movf Reg3b, W
  382. movwf TmpReg2
  383. movlw 0x02
  384. movwf ByteCounter
  385. movlw TmpReg1
  386. movwf FSR
  387. talkCont
  388. call Tlt ; to return for the end of Talk Start Bit
  389. SendStart
  390. clrf TMR0 ; byte epoch
  391. call SendHigh
  392. SendByte
  393. movf INDF, w
  394. movwf ShiftReg
  395. movlw 8
  396. movwf BitCounter
  397. SendBit
  398. btfsc ShiftReg,7 ; sending MSB first, so test high bit of ShiftReg
  399. call SendHigh
  400. btfss ShiftReg,7
  401. call SendLow
  402. NextBit
  403. rlf ShiftReg, f ; Temporary Data Register
  404. decfsz BitCounter, f ; count down as bits are sent
  405. goto SendBit ; loop until 8 bits are sent
  406. decfsz ByteCounter, f ; any more bytes to send?
  407. goto NextByte ; yes,
  408. goto SendStopBit ; no, send stop bit
  409. NextByte
  410. incf FSR, f ; point INDF at next byte
  411. goto SendByte ; and start sending
  412. SendStopBit
  413. bsf Flags1, F1Stop ; indicate to LineHi that this is the Stop Bit
  414. call SendLow
  415. bcf Flags1, F1Cllsn ; a Collision did not occur, clear the flag
  416. bcf Flags2, F2Srq ; an Srq is no longer needed
  417. btfsc ReqReg, reqReg3 ; If current Data Reg. is 3, don't allow Reg. 3
  418. goto RunTsk2 ; to be cleared (or at least the 1st 2 bytes)
  419. movf RAMaddr, W ; clear the Data Registers from which the Data
  420. movwf FSR ; was sent via temporary registers
  421. clrf INDF ; Clear the registers holding the original Data
  422. incf FSR, F ; which was just sent via the temporary regs.
  423. clrf INDF ; Go setup to run the 2nd Application Task for
  424. goto RunTsk2 ; the time between the end of data sent, and
  425. ; the beginning of the next Attention Signal
  426. ; --------------------------------------------------------------------------
  427. ;*** RECEIVE DATA FROM THE HOST *** (Listen; calls Tlt, GetBit) ***
  428. ; Get the Tlt Signal (Stop to Start Time)
  429. ; Tlt recognizes the beginning of the Start Bit
  430. ; Load indirect address of temporary Data register
  431. ; Get the rest of the Start Bit
  432. ; Receive the first Data byte from the Host into the temporary Data register
  433. ; by calling GetBit - GetBit uses indirect address
  434. ; Set indirect address to 2nd temporary Data register
  435. ; Receive the second Data byte from the Host into the temporary Data register
  436. ; And then receive the Data Stop Bit
  437. ; if the data was not for Reg. 3, move the Data now stored in the temporary
  438. ; Data registers into the RAM locations of the Data register designated
  439. ; in RAMaddr, and go run the 2nd Application Task.
  440. ; if the data was for Reg. 3, go interpret what the Data Command was and
  441. ; take appropriate action.
  442. Listen banksel Flags1
  443. bsf Flags1, F1Lstn ; Set Listen Flag to tell Tlt (Stop to Start Time)
  444. call Tlt ; to look for the beginning of the Start Bit.
  445. movlw TmpReg1 ; receive bits into temporary registers
  446. movwf FSR ; use indirect addressing to store received Data
  447. clrf INDF ; in temporary registers
  448. incf FSR, F
  449. clrf INDF ; clear any data currently in temporary registers
  450. decf FSR, F
  451. movlw BIT_TST ; load the TimeVariable to look for the rest of
  452. banksel TimeVar
  453. movwf TimeVar ; the Start Bit
  454. bcf STATUS, C ; clear the Carry bit so it doesn't wrap around
  455. call Get_Bit ; get the rest of the Start bit
  456. btfss INDF,0 ; it should be a '1' bit
  457. goto AttnSig ; if not, abort to the Attn Signal
  458. bcf INDF,0 ; don't let the Start Bit be the 1st bit of Data
  459. SetRecv movlw 8 ; setup to receive 8 bits at a time into the reg.
  460. banksel BitCounter
  461. movwf BitCounter ; count down as bits come in
  462. RcvData movlw MAX_BIT ; get & rotate a 1 or 0 bit into Data Reg., and
  463. movwf TimeVar ; see if MAX_BIT time is exceeded & if so, abort
  464. bcf STATUS, C ; clear Carry bit so it doesn't wrap around
  465. rlf INDF, F ; rotate the bit into the Register (the 1st
  466. call Get_Bit ; rotation doesn't count)
  467. decfsz BitCounter, F ; decrement the counter each time a bit is received
  468. goto RcvData ; loop until 8 bits are received
  469. btfsc Flags1, F1Rcvd1 ; see whether the 2nd Data byte was just received
  470. goto RcvStop ; if so, go get the Stop Bit
  471. bsf Flags1, F1Rcvd1 ; if not, set the Received-1st-Byte Flag,
  472. incf FSR, F ; increment FSR to receive 2nd Byte of the Data
  473. goto SetRecv ; Reg. & go prepare to receive the next byte
  474. RcvStop
  475. movlw MAX_BIT ; Get the '0' Stop Bit
  476. movwf TimeVar ;
  477. RcvStopLoop
  478. movf TMR0, W ; Check the time, then check if the line went high
  479. subwf TimeVar, W ; See if more than MAX_BIT usecs have passed
  480. btfss STATUS, C ; if so, abort to Attn Signal
  481. goto AttnSig
  482. btfss PORTA, ADBPin ; if not, check whether the line went high
  483. goto RcvStopLoop ; if still low, loop to check the time again
  484. movlw BIT_TST ; if high, make sure the Stop Bit was '0'
  485. movwf TimeVar ; if the time was < BIT_TST, abort to
  486. movf TMR0, W ; the Attn Signal
  487. subwf TimeVar, W ; if the time was > BIT_TST, the '0' Stop
  488. btfsc STATUS, C ; Bit was received
  489. goto AttnSig ; clear the RTCC so second Task may use idle time
  490. RcvdDat clrf TMR0 ; Move Data to registers (unless for Reg 3.)
  491. btfsc ReqReg, reqReg3 ; see if Data was received for Register 3,
  492. goto Reg3Cmd ; if so, go interpret the Listen Reg. 3 Command
  493. movf RAMaddr, W ; if not, move the received Data bytes to their
  494. movwf FSR ; indicated registers using indirect address,
  495. movf TmpReg1, W
  496. movwf INDF
  497. incf FSR, F
  498. movf TmpReg2, W
  499. movwf INDF
  500. bsf Flags2, F2DRcvd ; set the Data-has-been-received flag,
  501. goto RunTsk2 ; and go prepare to run the 2nd Application Task
  502. ; --------------------------------------------------------------------------
  503. ;*** INTERPRET THE LISTEN REG. 3 COMMAND SENT BY THE HOST *** (Reg3Cmd) ***
  504. ; This interprets the Data received for Register 3 as one of the
  505. ; following Commands and runs the corresponding routine:
  506. ;
  507. ; Mask the Data Command received using the following Constants passed
  508. ; to the IntData (Interpret Data Command) macro:
  509. ; SELFTST (FF) - the Device is instructed to do a Self-Test
  510. ; LISTEN1 (00) - unconditionally change Device Address and/or Status bits
  511. ; LISTEN2 (FE) - change only the Device Address, and only change it
  512. ; if the Device Address is marked as movable
  513. ; DEV_ACT (FD) - change Device Address only if the Device Activator is
  514. ; pressed (as defined in Device specification)
  515. Reg3Cmd
  516. movf TmpReg2, W
  517. xorlw LISTEN1
  518. btfsc STATUS, Z
  519. goto UpDat3a ; update bits Address and Status Bits (8 to 13)
  520. movf TmpReg2, W
  521. xorlw LISTEN2
  522. btfsc STATUS, Z
  523. goto NewAddr ; change the Device Address (Bits 8 to 12)
  524. movf TmpReg2, W ; if none of these Commands were given, put the
  525. movwf Reg3b ; recieved Data into Reg. 3b as a new Device
  526. goto RunTsk2 ; Handler ID and go prepare to run the 2nd Task
  527. UpDat3a banksel TmpReg1
  528. movf TmpReg1, W ; Unconditionally change the Device Address and/or
  529. ; the Status Bits of Reg. 3a
  530. bsf W, ExpEvnt ; NOTE: Exceptional Event should remain as set to
  531. movwf Reg3a ; a '1' unless otherwise indicated
  532. goto RunTsk2 ; Go prepare to run the 2nd Application Task
  533. ; if it was, change Device Address, if movable
  534. NewAddr btfsc Flags1, F1Cllsn ; If a collison occurred during the last Talk
  535. goto AttnSig ; Reg. 3, the Address was marked unmovable,
  536. movf TmpReg1, W ; abort to the Attention Signal.
  537. xorlw 00h
  538. btfsc STATUS, Z
  539. goto AttnSig
  540. movf Reg3a, W ; Create the new Device Address by masking in
  541. andlw 0xF0 ; the Address received by the host, not allowing
  542. movwf TmpReg2 ; the upper nibble Status Bits in Reg. 3a to
  543. movf TmpReg1, W ; be affected.
  544. andlw 0x0F
  545. movwf DeviceAddr
  546. iorwf TmpReg2, W ; NOTE: Exceptional Event should remain as set to
  547. bsf W, ExpEvnt ; a '1' unless otherwise indicated
  548. movwf Reg3a ; when the new Device Address is in place,
  549. goto RunTsk2 ; go prepare to run the 2nd Application Task
  550. ; --------------------------------------------------------------------------
  551. ;*** FLUSH THE REGISTER SPECIFIED BY THE COMMAND BYTE *** (Flush) ***
  552. Flush banksel RAMaddr
  553. movf RAMaddr, W ; Clear the Data in the specified Register
  554. movwf FSR ; use indirect address to clear the RAM locations
  555. clrf INDF ; holding the Data
  556. incf FSR, F
  557. clrf INDF
  558. goto RunTsk2
  559. ;*** PUT THE CODE FOR OTHER APPLICATION HERE *** (RunTsk2, Task_2) ***
  560. ; bsf Flags2, F2SFail ; code would go before here if a Self Test
  561. ; bcf Flags2, F2SFail ; was performed and it failed or passed
  562. RunTsk2 banksel bank0
  563. clrf TmpReg1 ; When finished with Data interpretation,
  564. clrf TmpReg2 ; clear the temporary Data registers, and
  565. movlw TSK2MAX ; load Task 2 TimeVariable with amount allowed
  566. movwf Tsk2Var ; between end of Data and Attention Signal
  567. Task_2 btfsc Flags2, F2Srq ; If the Srq Flag has not been cleared, then data
  568. goto AttnTst ; must still be sent from first Service Request
  569. call PreScale8 ; Turn on the RTCC prescale for > 250 usec count
  570. btfss Flags2, F2DRcvd
  571. goto Tsk2Tmp
  572. btfsc ReqReg, reqReg1 ; F2DRcvd == true && register == 1 = Listen Register 1 = configure port B
  573. call ConfigurePortB
  574. btfsc ReqReg, reqReg2 ; F2DRcvd == true && register == 2 = Listen Register 2 = configure port A
  575. call HandlePortA
  576. Tsk2Tmp movf TMR0,W ; Check the time to see if more than the maximum
  577. subwf Tsk2Var,W ; time limit has been exceeded
  578. btfsc STATUS,C ; if so, go determine what part of Attn Signal
  579. goto Tsk2Tmp
  580. AttnTst btfss Flags1, F1Attn ; After this portion of the 2nd Task is complete,
  581. goto AttnSig ; If 2nd Task is NOT run during Attn Signal,
  582. bcf Flags1, F1Attn ; go get the start of the Attn Signal
  583. goto AttnMin ; otherwise, go get the rest of the Attn Signal
  584. ; ---------------------------------------------------------------------------------
  585. ; ConfigurePortB
  586. ; ---------------------------------------------------------------------------------
  587. ; Command: Listen ADB Register 1
  588. ; Description: Configure/Set Port B
  589. ; +---------------------------------------+---------------------------------------+
  590. ; | Reg1a | Reg1b |
  591. ; +---------------------------------------+---------------------------------------+
  592. ; | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  593. ; | | | | | | | | | |
  594. ; Ch 4 H/L -----------+ | | | | | | | | |
  595. ; Ch 3 H/L ----------------+ | | | | | | | |
  596. ; Ch 2 H/L ---------------------+ | | | | | | |
  597. ; Ch 1 H/L --------------------------+ | | | | | |
  598. ; AD Config H --------------------------------------+ | | | | |
  599. ; AD Config L--------------------------------------------+ | | | |
  600. ; Ch 4 dir 1=in ----------------------------------------------+ | | |
  601. ; Ch 3 dir 1=in ---------------------------------------------------+ | |
  602. ; Ch 2 dir 1=in --------------------------------------------------------+ |
  603. ; Ch 1 dir 1=in -------------------------------------------------------------+
  604. ;
  605. ; AD = Config bits:
  606. ; 00 = Channel 1, 2, 3 and 4 are analog inputs
  607. ; 01 = Channel 1, 2 and 3 are analog inputs, channel 4 is an analog reference input
  608. ; 10 = Channel 1 and 2 are analog inputs, channel 3 and 4 are digital in/out
  609. ; 11 = Channel 1, 2, 3 and 4 are digital in/out
  610. ConfigurePortB
  611. movf Reg1b, w ; did analog mode change?
  612. xorwf PortBCfg, w
  613. andlw b'00110000'
  614. btfsc STATUS, Z
  615. goto CfgPortBDir
  616. btfsc Reg1b, 5 ; AD config changed, decode the AD Config bits
  617. goto $+4
  618. btfss Reg1b, 4
  619. goto ad4 ; 00
  620. goto ad3 ; 01
  621. btfss Reg1b, 4
  622. goto ad2 ; 10
  623. goto ad0 ; 11
  624. ad4 ; Channel 1, 2, 3, 4 = analog in
  625. banksel bank1
  626. bcf ADCON1, VCFG1 ; vRef = AVss
  627. movlw b'00001111'
  628. iorwf ADBIOPrtBTRIS, f
  629. movwf ANSEL
  630. banksel bank0
  631. bsf ADCON0, ADON ; turn on ADC
  632. goto CfgPortBDir
  633. ad3 ; Channel 1, 2, 3 = analog in
  634. ; Channel 4 = analog reference input
  635. banksel bank1
  636. bsf ADCON1, VCFG1 ; vRef = +vRef
  637. movlw b'00001111'
  638. iorwf ADBIOPrtBTRIS, f
  639. movwf ANSEL
  640. banksel bank0
  641. bsf ADCON0, ADON ; turn on ADC
  642. goto CfgPortBDir
  643. ad2 ; Channel 1, 2 = analog in
  644. ; Channel 3, 4 = digital i/o
  645. banksel bank1
  646. movlw b'00000011'
  647. iorwf ADBIOPrtBTRIS, f
  648. movwf ANSEL
  649. bcf ADCON1, VCFG1 ; vRef = AVss
  650. banksel bank0
  651. bsf ADCON0, ADON ; turn on ADC
  652. goto CfgPortBDir
  653. ad0 ; Channel 1, 2, 3, 4 = digital i/o
  654. banksel bank0
  655. bcf ADCON0, ADON ; turn off ADC
  656. banksel bank1
  657. bcf ADCON1, VCFG1 ; vRef = AVss
  658. clrf ANSEL
  659. banksel bank0
  660. CfgPortBDir
  661. btfss Reg1b, 5 ; Are there any digital pins enabled?
  662. goto SavePortBConfig ; ADB I/O port B is all analog, no digital pins to configure
  663. movf Reg1b, w
  664. andlw b'00001111' ; 11
  665. btfss Reg1b, 4
  666. andlw b'00001100' ; 10
  667. banksel bank1
  668. iorwf ADBIOPrtBTRIS, f
  669. banksel bank0
  670. SavePortBConfig ; save config
  671. movf Reg1b, w
  672. andlw b'00111111'
  673. movwf PortBCfg
  674. SetPortB
  675. btfss Reg1b, 5 ; Are there any digital pins enabled?
  676. return
  677. ; set up mask
  678. movlw b'00001111' ; mask Reg1a so that only the pins we
  679. andwf Reg1a, f ; want are present
  680. movlw b'11110000' ; mask of changing bits of shadow register
  681. andwf ADBIOPortBShadow, w ; and mask off the active output pins
  682. iorwf Reg1a, w ; drop in the new pin values
  683. movwf ADBIOPortBShadow ; put it back on the port
  684. movwf ADBIOPortB
  685. return
  686. ; ---------------------------------------------------------------------------------
  687. ; HandlePortA
  688. ; ---------------------------------------------------------------------------------
  689. HandlePortA
  690. btfss Reg1a, 7
  691. goto ControlPortA
  692. goto ConfigurePortA
  693. ; ---------------------------------------------------------------------------------
  694. ; ControlPortA
  695. ; ---------------------------------------------------------------------------------
  696. ; Command: Listen ADB Register 2
  697. ; Description: Control a single channel in ADB I/O port A
  698. ; +---------------------------------------+---------------------------------------+
  699. ; | Reg1a | Reg1b |
  700. ; +---------------------------------------+---------------------------------------+
  701. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  702. ; | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  703. ; | | | | | |
  704. ; | +- 1 = High | | | |
  705. ; +------ Always 0 | | +------ Delay in 1/10 Seconds -----+
  706. ; | |
  707. ; Channel Select H -------------+ |
  708. ; Channel Select L ------------------+
  709. ; H L
  710. ; CS 0 0 = ADBIOPinA1 = RB7
  711. ; CS 0 1 = ADBIOPinA2 = RB6
  712. ; CS 1 0 = ADBIOPinA3 = RB5
  713. ; CS 1 1 = ADBIOPinA4 = RB4
  714. ControlPortA
  715. ; first handle actually setting the port
  716. btfsc Reg1a, 1 ; Translate channel select into pin mask
  717. goto $+5
  718. movlw b'01111111' ; 00 = 01111111
  719. btfsc Reg1a, 0
  720. movlw b'10111111' ; 01 = 10111111
  721. goto $+4
  722. movlw b'11011111' ; 10 = 11011111
  723. btfsc Reg1a, 0
  724. movlw b'11101111' ; 11 = 11101111
  725. andwf ADBIOPortAShadow, f ; zero out pin in shadow
  726. btfss Reg1a, 6 ; are we setting the port low?
  727. goto controlPortALow ; yep. then the mask is all that is needed.
  728. xorlw 0xff ; need to set port high. to do this, invert
  729. ; the mask and OR it with the already masked
  730. iorwf ADBIOPortAShadow, f ; shadow register.
  731. controlPortALow
  732. movf ADBIOPortAShadow, w ; put shadow value on the port
  733. movwf ADBIOPortA
  734. ; now set the appropriate timer for the port
  735. ; if the timer value is 0, then the timer does not operate
  736. movf Reg1a, w ; grab channel from Reg1a
  737. andlw b'00000011' ; mask for just the channel select bits
  738. addlw A1Timer ; add address of first port timer
  739. movwf FSR ; load into FSR
  740. movf Reg1b, w ; grab timer value from command
  741. movwf INDF ; save into timer for port
  742. return
  743. ; ---------------------------------------------------------------------------------
  744. ; ConfigurePortA
  745. ; ---------------------------------------------------------------------------------
  746. ; Command: Listen ADB Register 2
  747. ; Description: Configure ADB I/O port A
  748. ; +---------------------------------------+---------------------------------------+
  749. ; | Reg1a | Reg1b |
  750. ; +---------------------------------------+---------------------------------------+
  751. ; | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  752. ; | | | | | | | | |
  753. ; +------ Always 1 | | | | | | | |
  754. ; | | | | | | | |
  755. ; Ch 4 H/L -----------+ | | | | | | |
  756. ; Ch 3 H/L ----------------+ | | | | | |
  757. ; Ch 2 H/L ---------------------+ | | | | |
  758. ; Ch 1 H/L --------------------------+ | | | |
  759. ; Ch 4 dir 1=in ----------------------------------------------+ | | |
  760. ; Ch 3 dir 1=in ---------------------------------------------------+ | |
  761. ; Ch 2 dir 1=in --------------------------------------------------------+ |
  762. ; Ch 1 dir 1=in -------------------------------------------------------------+
  763. ConfigurePortA
  764. movlw b'00001111'
  765. andwf Reg1a, f ; mask port values to guard against spurious bits
  766. andwf Reg1b, f ; mask port dir to guard against spurious bits
  767. ; kill off any timers
  768. clrf A1Timer
  769. clrf A2Timer
  770. clrf A3Timer
  771. clrf A4Timer
  772. ; first handle port direction
  773. banksel bank1
  774. movf ADBIOPrtATRIS, w ; get current TRIS setting
  775. banksel bank0
  776. andlw b'11110000' ; mask in preparation for over-writing lower 4 bits
  777. iorwf Reg1a, w ; load in lower 4 bits
  778. banksel bank1
  779. movwf ADBIOPrtATRIS ; put back in TRIS
  780. banksel bank0
  781. ; now handle port value changes
  782. return
  783. ; --------------------------------------------------------------------------
  784. ; Read Macros
  785. ; Macros to help with the read port A/read port B commands
  786. ; --------------------------------------------------------------------------
  787. rddp macro port, pin, addr
  788. movlw 0x00
  789. btfsc port, pin
  790. movlw 0xFF
  791. movwf PortTalkBytes+addr
  792. endm
  793. rdpb macro pin, addr
  794. btfss ADCON1, pin
  795. goto $+5
  796. movlw pin
  797. call readADC
  798. movwf PortTalkBytes+addr
  799. goto $+5
  800. rddp ADBIOPortB, pin, addr
  801. endm
  802. readADC
  803. movwf ADCPort ; save port
  804. rlf ADCPort,f
  805. rlf ADCPort,f
  806. rlf ADCPort,w
  807. andlw b'00011000'
  808. movwf ADCPort
  809. ; acquisition delay (20 uS)
  810. movlw 0x0D
  811. movwf d1
  812. readADC_delay
  813. decfsz d1, f
  814. goto readADC_delay
  815. movf ADCON0, w
  816. andlw b'11100111'
  817. iorwf ADCPort, w
  818. movwf ADCON0
  819. bsf ADCON0, GO ;start new conversion
  820. readADC_acquire
  821. btfsc ADCON0, GO ; a/d done?
  822. goto readADC_acquire
  823. movf ADRESH, w ; get a/d value
  824. return
  825. ; ---------------------------------------------------------------------------------
  826. ; ReadPortA
  827. ; ---------------------------------------------------------------------------------
  828. ; Command: Talk ADB Register 2
  829. ; Description: Reads port A digital channels into PortTalkBytes
  830. ; +---------------------------------------+
  831. ; | PortTalkBytes[0] |
  832. ; +---------------------------------------+
  833. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  834. ; | | 1 1 | | | |
  835. ; | | | | | +-- Channel 1 direction 0 = out, 1 = in
  836. ; | | | | +------- Channel 2 direction 0 = out, 1 = in
  837. ; | | | +------------ Channel 3 direction 0 = out, 1 = in
  838. ; | | +----------------- Channel 4 direction 0 = out, 1 = in
  839. ; | +-------------------------------- Unit ID L
  840. ; +------------------------------------- Unit ID H
  841. ;
  842. ; +---------------------------------------+
  843. ; | PortTalkBytes[1-4] |
  844. ; +---------------------------------------+
  845. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  846. ; | |
  847. ; | |
  848. ; +----- 0x00 = low, 0xFF = high ----+
  849. ReadPortA
  850. movf UnitID, w ; Populate config byte
  851. iorwf PortACfg, w
  852. movwf PortTalkBytes
  853. rddp ADBIOPortA, ADBIOPinA1, 1
  854. rddp ADBIOPortA, ADBIOPinA2, 2
  855. rddp ADBIOPortA, ADBIOPinA3, 3
  856. rddp ADBIOPortA, ADBIOPinA4, 4
  857. return
  858. ; ---------------------------------------------------------------------------------
  859. ; ReadPortB
  860. ; ---------------------------------------------------------------------------------
  861. ; Command: Talk ADB Register 1
  862. ; Description: Reads port B analog or digital channels into PortTalkBytes
  863. ; +---------------------------------------+
  864. ; | PortTalkBytes[0] |
  865. ; +---------------------------------------+
  866. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  867. ; | | | | | | | |
  868. ; | | | | | | | +-- Channel 1 direction 0 = out, 1 = in
  869. ; | | | | | | +------- Channel 2 direction 0 = out, 1 = in
  870. ; | | | | | +------------ Channel 3 direction 0 = out, 1 = in
  871. ; | | | | +----------------- Channel 4 direction 0 = out, 1 = in
  872. ; | | | +---------------------- AD Config L
  873. ; | | +--------------------------- AD Config H
  874. ; | +-------------------------------- Unit ID L
  875. ; +------------------------------------- Unit ID H
  876. ;
  877. ; +---------------------------------------+
  878. ; | PortTalkBytes[1-4] |
  879. ; +---------------------------------------+
  880. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  881. ; | |
  882. ; | |
  883. ; +----- 0x00 = low, 0xFF = high ----+
  884. ; +--------- or Analog Value --------+
  885. ReadPortB
  886. movf UnitID, w ; Populate config byte
  887. iorwf PortBCfg, w
  888. movwf PortTalkBytes
  889. rdpb ADBIOPinB1, 1
  890. rdpb ADBIOPinB2, 2
  891. rdpb ADBIOPinB3, 3
  892. rdpb ADBIOPinB4, 4
  893. return
  894. end