PDA

View Full Version : Using an Assmbly Routine in PBP



alanmcf
- 1st August 2008, 01:14
Hi--

I'm trying to adapt Microchip's AN1076 appnote on DMX to use as an assembly language subroutine in PBP. I'm using a PIC18F4520, 16MHz resonator, PBP 2.5a. What the code should do is initialize the LCD, read the DMX data stream, and then display the value present on DMX channel 7 on the LCD. I am feeding in a DMX signal, and I've had a PBP-coded subroutine working just fine on my hardware test board, but I need more speed. Both the SetupSerial subroutine and the DMXloop subroutine compile just fine, but when I call the DMXloop subroutine, that's the last I see of my program's execution, nothing else happens. I assume I'm jumping off into oblivion somehow... my understanding of assembly is limited, so I'd appreciate any commentary.

Thanks in advance--

--Alan



' for PIC18F4530
DEFINE OSC 16
INCLUDE "modedefs.bas"
include "LCD_defines602.pbp"

' ****************************************
' SETUP
' ****************************************

PORTA = %00000000
PORTB = %00000000
PORTC = %00000000
PORTD = %00000000
trisa = %11111101
trisb = %01111111
TRISC = %11101000
trisd = %11001011

ADCON1 = %00001111 'port a is all digital IO
CMCON = 7 'and turn off those pesky comparators
RBPUx VAR INTCON2.7 'port b pull-ups 1 = disabled 0 = enabled
RBPUx = 0
trise.4 =%0 'disable PSP port

' ===================================
' define hardware pins:
' ===================================

BKLT var portd.5 'LCD backlight

' ================================
' define constants & variables:
' ================================

DMXrxbuffer var byte[512]
CountH var byte
CountL var byte
count0 var byte


' ****************************************
' INITIALIZATION
' ****************************************
init:
call SetupSerial 'set up USART and clear DMXrxbuffer

' ****************************************
' MAIN LOOP
' ****************************************

begin: low bklt 'turn on backlight
pause 125 'pause to let LCD initialize
lcdout $fe,1 'clear screen
LCDout " test routine " 'display splashscreen
lcdout $fe,$c0,"S/W Version 6xxx"
pause 1200


low bklt

mainloop:


Call DMXloop
lcdout $fe,1
pause 3
lcdout dec DMXrxbuffer[7]
pause 300

goto mainloop


asm

_DMXloop

; first loop, synchronizing with the transmitter
_WaitBreak
btfsc PIR1,RCIF ; if a byte is received correctly
movf RCREG,W ; discard it
btfss RCSTA,FERR ; else
bra _WaitBreak ; continue waiting until a frame error is detected
movf RCREG,W ; read the Receive buffer to clear the error condition

; second loop, waiting for the START code
_WaitForStart
btfss PIR1,RCIF ; wait until a byte is correctly received
bra _WaitForStart
btfsc RCSTA,FERR
bra _WaitForStart
movf RCREG,W

; check for the START code value, if it is not 0, ignore the rest of the frame
andlw 0xff
bnz _DMXloop ; ignore the rest of the frame if not zero

; init receive counter and buffer pointer
clrf _CountL
clrf _CountH
lfsr 0,_DMXrxbuffer

; third loop, receiving 512 bytes of data
_WaitForData
btfsc RCSTA,FERR ; if a new framing error is detected (error or short frame)
bra _RXend ; the rest of the frame is ignored and a new synchronization
; is attempted

btfss PIR1,RCIF ; wait until a byte is correctly received
bra _WaitForData ;
movf RCREG,W ;

_MoveData
movwf POSTINC0 ; move the received data to the buffer
; (auto-incrementing pointer)
incf _CountL,F ; increment 16-bit counter
btfss STATUS,C
bra _WaitForData
incf _CountH,F

btfss _CountH,1 ; check if 512 bytes of data received
bra _WaitForData

_RXend
return

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

; Setup Serial port and buffers
_SetupSerial

;Clear the receive buffer
lfsr 0,_DMXrxbuffer
_CBloop
clrf POSTINC0 ; clear INDF register then increment pointer
incf _CountL,F
btfss STATUS,C
bra _CBloop
incf _CountH,F

btfss _CountH,1
bra _CBloop

; Setup EUSART
bsf TRISC,7 ; allow the EUSART RX to control pin RC7
bsf TRISC,6 ; allow the EUSART TX to control pin RC6

movlw 0x04 ; Disable transmission
movwf TXSTA ; enable transmission and CLEAR high baud rate

movlw 0x90
movwf RCSTA ; enable serial port and reception

bsf BAUDCON,BRG16 ; Enable UART for 16-bit Asyn operation
clrf SPBRGH

movlw .15 ; Baud rate is 250KHz for 16MHz Osc. freq.
movwf SPBRG

return

endasm

Darrel Taylor
- 1st August 2008, 04:35
Well, I can't see anything wrong with the ASM part. It compiles, and looks like it should work. But there are a couple possibilities ....

If you are expecting to receive data from DMX channel 7, it will be in DMXrxbuffer[6], since the first "Device ID" byte (always 0) is discarded.

And, 250k baud is pretty fast for a resonator. You might want to try a crystal with caps.
<br>

alanmcf
- 1st August 2008, 04:57
Hi Darrel--

Right on about the channel, it should say 6. Otherwise, I don't think it's a hardware issue, i.e. resonator vs. crystal... I've been using PBP code (follows) to capture a single channel or two and it works great, but I'd like to get the whole 512 channels, hence trying to adapt AN1075. I think its getting lost somewhere... could this have something to do with BANK0, BANK1, etc?

This is the PBP routine that I have been using to read 2-3 channels at a time; on this same hardware platform it works great...



'================================================= ===
' DMX Subroutines
'================================================= ===

readdmx:
counter = 1
PIE1 = 0 ' Mask the interrupt
pulsin target, 0, counter
idleflag = 0
DMX_OK = 1
if counter = 0 then
idleflag = 1 'either no DMX or break timed out
DMX_OK = 0 'set DMX as not present
goto noshow_exit
endif

if counter < 35 then readDMX 'active pulse too short, keep looking
'otherwise its valid DMX & time to read the start code
dummy = rcreg
dummy = rcreg 'do this twice to clear out ang garbage in the USART
spbrg = 0
txsta.2 = 0 'brgh = 0
txsta.4 = 0
rcsta.7 = 1 'turn on the USART
rcsta.6 = 0 'setting 8 bit receive mode, no parity, etc.
rcsta.4 = 0
rcsta.4 = 1 'toggle the rcsta.4 bit to make-ready

while rcif = 0 : wend 'hover until start code is received

startcode = rcreg 'read the startcode somewhere, tho most likely we'll never look at it

if dmx_channel = 1 then 'if DMX address is 1, do this special case
dummy = rcreg
goto exit_readDMX
endif

'else, do this code for DMX addresses 2-512:
count0 = 0
While count0 < (dmx_channel-1) 'set up loop to count up to just 1 shy of target address
while rcif = 0 : wend 'wait for a byte
dummy = rcreg
count0 = count0 + 1
WEND
exit_readDMX:
DMX_data = rcreg 'put the DMX byte into a variable and exit
noshow_exit:
rcsta.7 = 0 'turn off the USART
if intensity > 0 then
PIE1 = 1 'restore interrupt
else
PIE1 = 0 'if the intensity is >0, let the elapsed timer run
endif
return

Darrel Taylor
- 1st August 2008, 05:28
... could this have something to do with BANK0, BANK1, etc?

On an 18F, banking problems don't show up till you have more than ~200 bytes worth of variables.... You have 3. Not including the array, which is handled nicely by the FSR0 indirect.

One thing your PBP version has, that the ASM doesn't, is clearing an OERR condition (CREN toggle).

OERR locks up the USART until cleared, and many bytes could be received before the program looks for data. So it's probably overflowed before it gets to the ASM routine.
<br>

leisryan
- 4th September 2008, 10:04
On an 18F, banking problems don't show up till you have more than ~200 bytes worth of variables.... You have 3. Not including the array, which is handled nicely by the FSR0 indirect.

One thing your PBP version has, that the ASM doesn't, is clearing an OERR condition (CREN toggle).

OERR locks up the USART until cleared, and many bytes could be received before the program looks for data. So it's probably overflowed before it gets to the ASM routine.
<br>


Sir Darrel;
I'd like to ask which would you most prefer and or convenient with PIC18F data ram addressing "Access Ram" or "Indirect Addressing"

Darrel Taylor
- 4th September 2008, 11:34
I'd like to ask which would you most prefer and or convenient with PIC18F data ram addressing "Access Ram" or "Indirect Addressing"

They're really two completely different things.
But if I had to choose one, I'd say "Indirect Addressing".

Access Ram is more for optimizing the code, reducing the size by letting you do things with less bank switching. It doesn't really give any additional functionality.

But "Indirect Addressing" let's you use the entire RAM space like it's a big array, which adds just a TON of functionality. Strings, packets, buffers, software stacks, etc. etc.
<br>

leisryan
- 5th September 2008, 00:25
They're really two completely different things.
But if I had to choose one, I'd say "Indirect Addressing".

Access Ram is more for optimizing the code, reducing the size by letting you do things with less bank switching. It doesn't really give any additional functionality.

But "Indirect Addressing" let's you use the entire RAM space like it's a big array, which adds just a TON of functionality. Strings, packets, buffers, software stacks, etc. etc.
<br>

Wow!!! I really appreciate it really enlightening!!! Is bank switching still occurs in "Indirect Addressing" Un-noticeably though?

Darrel Taylor
- 5th September 2008, 09:35
> Is bank switching still occurs in "Indirect Addressing" Un-noticeably though?

Well, YES and NO.

But, if I had to choose one ... :)
I'd say NO.

On 18F's, the FSRx registers are 12-bits wide.
Which means it can address any location from 0 to 4095 ($000 to $FFF).
It can access memory locations in ANY BANK without having to change the current bank (BSR). It's just a single address.

The beauty of this, is that no matter what bank your program is currently using, you can read/write from any other bank without switching the banks back and forth. Which may be where your original question was aimed, because Indirect addressing can be a good tool for optimization, much like the Access RAM.