As I have had problems in the past with My LCDS not displaying properly when I have interrupts enabled in my program and it has frustrated me for awhile, I decided to see if I could write my own serial output function, that would use a timer to assist in generating pulses. I would have loved to use WTimer as it is a 16 bit timer and it would be easier to code it up and make it work properly. But HServo uses wtimer and it resets the values and the like so I ended up using TimerV. I am still in the process of testing and cleaning it up, but at least it looks like it might have a chance of working at least for not long duration interrupts.
I will include my current test program at the end of this post, which includes the current sources. Still needs to be cleaned up. Watching the output with the Logic Analyzer, I did 4 different outputs to different IO pins. Three of them with my function and the fourth with serout. The calls looked like:
b1 = "A"
ab2 = "XYZ",15
gosub TASerout[0, i9600, @b1, 1]
gosub TASerout[1, n9600, @b1, 1]
gosub TASerout[2, i19200, @ab2, 4]
Serout p3, i9600, "ABCDEF"][/code]
The result with no interrupts enabled:
http://i416.photobucket.com/albums/pp245/Kurts_Robots/HASerialoutput.png
Now with a simple TimerA overlflow counter with it incrementing the timer on every 32nd clock:
http://i416.photobucket.com/albums/pp245/Kurts_Robots/HASerialwithinterrupt.png
You will notice the first three lines, which were generated by my code still look like they got the right pulses, but the 4th one that was generated by Serout was corrupted.
Again please note this a work in progress, I have not actually tried outputing to my real devices yet, but I was just glad to get it to this point
Kurt
P.S. - Here is the complete code...
[code];------------------------------------
; test program for Timer Assisted Serout.
; This program will see if is possible to use TimerV on the BAP
; to generate the pulses for serial output and handle external
; interrupts more reliably then the simple b it bang versions.
;
;------------------------------------
b1 var byte
ab2 var byte(4)
; BUGBUG:: debug information
DTBM var word
DBTCORA var byte
BTCRV1 var byte
DBTCRV0 var byte
DBPINPORT var word
DBPINBIT var byte
DBINVERT var byte
DBCNT var word
DBOUTPUTBYTE var byte
ONINTERRUPT TIMERAINT,IntHandler
timer var long
;==============================================================================
; Complete initialization
;==============================================================================
b1 = "A"
ab2 = "XYZ",15
TMA = (TMA & 0xF0) | 0x6 ;Sets TimerA to increment once every 32 instructions
ENABLE TIMERAINT
ENABLE
;==============================================================================
; Main Loop
;==============================================================================
sound 9,[50\4400]
high p12
high p13
high p14
serout S_OUT, i9600, "9600:", dec n9600, " 192:", dec n19200, " 115200: ", dec n115200, " 300: ", dec n300, " 2400:", dec n2400, " S_OUT=",dec s_out, 13]
main:
gosub TASerout[0, i9600, @b1, 1]
gosub TASerout[1, n9600, @b1, 1]
gosub TASerout[2, i19200, @ab2, 4]
Serout p3, i9600, "ABCDEF"]
; dump some debug information out to serial port to see our status
serout S_OUT, i9600, [hex DTBM, ":", hex DBTCORA," ",hex BTCRV1, " ",hex DBTCRV0, " ",hex DBPINPORT, " ",hex DBPINBIT, " ", hex DBINVERT, " ", hex DBCNT," ",hex DBOUTPUTBYTE, "(",DBOUTPUTBYTE,")",13]
pause 100
goto main
;==============================================================================
; Dummy interrupt handler...
;==============================================================================
IntHandler:
timer = timer + 1
resume
;==============================================================================
; TASerout(pin, baudmode, buffer, bufferlen
;
; First attempt will be to use TimerV which is only 8 bits, not sure exactly how
; accurate some of these need to be, but will try to scale the timer counter to
; keep the value we are checking to be under 256. The scaller for the clock has
; only the valid values of: 4, 8, 16, 32, 64, 128, so our bit baud rate can maybe
; work with a min baud rate of: 490, I wish I could use TimerW...
;
;==============================================================================
TASPin var byte
TASBM var word
TASPBUF var POINTER
TASCnt var word
TASerout[TASPin, TASBM, TASPBUF, TASCNT]
; BUGBUG: could do this in assembly as well
; ok need to initialize TimerV
; transistion to assembly...
; bset.b #4,@PCR8:8 ; make sure set to output, basic should have done earlier!
; bset.b #5,@PCR8:8 ; make sure set to output, basic should have done earlier!
; bset.b #6,@PCR8:8 ; make sure set to output, basic should have done earlier!
mov.w @TASBM:16, r1 ; get the baudmode.
mov.w r1, @DTBM ; see what our baud mode was...
bld.b #6, r1h ; Get the normal/invert bit into C
subx.b r3h, r3h ; r3h = 0 if Normal or ff if inverted
and.w #0x1fff, r1 ; extract the bit time
mov.w #3,e1 ; start off assuming clock will be divided by 8 as the baud mode is set this way
_TASOMCL:
or.b r1h, r1h ; see if our count is < 256
beq _TASOBMLD:8 ; yep done with this loop
shlr.w r1 ; nope divide by 2
add.w #1, e1 ; change clock input for TimerV
jmp _TASOMCL:8 ; Check again
_TASOBMLD:
; BUGBUG: should verify that we are in a valid range...
mov.b r1l, @TCORA:8 ; save away the value that we should count up to for each bit
mov.b r1l, @DBTCORA:16 ; BUGBUG: Debug
mov.w e1, r1
mov.b #0, r1h ; zero out the high byte
rotr.w r1 ; so low order bit now in high bit of high word
rotl.b r1h ; now in low bit of r1h
mov.b r1h, @TCRV1:8 ; OK so should have the low bit of timer calc stored properly away.
mov.b r1h, @BTCRV1:16 ; BUGBUG::: debug infor...
or.b #0x08, r1l ; Added in the bits: CCLR0 for the TCRV0
mov.b r1l, @TCRV0:8 ; save away the generated configuration byte
mov.b r1l, @DBTCRV0:16 ; BUGBUG:: DEBUG
; first lets use the Porttable that BAP has to convert logical pin to Port/pin
xor.l er0, er0 ; zero out er0
mov.b @TASPIN:16, r0l ; move the logical pin number into r0l
and.b #0x3f, r0l ; make sure we are in the range 0-63
shll.b r0l ; double the offset as the port table is 2 bytes per entry.
mov.w @(_PORTTABLE:16, er0), r2 ; OK R2 now has the two bytes high being the bit, and low being the port...
mov.b r2h, r3l ; Ok r3l now has the pin number
mov.b #0xff, r2h ; setup 32 bit address to port register PDRx
; make sure it is setup for output
mov.b @(0x70-0xD0, er2), r0l ; get the current value for PCRx byte from the shadow location
bset.b r3l, r0l ; set the appropriate bit for our port
mov.b r0l, @(0x70-0xD0, er2) ; save away the updated value to the shadow location
mov.b r0l, @(0x10, er2) ; save away in the actual PCRx byte
; Make sure the IO line is correct to start off with
or.b r3h, r3h
beq _TASOINORMAL:8 ; OK will start up normal
bset.b r3l,@er2 ; Inverted mode start high
jmp _TASOINITBUF:8 ; continue to setup pointers to buffers
_TASOINORMAL:
bclr.b r3l, @er2 ; this sets the IO line to low...
; Now setup data pointer and counter.
_TASOINITBUF:
mov.l @TASPBUF:16, er4 ; OK now ER4 has pointer to the buffer to output.
mov.w @TASCNT:16, e3 ; Now E3 has the count of bytes to output
; put up to one bit delay at the start to get everything in sync...
_TASOWAB:
bld.b #6, @TCSRV:8 ; see if we had a timer cycle go through
bcc #_TASOWAB:8 ; nope
bclr.b #6, @TCSRV:8 ; clear out the status
;BUGBUG: -------------- save some debug information here...
mov.w r2, @DBPINPORT:16
mov.b r3l, @DBPINBIT:16
mov.b r3h, @DBINVERT:16
mov.w e3, @DBCNT:16
;------------------------------------------------
; Main output loop: helps to know what each register is doing:
; r2 - Word address for PDRx for the output pin
; r3l - bit number of IO PIN
; r3h - 0 if Normal communication, FF if inverted.
; e3 - Count of bytes left to output
; er4 - Pointing to the current byte to output
_TASOBYTELOOP:
or.w e3, e3 ; see if more bytes left to go
beq _TASODONE:16 ; NO BYtes left go to do the cleanup
mov.b @er4+, r0l ; Ok have the next byte to output
mov.b r0l, @DBOUTPUTBYTE:16 ; BUGBUG::: Debug save away the byte to debug
xor.b r3h,r0l ; Hack if inverted mode we will invert all of the bits here...
mov.b #8, r0h ; Ok we now have 8 bits to output.
; align our self with the bit clock to make sure we don't give to small of a start pulse
_TASOWSB0:
bld.b #6, @TCSRV:8 ; see if we had a timer cycle go through
bcc #_TASOWSB0:8 ; nope
bclr.b #6, @TCSRV:8 ; clear out the status
; need to do the start bit, for the heck of it we will wait until we get a counter match/reset before we do anything
; The value depends on if we are inverted or not...
or.b r3h, r3h
beq _TASOSBNORMAL:8 ; OK will start up normal
bclr.b r3l, @er2 ; this sets the IO line to low...
jmp _TASOWSB:8 ; continue to setup pointers to buffers
_TASOSBNORMAL:
bset.b r3l,@er2 ; Inverted mode start high
_TASOWSB:
bld.b #6, @TCSRV:8 ; see if we had a timer cycle go through
bcc #_TASOWSB:8 ; nope
bclr.b #6, @TCSRV:8 ; clear out the status
_TASOBITLOOP:
; bnot.b #6,@PDR8:8
; now lets process the next bit
shlr.b r0l ; ok lets shift it down lowest bit goes into carry.
bcc _TASOBIT0:8 ; not set so was zero
bclr.b r3l,@er2 ; The bit is a zero
jmp _TASOBITDELAY:8 ;
_TASOBIT0:
bset.b r3l, @er2 ; Ok this bit goes high
_TASOBITDELAY:
bld.b #6, @TCSRV:8 ; see if we had a timer cycle go through
bcc #_TASOBITDELAY:8 ; nope
bclr.b #6, @TCSRV:8 ; clear out the status
; now see if we finished doing all of the bits
dec.b r0h
bne _TASOBITLOOP:8 ; nope still more bits to output
bset.b #5,@PCR8:8 ; make sure set to output, basic should have done earlier!
; bclr.b #5, @PDR8:8 ; Ok lets try setting one LED ON to debug
; now we need to output the Stop bit
; need to do the start bit, for the heck of it we will wait until we get a counter match/reset before we do anything
; The value depends on if we are inverted or not...
or.b r3h, r3h
beq _TASOSTNORMAL:8 ; OK will start up normal
bset.b r3l,@er2 ; Inverted mode start high
jmp _TSOSTOPDELAY:8 ; continue to setup pointers to buffers
_TASOSTNORMAL:
bclr.b r3l, @er2 ; this sets the IO line to low...
_TSOSTOPDELAY:
bld.b #6, @TCSRV:8 ; see if we had a timer cycle go through
bcc #_TSOSTOPDELAY:8 ; nope
bclr.b #6, @TCSRV:8 ; clear out the status
; now jump up to see if there are any more bytes left to output
dec.w #1,e3 ; decrement the count and go back up to check to see if we are done
jmp _TASOBYTELOOP:8
_TASODONE:
; transistion back to basic
return