' ========================================================================= ' ' File...... EZ-8_Touch_Controller.SXB ' Purpose... ' Author.... Jon "JonnyMac" Williams, EFX-TEK ' Copyright (c) 2008-2010 EFX-TEK ' All Rights Reserved ' License: MIT ' E-mail.... jwilliams@efx-tek.com ' Started... ' Updated... 30 MAR 2010 ' ' ========================================================================= ' ------------------------------------------------------------------------- ' Program Description ' ------------------------------------------------------------------------- ' ' Eight-channel "bit-banger"; may be programmed in place or via serial ' connection to PC. ' ' EEPROM Usage ' $0000 -- frame timing (for future use) ' $0001 -- code protect if = $CF ' $0002 -- LSB of start of show ($40) ' $0003 -- MSB of start of show ($00) ' ' $0004 -- LSB of end of show ' $0005 -- MSB of end of show ' ' $0006 -- LSB of end of channel 1 ' $0007 -- MSB of end of channel 1 ' $0008 -- LSB of end of channel 2 ' $0009 -- MSB of end of channel 2 ' $000A -- LSB of end of channel 3 ' $000B -- MSB of end of channel 3 ' $000C -- LSB of end of channel 4 ' $000D -- MSB of end of channel 4 ' $000E -- LSB of end of channel 5 ' $000F -- MSB of end of channel 5 ' $0010 -- LSB of end of channel 6 ' $0011 -- MSB of end of channel 6 ' $0012 -- LSB of end of channel 7 ' $0013 -- MSB of end of channel 7 ' $0014 -- LSB of end of channel 8 ' $0015 -- MSB of end of channel 8 ' ' $0016 -- reserved ' ... ' $003F -- reserved ' ' $0040 -- beginning of show data ' $FFFF -- end of EEPROM ' ------------------------------------------------------------------------- ' Device Settings ' ------------------------------------------------------------------------- ID "EZ8 1.1a" DEVICE SX28, OSCHS2, BOR42 FREQ 50_000_000 IRC_CAL IRC_SLOW ' ------------------------------------------------------------------------- ' Conditional Compilation Symbols ' ------------------------------------------------------------------------- ' ------------------------------------------------------------------------- ' I/O Pins ' ------------------------------------------------------------------------- Outs PIN RC Ch8 PIN RC.7 OUTPUT Ch7 PIN RC.6 OUTPUT Ch6 PIN RC.5 OUTPUT Ch5 PIN RC.4 OUTPUT Ch4 PIN RC.3 OUTPUT Ch3 PIN RC.2 OUTPUT Ch2 PIN RC.1 OUTPUT Ch1 PIN RC.0 OUTPUT LedGrn PIN RB.7 OUTPUT LedRed PIN RB.6 OUTPUT PgmBtn PIN RB.5 INPUT PULLUP StartBtn PIN RB.4 INPUT PULLUP MS3 PIN RB.3 INPUT PULLUP MS2 PIN RB.2 INPUT PULLUP MS1 PIN RB.1 INPUT PULLUP MS0 PIN RB.0 INPUT PULLUP TX PIN RA.3 OUTPUT RX PIN RA.2 INPUT SCL PIN RA.1 INPUT SDA PIN RA.0 INPUT ' ------------------------------------------------------------------------- ' Constants ' ------------------------------------------------------------------------- ' Dividers for ISR UART ' -- values set for 5.0us Baud9600 CON 21 Baud19K2 CON 10 Baud38K4 CON 5 Baud1x0 CON Baud9600 ' 1 bit period (ISR counts) Baud1x5 CON Baud1x0 * 3 / 2 ' 1.5 bit periods LF CON 10 CLS CON 12 CR CON 13 Yes CON 1 No CON 0 IsOn CON 1 IsOff CON 0 Pressed CON 0 ' for active-low buttons NotPressed CON 1 CP_FLAG CON $01 EE_START WCON $0040 ' $0000-$003F reserved START_LSB CON EE_START & $FF START_MSB CON EE_START >> 8 EE_LAST WCON $FFFF ' for 24LC512 ($7FFF for x256) LAST_LSB CON EE_LAST & $FF LAST_MSB CON EE_LAST >> 8 EE_FINAL WCON $0000 ' 24LC512 ($8000 for x256) SOS_LSB CON $0002 ' start of show storage SOS_MSB CON $0003 EOS_LSB CON $0004 ' end of show storage EOS_MSB CON $0005 EC1_LSB CON $0006 ' end of channel storage EC1_MSB CON $0007 EC8_LSB CON $0014 EC8_MSB CON $0015 SlaveWR CON %1010_0000 ' I2C device type SlaveRD CON %1010_0001 Ack CON 0 Nak CON 1 LED_OFF CON 0 LED_GRN CON 1 LED_RED CON 2 LED_YEL CON 3 LED_FLASH CON 4 LED_FGRN CON 5 ' flashing LED_FRED CON 6 LED_FYEL CON 7 ' ------------------------------------------------------------------------- ' Variables ' ------------------------------------------------------------------------- flags VAR Byte ' (global) isrFlag VAR flags.0 ' mark ISR newFrame VAR flags.1 ' starting new frame ackNak VAR flags.2 ' for I2C rxReady VAR flags.3 ' pc rx byte(s) waiting rxEnable VAR flags.4 ' enable/disable UART protect VAR flags.6 ledFlash VAR flags.7 btnFlags VAR Byte ' (global) swMS0 VAR btnFlags.0 swMS1 VAR btnFlags.1 swMS2 VAR btnFlags.2 swMS3 VAR btnFlags.3 btnStart VAR btnFlags.4 btnRec VAR btnFlags.5 idx VAR Byte cmd VAR Byte channel VAR Byte chData VAR Byte chMask VAR Byte eeStart VAR Word ' start of show eeStop VAR Word ' end of show data rxState VAR Byte tmpW1 VAR Word ' work vars tmpB1 VAR Byte tmpB2 VAR Byte tmpB3 VAR Byte tmpB4 VAR Byte rxSerial VAR Byte (16) BANK rxBuf VAR rxSerial(0) ' 8-byte buffer rxCount VAR rxSerial(8) ' rx bit count rxDivide VAR rxSerial(9) ' bit divisor timer rxByte VAR rxSerial(10) ' recevied byte rxHead VAR rxSerial(11) ' buffer head (write to) rxTail VAR rxSerial(12) ' buffer tail (read from) rxBufCnt VAR rxSerial(13) ' # bytes in buffer txSerial VAR Byte (16) BANK txBuf VAR txSerial(0) ' eight-byte buffer txCount VAR txSerial(8) ' tx bit count txDivide VAR txSerial(9) ' bit divisor timer txLo VAR txSerial(10) ' holds start bit txHi VAR txSerial(11) ' tx output reg txHead VAR txSerial(12) ' buffer head (write to) txTail VAR txSerial(13) ' buffer tail (read from) txBufCnt VAR txSerial(14) ' # bytes in buffer pgmTimers VAR Byte (5) BANK ' for timers and debounce ms1Timer_LSB VAR pgmTimers(0) ' isr ticks/millisecond ms1Timer_MSB VAR pgmTimers(1) frmTimer VAR pgmTimers(2) ' frame timer (ms) btnTimer VAR pgmTimers(3) ' debounce timer (ms) btnTemp VAR pgmTimers(4) ' work var for debounce ledCtrl VAR Byte (8) BANK ' LED color / flash ctrl ledState VAR ledCtrl(0) ' 0-7; off, grn, red, yel led1ms_LSB VAR ledCtrl(1) led1ms_MSB VAR ledCtrl(2) ledWork_LSB VAR ledCtrl(3) ledWork_MSB VAR ledCtrl(4) ledTimer_LSB VAR ledCtrl(5) ' flash timer ledTimer_MSB VAR ledCtrl(6) rgTimer VAR ledCtrl(7) eeBuf VAR Byte (16) ' ========================================================================= INTERRUPT NOPRESERVE 200_000 ' (4) 5.00us ' ========================================================================= Mark_ISR: \ SETB isrFlag ' (1) ' ------- ' RX UART ' ------- ' ' UART code by C. Gracey, A. Williams, et al ' -- buffer and flow control mods by Jon Williams ' Receive: ASM JNB rxEnable, RX_Done BANK rxSerial ' (1) JB rxBufCnt.3, RX_Done ' (2/4) skip if buffer is full MOVB C, RX ' (4) sample serial input TEST rxCount ' (1) receiving now? JNZ RX_Bit ' (2/4) yes, get next bit MOV W, #9 ' (1) no, prep for next byte SC ' (1/2) MOV rxCount, W ' (1) if start, load bit count MOV rxDivide, #Baud1x5 ' (2) prep for 1.5 bit periods RX_Bit: DJNZ rxDivide, RX_Done ' (2/4) complete bit cycle? MOV rxDivide, #Baud1x0 ' (2) yes, reload bit timer DEC rxCount ' (1) update bit count SZ ' (1/2) RR rxByte ' (1) position for next bit SZ ' (1/2) JMP RX_Done ' (3) RX_Buffer: MOV W, #rxBuf ' (1) point to buffer head ADD W, rxHead ' (1) MOV FSR, W ' (1) MOV IND, rxByte ' (2) move rxByte to head INC rxHead ' (1) update head CLRB rxHead.3 ' (1) keep 0..7 INC rxBufCnt ' (1) update buffer count SETB rxReady ' (1) set ready flag RX_Done: ENDASM ' ------- ' TX UART ' ------- ' ' UART code by C. Gracey, A. Williams, et al ' -- buffer and flow control mods by Jon Williams ' Transmit: ASM BANK txSerial ' (1) TEST txCount ' (1) transmitting now? JZ TX_Buffer ' (2/4) if txCount = 0, no DEC txDivide ' (1) update bit timer JNZ TX_Done ' (2/4) time for new bit? MOV txDivide, #Baud1x0 ' (2) yes, reload timer STC ' (1) set for stop bit RR txHi ' (1) rotate TX char buf RR txLo ' (1) DEC txCount ' (1) update the bit count MOVB TX, txLo.6 ' (4) output the bit JMP TX_Done ' (3) TX_Buffer: TEST txBufCnt ' (1) anything in buffer? JZ TX_Done ' (2/4) exit if empty MOV W, #txBuf ' (2) point to buffer tail ADD W, txTail ' (1) MOV FSR, W ' (1) MOV txHi, IND ' (2) move byte to TX reg CLR txLo ' (1) clear for start bit MOV txCount, #10 ' (2) start + 8 + 1 stop INC txTail ' (1) update tail pointer CLRB txTail.3 ' (1) keep 0..7 DEC txBufCnt ' (1) update buffer count TX_Done: ENDASM ' ----------------------------- ' Frame Timer & Button Debounce ' ----------------------------- ' Check_Frame: ASM BANK pgmTimers ' (1) point to timer INC ms1Timer_LSB ' (1) ADDB ms1Timer_MSB, Z ' (2) CJNE ms1Timer_LSB, #200, DB_Exit ' (4/6) at 1ms? ' CJNE ms1Timer_MSB, #000, DB_Exit ' (4/6) CLR ms1Timer_LSB ' (1) yes, re-start ' CLR ms1Timer_MSB Frame_Timer: INC frmTimer ' (1) yes, update frame timer CJB frmTimer, #50, DB_Check ' (4/6) new frame SETB newFrame ' (1) mark CLR frmTimer ' (1) restart timer DB_Check: INC btnTimer CJB btnTimer, #25, DB_Port_Scan ' (2/4) keep scanning for 25ms CLR btnTimer ' (1) restart scan timer MOV btnFlags, btnTemp ' (2) update program flags MOV btnTemp, #%0011_1111 ' (2) reset for next scan JMP DB_Exit DB_Port_Scan: MOV W, /RB ' (1) scan port bits (invert) AND btnTemp, W ' (1) clear any released DB_Exit: ENDASM ' -------------- ' LED Controller ' -------------- ' Led_Control: ASM BANK ledCtrl ' (1) INC led1ms_LSB ' (1) ADDB led1ms_MSB, Z ' (2) CJNE led1ms_LSB, #200, Led_Run ' (4/6) ' CJNE led1ms_MSB, #000, Led_Run ' (4/6) CLR led1ms_LSB ' (1) ' CLR led1ms_MSB ' (1) INC ledWork_LSB ' (1) ADDB ledWork_MSB, Z ' (2) CJNE ledWork_LSB, ledTimer_LSB, Led_Run ' (4/6) CJNE ledWork_MSB, ledTimer_MSB, Led_Run ' (4/6) CLR ledWork_LSB ' (1) CLR ledWork_MSB ' (1) XOR flags, #%1000_0000 ' (2) toggle flash bit Led_Run: JNB ledState.2, Led_Select ' (2/4) flashing mode? JNB ledFlash, Led_0 ' (2/4) off? Led_Select: MOV W, ledState ' (1) get state AND W, #%0000_0011 ' (1) keep legal (0 to 3) JMP PC+W ' (3) jump to handler JMP Led_0 ' (3) JMP Led_1 ' (3) JMP Led_2 ' (3) JMP Led_3 ' (3) Led_0: ' LED off CLRB LedGrn ' (1) CLRB LedRed ' (1) JMP Led_Exit ' (3) Led_1: ' LED green SETB LedGrn ' (1) CLRB LedRed ' (1) JMP Led_Exit ' (3) Led_3: ' LED yellow INC rgTimer ' (1) JNB rgTimer.3, Led_1 ' (2/4) 7G:1R CLR rgTimer ' (1) Led_2: ' LED red CLRB LedGrn ' (1) SETB LedRed ' (1) JMP Led_Exit ' (3) Led_Exit: ENDASM RETURNINT ' (4) ' ========================================================================= ' Subroutine / Function Declarations ' ========================================================================= I2C_START SUB 0 I2C_STOP SUB 0 I2C_OUT FUNC 1, 1 I2C_IN FUNC 1, 1 EE_WAIT SUB 0 WRITE_EE SUB 3, 3, Word, Byte READ_EE FUNC 1, 2, 2, Byte, Word WR_BLOCK SUB 3, 3, Word, Byte RD_BLOCK SUB 3, 3, Word, Byte CLEAR_EE SUB 0 CLR_CHANNEL SUB 1 RX_BYTE FUNC 1, 0 FLUSH_RX SUB 0 TX_BYTE SUB 1 TX_STR SUB 2, 2, Word TX_HEX2 SUB 1 UCASE FUNC 1, 1 ' alpha to uppercase SET_FLASH SUB 2, 2, Word ' set LED flash rate (ms) DELAY_MS SUB 2, 2, Word ' replaces PAUSE RESET_EOS SUB 0 ' reset end of show addr LOAD_DEFAULTS SUB 0 CHECK_PROTECT SUB 0 ' ========================================================================= PROGRAM Start ' ========================================================================= Start: TX = 1 ' set to idle DELAY_MS 100 SET_FLASH 33 ' led flash timing Check_Buttons: cmd = btnFlags & %0011_0000 ' check for Start+Record IF cmd = %0011_0000 THEN Validate_Erase IF cmd = %0010_0000 THEN Check_Rec ' for release of REC GOTO Main Check_Rec: cmd = btnFlags & %0010_0000 IF cmd = %0010_0000 THEN DO IF btnRec = No THEN EXIT DELAY_MS 250 IF ledState = LED_RED THEN ledState = LED_OFF ELSE ledState = LED_RED ENDIF LOOP GOTO Check_Buttons ENDIF Validate_Erase: ' 2-second warning ledState = LED_YEL FOR tmpB1 = 1 TO 40 DELAY_MS 50 cmd = btnFlags & %0011_0000 ' re-scan IF cmd <> %0011_0000 THEN Clear_Buttons ' abort if released NEXT Erase_EE: channel = btnFlags & %0000_1111 ' read channel ledState = LED_FYEL ' indicate erase IF channel = 0 THEN CLEAR_EE LOAD_DEFAULTS ELSEIF channel <> 9 THEN ' erase ch# idx = channel - 1 ' z-adjust chMask = %1111_1111 PUTBIT chMask, idx, 0 ' clear channel bit CLR_CHANNEL chMask idx = channel - 1 ' z-align idx = idx << 1 ' x2 for word idx = idx + EC1_LSB ' LSB of track end WRITE_EE idx, $40 ' reset ch eos INC idx WRITE_EE idx, $00 RESET_EOS ' reset show length ENDIF ledState = LED_YEL Clear_Buttons: DO ' force release of Start+Rec DELAY_MS 100 cmd = btnFlags & %0011_0000 LOOP UNTIL cmd = %0000_0000 Main: channel = btnFlags & %0000_1111 ' read channel IF channel = 0 THEN Play_Show IF channel < 9 THEN Record_Channel IF channel = 9 THEN PC_Slave Channel_Error: ' ch switch is broken DO ledState = LED_RED DELAY_MS 500 ledState = LED_YEL DELAY_MS 500 LOOP ' -------------- ' Play Show Data ' -------------- ' Play_Show: FLUSH_RX rxState = 0 ledState = LED_GRN IF btnStart = No THEN Main ' wait for start button Play_Now: eeStart = EE_START ' start of show data eeStop_LSB = READ_EE EOS_LSB ' end of show data eeStop_MSB = READ_EE EOS_MSB No_Show: IF eeStop = eeStart THEN FOR idx = 1 TO 4 ledState = LED_RED DELAY_MS 250 ledState = LED_GRN DELAY_MS 250 NEXT GOTO Main ENDIF ledState = LED_FGRN ' indicate playback newFrame = 0 ' clear old flag Playback: IF btnRec THEN Playback_Exit ' stop show if REC pressed ' IF rxReady THEN Playback_Exit ' stop on serial input IF newFrame = 0 THEN Playback ' wait for frame start newFrame = 0 Outs = READ_EE eeStart ' play frame INC eeStart ' point to next frame IF eeStart = EE_FINAL THEN Playback_Exit ' at end of memory IF eeStart <= eeStop THEN Playback Playback_Exit: Outs = %0000_0000 GOTO Main ' ------------------- ' Record Channel Data ' ------------------- ' Record_Channel: FLUSH_RX rxState = 0 ledState = LED_RED IF btnStart = No THEN Main ' wait for start press \ JB btnStart, $ ' wait for start release eeStart = EE_START ' start of show data ledState = LED_FRED ' indicate channel record newFrame = 0 ' re-sync frame timer Record_Frame: \ JNB newFrame, $ ' wait for frame marker newFrame = 0 chData = READ_EE eeStart ' get current data idx = channel - 1 ' z-adjust chMask = %0000_0000 PUTBIT chMask, idx, 1 IF PgmBtn = Pressed THEN ' direct sample of Rec chData = chData | chMask ' set channel ELSE chData = chData &~ chMask ' clear channel ENDIF Outs = chData ' show new status WRITE_EE eeStart, chData ' write to EE IF eeStart < EE_LAST THEN ' if not at end of EE INC eeStart ' incrment pointer ELSE GOTO Save_Show ' else call it quits ENDIF Record_Finish: IF btnStart = No THEN Record_Frame ' continue? ledState.2 = 0 ' no, stop flashing Outs = %0000_0000 \ JB btnStart, $ ' wait for start release Save_Show: idx = channel - 1 ' z-align idx = idx << 1 ' x2 for word idx = idx + EC1_LSB ' LSB of channel end WRITE_EE idx, eeStart_LSB INC idx WRITE_EE idx, eeStart_MSB RESET_EOS ' reset end of show GOTO Main ' ------------------------ ' Process Commands from PC ' ------------------------ ' PC_Slave: rxEnable = 1 ' enable UART ledState = LED_OFF ' kill mode LED IF rxReady = No THEN Main ' recheck mode if no byte waiting IF rxState = 0 THEN Wait_Bang IF rxState = 1 THEN Get_Command IF rxState >= 2 THEN Reset_EZ8 Wait_Bang: IF rxState = 0 THEN cmd = RX_BYTE IF cmd = "!" THEN rxState = 1 ENDIF GOTO Main ENDIF Get_Command: cmd = RX_BYTE cmd = UCASE cmd rxState = 0 IF cmd = "!" THEN Main IF cmd = "R" THEN Show_RevCode IF cmd = "E" THEN Show_EOS IF cmd = "C" THEN Channel_End IF cmd = "S" THEN Set_Outs IF cmd = "P" THEN Play_Now ' see above IF cmd = "I" THEN Show_Inputs IF cmd = "U" THEN Upload_Show IF cmd = "D" THEN Download_Show IF cmd = "X" THEN Reset_EZ8 Bad_Command: GOTO Main Show_RevCode: ' string + CR TX_STR Rev_Code CHECK_PROTECT IF protect = Yes THEN TX_STR "-CP" ENDIF TX_BYTE CR GOTO Main Show_EOS: tmpB1 = READ_EE EOS_MSB TX_HEX2 tmpB1 tmpB1 = READ_EE EOS_LSB TX_HEX2 tmpB1 TX_BYTE CR GOTO Main Channel_End: FOR channel = 0 TO 7 idx = "1" + channel TX_BYTE idx TX_BYTE ":" idx = channel << 1 idx = idx + EC1_MSB chData = READ_EE idx TX_HEX2 chData DEC idx chData = READ_EE idx TX_HEX2 chData TX_BYTE CR NEXT GOTO Main Set_Outs: ' direct output control Outs = RX_BYTE GOTO Main Show_Inputs: TX_HEX2 btnFlags TX_BYTE CR GOTO Main Upload_Show: CHECK_PROTECT IF protect = Yes THEN Main ' no upload if protected eeStop_LSB = READ_EE EOS_LSB ' send show length eeStop_MSB = READ_EE EOS_MSB TX_BYTE eeStop_LSB TX_BYTE eeStop_MSB DELAY_MS 10 ' let host prep FOR eeStart = $0000 TO eeStop ' send upload show data chData = READ_EE eeStart TX_BYTE chData NEXT GOTO Main Download_Show: eeStart_LSB = RX_BYTE ' receive block address eeStart_MSB = RX_BYTE FOR idx = 0 TO 15 ' recieve block eeBuf(idx) = RX_BYTE NEXT WR_BLOCK eeStart, @eeBuf ' write to eeprom EE_WAIT ' let write finish TX_BYTE ">" ' ready for another block GOTO Main Reset_EZ8: IF rxState = 0 THEN rxState = 2 GOTO Main ENDIF cmd = RX_BYTE ' wait for "eZ8" IF rxState = 2 THEN IF cmd <> "e" THEN Reset_Done rxState = 3 ELSEIF rxState = 3 THEN IF cmd <> "Z" THEN Reset_Done rxState = 4 ELSEIF rxState = 4 THEN IF cmd <> "8" THEN Reset_Done ledState = LED_FYEL ' signal erasure CLEAR_EE ' do it LOAD_DEFAULTS TX_BYTE ">" ' ready to new data rxState = 0 ENDIF GOTO Main Reset_Done: rxState = 0 GOTO Main ' ------------------------------------------------------------------------- ' Subroutine / Function Code ' ------------------------------------------------------------------------- ' Use: I2C_START ' -- generates I2C start condition on SDA/SCL pins SUB I2C_START I2CSTART SDA ENDSUB ' ------------------------------------------------------------------------- ' Use: I2C_STOP ' -- generates I2C stop condition on SDA/SCL pins SUB I2C_STOP I2CSTOP SDA ENDSUB ' ------------------------------------------------------------------------- ' Use: { ackResult = } I2C_OUT byteVal ' -- writes "byteVal" to SDA pin ' -- affects global var "ackNak" ' -- may be used like a subroutine FUNC I2C_OUT I2CSEND SDA, __PARAM1, ackNak __PARAM1 = ackNak ENDFUNC ' ------------------------------------------------------------------------- ' Use: byteVal = I2C_IN AckBit ' -- reads "byteVal" from SDA pin ' -- affects global ackNak flag FUNC I2C_IN ackNak = __PARAM1.0 I2CRECV SDA, __PARAM1, ackNak ENDFUNC ' ------------------------------------------------------------------------- ' Use: EE_WAIT ' -- waits while EE is busy with write cycle SUB EE_WAIT DO I2C_START I2C_OUT SlaveWr LOOP UNTIL ackNak = Ack ENDSUB ' ------------------------------------------------------------------------- ' Use: WRITE_EE address, value ' -- "value" is a byte SUB WRITE_EE wrAddr VAR tmpW1 wrValue VAR tmpB1 wrAddr = __WPARAM12 ' address to write to wrValue = __PARAM3 ' value to write EE_WAIT ' let EEPROM be ready 'I2C_START I2C_OUT SlaveWr ' initial write I2C_OUT wrAddr_MSB ' send address, high byte I2C_OUT wrAddr_LSB ' send address, low byte I2C_OUT wrValue ' send data byte I2C_STOP ' finish ENDSUB ' ------------------------------------------------------------------------- ' Use: value = READ_EE address ' -- reads "value" from EEPROM location "address" FUNC READ_EE rdAddr VAR tmpW1 rdResult VAR tmpB1 rdAddr = __WPARAM12 ' address to read EE_WAIT 'I2C_START I2C_OUT SlaveWr ' write address I2C_OUT rdAddr_MSB ' send address, high byte I2C_OUT rdAddr_LSB ' send address, low byte I2C_START ' restart for read I2C_OUT SlaveRd rdResult = I2C_IN Nak I2C_STOP RETURN rdResult ENDFUNC ' ------------------------------------------------------------------------- ' Use: WR_BLOCK address, @array ' -- "array" is 16-byte array to write SUB WR_BLOCK wbAddr VAR tmpW1 wbPntr VAR tmpB1 wbIdx VAR tmpB2 wbTemp VAR tmpB3 wbAddr = __WPARAM12 ' address to start from wbPntr = __PARAM3 ' first element of array EE_WAIT 'I2C_START I2C_OUT SlaveWr I2C_OUT wbAddr_MSB I2C_OUT wbAddr_LSB FOR wbIdx = 1 TO 16 I2C_OUT __RAM(wbPntr) INC wbPntr NEXT I2C_STOP ENDSUB ' ------------------------------------------------------------------------- ' Use: RD_BLOCK address, @array ' -- "array" is 16-byte array for read ' -- address should fall on even EE page boundary SUB RD_BLOCK rbAddr VAR tmpW1 rbPntr VAR tmpB1 rbIdx VAR tmpB2 rbAddr = __WPARAM12 ' address to start from rbPntr = __PARAM3 ' first element of array EE_WAIT 'I2C_START I2C_OUT SlaveWr I2C_OUT rbAddr_MSB I2C_OUT rbAddr_LSB I2C_START I2C_OUT SlaveRd FOR rbIdx = 1 TO 15 __RAM(rbPntr) = I2C_IN Ack INC rbPntr NEXT __RAM(rbPntr) = I2C_IN Nak ' final byte needs NAK ENDSUB ' ------------------------------------------------------------------------- ' Use: CLEAR_EE ' -- clears entire EEPROM to 0s SUB CLEAR_EE ceAddr VAR tmpW1 ceIdx VAR tmpB1 ceAddr = $0000 Clear_Block: EE_WAIT 'I2C_START I2C_OUT SlaveWr I2C_OUT ceAddr_MSB I2C_OUT ceAddr_LSB FOR ceIdx = 1 TO 64 ' use block write I2C_OUT $00 NEXT I2C_STOP ceAddr = ceAddr + 64 IF ceAddr <> EE_FINAL THEN Clear_Block ENDSUB ' ------------------------------------------------------------------------- ' Use: CLR_CHANNEL mask ' -- uses program vars: eeStart, eeStop, and eeBuf() SUB CLR_CHANNEL cbIdx VAR tmpB1 cbMask VAR tmpB2 cbMask = __PARAM1 eeStart = EE_START ' set start of show eeStop_LSB = READ_EE EOS_LSB ' get end of show eeStop_MSB = READ_EE EOS_MSB Clear_Bits: EE_WAIT 'I2C_START I2C_OUT SlaveWr I2C_OUT eeStart_MSB ' write block address I2C_OUT eeStart_LSB Get_Block: ' read 16-byte block from ee I2C_START I2C_OUT SlaveRd FOR cbIdx = 0 TO 14 eeBuf(cbIdx) = I2C_IN Ack NEXT eeBuf(15) = I2C_IN Nak Mask_Block: FOR cbIdx = 0 TO 15 eeBuf(cbIdx) = eeBuf(cbIdx) & cbMask ' apply mask to block NEXT Put_Block: ' write block back to ee I2C_START I2C_OUT SlaveWr I2C_OUT eeStart_MSB I2C_OUT eeStart_LSB FOR cbIdx = 0 TO 15 I2C_OUT eeBuf(cbIdx) NEXT I2C_STOP eeStart = eeStart + 16 ' update block pointer IF eeStart = EE_FINAL THEN CC_Exit ' stop on roll-over IF eeStart < eeStop THEN Clear_Bits CC_Exit: ENDSUB ' ------------------------------------------------------------------------- ' Use: aByte = RX_BYTE ' -- returns "aByte" from 8-byte circular buffer ' -- will wait if buffer is presently empty ' -- rxBufCnt holds byte count of receive buffer (0 to 8) FUNC RX_BYTE ASM JNB rxReady, $ ' wait if empty BANK rxSerial MOV FSR, #rxBuf ' point to rxBuf(rxTail) ADD FSR, rxTail MOV __PARAM1, IND ' get byte at tail INC rxTail ' update tail CLRB rxTail.3 ' keep 0..7 DEC rxBufCnt ' update buffer count SNZ ' exit if not zero CLRB rxReady ' else clear ready flag BANK $00 ENDASM ENDFUNC ' ------------------------------------------------------------------------- ' Use: FLUSH_RX ' -- flushes rx buffer and disables UART SUB FLUSH_RX ASM CLRB rxEnable BANK rxSerial CLR rxCount CLR rxDivide CLR rxHead CLR rxTail CLR rxBufCnt BANK $00 CLRB rxReady ENDASM ENDSUB ' ------------------------------------------------------------------------- ' Use: TX_BYTE aByte ' -- moves "aByte" to 8-byte circular buffer (when space is available) ' -- will wait if buffer is presently full ' -- txBufCnt holds byte count of transmit buffer (0 to 8) SUB TX_BYTE ASM BANK txSerial JB txBufCnt.3, @$ ' prevent buffer overrun MOV W, #txBuf ' point to buffer head ADD W, txHead MOV FSR, W MOV IND, __PARAM1 ' move byte to tx buf INC txHead ' update head pointer CLRB txHead.3 ' keep 0..7 INC txBufCnt ' update buffer count BANK __DEFAULT ENDASM ENDSUB ' ------------------------------------------------------------------------- ' Use: TX_STR [String | Label] ' -- pass embedded string or DATA label SUB TX_STR tsAddr VAR tmpW1 tsChar VAR __PARAM1 tsAddr = __WPARAM12 ' capture address DO READINC tsAddr, tsChar ' read a character IF tsChar = 0 THEN EXIT ' if 0, string complete TX_BYTE tsChar ' send the byte LOOP ENDSUB ' ------------------------------------------------------------------------- ' Use: TX_HEX2 aByte ' -- transmit byte in HEX2 format SUB TX_HEX2 hxValue VAR tmpB1 hxNib VAR tmpB2 hxValue = __PARAM1 hxNib = hxValue & $F0 SWAP hxNib READ Hex_Digits + hxNib, hxNib TX_BYTE hxNib hxNib = hxValue & $0F READ Hex_Digits + hxNib, hxNib TX_BYTE hxNib ENDSUB ' ------------------------------------------------------------------------- ' Use: result = UCASE char ' -- converts "char" to uppercase if "a" to "z" FUNC UCASE ASM CJB __PARAM1, #"a", @UC_Exit CJA __PARAM1, #"z", @UC_Exit CLRB __PARAM1.5 ENDASM UC_Exit: ENDFUNC ' ------------------------------------------------------------------------- ' Use: SET_FLASH timing ' -- timing expressed in milliseconds ' -- flash frequency = 1 / (timing * 2) SUB SET_FLASH ASM BANK ledCtrl MOV ledTimer_LSB, __WPARAM12_LSB MOV ledTimer_MSB, __WPARAM12_MSB CLR ledWork_LSB CLR ledWork_MSB BANK $00 ENDASM ENDSUB ' ------------------------------------------------------------------------- ' Use: DELAY_MS duration ' -- duration in milliseconds ' -- replaces PAUSE (uses ISR timing) SUB DELAY_MS msDuration VAR __WPARAM12 ' # milliseconds msTix VAR __WPARAM34 ' ticks/ms DO WHILE msDuration > 0 msTix = 200 DO WHILE msTix > 0 \ CLRB isrFlag \ JNB isrFlag, $ DEC msTix LOOP DEC msDuration LOOP ENDSUB ' ------------------------------------------------------------------------- ' Use: RESET_EOS ' -- resets eos address to longest channel ' -- uses program vars: eeStart, eeStop, and idx SUB RESET_EOS eeStop = EE_START ' lowest eos address FOR idx = EC1_LSB TO EC8_MSB ' loop through tracks eeStart_LSB = READ_EE idx ' read track end address INC idx eeStart_MSB = READ_EE idx IF eeStart > eeStop THEN ' longer? eeStop = eeStart ' yes, reset ENDIF NEXT WRITE_EE EOS_LSB, eeStop_LSB ' save to EOS WRITE_EE EOS_MSB, eeStop_MSB ENDSUB ' ------------------------------------------------------------------------- ' Use: LOAD_DEFUALTS ' -- loads default starting/end data for show and tracks SUB LOAD_DEFAULTS ldIdx VAR tmpB2 ldData VAR tmpB3 FOR ldIdx = $0000 TO EC8_MSB ' load default data READ Defaults+ldIdx, ldData WRITE_EE ldIdx, ldData NEXT protect = No ' disable code protect ENDSUB ' ------------------------------------------------------------------------- ' Use: CHECK_PROTECT SUB CHECK_PROTECT '{$IFUSED CHECK_PROTECT} cpVal VAR tmpB2 cpVal = READ_EE CP_FLAG IF cpVal = $CF THEN protect = Yes ELSE protect = No ENDIF '{$ENDIF} ENDSUB ' ========================================================================= ' User Data ' ========================================================================= Rev_Code: DATA "EZ-8 1.1a", 0 Hex_Digits: DATA "0123456789ABCDEF" Defaults: DATA 50 ' default frame rate DATA 0 ' code protect (clear) WDATA EE_START ' start of show WDATA EE_START ' end of show WDATA EE_START ' end of Ch1 WDATA EE_START WDATA EE_START WDATA EE_START WDATA EE_START WDATA EE_START WDATA EE_START WDATA EE_START ' end of Ch8