serout versus hserout problem

fastgrandad

New Member
Hi

I am writing a program that uses the Time variable and found it to be slow as a result of using serout to send data to an axe133 OLED display. Other posts on the Time/serout issue state that using the hserout hardware port avoids this problem.

My simple test program using serout works fine but converting it to hserout doesn't; all I get are random characters and I can't see why. They both use the same pin on the 20M2 chip, C.0, and are set for 2400 Baud. I have tried inverted and non-inverted data settings on the 20M2 and the axe133, put in extended pauses between each hserout command, but to no avail. The working serout and non working hserout versions are listed below.

Can someone please tell me why the latter doesn't work?

serout version

Code:
#no_data
init:
    Symbol OLEDPin= C.0        ; Sets Picaxe output Pin
    Symbol Baud = N2400        ; Set Baud rate for OLED
    b0=0
    pause 2000                 ; wait for display to initialise

Main:
do
    serout OLEDPin,Baud,(254,1)    ; Clear display
    pause 30
    serout OLEDPin,Baud,(254,128)    ; move to start of first line
    serout OLEDPin,Baud,("Test display ",#b0)
    pause 1000
    b0=b0+1
loop until b0>5
    serout OLEDPin,Baud,(254,1)    ; Clear display
    serout OLEDPin,Baud,(254,128)    ; move to start of first line
    serout OLEDPin,Baud,("Test end")
    pause 1000

Goto Main
end
hserout version

Code:
#no_data
init:
    hsersetup B2400_4, %10
    pause 2000                ; wait for display to initialise
    b0=0

Main:
do
    hserout 0,(254,1)            ; Clear display
    pause 200
    hserout 0,(254,128)        ; move to start of first line
    pause 200
    hserout 0,("Test display ",#b0)
    pause 1000
    b0=b0+1                ; increment b0
loop until b0>5
    hserout 0,(254,1)            ; Clear displapause 30
    pause 200
    hserout 0,(254,128)        ; move to start of first line
    pause 200
    hserout 0,("Test end")
    pause 1000
Goto Main
end
I'm sure it's something silly but can't see it!

Thanks
Paul
 

PhilHornby

Senior Member
My guess ...

is that the hserout 0,("Test display ",#b0) outputs data slightly faster than serout OLEDPin,Baud,("Test display ",#b0) and outruns the other end.

If so, you'd have to split the hserout into multiple hserout : pause statements, with one byte per hserout :(

(I've not looked at the code for the AXE133, to understand why it would upset it.)
 

AllyCat

Senior Member
Hi,

Yes, the HSEROUT command probably sends almost "concatonated" characters, where the next character's Start bit follows immediately after the previous Stop bit. The same occurs with the Program Editor's Terminal Emulator if you disable the default "Add 5ms delay between TX bytes" setting. But the AXE133 uses a SERIN command which "bit bangs" the serial input, so it has only the period of the Stop bit to perform all its decoding and control functions (and so it generally fails).

Thus, as Phil says, you probably need to transmit each byte with a separate HSEROUT command, although an intermediate Pause is probably not necessary. This can be rather inconvenient for Text Strings, but I recently gave an example code snippet in post #2 HERE which could use HSEROUT in place of the SEROUT shown there.

Cheers, Alan.
 

fastgrandad

New Member
Thanks for the quick replies. I've read a few of your posts on this and other topics Alan and they've been really helpful.

Breaking up the strings, including the control codes, certainly works but is going to be mighty tedious to implement on the final program for longer variable strings! Incidentally it does need the pauses between bites to work.

Code:
#no_data
init:
    hsersetup B2400_4, %10
    pause 2000                ; wait for display to initialise

Main:
    b0=0
do
    hserout 0,(254)
    pause 20
    hserout 0,(1)            ; Clear display
    pause 20
    hserout 0,(254)
    pause 20
    hserout 0,(128)        ; move to start of first line
    pause 200
    hserout 0, ("T")
    pause 20
    hserout 0, ("e")
    pause 20
    hserout 0, ("s")
    pause 20
    hserout 0, ("t")
    pause 20
    hserout 0, (" ")
    pause 20
    hserout 0, (#b0)
    pause 1000
    b0=b0+1                ; increment b0
loop until b0>5
goto main
Maybe needs a routine to buffer and stutter the output. Something to amuse myself with, but if anyone has a good idea do please share it....

Thanks

Paul
 

AllyCat

Senior Member
Hi,
Breaking up the strings, including the control codes, certainly works but is going to be mighty tedious to implement on the final program for longer variable strings!
Certainly there's no need to write the code all "In-Line". Here's the example I referenced above, modified for HSEROUT. It could be converted to a subroutine, with a start address pointer and a string length parameter, or use an "End of String" marker (typically a zero byte, or maybe a CR). There are plenty of other examples on the forum, also using READ or READTABLE commands (which can contain long strings), often associated with LCD/LED/OLED driver programs.

Code:
     FOR b0 = 0 to 12                                 ; Start a loop
        LOOKUP b0 , ("Hello World",13,10) , b1        ; Read value into b1
        HSEROUT 0 , (b1)                              ; Transmit character byte
        PAUSE  1                                      ; Probably not required
     NEXT b0                                          ; Next loop
EDIT: Note that the hserout 0, (#b0) will generally transmit more than one character, which probably need to be separated by a BIN2ASCII b0,b2,b3,b4 or similar (manually formatting 1-3 digits, with or without leading zeros, can be a pain). But the "Lookup" strings can be quite flexible, so this 12 character example should be accepted : LOOKUP b0, (254 , 1 , 254 ,128 , "Test " , b2 , b3 , b4) , b1. Surprisingly, the LOOKUP has a constant delay (dependent only on the number of characters in the whole string). In this case, it's equivalent to approximately a PAUSE 4, with a single pass around the complete loop equivalent to around a PAUSE 7 (i.e. 7 ms), of which each character transmits in just over 4 ms at 2400 baud (i.e. 10 bits * 420 us).

Cheers, Alan.
 
Last edited:

AllyCat

Senior Member
Hi,
Incidentally it does need the pauses between bites to work.
Ah yes. Some further thoughts (in addition to the Edit in my previous post):

Normally, the HSEROUT feature is used to transmit characters at a (much) higher Baud rate (9600 baud and above), when the PAUSE probably would not be required (at least when using a "Lookup-Transmit" loop) because each byte would transmit in 1 ms or less. But here, the HSEROUT was introduced to avoid the Time variable "slowing down" (and also any Servo pulses being corrupted if they are used), so each character (byte) takes over 4 ms to transmit. Then, some time (typically a ms or two) is required between bytes to allow the AXE133 program sufficient time to "decode" each character (or certain "control" bytes may take much longer).

The fundamental issue is that the (PICaxe interpreter) "time/servo" system uses 20 ms "sub-ticks" (of Timer 1) that employ an internal interrupt to preload T1 with a value that gives a rollover every 20 ms. But these interrupts must be disabled to avoid corrupting the bit-timings during the SEROUT and SERTXD commands. Thus a "long" string of characters, taking over 20 ms, will definitely slow down the time variable (and corrupt the servo pulses) as shown in the Logic Analyser waveforms in post #2 of This Recent Thread.

What is not clear (to me) is if disabling the interrupts for (say) 4 ms (or anything less than 20 ms) disrupts the time counting (it certainly may disrupt the servo pulses). Basically, it depends if the Interrupt Service Routine pre-loads Timer 1 with a "Pre-Defined" value (typically it would be a little more than 45536, to reduce 65.536 ms down to 20 ms), or if (as I would hope) it Reads the present Timer value, ADDS the required pre-load "skip time" and then Writes that value to the Timer "Special Function Register(s)". Therefore, it might be that the SEROUT/SERTXD commands still can be used, provided that the interrupts are not disabled for more than 20 ms. That could be a string of up to 4 character/bytes at 2400 baud (which might allow the "#b1" to be used within a SEROUT command? Maybe one day I'll give it a test. ;)

Cheers, Alan.
 

PhilHornby

Senior Member
Breaking up the strings, including the control codes, certainly works but is going to be mighty tedious to implement on the final program for longer variable strings! Incidentally it does need the pauses between bites to work.
This is the sort of approach you end up taking, when driving a display directly - I've had to write such routines for my LCD-based projects (driven directly). Now, if I was to entertain the extravagance of having a Picaxe set aside purely to drive the display, I would want it to behave more like the Nextion displays...

A simple improvement to the AXE133 firmware would be to change the serin to use a 'qualifier' (and maybe a handshake, to formalise the comms.) That way, it could work in a more 'fire-and-forget' manner. It strikes me there is a "case of the tail wagging the dog" at the moment. It's imposing restrictions on the main program, when its purpose in life is to make things easier!

The current requirement for the pauses is probably because of the 'hardware' buffering used by hserout. It always completes when the last character transmission starts, rather than when it ends - otherwise the delay caused by the Picaxe interpreter would probably have been enough.
 

inglewoodpete

Senior Member
When I encountered the speed limitation of the 18M2 backpack for the OLED/LCDs, I developed a 20X2-based backpack, documented here.

The code provided in the article offers three different options: high speed serial @76,800 baud (possibly 115,200 - read the article), i2c serial or i2c with character-mapping. The code I provided can be modified to only use one of the communication options.
 
Top