;***************************************************************************************** ; Copyright © [24.02.2002] Timothy Stranex ;***************************************************************************************** ; ; Filename: digilight.src ; ; Authors: Timothy Stranex (perspex@dream.za.net) ; ; Part: SX52BD ; Freq: 50MHz ; ; Date Written : Feb 24 2002 ; ; Program Description: ; ; Changes the intensity of upto 6 different lights using pwm. The intesity ; values are changed through an RS232 port. ; ; Acknowlegments: ; Ubicom - Vpg UART 1.04 ; ; Interface Pins: ; ; rs232RxPin equ rd.0 ;UART receive input ; rs232TxPin equ rd.1 ;UART transmit output ; rts_pin equ rd.2 ;UART 1 RTS input ; cts_pin equ rd.3 ;UART 1 CTS output ; ; pwm_ch0 equ rb.0 ; pwm_ch1 equ rb.1 ; pwm_ch2 equ rb.2 ; pwm_ch3 equ rb.3 ; pwm_ch4 equ rb.4 ; pwm_ch5 equ rb.5 ; ;***************************************************************************************** ;***************************************************************************************** ; Target SX ; Uncomment one of the following lines to choose the SX18AC,SX20AC,SX28AC,SX48BD, SX52BD. ;***************************************************************************************** ;SX18_20 ;SX28AC SX48_52 ;***************************************************************************************** ; Assembler Used ; Uncomment the following line if using the Parallax SX-Key assembler. SASM assembler ; enabled by default. ;***************************************************************************************** ;SX_Key ;***************************************************************************************** ; Uncomment one of the following to run the uart vp at the required baud rate ;***************************************************************************************** ;baud1200 ;baud rate of 1.2 Kbps ;baud2400 ;baud4800 ;baud rate of 4.8 Kbps baud9600 ;baud rate of 9.6 kbps ;baud1920 ;baud rate of 19.2kbps ;baud5760 ;baud rate of 57.6kbps PWMDivide equ 127 ;***************************************************************************************** ; Assembler directives ; ; High speed external osc, turbo mode, 8-level stack, and extended option reg. ; SX18/20/28 - 4 pages of program memory and 8 banks of RAM enabled by default. ; SX48/52 - 8 pages of program memory and 16 banks of RAM enabled by default. ;***************************************************************************************** IFDEF SX_Key ;SX-Key Directives IFDEF SX18_20 ;SX18AC or SX20AC device directives for SX-Key device SX18L,oschs2,turbo,stackx_optionx ENDIF IFDEF SX28AC ;SX28AC device directives for SX-Key device SX28L,oschs2,turbo,stackx_optionx ENDIF IFDEF SX48_52 ;SX48/52/BD device directives for SX-Key device oschs2 ENDIF freq 50_000_000 ELSE ;SASM Directives IFDEF SX18_20 ;SX18AC or SX20AC device directives for SASM device SX18,oschs2,turbo,stackx,optionx ENDIF IFDEF SX28AC ;SX28AC device directives for SASM device SX28,oschs2,turbo,stackx,optionx ENDIF IFDEF SX48_52 ;SX48BD or SX52BD device directives for SASM device SX52,oschs2 ENDIF ENDIF id '1UART_VP' ; reset resetEntry ; set reset vector ;********************************************************************************* ;--------------------------------------Macro's------------------------------------ ; Macro: _bank ; Sets the bank appropriately for all revisions of SX. ; ; This is required since the bank instruction has only a 3-bit operand, it cannot ; be used to access all 16 banks of the SX48/52. FSR.7 (SX48/52bd production ; release) needs to be set appropriately, depending on the bank address being ; accessed. This macro fixes this. ; ; So, instead of using the bank instruction to switch between banks, use _bank ; instead. ;********************************************************************************* _bank macro 1 noexpand bank \1 IFDEF SX48_52 IF \1 & %10000000 ;SX48BD and SX52BD (production release) bank instruction expand setb fsr.7 ;modifies FSR bits 4,5 and 6. FSR.7 needs to be set by software. noexpand ELSE expand clrb fsr.7 noexpand ENDIF ENDIF endm ;********************************************************************************* ; Macro: _mode ; Sets the MODE register appropriately for all revisions of SX. ; ; This is required since the MODE (or MOV M,#) instruction has only a 4-bit operand. ; The SX18/20/28AC use only 4 bits of the MODE register, however the SX48/52BD have ; the added ability of reading or writing some of the MODE registers, and therefore ; use 5-bits of the MODE register. The MOV M,W instruction modifies all 8-bits of ; the MODE register, so this instruction must be used on the SX48/52BD to make sure ; the MODE register is written with the correct value. This macro fixes this. ; ; So, instead of using the MODE or MOV M,# instructions to load the M register, use ; _mode instead. ;********************************************************************************* _mode macro 1 noexpand IFDEF SX48_52 expand mov w,#\1 ;loads the M register correctly for the SX48BD and SX52BD mov m,w noexpand ELSE expand mov m,#\1 ;loads the M register correctly for the SX18AC, SX20AC ;and SX28AC noexpand ENDIF endm ;********************************************************************************* ; INCP/DECP macros for incrementing/decrementing pointers to RAM ; used to compensate for incompatibilities between SX28AC and SX52BD ;********************************************************************************* INCP macro 1 ; Increments a pointer to RAM inc \1 IFNDEF SX48_52 setb \1.4 ; If SX18 or SX28AC,keep bit 4 of the pointer = 1 ENDIF ; to jump from $1f to $30,etc endm DECP macro 1 ; Decrements a pointer to RAM IFDEF SX48_52 dec \1 ELSE clrb \1.4 ; If SX18 or SX28AC, forces rollover to next bank dec \1 ; if it rolls over. (skips banks with bit 4 = 0) setb \1.4 ; Eg: $30 ---> $20 ---> $1f ---> $1f ENDIF ; AND: $31 ---> $21 ---> $20 ---> $30 endm ;********************************************************************************* ; Error generating macros ; Used to generate an error message if the label is intentionally moved into the ; second page. ; Use for lookup tables. ;********************************************************************************* tableStart macro 0 ; Generates an error message if code that MUST be in ; the first half of a page is moved into the second half if $ & $100 ERROR 'Must be located in the first half of a page.' endif endm tableEnd macro 0 ; Generates an error message if code that MUST be in ; the first half of a page is moved into the second half if $ & $100 ERROR 'Must be located in the first half of a page.' endif endm ;***************************************************************************************************** ;----------------------------------------------Memory Organization------------------------------------ ;****************************************************************************************************** ;********************************************************************************************* ;--------------------------------- Data Memory address definitions------------------------------------- ; These definitions ensure the proper address is used for banks 0 - 7 for 2K SX devices ; (SX18/20/28) and 4K SX devices (SX48/52). ;********************************************************************************************* IFDEF SX48_52 global_org = $0A bank0_org = $00 bank1_org = $10 bank2_org = $20 bank3_org = $30 bank4_org = $40 bank5_org = $50 bank6_org = $60 bank7_org = $70 ELSE global_org = $08 bank0_org = $10 bank1_org = $30 bank2_org = $50 bank3_org = $70 bank4_org = $90 bank5_org = $B0 bank6_org = $D0 bank7_org = $F0 ENDIF ;********************************************************************************************* ;-------------------------------- Global Register definitions---------------------------- ; NOTE: Global data memory starts at $0A on SX48/52 and $08 on SX18/20/28. ;********************************************************************************************* org global_org flags0 equ global_org + 0 ; stores bit-wise operators like flags ; and function-enabling bits (semaphores) ;-----------------------------VP: RS232 Receive------------------------------------------ rs232RxFlag equ flags0.0 ;indicates the reception of a bit from the UART isrTemp0 equ global_org + 1 ; Interrupt Service Routine's temp register. ; Don't use this register in the mainline. localTemp0 equ global_org + 2 ; temporary storage register ; Used by first level of nesting ; Never guaranteed to maintain data localTemp1 equ global_org + 3 ; temporary storage register ; Used by second level of nesting ; or when a routine needs more than one ; temporary global register. localTemp2 equ global_org + 4 ; temporary storage register ; Used by third level of nesting or by ; main loop routines that need a loop ; counter, etc. ;********************************************************************************************* ;--------------------------- RAM Bank Register definitions--------------------------------- ;***************************************************************************************** ;********************************************************************************* ; Bank 0 ;********************************************************************************* org bank0_org bank0 = $ ;********************************************************************************* ; Bank 1 ;********************************************************************************* org bank1_org bank1 = $ rs232TxBank = $ ;UART bank rs232Txhigh ds 1 ;hi byte to transmit rs232Txlow ds 1 ;low byte to transmit rs232Txcount ds 1 ;number of bits sent rs232Txdivide ds 1 ;xmit timing (/16) counter rs232Txflag ds 1 rs232RxBank = $ rs232Rxcount ds 1 ;number of bits received rs232Rxdivide ds 1 ;receive timing counter rs232Rxbyte ds 1 ;buffer for incoming byte string ds 1 ;used by send_string to store the address in memory rs232byte ds 1 ;used by serial routines hex ds 1 MultiplexBank = $ isrMultiplex ds 1 ;********************************************************************************* ; Bank 2 ;********************************************************************************* org bank2_org bank2 = $ PWM_Bank = $ PWM_Divide ds 1 PWM_Duty0 ds 1 PWM_Duty1 ds 1 PWM_Duty2 ds 1 PWM_Duty3 ds 1 PWM_Duty4 ds 1 PWM_Duty5 ds 1 PWM_Count ds 1 ;********************************************************************************* ; Bank 3 ;********************************************************************************* org bank3_org bank3 = $ ;********************************************************************************* ; Bank 4 ;********************************************************************************* org bank4_org bank4 = $ ;********************************************************************************* ; Bank 5 ;********************************************************************************* org bank5_org bank5 = $ ;********************************************************************************* ; Bank 6 ;********************************************************************************* org bank6_org bank6 = $ ;********************************************************************************* ; Bank 7 ;********************************************************************************* org bank7_org bank7 = $ IFDEF SX48_52 ;********************************************************************************* ; Bank 8 ;********************************************************************************* org $80 ;bank 8 address on SX52 bank8 = $ ;********************************************************************************* ; Bank 9 ;********************************************************************************* org $90 ;bank 9 address on SX52 bank9 = $ ;********************************************************************************* ; Bank A ;********************************************************************************* org $A0 ;bank A address on SX52 bankA = $ ;********************************************************************************* ; Bank B ;********************************************************************************* org $B0 ;bank B address on SX52 bankB = $ ;********************************************************************************* ; Bank C ;********************************************************************************* org $C0 ;bank C address on SX52 bankC = $ ;********************************************************************************* ; Bank D ;********************************************************************************* org $D0 ;bank D address on SX52 bankD = $ ;********************************************************************************* ; Bank E ;********************************************************************************* org $E0 ;bank E address on SX52 bankE = $ ;********************************************************************************* ; Bank F ;********************************************************************************* org $F0 ;bank F address on SX52 bankF = $ ENDIF ;***************************************************************************************** ;---------------------------------- Port Assignment-------------------------------------- ;***************************************************************************************** RA_latch equ %00000000 ;SX18/20/28/48/52 port A latch init RA_DDIR equ %11111111 ;SX18/20/28/48/52 port A DDIR value RA_LVL equ %00000000 ;SX18/20/28/48/52 port A LVL value RA_PLP equ %00001100 ;SX18/20/28/48/52 port A PLP value RB_latch equ %00000000 ;SX18/20/28/48/52 port B latch init;intial value affter reset RB_DDIR equ %11000000 ;SX18/20/28/48/52 port B DDIR value;0=Output,1=Input RB_ST equ %11111111 ;SX18/20/28/48/52 port B ST value;0=Enable,1=Disable RB_LVL equ %00000000 ;SX18/20/28/48/52 port B LVL value;0=CMOS,1=TTL RB_PLP equ %00000000 ;SX18/20/28/48/52 port B PLP value;0=Enable,1=Disable RC_latch equ %00000000 ;SX18/20/28/48/52 port C latch init;intial value affter reset RC_DDIR equ %11111111 ;SX18/20/28/48/52 port C DDIR value;0=Output,1=Input RC_ST equ %11111111 ;SX18/20/28/48/52 port C ST value;0=Enable,1=Disable RC_LVL equ %00000000 ;SX18/20/28/48/52 port C LVL value;0=CMOS,1=TTL RC_PLP equ %00000000 ;SX18/20/28/48/52 port C PLP value;0=Enable,1=Disable IFDEF SX48_52 RD_latch equ %00000000 ;SX48/52 port D latch init;intial value affter reset RD_DDIR equ %11111101 ;SX48/52 port D DDIR value;0=Output,1=Input RD_ST equ %11111111 ;SX48/52 port D ST value;0=Enable,1=Disable RD_LVL equ %00000000 ;SX48/52 port D LVL value;0=CMOS,1=TTL RD_PLP equ %00000000 ;SX48/52 port D PLP value;0=Enable,1=Disable RE_latch equ %00000000 ;SX48/52 port E latch init;intial value affter reset RE_DDIR equ %11111111 ;SX48/52 port E DDIR value;0=Output,1=Input RE_ST equ %11111111 ;SX48/52 port E ST value;0=Enable,1=Disable RE_LVL equ %00000000 ;SX48/52 port E LVL value;0=CMOS,1=TTL RE_PLP equ %00000000 ;SX48/52 port E PLP value;0=Enable,1=Disable ENDIF ;***************************************************************************************** ;--------------------------------- Pin Definitions---------------------------------------- ;***************************************************************************************** rs232RTSpin equ rb.4 ;UART RTS input rs232CTSpin equ rd.3 ;UART CTS output rs232Rxpin equ rd.0 ;UART receive input rs232Txpin equ rd.1 ;UART transmit output CH0_MASK equ %00000001 ;PWM0 output CH1_MASK equ %00000010 ;PWM1 output CH2_MASK equ %00000100 ;PWM2 output CH3_MASK equ %00001000 ;PWM3 output CH4_MASK equ %00010000 ;PWM4 output CH5_MASK equ %00100000 ;PWM5 output ;***************************************************************************************** ;---------------------------------- Program constants------------------------------------- ;***************************************************************************************** _enter equ 13 ; ASCII value for carridge return _linefeed equ 10 ; ASCII value for a line feed ;***************************************************************************************** ; UART Constants values ;***************************************************************************************** intPeriod = 217 UARTfs = 230400 Num = 4 IFDEF baud1200 UARTBaud = 1200 ENDIF IFDEF baud2400 UARTBaud = 2400 ENDIF IFDEF baud4800 UARTBaud = 4800 ENDIF IFDEF baud9600 UARTBaud = 9600 ENDIF IFDEF baud1920 UARTBaud = 19200 ENDIF IFDEF baud5760 UARTBaud = 57600 ENDIF UARTDivide = (UARTfs/(UARTBaud*Num)) UARTStDelay = UARTDivide +(UARTDivide/2)+1 IFDEF SX48_52 ;***************************************************************************************** ; SX48BD/52BD Mode addresses ; *On SX48BD/52BD, most registers addressed via mode are read and write, with the ; exception of CMP and WKPND which do an exchange with W. ;***************************************************************************************** ;---------------------------------- Timer (read) addresses-------------------------------- TCPL_R equ $00 ;Read Timer Capture register low byte TCPH_R equ $01 ;Read Timer Capture register high byte TR2CML_R equ $02 ;Read Timer R2 low byte TR2CMH_R equ $03 ;Read Timer R2 high byte TR1CML_R equ $04 ;Read Timer R1 low byte TR1CMH_R equ $05 ;Read Timer R1 high byte TCNTB_R equ $06 ;Read Timer control register B TCNTA_R equ $07 ;Read Timer control register A ;---------------------------------- Exchange addresses------------------------------------ CMP equ $08 ;Exchange Comparator enable/status register with W WKPND equ $09 ;Exchange MIWU/RB Interrupts pending with W ;----------------------------------port setup (read) addresses---------------------------- WKED_R equ $0A ;Read MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_R equ $0B ;Read MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_R equ $0C ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_R equ $0D ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_R equ $0E ;Read Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_R equ $0F ;Read Port Direction ;-----------------------------------Timer (write) addresses------------------------------- CLR_TMR equ $10 ;Resets 16-bit Timer TR2CML_W equ $12 ;Write Timer R2 low byte TR2CMH_W equ $13 ;Write Timer R2 high byte TR1CML_W equ $14 ;Write Timer R1 low byte TR1CMH_W equ $15 ;Write Timer R1 high byte TCNTB_W equ $16 ;Write Timer control register B TCNTA_W equ $17 ;Write Timer control register A ;-------------------------------------Port setup (write) addresses------------------------ WKED_W equ $1A ;Write MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_W equ $1B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_W equ $1C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_W equ $1D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_W equ $1E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_W equ $1F ;Write Port Direction ELSE ;***************************************************************************************** ; SX18AC/20AC/28AC Mode addresses ; *On SX18/20/28, all registers addressed via mode are write only, with the exception of ; CMP and WKPND which do an exchange with W. ;***************************************************************************************** ;------------------------------------------Exchange addresses----------------------------- CMP equ $08 ;Exchange Comparator enable/status register with W WKPND equ $09 ;Exchange MIWU/RB Interrupts pending with W ;-----------------------------------------Port setup (read) addresses--------------------- WKED_W equ $0A ;Write MIWU/RB Interrupt edge setup, 1 = falling, 0 = rising WKEN_W equ $0B ;Write MIWU/RB Interrupt edge setup, 0 = enabled, 1 = disabled ST_W equ $0C ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled LVL_W equ $0D ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled PLP_W equ $0E ;Write Port Schmitt Trigger setup, 0 = enabled, 1 = disabled DDIR_W equ $0F ;Write Port Direction ENDIF ;***************************************************************************************** ;----------------------------------------------Program memory ORG defines----------------- ;***************************************************************************************** INTERRUPT_ORG equ $0 ; Interrupt must always start at location zero RESETENTRY_ORG equ $1FB ; The program will jump here on reset SUBROUTINES_ORG equ $200 ; The subroutines are in this location STRINGS_ORG equ $300 ; The strings are in the location $300 PAGE3_ORG equ $400 ; Page 3 is empty MAINPROGRAM_ORG equ $600 ; The main program is in the lastpage of program memory ;***************************************************************************************** org INTERRUPT_ORG ; First location in program memory. ;***************************************************************************************** ;***************************************************************************************** ;--------------------------------------------Interrupt Service Routine-------------------- ; Note 1: The interrupt code must always originate at address $0. ; Interrupt Frequency = (Cycle Frequency / -(retiw value)) ; For example: With a retiw value of -217 and an oscillator frequency ; of 50MHz, this code runs every 4.32us. ; Note 2: Mode Register 'M' is not saved in SX 28 but saved in SX 52 when an Interrupt ; occurs. If the code is to run on a SX 28 and 'M' register is used in the ISR, ; then the 'M' register has to be saved at the Start of ISR and restored at the ; End of ISR. ;***************************************************************************************** org $0 interrupt ;3 ;***************************************************************************************** ; Interrupt ; Interrupt Frequency = (Cycle Frequency / -(retiw value)) For example: ; With a retiw value of -217 and an oscillator frequency of 50MHz, this code runs ; every 4.32us. ;***************************************************************************************** ;***************************************************************************************** ;--------------------------------------------VP:VP Multitasker---------------------------- ; Virtual Peripheral Multitasker : up to 16 individual threads, each running at the ; (interrupt rate/16). Change them below: ; Input variable(s): isrmultiplex: variable used to choose threads ; Output variable(s): None,executes the next thread ; Variable(s) affected: isrmultiplex ; Flag(s) affected: None ; Program Cycles: 9 cycles (turbo mode) ;***************************************************************************************** _bank Multiplexbank ; inc isrMultiplex ; toggle interrupt rate mov w,isrMultiplex ; ;***************************************************************************************** ; The code between the tableStart and tableEnd statements MUST be completely within the first ; half of a page. The routines it is jumping to must be in the same page as this table. ;***************************************************************************************** tableStart ; Start all tables with this macro jmp pc+w ; jmp isrThread1 ; jmp isrThread2 ; jmp isrThread3 ; jmp isrThread4 ; jmp isrThread1 ; jmp isrThread5 ; jmp isrThread6 ; jmp isrThread7 ; jmp isrThread1 ; jmp isrThread8 ; jmp isrThread9 ; jmp isrThread10 ; jmp isrThread1 ; jmp isrThread11 ; jmp isrThread12 ; jmp isrThread13 ; tableEnd ; End all tables with this macro. ;***************************************************************************************** ;VP: VP Multitasker ; ISR TASKS ;***************************************************************************************** isrThread1 ; Serviced at ISR rate/4 ;---------------------------------------------VP: RS232 Transmit-------------------------- ;***************************************************************************************** ; Virtual Peripheral: Universal Asynchronous Receiver Transmitter (UART) ; These routines send and receive RS232 serial data, and are currently ; configured (though modifications can be made) for the popular ; "No parity-checking, 8 data bit, 1 stop bit" (N,8,1) data format. ; ; RECEIVING: The rs232Rxflag is set high whenever a valid byte of data has been ; received and it is the calling routine's responsibility to reset this flag ; once the incoming data has been collected. ; ; TRANSMITTING: The transmit routine requires the data to be inverted ; and loaded (rs232Txhigh+rs232Txlow) register pair (with the inverted 8 data bits ; stored in rs232Txhigh and rs232Txlow bit 7 set high to act as a start bit). Then ; the number of bits ready for transmission (10=1 start + 8 data + 1 stop) ; must be loaded into the rs232Txcount register. As soon as this latter is done, ; the transmit routine immediately begins sending the data. ; This routine has a varying execution rate and therefore should always be ; placed after any timing-critical virtual peripherals such as timers, ; adcs, pwms, etc. ; Note: The transmit and receive routines are independent and either may be ; removed, if not needed, to reduce execution time and memory usage, ; as long as the initial "BANK serial" (common) instruction is kept. ; Input variable(s) : rs232Txlow (only high bit used), rs232Txhigh, rs232Txcount ; Output variable(s) : rs232Rxflag, rs232Rxbyte ; Variable(s) affected : rs232Txdivide, rs232Rxdivide, rs232Rxcount ; Flag(s) affected : rs232Rxflag ; Variable(s) affected : Txdivide ; Program cycles: 17 worst case ; Variable Length? Yes. ;***************************************************************************************** rs232Transmit _bank rs232TxBank ;2 switch to serial register bank decsz rs232Txdivide ;1 only execute the transmit routine jmp :rs232TxOut ;1 mov w,#UARTDivide ;1 load UART baud rate (50MHz) mov rs232Txdivide,w ;1 test rs232Txcount ;1 are we sending? snz ;1 jmp :rs232TxOut ;1 :txbit clc ;1 yes, ready stop bit rr rs232Txhigh ;1 and shift to next bit rr rs232Txlow ;1 dec rs232Txcount ;1 decrement bit counter snb rs232Txlow.6 ;1 output next bit clrb rs232TxPin ;1 sb rs232Txlow.6 ;1 setb rs232TxPin ;1,17 :rs232TxOut ;***************************************************************************************** ;----------------------------------------VP: RS232 Receive-------------------------------- ; Virtual Peripheral: Universal Asynchronous Receiver Transmitter (UART) ; These routines send and receive RS232 serial data, and are currently ; configured (though modifications can be made) for the popular ; "No parity-checking, 8 data bit, 1 stop bit" (N,8,1) data format. ; RECEIVING: The rx_flag is set high whenever a valid byte of data has been ; received and it is the calling routine's responsibility to reset this flag ; once the incoming data has been collected. ; Output variable(s) : rx_flag, rx_byte ; Variable(s) affected : tx_divide, rx_divide, rx_count ; Flag(s) affected : rx_flag ; Program cycles: 23 worst case ; Variable Length? Yes. ;***************************************************************************************** rs232Receive _bank rs232RxBank ;2 sb rs232RxPin ;1 get current rx bit clc ;1 snb rs232RxPin ;1 stc ;1 test rs232Rxcount ;1 currently receiving byte? sz ;1 jmp :rxbit ;1 if so, jump ahead mov w,#9 ;1 in case start, ready 9 bits sc ;1 skip ahead if not start bit mov rs232Rxcount,w ;1 it is, so renew bit count mov w,#UARTStDelay ;1 ready 1.5 bit periods (50MHz) mov rs232RxDivide,w ;1 :rxbit decsz rs232Rxdivide ;1 middle of next bit? jmp :rs232RxOut ;1 mov w,#UARTDivide ;1 yes, ready 1 bit period (50MHz) mov rs232Rxdivide,w ;1 dec rs232Rxcount ;1 last bit? sz ;1 if not rr rs232Rxbyte ;1 then save bit snz ;1 if so, setb rs232RxFlag ;1,23 then set flag :rs232RxOut ;***************************************************************************************** ;===================================== PUT YOUR OWN VPs HERE============================== ; Virtual Peripheral: 6 channel 8bit PWM ; ; Input variable(s): PWM_Duty0 - PWM_Duty5, PWM_Count, PWM_Divide ; Output variable(s): ; Variable(s) affected: PWM_Count, PWM_Divide ; Flag(s) affected: ;***************************************************************************************** ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread2 ; Serviced at ISR rate/16 _bank PWM_Bank ; 2 decsz PWM_Divide ; 1 jmp :END mov w, #PWMDivide ; 1 mov PWM_Divide, w ; 1 incsz PWM_Count ; 1 jmp :CH0 ; 1 clr rb ; 1 :CH0 mov w, CH0_MASK ; 1 incsz PWM_Duty0 ; 1 jmp :CH0 ; 1 or rb, w ; 1 :CH1 mov w, CH1_MASK ; 1 incsz PWM_Duty1 ; 1 jmp :CH2 ; 1 or rb, w ; 1 :CH2 mov w, CH2_MASK ; 1 incsz PWM_Duty2 ; 1 jmp :CH3 ; 1 or rb, w ; 1 :CH3 mov w, CH3_MASK ; 1 incsz PWM_Duty3 ; 1 jmp :CH4 ; 1 or rb, w ; 1 :CH4 mov w, CH4_MASK ; 1 incsz PWM_Duty4 ; 1 jmp :CH5 ; 1 or rb, w ; 1 :CH5 mov w, CH5_MASK ; 1 incsz PWM_Duty5 ; 1 jmp :END ; 1 or rb, w ; 1, 32 END: ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread3 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread4 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread5 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread6 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread7 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread8 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread9 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread10 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread11 ; Serviced at ISR rate/16 ;----------------------------------------------------------------------------------------- jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread12 ; Serviced at ISR rate/16 jmp isrOut ; 7 cycles until mainline program resumes execution ;----------------------------------------------------------------------------------------- isrThread13 ; Serviced at ISR rate/16 ; This thread must reload the isrMultiplex register _bank Multiplexbank mov isrMultiplex,#255 ;reload isrMultiplex so isrThread1 will be run on the ; next interrupt. jmp isrOut ; 7 cycles until mainline program resumes execution ; This thread must reload the isrMultiplex register ; since it is the last one to run in a rotation. ;----------------------------------------------------------------------------------------- isrOut ;***************************************************************************************** ; Set Interrupt Rate ;***************************************************************************************** isrend mov w,#-intperiod ;refresh RTCC on return ;(RTCC = 217-no of instructions executed in the ISR) retiw ;return from the interrupt ;***************************************************************************************** ; End of the Interrupt Service Routine ;***************************************************************************************** ;***************************************************************************************** ; RESET VECTOR ;***************************************************************************************** ;***************************************************************************************** ;----------------------------------------Reset Entry-------------------------------------- ;***************************************************************************************** org RESETENTRY_ORG resetEntry ; Program starts here on power-up page _resetEntry jmp _resetEntry ;***************************************************************************************** ;-----------------------------------------UART Subroutines-------------------------------- ;***************************************************************************************** org SUBROUTINES_ORG ;***************************************************************************************** ; Function : getbyte ; INPUTS : NONE ; OUTPUTS : Received byte in rs232Rxbyte ; Get byte via serial port and echo it back to the serial port ;***************************************************************************************** getbyte jnb rs232RxFlag,$ ; wait till byte is received clrb rs232RxFlag ; reset the receive flag _bank rs232RxBank ; switch to rs232 bank mov rs232byte,rs232Rxbyte ; store byte (copy using W) retp ;***************************************************************************************** ; Function : sendbyte ; INPUTS : 'w' - the byte to be sent via RS-232 ; OUTPUTS : Outputs The byte via RS-232 ; Send byte via serial port ;***************************************************************************************** sendbyte mov localTemp0,w _bank rs232TxBank :wait test rs232Txcount ; wait for not busy sz jmp :wait ; not w ; ready bits (inverse logic) mov rs232Txhigh,w ; store data byte setb rs232Txlow.7 ; set up start bit mov w,#10 ; 1 start + 8 data + 1 stop bit mov rs232Txcount,w retp ; leave and fix page bits ;***************************************************************************************** ; Function : sendstring ; Care should be taken that the srings are located within program ; memory locations $300-$3ff as the area ; INPUTS : 'w' - the address of a null-terminated string in program memory ; OUTPUTS : Outputs the string via RS-232 ; Send string pointed to by address in W register ;***************************************************************************************** sendstring _bank rs232TxBank mov localTemp1,w ; store string address :loop mov w,#STRINGS_ORG>>8 ; with indirect addressing mov m,w mov w,localTemp1 ; read next string character iread ; using the mode register test w ; are we at the last char? snz ; if not=0, skip ahead jmp :out ; yes, leave & fix page bits call sendbyte ; not 0, so send character _bank rs232TxBank inc localTemp1 ; point to next character jmp :loop ; loop until done :out mov w,#$1F ; reset the mode register mov m,w retp ;***************************************************************************************** ; Function : uppercase ; INPUTS : byte - the byte to be converted ; OUTPUTS : byte - converted byte ; Convert byte to uppercase. ;***************************************************************************************** uppercase mov w,#'a' ;if byte is lowercase, then skip ahead mov w,rs232byte-w sc retp mov w,#'a'-'A' ;change byte to uppercase sub rs232byte,w retp ;leave and fix page bits ;***************************************************************************************** ; Function : sendhex ; INPUTS : 'w' - the byte to be output ; OUTPUTS : Outputs the hex byte via RS-232 ; Output a hex number ;***************************************************************************************** sendhex mov localTemp1,w swap wreg and w,#$0f call hextable call sendbyte mov w,localTemp1 and w,#$0f call hextable call sendbyte retp ;***************************************************************************************** ; Function : gethex ; Inputs : None ; OUTPUTS : Received HEX value is in 'hex' register. ; This routine returns with an 8-bit value in the W and in the hex ; register. It accepts a hex number from the terminal screen and ; returns. Remember to write a prompt to the screen before calling get_hex ;***************************************************************************************** gethex _bank rs232RxBank ;2 mov w,#_enterhex call @sendstring call :getvalidhex mov w,rs232byte ; send the received (good) byte call sendbyte swap localTemp2 ; put the nibble in the upper nibble of mov w,localTemp2 mov hex,w ; hex register call :getvalidhex mov w,rs232byte ; send the second received byte call sendbyte mov w,localTemp2 and w,#$0f or w,hex mov hex,w retp :getvalidhex :gh1 clr localTemp2 jnb rs232Rxflag,$ ; get a byte from the terminal clrb rs232Rxflag mov rs232byte,rs232Rxbyte call uppercase ; uppercase it. :loop mov w,localTemp2 ; get the value at temp (index) call hextable xor w,rs232byte snz ; compare it to the received byte ret inc localTemp2 ; if they are equal, we have the jb localTemp2.4,:gh1 ; upper nybble. Continue if not. jmp :loop ret hextable add pc,w retw '0' retw '1' retw '2' retw '3' retw '4' retw '5' retw '6' retw '7' retw '8' retw '9' retw 'A' retw 'B' retw 'C' retw 'D' retw 'E' retw 'F' ;***************************************************************************************** org STRINGS_ORG ; This label defines where strings are kept in program space. ; all the following strings must be within the same half page of ; theprogram memory for sendstring to work,and they must be ; preceeded by this label. ;***************************************************************************************** ;***************************************************************************************** ;---------------------------------------String Data--------------------------------------- ;***************************************************************************************** ;VP: RS232 Transmit _welcome dw 13,10,'Welcome to Tim's Digiligt Controller', 0 _error dw 13,10,'ERR, I don't speak french', 0 _ok dw 13,10,'OK', 0 _hex dw 13,10,'0x', 0 org PAGE3_ORG jmp $ ;***************************************************************************************** ;---------------------------------------- Main Program ----------------------------------- ; Program execution begins here on power-up or after a reset ;***************************************************************************************** org MAINPROGRAM_ORG _resetEntry ;***************************************************************************************** ;---------------------------- Initialise all port configuration -------------------------- ;***************************************************************************************** _mode ST_W ;point MODE to write ST register mov w,#RB_ST ;Setup RB Schmitt Trigger, 0 = enabled, 1 = disabled mov !rb,w mov w,#RC_ST ;Setup RC Schmitt Trigger, 0 = enabled, 1 = disabled mov !rc,w IFDEF SX48_52 mov w,#RD_ST ;Setup RD Schmitt Trigger, 0 = enabled, 1 = disabled mov !rd,w mov w,#RE_ST ;Setup RE Schmitt Trigger, 0 = enabled, 1 = disabled mov !re,w ENDIF _mode LVL_W ;point MODE to write LVL register mov w,#RA_LVL ;Setup RA CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !ra,w mov w,#RB_LVL ;Setup RB CMOS or TTL levels, 1 = TTL, 0 = CMOS,0,1 = TTL, 2..7 = CMOS mov !rb,w mov w,#RC_LVL ;Setup RC CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !rc,w IFDEF SX48_52 mov w,#RD_LVL ;Setup RD CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !rd,w mov w,#RE_LVL ;Setup RE CMOS or TTL levels, 1 = TTL, 0 = CMOS mov !re,w ENDIF _mode PLP_W ;point MODE to write PLP register mov w,#RA_PLP ;Setup RA Weak Pull-up, 0 = enabled, 1 = disabled mov !ra,w mov w,#RB_PLP ;Setup RB Weak Pull-up, 0 = enabled, 1 = disabled mov !rb,w mov w,#RC_PLP ;Setup RC Weak Pull-up, 0 = enabled, 1 = disabled mov !rc,w IFDEF SX48_52 mov w,#RD_PLP ;Setup RD Weak Pull-up, 0 = enabled, 1 = disabled mov !rd,w mov w,#RE_PLP ;Setup RE Weak Pull-up, 0 = enabled, 1 = disabled mov !re,w ENDIF _mode DDIR_W ;point MODE to write DDIR register mov w,#RA_DDIR ;Setup RA Direction register, 0 = output, 1 = input mov !ra,w mov w,#RB_DDIR ;Setup RB Direction register, 0 = output, 1 = input mov !rb,w mov w,#RC_DDIR ;Setup RC Direction register, 0 = output, 1 = input mov !rc,w IFDEF SX48_52 mov w,#RD_DDIR ;Setup RD Direction register, 0 = output, 1 = input mov !rd,w mov w,#RE_DDIR ;Setup RE Direction register, 0 = output, 1 = input mov !re,w ENDIF mov w,#RA_latch ;Initialize RA data latch mov ra,w mov w,#RB_latch ;Initialize RB data latch mov rb,w mov w,#RC_latch ;Initialize RC data latch mov rc,w IFDEF SX48_52 mov w,#RD_latch ;Initialize RD data latch mov rd,w mov w,#RE_latch ;Initialize RE data latch mov re,w ENDIF ;***************************************************************************************** ;------------------------------- Clear all Data RAM locations ---------------------------- ;***************************************************************************************** IFDEF SX48_52 ;SX48/52 RAM clear routine mov w,#$0a ;reset all ram starting at $0A mov fsr,w :zeroRam clr ind ;clear using indirect addressing incsz fsr ;repeat until done jmp :zeroRam _bank bank0 ;clear bank 0 registers clr $10 clr $11 clr $12 clr $13 clr $14 clr $15 clr $16 clr $17 clr $18 clr $19 clr $1a clr $1b clr $1c clr $1d clr $1e clr $1f ELSE ;SX18/20/28 RAM clear routine clr fsr ;reset all ram banks :zeroRam sb fsr.4 ;are we on low half of bank? ;If so, don't touch regs 0-7 setb fsr.3 ; To clear from 08 - Global Registers clr ind ;clear using indirect addressing incsz fsr ;repeat until done jmp :zeroRam ENDIF ;***************************************************************************************** ; Initialize program/VP registers ;***************************************************************************************** _bank rs232TxBank ;select rs232 bank mov w,#UARTDivide ;load Txdivide with UART baud rate mov rs232TXdivide,w _bank PWM_Bank mov w, #PWMDivide mov PWM_Divide, w ;***************************************************************************************** ; Setup and enable RTCC interrupt, WREG register, RTCC/WDT prescaler ;***************************************************************************************** RTCC_ON = %10000000 ;Enables RTCC at address $01 (RTW hi) ;*WREG at address $01 (RTW lo) by default RTCC_ID = %01000000 ;Disables RTCC edge interrupt (RTE_IE hi) ;*RTCC edge interrupt (RTE_IE lo) enabled by default RTCC_INC_EXT = %00100000 ;Sets RTCC increment on RTCC pin transition (RTS hi) ;*RTCC increment on internal instruction (RTS lo) is default RTCC_FE = %00010000 ;Sets RTCC to increment on falling edge (RTE_ES hi) ;*RTCC to increment on rising edge (RTE_ES lo) is default RTCC_PS_ON = %00000000 ;Assigns prescaler to RTCC (PSA lo) RTCC_PS_OFF = %00001000 ;Assigns prescaler to WDT (PSA hi) PS_000 = %00000000 ;RTCC = 1:2, WDT = 1:1 PS_001 = %00000001 ;RTCC = 1:4, WDT = 1:2 PS_010 = %00000010 ;RTCC = 1:8, WDT = 1:4 PS_011 = %00000011 ;RTCC = 1:16, WDT = 1:8 PS_100 = %00000100 ;RTCC = 1:32, WDT = 1:16 PS_101 = %00000101 ;RTCC = 1:64, WDT = 1:32 PS_110 = %00000110 ;RTCC = 1:128, WDT = 1:64 PS_111 = %00000111 ;RTCC = 1:256, WDT = 1:128 OPTIONSETUP equ RTCC_PS_OFF ;the default option setup for this program. mov w,#OPTIONSETUP ;setup option register for RTCC interupts enabled mov !option,w ;and no prescaler. jmp @mainLoop ;***************************************************************************************** ;-------------------------------------- MAIN PROGRAM CODE -------------------------------- ;***************************************************************************************** ;Send hello message ;Check for received byte ; ;Send welcome msg mov w, #_welcome call @sendstring ;Wait for command :loop call @getbyte cje rs232Rxbyte, #'S', :set cje rs232Rxbyte, #'G', :get jmp :loop :get call @getbyte mov w, #hex call @sendstring cje rs232Rxbyte, #'0', :get_ch0 cje rs232Rxbyte, #'1', :get_ch1 cje rs232Rxbyte, #'2', :get_ch2 cje rs232Rxbyte, #'3', :get_ch3 cje rs232Rxbyte, #'4', :get_ch4 cje rs232Rxbyte, #'5', :get_ch5 :gotit call @sendhex jmp :loop :get_ch0 mov w, PWM_Duty0 jmp :gotit :get_ch1 mov w, PWM_Duty1 jmp :gotit :get_ch2 mov w, PWM_Duty2 jmp :gotit :get_ch3 mov w, PWM_Duty3 jmp :gotit :get_ch4 mov w, PWM_Duty4 jmp :gotit :get_ch5 mov w, PWM_Duty5 jmp :gotit :set call @getbyte cje rs232Rxbyte, #'0', :set_ch0 cje rs232Rxbyte, #'1', :set_ch1 cje rs232Rxbyte, #'2', :set_ch2 cje rs232Rxbyte, #'3', :set_ch3 cje rs232Rxbyte, #'4', :set_ch4 cje rs232Rxbyte, #'5', :set_ch5 :setedit mov w, #_ok call @sendstring jmp :loop :set_ch0 call @getbyte mov PWM_Duty0, w jmp :setedit :set_ch1 call @getbyte mov PWM_Duty1, w jmp :setedit :set_ch2 call @getbyte mov PWM_Duty2, w jmp :setedit :set_ch3 call @getbyte mov PWM_Duty3, w jmp :setedit :set_ch4 call @getbyte mov PWM_Duty4, w jmp :setedit :set_ch5 call @getbyte mov PWM_Duty5, w jmp :setedit ;***************************************************************************************** END ;End of program code ;***************************************************************************************** ;That's All Folks