PDA

View Full Version : Serout code space



Art
- 20th November 2016, 14:08
Hi Guys,
I thought it should be possible to save space if bit banging serial manually.
Maybe just if one speed, or one direction is needed, which is transmit only in this case,
and the byte value is destroyed by the send each time.
That’s what the code is. The delay of course depends on the baud rate you want, and the pic’s clock speed.

Now I’m thinking on the receive side, a fast enough pic should be able to determine the received baud rate
with the very first received byte, by measuring the duration of the start to stop bit,
rather then sending a known byte value and trying to receive at each baud rate until it’s interpreted properly.




‘ PBP software serial out 8N1
delay var word ‘ set baud rate delay
txbyte var byte ‘ byte to send
count var byte ‘ counter

delay = 0’ set serial delay here

main:
txbyte = “H"
GOSUB serialout
txbyte = “E"
GOSUB serialout
txbyte = “L"
GOSUB serialout
txbyte = “L"
GOSUB serialout
txbyte = “O"
GOSUB serialout
txbyte = $20 ‘ space
GOSUB serialout
goto main


serialout:
‘ start bit
PORTB.1 = 0’ tx clear
PAUSEUS delay ‘ start bit delay

‘ send byte
FOR count = 0 TO 7
IF txbyte.bit0 = 1 THEN
PORTB.1 = 1
ELSE
PORTB.1 = 0
ENDIF
txbyte = txbyte >> 1
PAUSEUS delay ‘ data bit delay
NEXT count
PORTB.1 = 1
PAUSEUS delay ‘ stop bit delay
RETURN

HenrikOlsson
- 20th November 2016, 17:37
Hi Art,
Interesting. I suppose you've verified that it actually is "better"? By how much? I think it's not really fair to compare against SEROUT. Instead, you should compare against DEBUG since it, just like your routine, handles the baudrate calculation at compile time - unlike SEROUT/SEROUT2.

Like compare your code with

DEFINE DEBUG_REG PORTB
DEFINE DEBUG_BIT 1
DEFINE DEBUG_BAUD 2400

Main:
DEBUG "Hello", $20
Goto Main

I might be missing something but as far as I can see the problem with doint autobaud detect on an unknown byte is you don't know what the first databit after the startbit actually is so you don't really KNOW if the next edge is the end of the startbit or the end of any arbitrary databit. I believe a common byte is either $55 or $AA because every bit changes.

In any case, please keep posting about your findings!

/Henrik.

Art
- 21st November 2016, 03:06
Haha, you’re right there. I can’t even measure the start bit alone because the next bit could be either value.
I didn’t consider that!

IIRC, 2400 baud timing is 417uS, so you’d maybe subtract a little from that to make up for the instruction time of the serial code itself.
No, it’s not fair to compare with Serout, and Debug didn’t even occur to me.

So long as I could use asm like PBP compiler does in the end, it could be smaller.
When I did decompile PBP in the past, all bytes were sent to functions like this via it’s intermediate system variables,
so that’s an extra copy for nothing:



Your PBP var -> system var -> serial routine


Unless that has been changed in further PBP revisions, it’s still one up :D
It also occurred to me since last night that serial input code may, or may not be included in a PBP program if only output code is used.

Ps. It probably goes without saying, the main loop in that example was verbose for readability, and should be replaced by reading the data out of an array!

Art
- 21st November 2016, 03:10
and:


IF txbyte.bit0 = 1 THEN
PORTB.1 = 1
ELSE
PORTB.1 = 0
ENDIF


should be replaced with:



PORTB.1 = txbyte.bit0


While still in BASIC.

richard
- 21st November 2016, 03:52
IT MAY NOT BE WORTH THE EFFORT ,tried this on a 12f683

90 words


#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_ON & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW WE WILL BE RUNNING AT 8MHZ

'PIN DEFENITIONS
'
'GP3
'GP4 USED FOR TRIGGER INPUT
'GP5 USED FOR LED
'SET UP THE REGISTERS
OSCCON = %01110001 '8MHZ INTERNAL CLOCK USED
CMCON0 = %00000111 'CIN PINS ARE I/O, COUT PIN IS I/O
TRISIO = %00111011 ' GP2 OUTPUT THE REST ARE INPUTS
ANSEL = 0 'NO ANALOG PORTS - ALL DIGITAL
WPU = %00010000 'GP4 WEAK PULL UP ENABLED.

DEFINE DEBUG_REG GPIO
DEFINE DEBUG_BIT 2
DEFINE DEBUG_BAUD 9600
DEFINE DEBUG_MODE 0
' LATB.7=1
'PBP software serial out 8N1
delay var word ' set baud rate delay
txbyte var byte ' byte to send
bcount var byte ' counter
serpin var gpio.2
delay = 100 ' set serial delay here 9600
main:
txbyte = "H"
GOSUB serialout
txbyte = "E"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "O"
GOSUB serialout
txbyte = $20 ' space
GOSUB serialout
goto main

serialout:
Debug txbyte
RETURN


98 words for arts version


#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_ON & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW WE WILL BE RUNNING AT 8MHZ

'PIN DEFENITIONS
'
'GP3
'GP4 USED FOR TRIGGER INPUT
'GP5 USED FOR LED
'SET UP THE REGISTERS
OSCCON = %01110001 '8MHZ INTERNAL CLOCK USED
CMCON0 = %00000111 'CIN PINS ARE I/O, COUT PIN IS I/O
TRISIO = %00111011 ' GP2 OUTPUT THE REST ARE INPUTS
ANSEL = 0 'NO ANALOG PORTS - ALL DIGITAL
WPU = %00010000 'GP4 WEAK PULL UP ENABLED.

'PBP software serial out 8N1
delay var word ' set baud rate delay
txbyte var byte ' byte to send
bcount var byte ' counter
serpin var gpio.2
delay = 100 ' set serial delay here 9600
main:
txbyte = "H"
GOSUB serialout
txbyte = "E"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "O"
GOSUB serialout
txbyte = $20 ' space
GOSUB serialout
goto main

serialout:

' start bit
serpin = 0 ' tx clear
PAUSEUS delay ' start bit delay
' send byte
FOR bcount = 0 TO 7
serpin=txbyte.0
txbyte = txbyte >> 1
PAUSEUS delay ' data bit delay

NEXT
serpin= 1
PAUSEUS delay ' stop bit delay
RETURN

Art
- 21st November 2016, 05:29
Nice :D
If it could be matched in space, I’d still prefer to see my own code, just that I’ve never had a reason to do it until now.
It would be less in asm though, and I still think I could top it.

It was worth the effort to do with a dsPic where the pin was not mappable to UART, so incidentally tried with PBP as well.

No BASIC For/Next loop, instead I’d count down to zero.
No shift command, instead an asm rotate to ensure only 1 instruction,
My own delay routine, which is conveniently right before a return, so can be called multiple times.
watchdog timer resets also have to be turned off because PBP won’t put them in it’s own routines, but in YOUR code.

To my disadvantage, there needs to be some value stored in Delay, which would claim some more space.


Something like this (untested).. and I can’t remember if PBP labels need the underscore or not.


count var byte
pdelay var byte

serialout:
@ movlw ,8
@ movwf _count ,F
@ clrf PORTB ,1
@ call pausedelay
sendbyte:
PORTB.1 = txbyte.bit0
@ rrf txbyte ,F
@ call pausedelay
@ decfsz _count
goto sendbyte
@ bsf PORTB ,1
pausedelay:
@ movlw ,210
@ movwf _pdelay ,F
zpausedelay:
decfsz _pdelay
@ goto zpausedelay
@ return

richard
- 21st November 2016, 09:27
asm version 52 words


#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_ON & _CP_OFF
#ENDCONFIG
DEFINE OSC 8 'LETS PBP KNOW WE WILL BE RUNNING AT 8MHZ

'PIN DEFENITIONS
'
'GP3
'GP4 USED FOR TRIGGER INPUT
'GP5 USED FOR LED
'SET UP THE REGISTERS
OSCCON = %01110001 '8MHZ INTERNAL CLOCK USED
CMCON0 = %00000111 'CIN PINS ARE I/O, COUT PIN IS I/O
TRISIO = %00111010 ' GP2 OUTPUT THE REST ARE INPUTS
ANSEL = 0 'NO ANALOG PORTS - ALL DIGITAL
WPU = %00010000 'GP4 WEAK PULL UP ENABLED.

' DEFINE DEBUG_REG GPIO
' DEFINE DEBUG_BIT 2
' DEFINE DEBUG_BAUD 9600
' DEFINE DEBUG_MODE 0
'' LATB.7=1
'PBP software serial out 8N1
delay var byte bank0 ' set baud rate delay
txbyte var byte bank0' byte to send
bcount var byte bank0' counter
serpin var gpio.0
; set serial delay for 9600b
main:
txbyte = "H"
GOSUB serialout
txbyte = "E"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "L"
GOSUB serialout
txbyte = "O"
GOSUB serialout
txbyte = $20 ' space
GOSUB serialout

goto main


serialout:
asm
movlw 8
movwf _bcount
bcf GPIO ,0
call pausedelay
sendbyte
btfss _txbyte ,0
goto snd0
bsf GPIO ,0
goto sndd
snd0
bcf GPIO ,0
sndd
rrf _txbyte ,F
call pausedelay
decfsz _bcount ,F
goto sendbyte
bsf GPIO ,0
pausedelay
movlw 67
movwf _delay
zpausedelay
decfsz _delay ,F
goto zpausedelay
return
endasm

richard
- 21st November 2016, 09:35
printout from pickit2

Art
- 21st November 2016, 17:22
Thanks for running it :) That’s getting worthwhile then. Using Pauseus in the first post would have added code to it.

I might as well have a shot at the serial input over the next few days then.
Basically I did this on dspic in C, and it wrote easily into PBP as well.
The pic at the receive end is supposed to be 16F628A in PBP/asm.

My mp3 player serial spits out the artist & title info from the ID tags as tracks are skipped (that much is working).
Then the 16F628A is supposed to receive the serial, and transmit IR to an electronic sign the same way a user would normally use a remote to reprogram the scrolling message :D

Art
- 27th November 2016, 02:35
This time going for serial input of a string terminated with either 0x00 or 0x0D (or any value below 0x20 really) into an array.
So far one byte, and untested, but I do have a PBP program on 16F628A ready to test and use it when done.
It’s on the receive side where I want serene replaced because I can keep going with my own data until the program memory is full.



rxbyte var byte
count var byte
delay var byte
shortdelay var byte

delay = 100 ‘ actual serial timing
shortdelay = 50 ‘ time/2


serinbyte:
IF PORTB.1 = 1 THEN
‘ optional countdown to timeout here
GOTO serinbyte
ENDIF
pauseus delay
pauses shortdelay
FOR count = 0 TO 7
rxbyte.bit7 = PORTB.1
rxbyte = rxbyte >> 1
pauseus delay
NEXT count
pauses shortdelay
rxbyte = rxbyte ^ $FF
return

richard
- 27th November 2016, 05:39
i'd bet this won't stack_up any better than debug either as is


until the program memory is full.

sram ?

Art
- 27th November 2016, 06:57
Storing data in program memory until full yes.

Probably not like this, but I'd rather have the whole thing work in PBP
before doing any of it in asm.
Hserout of course will beat both of them,
but sometimes you want all eight bits of Portb for something else.