I ported the Tiny-Software-Transmitter to PIC MC. The attached sample realizes a software UART (in fact ist an 'AT', because ist neither Universal nor a Receiver but an RS232 Asynchron Transmitter).
Tiny means, there are only 24 words (!) added to the hex to be able to send a byte.
- 13 lines of assembler code
- no timers are used
- no other hardware modules are used
- no interrupt is used
- 9600 - 128000 baud are possible at 16 Mhz
- 8N1 format only
- Tx-Pin is user configurable
Because I'm new to ASM I need some help. The code works for me on a PIC12f1501 an a PIC18f13k50. But it lacks on 'bank selection' and 'page selection' in the asm code. Can that be a problem, if the code would be inserted in another (more complex) program? How can this be fixed? If I try to add 'banksel' in the code, GCB generates an error - why?
Frank
The sample:
'''A demonstration program for GCB - PIC only -
'''---------------------------------------------------------------------------------
'''This program is a super slim software serial transmitter (151 words on a PIC12f1501)
''' realized with 13-line asm code, PIC-Assembler so it's PIC only
''' tested up to 128000 baud on a 16 Mhz PIC 12f1501
'''The pulse polarity ist designed for TTL-USB-Serial-Converters,
''' to invert, switch bcf / bsf (... TTX_PORT,TTX_PIN) in TTxSendByte
'''
'''@author Frank Steinberg guided by the code of Ralph Doncaster:
''' http://nerdralph.blogspot.de/2013/12/writing-avr-assembler-code-with-arduino.html
'''@licence GPL
'''@version 1.0
'''@date 21.12.2016
'''********************************************************************************
; ----- Configuration
#chip 12F1501, 16
#config LVP = Off
#option Explicit
'OSCCON = b'01011010' 'set internal oscillator to 1 Mhz
'OSCCON = b'01110010' 'set internal oscillator to 8 Mhz
OSCCON = b'01111010' 'set internal oscillator to 16 Mhz
; ----- Define Hardware settings
; Config Tiny Software Tx:
; calculate delay-counter: TTX_DELAY=((CPUFrequency/4/BaudRate)-11)/3)
; 16Mhz: 7=128000 8=115200 19=57600 31=38400 43=28800 66=19200 135=9600
; 1Mhz: 5=9600 31=2400
#define TTX_DELAY 8 '115200 baud
#define TTX_PORT PORTA 'use this port to send serial data
#define TTX_PIN 2 'use this pin to send serial data
Dir TTX_PORT.TTX_PIN Out '... and make it output
Set TTX_PORT.TTX_PIN On 'set HIGH to make the first startbit recognizable
; ----- Variables
Dim xx As Byte
xx = 48 'begin with a 0
Dim TTxSVar As String * 20 'create a string
; ----- Main body of program commences here.
Do Forever
TTxSendByte(13) 'new line in Terminal
TTxSendByte(10)
TTxSendByte(">")
TTxSendByte(xx) 'send an alternating byte
TTxSendText(" TinyTx Software Transmitter ") 'send the text
'TTxSVar = Str(xx) 'Str(xx) adds 278 byte code!
'TTxSendString
xx += 1 'alternate byte
Wait 1 s 'time to enjoy the result
Loop 'jump back to the start of the program
Sub TTxSendText (In TTxText) 'Send given text bytewise
Dim TTxText As String * 20 'create a string
Dim ii As Byte
For ii = 1 To TTxText(0) 'first byte in array is the string-length
TTxSendByte(TTxText(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendString 'Send string >TTxSVar< bytewise
Dim ii As Byte
For ii = 1 To TTxSVar(0) 'first byte in array is the string-length
TTxSendByte(TTxSVar(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendByte (In TTxDataByte) 'serial out one byte (8 databit, no paritybit, 1 stopbit)
Dim TTxDlyCnt, TTxBitCnt As Byte
TTxBitCnt = 10 ;10 bits to transmit (1 start + 8 data + 1 stop)
bcf STATUS,C ;clear CarryFlag to 0 (needed for startbit LOW)
TTxLoop:
btfss STATUS,C ;skip next line if CarryFlag=1
bcf TTX_PORT,TTX_PIN ;set pin LOW if CarryFlag=0
btfsc STATUS,C ;skip next line if CarryFlag=0
bsf TTX_PORT,TTX_PIN ;set pin HIGH if CarryFlag=1
TTxDlyCnt = TTX_DELAY ;number of delay-loops
decfsz TTxDlyCnt,1 ;decrement delaycounter, skip next line if 0
GOTO $-1 ;loop to line above until delaycounter=0
bsf STATUS,C ;set CarryFlag to 1 (fills databyte with 8*1 - needed for stopbit HIGH)
rrf TTxDataByte,1 ;shift next bit to CarryFlag
decfsz TTxBitCnt,1 ;decrement bitcounter, skip next line if 0
GOTO TTxLoop ;process next bit until bitcounter=0
End Sub
Last edit: Frank Steinberg 2016-12-22
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Do not struggle with banksel - simply mix ASM and Great Cow BASIC.
You assign a variable. Use GCB assignment. GCB will sort out pages andg banks.
You need a goto. Use GCB goto. GCB will sort the correct addressing across all the chips.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You assign a variable. Use GCB assignment. GCB will sort out pages andg banks.
I wonder if is's really ruled out, that GCB adds a 'banksel'. In this case the asm code won' t work anymore, because the jumps are only to the next line. I could handle that by adding goto-jumps to labels !? But that is extra code an slows it down (slightly).
You need a goto. Use GCB goto. GCB will sort the correct addressing across all the chips.
How can I force that; it's the same command?
Frank
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You lucky one!
I am filled with family and Christmas obligations until the 26th.
Ideas for the next steps:
creating compatible code for IC and AVR
finding a smart way to detect the interrupt status (enabled or not) to restore it after sending a byte
to do the baud calculation by a script
creating a proper GCB library
That's my last code, so the first step is mostly done (hopefully)
'''A demonstration program for GCB - PIC only -
'''---------------------------------------------------------------------------------
'''This program is a super slim software serial transmitter (151 words on a PIC12f1501)
''' realized with 13-line asm code, PIC-Assembler so it's PIC only
''' tested up to 128000 baud on a 16 Mhz PIC 12f1501
'''The pulse polarity ist designed for TTL-USB-Serial-Converters,
''' to invert, switch bcf / bsf (... TTX_PORT,TTX_PIN) in TTxSendByte
'''
'''@author Frank Steinberg guided by the code of Ralph Doncaster:
''' http://nerdralph.blogspot.de/2013/12/writing-avr-assembler-code-with-arduino.html
'''@licence GPL
'''@version 1.0
'''@date 24.12.2016
'''********************************************************************************
; ----- Configuration
#chip 12F1501, 16
#config LVP = Off
#option Explicit
'OSCCON = b'01011010' 'set internal oscillator to 1 Mhz
'OSCCON = b'01110010' 'set internal oscillator to 8 Mhz
OSCCON = b'01111010' 'set internal oscillator to 16 Mhz
; ----- Define Hardware settings
; Config Tiny Software Tx:
; calculate delay-counter: TTX_DELAY=((CPUFrequency/4/BaudRate)-13)/3)
; 16Mhz: 6=128000 7=115200 19=57600 31=38400 43=28800 66=19200 135=9600
; 1Mhz: 5=9600 31=2400
#define TTX_DELAY 6 '115200 baud
#define TTX_PIN PORTA.2 'use this pin to send serial data
Dir TTX_PIN Out '... and make it output
Set TTX_PIN On 'set HIGH to make the first startbit recognizable
; ----- Variables
Dim xx As Byte
xx = 48 'begin with a 0
Dim TTxSVar As String * 20 'create a string
; ----- Main body of program commences here.
Do Forever
TTxSendByte(13) 'new line in Terminal
TTxSendByte(10)
TTxSendByte("T")
TTxSendText("inyTx Software Transmitter: ") 'send a text
TTxSendByte(xx) 'send an alternating byte
'TTxSVar = Str(xx) 'Str(xx) adds 278 byte code!
'TTxSendString
xx += 1 'alternate byte
Wait 1 s 'time to enjoy the result
Loop 'jump back to the start of the program
Sub TTxSendText (In TTxText) 'Send given text bytewise
Dim TTxText As String * 20 'create a string
Dim ii As Byte
For ii = 1 To TTxText(0) 'first byte in array is the string-length
TTxSendByte(TTxText(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendString 'Send string >TTxSVar< bytewise
Dim ii As Byte
For ii = 1 To TTxSVar(0) 'first byte in array is the string-length
TTxSendByte(TTxSVar(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendByte (In TTxDataByte) 'serial out one byte (8 databit, no paritybit, 1 stopbit)
Dim TTxDlyCnt, TTxBitCnt As Byte
TTxBitCnt = 10 ;10 bits to transmit (1 start + 8 data + 1 stop) [GCB]
bcf STATUS,C ;clear CarryFlag to 0 (needed for startbit LOW) [ASM]
TTxLoop:
;9 cycle loop + delay per byte
btfsc STATUS,C ;skip next line if CarryFlag=0 [ASM]
goto TTx1 ;goto TTx1 if CarryFlag=1
Set TTX_PIN Off ;set pin LOW if CarryFlag=0 [GCB]
TTx1:
btfss STATUS,C ;skip next line if CarryFlag=1 [ASM]
goto TTxDone ;goto TTxDone if CarryFlag=0
Set TTX_PIN On ;set pin HIGH if CarryFlag=1 [GCB]
TTxDone:
TTxDlyCnt = TTX_DELAY ;number of delay-loops [GCB]
TTxDelay:
;delay-loop = (x cycle * delaycounter) -1
decfsz TTxDlyCnt,F ;decrement delaycounter, skip next line if 0 [ASM]
goto TTxDelay ;loop to TTxDelay until delaycounter=0
bsf STATUS,C ;set CarryFlag to 1 (fills databyte with 8*1 - needed for stopbit HIGH)[ASM]
rrf TTxDataByte,F ;shift next bit to CarryFlag [ASM]
decfsz TTxBitCnt,F ;decrement bitcounter, skip next line if 0 [ASM]
goto TTxLoop ;process next bit until bitcounter=0
End Sub
... and for AVR:
'''A demonstration program for GCB - AVR only -
'''--------------------------------------------------------------------------------------------------------------------------------
'''This program is a super slim software serial transmitter (322 bytes flash)
''' realized with 15-line asm code, AVR-Assembler so it's AVR only
''' tested up to 256000 baud on an 16 or 16.5 Mhz attiny85 (digispark)
'''The pulse logic ist designed for TTL-USB-Serial-Converters,
''' to invert, switch On / Off in Line 66 & 69 (Set TTX_PIN ...)
'''
'''@author Frank Steinberg with the largest portion of Ralph Doncaster:
''' http://nerdralph.blogspot.de/2013/12/writing-avr-assembler-code-with-arduino.html
'''@licence GPL
'''@version 1.0
'''@date 24.12.2016
'''********************************************************************************
; ----- Configuration
#chip tiny85, 16 'intended for digispark board
#option Explicit
; ----- Define Hardware settings
; Config Software Tx:
; [ calculate delay-counter: TTX_DELAY=((CPUFrequency/BaudRate)-9)/3) ]
#define TTX_DELAY 17 '16.5Mhz: 17=256000 19=230400 44=115200 '1Mhz: 5=38400 135=2400
#define TTX_PIN PORTB.3 'use this port to send serial data
Dir TTX_PIN Out '... and make it output
Set TTX_PIN On 'set HIGH to make the first startbit recognizable
; ----- Variables
Dim TTxSVar As String * 20 'create a string
Dim xx As Byte
xx = 48 'begin with a 0
; ----- Main body of program commences here.
Do Forever
TTxSendByte(13) 'new line in Terminal
TTxSendByte(10) '
TTxSendByte("T") 'this is a valid byte too
TTxSendText("inyTx Software Transmitter: ") 'send a text
TTxSendByte(xx) 'send an alternating byte
'TTxSendByte(9) 'Tab
'TTxSVar = Str(xx) 'this adds 564 byte code!
'TTxSendString 'this adds 2 byte code
xx += 1 'alternate byte
Wait 1 s 'time to enjoy the result
Loop
Sub TTxSendText (In TTxText) 'Send given text bytewise
Dim TTxText As String * 20 'create a string
Dim ii As Byte
For ii = 1 To TTxText(0) 'first byte in array is the string-length
TTxSendByte(TTxText(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendString 'Send string >TTxSVar< bytewise
Dim ii As Byte
For ii = 1 To TTxSVar(0) 'first byte in array is the string-length
TTxSendByte(TTxSVar(ii)) 'send via subroutine
Next
End Sub
Sub TTxSendByte (In TTxByte) 'serial out one byte (8 databit, no paritybit, 1 stopbit)
'cli ;disable interrupts
push R24 ;save register content to stack
push R25 ;
push R26 ;
lds R24, TTxByte ;load data-byte to register
ldi R25, 10 ;load number of bits to register (1 start + 8 data + 1 stop)
com R24 ;invert bits and set carry
TTxLoop:
;9 cycle loop + delay per byte
brcc TTx1 ;jump to TTx1 if CarryFlag=0
Set TTX_PIN Off ;set pin LOW if CarryFlag=1 (translated by GCB to ASM: cbi ...)
TTx1:
brcs TTxDone ;jump to TTxDone if CarryFlag=1
Set TTX_PIN On ;set pin HIGH if CarryFlag=0 (translated by GCB to ASM: sbi ...)
TTxDone:
ldi R26, TTX_DELAY ;load delaycounter to register
TTxDelay:
;delay-loop = (3 cycle * delaycounter) -1
dec R26 ;decrement delaycounter
brne TTxDelay ;loop to TTxDelay until delaycounter=0
lsr R24 ;shift next bit to CarryFlag
dec R25 ;decrement bitcounter
brne TTxLoop ;jump to TTxLoop and transmit next bit until bitcounter=0
pop R26 ;restore register content from stack
pop R25 ;
pop R24 ;
'sei ;enable interrupts
End Sub
Merry christmas to all
Last edit: Frank Steinberg 2016-12-25
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi
I ported the Tiny-Software-Transmitter to PIC MC. The attached sample realizes a software UART (in fact ist an 'AT', because ist neither Universal nor a Receiver but an RS232 Asynchron Transmitter).
Tiny means, there are only 24 words (!) added to the hex to be able to send a byte.
- 13 lines of assembler code
- no timers are used
- no other hardware modules are used
- no interrupt is used
- 9600 - 128000 baud are possible at 16 Mhz
- 8N1 format only
- Tx-Pin is user configurable
Because I'm new to ASM I need some help. The code works for me on a PIC12f1501 an a PIC18f13k50. But it lacks on 'bank selection' and 'page selection' in the asm code. Can that be a problem, if the code would be inserted in another (more complex) program? How can this be fixed? If I try to add 'banksel' in the code, GCB generates an error - why?
Frank
The sample:
Last edit: Frank Steinberg 2016-12-22
Good code, Frank. Really nice.
Do not struggle with banksel - simply mix ASM and Great Cow BASIC.
You assign a variable. Use GCB assignment. GCB will sort out pages andg banks.
You need a goto. Use GCB goto. GCB will sort the correct addressing across all the chips.
Thank you for the answer.
I wonder if is's really ruled out, that GCB adds a 'banksel'. In this case the asm code won' t work anymore, because the jumps are only to the next line. I could handle that by adding goto-jumps to labels !? But that is extra code an slows it down (slightly).
How can I force that; it's the same command?
Frank
@Frank. Which piece of code are we trying to optimise? i can try here over the Holiday period.
It is the Holiday period. :-)
You lucky one!
I am filled with family and Christmas obligations until the 26th.
Ideas for the next steps:
That's my last code, so the first step is mostly done (hopefully)
... and for AVR:
Merry christmas to all
Last edit: Frank Steinberg 2016-12-25