Shop OBEX P1 Docs P2 Docs Learn Events
Kye is a legend! - Zicog/Triblade/Xmodem/Wordstar all working — Parallax Forums

Kye is a legend! - Zicog/Triblade/Xmodem/Wordstar all working

Dr_AculaDr_Acula Posts: 5,484
edited 2009-08-16 04:28 in Propeller 1
This is so exciting that it needs a new post to say Thankyou.

For the last 10 days the Zicog has been stuck - it could not run wordstar properly nor games nor file transfers. Then along comes Kye with a tiny little post about some new serial code.

Now, in retrospect after much recoding, the previous serial code did work. But what Kye's code has done is greatly simplified the process, and in going through the simplification the bug became apparent in the zicog spin code.

Kye's SerialEngine object also saves a cog.

I have taken the zicog code and removed all references to the keyboard and tv and debug objects and replaced them with an object I've called a UART:
UART : "SerialEngine" ' kye's serial engine

There are some great little routines in that object. You can check bytes have arrived. You can send out bytes. You can send strings. Nothing really new in a way, but the syntax is so clear and logical that it makes subsequent debugging so much easier. There is a neat buffer too - and what this means in practice is you can start up wordstar and if you know the commands to open a file (N then the filename then return), you can type this all at the beginning as wordstar starts and it gets the keys when ready.

Here is the code that wasn't working:

PRI in_constat
'Handle reads from the console status port
  if kb.gotkey == 0                              'Is there a key press ?
    io_data := %00000010                         'No: Return no char ready for input and output rdy.
  else
    key := kb.key                                'Yes: Get the key
'    if key <> 0                                  'NULL character ?
'     TV.out("<")
'     TV.hex(key,4)
'     TV.out(">")
'      case key                                   'No: Translate some keys for CP/M
'        $00C8: key := $08                        'backspace
'        $0263: key := $03                        'control-c
'        $0265: key := $05                        'control-e
'        $0268: key := $08                        'control-h
'        $0270: key := $10                        'control-p
'        $0272: key := $12                        'control-r
'        $0273: key := $13                        'control-s
'        $0275: key := $15                        'control-u
'        $0278: key := $18                        'control-x
'        $027A: key := $1A                        'control-z
'        $00C9: key := $7F                        'rubout
'        $00C2: key := $5E                        'up arrow
'#ifdef convertkeys
'        $D0  : key := $1A                        'F1 -> Cltr-Z
'        $D1  : key := $13                        'F2 -> Ctrl-S
'        $D2  : key := $03                        'F3 -> Ctrl-C
'#endif  
          'if key => "a" and key =< "z"          'Use this for 4kBASIC which does not like lower case.
          '  key := key - $20
      io_data := %00000011                       'Return char ready for input and output rdy.
'    else
'      io_data := %00000010                       'Yes: Return no char ready for input and output rdy.
              
PRI in_condata
'Handle reads from the console data port
  io_data := key                         'Return the keyboard character





And here is the new code, greatly simplified.
PRI in_constat
'Handle reads from the console status port
  if UART.receiveNumber == 0                   'Is there a character in the buffer
    io_data := %00000010                       'No: Return no char ready for input 
  else
    io_data := %00000011                       'Return flag to say a character is available

PRI in_condata
'Handle reads from the console data port
  io_data := UART.receiveCharacter




And now for the error that has eluded us for so long. Very simple really. The in_constat code tests to see if a character has arrived, and if no it sets a flag 00000010 and if yes it sets a flag 00000011. But, it does not read the character. The character is only read by in_condata. The bug was this line
key := kb.key 'Yes: Get the key

Now, with a few more minor tweaks, we can capture some input and output ports. I used the N8VEM ones because it didn't involve an xmodem rewrite. There are still some minor timing bugs (it takes ages to start sending so just need to tweak a timing loop), but we just capture the In and Out statements. I'm going to post all the details on the zicog thread.

I guess the message here is that simplified code is neat code, and neat code enables bugs to become more obvious.

And to say a big thanks to Kye!!

Post Edited (Dr_Acula) : 8/12/2009 9:56:28 AM GMT

Comments

  • RossHRossH Posts: 5,512
    edited 2009-08-12 10:01
    A lesson it sometimes takes years to learn - "simple code good, complex code bad!" (apologies to George Orwell).

    Congratulations to you both.

    Ross.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Catalina - a FREE C compiler for the Propeller - see Catalina
  • demestavdemestav Posts: 4
    edited 2009-08-12 10:02
    It's really nice that you took the time and explain the bug. Personally I learn A LOT from my mistakes and how to fix them. It's nice to see how other people detect and fix theirs.
  • heaterheater Posts: 3,370
    edited 2009-08-12 10:40
    Dr_A: Brilliant, well done.

    That bug has been lurking in there since the beginning of PropAltair time. It never showed up for me because I never got off my demo board into running real CP/M apps like WordStar. Basicaly the key is read by Spin as soon as a key is seen to be available but if the Z80 code comes round too slowly there could be a new key received over writing the earlier one.

    Yep it was all my fault , sorry it ended up wasting so much of your time.

    The new UART code seems to be great, I will have to have a proper look at it.

    However a couple of little niggles:

    1) The old keyboard drivers should work (after fixing my cock up).
    2) The new UART driver has a different interface to the "standard" interface that was used in the emulator before.

    This means that if using the UART code one cannot just swap serial driver objects one has to change the calls as well.
    Can be done with more #defines of course. If we can tolerate the resulting #define jungle.

    Or can we just forget the old drivers and adopt Kye's permanently ?

    Still which ever way I'd love it if you and Cluso could agree on new version of ZiCog for the TriBlade platform. I could then check it out for use on a demo_board possibly add some Z80 emulation fixes and release a new ZiCog version from it.

    What do you think?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-08-12 11:54
    James, fantastic you have found the bug. Look forward to the code. Of course, the commented out code was obscuring what was really happening.

    Heater, yes I agree about the difference in using seperate calls. Since the keyboard is the smallest set of calls, this shoudl have a #if define around it to change from kb.gotkey to fdx.gotkey - hope you understand what I mean, but I will fix it over the weekend.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBladeProp, RamBlade, TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80), MoCog (6809)
    · Search the Propeller forums (via Google)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • KyeKye Posts: 2,200
    edited 2009-08-12 15:07
    Your welcome.

    Oh, if that serial driver code is working okay then I'll update the obex serial driver I have posted.

    I try to stagger making the new code and then releasing it so that I can find any bugs.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-12 23:01
    It works great. But there is still one minor thing, and that is the need for two stop bits when sending continuous bytes to the object. I think that comes down to the 10 vs 11 bit discussion a few days ago, specifically whether the code interprets a high to low transition at the end of the stop bit as the beginning of the next start bit.

    This problem is the same at fast baud rates and slow baud rates eg 110 baud, so I think it is a problem of tranistions not being interpreted properly (rather than, say, a problem with delays when storing a byte at the end of receiving it).

    Most serial code uses 1 stop bit, not two, and it would be great if we could get it working with the 'default' setting of 1 stop bit. Your thoughts would be most appreciated.
  • KyeKye Posts: 2,200
    edited 2009-08-13 01:57
    My driver actually does send packets at 10 bits at a time. I add in the extra 11th bit to fix the problem with the prop terminal.

    Here's a version with that line commented out.

    However, I expect that you'll find the driver has worse preformance and terminal software using the FTDI chip·will fail. (bytes are still received but they are mostly corrupted).

    I have not seen if this is a problem with a standard seial port.

    ... If you have no problems then it will pretty much be confirmed that the FTDI serial driver needs 11 bit frames instead of ten.





    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-13 02:52
    Hi Kye,

    I'm still at the bottom of the learning curve re PASM!

    receiver                rdlong  rate,              par                             ' Get new settings.  
                                                         
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                         
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
    
                            test    RXPin,             ina wz                          ' Wait for start bit.
    if_nz                   waitcnt counter,           rate                            '                        
    if_nz                   test    RXPin,             ina wc                          '         
    if_nz_and_c             jmp     #receiver                                          '
    
    ' //////////////////////Receiver Setup/////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     receiverCounter,   #9                              ' Setup loop to receive the packet.
    
    ' //////////////////////Receive Packet/////////////////////////////////////////////////////////////////////////////////////////
    
    receive                 test    RXPin,             ina wc                          ' Input bits. 
                            rcl     receiverBuffer,    #1                              '
    
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
    
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
                                                                            
    if_nz                   waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            djnz    receiverCounter,   #receive                        ' Ready next bit.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            rev     receiverBuffer,    #24                             ' Reverse backwards bits.
    
    



    At the beginning of the packet, when there is a high to low transition to signify the start of the start byte, how do you detect this? The code has lots of half bit delays which makes sense, but how do you synchronise at the beginning? Looking through the list of assembly instructions I was kind of expecting a waitpeq somewhere to start off the sequence? Or a tight loop with no delays looking for the transition? Or is this done in some other way?
  • KyeKye Posts: 2,200
    edited 2009-08-13 04:00
    This part:

    receiver                rdlong  rate,              par                             ' Get new settings.  
                                                         
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                         
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
    
                            test    RXPin,             ina wz                          ' Wait for start bit.
    if_nz                   waitcnt counter,           rate                            '                        
    if_nz                   test    RXPin,             ina wc                          '         
    if_nz_and_c             jmp     #receiver                                          '
    
    

    Gets the new rate, waits a half baud rate, then runs the transmiter code which is always run at 1x the baud rate.

    Then I test the line to look for the start bit, if I don't see it then I wait half a baud and test again. If I don't see it I run the transmiter code.

    If I do see the start bit then I run this code:

    ' //////////////////////Receiver Setup/////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     receiverCounter,   #9                              ' Setup loop to receive the packet.
    
    ' //////////////////////Receive Packet/////////////////////////////////////////////////////////////////////////////////////////
    
    receive                 test    RXPin,             ina wc                          ' Input bits. 
                            rcl     receiverBuffer,    #1                              '
    
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
    
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
                                                                            
    if_nz                   waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            djnz    receiverCounter,   #receive                        ' Ready next bit.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            rev     receiverBuffer,    #24                             ' Reverse backwards bits.
    


    I setup to sample nine bits. Now I do not sample the bits in the driver correctly. To run at the maximum frequency I had to forgo sampling at the middle of the bit period. The code just starts sampling after it it sees the start bit. So the bits do need to come right after each other with the same timing and not devite from each other.

    The rest of the stuff there is just to adjust the phase so that the transmiter code is always run at 1x the baud rate.

    ...

    So, try adding this piece of code in ...

    ' //////////////////////Receiver Setup/////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     receiverCounter,   #9                              ' Setup loop to receive the packet.
     
                            mov     buffer,            rate                            ' Waits 1/4 the baud rate. 250_000 BPS operation not possible
                            shr     rate,              #1                              '
                            sub     counter,           rate                            ' 230400 is still possible.
                            add     counter,           buffer                          '
                            waitcnt counter,           buffer                          '
    


    And see what happens. It will ensure then that the reciever samples the line somewhere between 1/4th and 3/4th into ever bit being sent.

    ...

    Now the receiver only samples nine bits and waits 1x the baud rate after each bit. This means that it ignores the stop bits and readies itself for the next start bit.

    I beleive the max232 may be causing alot of skew thus requring more stop bits. Its done that before to me.



    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-13 04:27
    Ah, now it is starting to make sense.

    I don't think it is the slew rate of the max232 as this problem is still there at 110 baud. There might be an issue replicating this using USB to serial chips if the chip inserted slightly longer start bits. Only a scope would tell that.

    Ok, here is a scenario - what if the phase of the receiver started such that it received data for the start bit just at the transition point - or just a few microseconds after. It then continues to sample at that transition point, but the clock in the propeller is fractionally slow (eg 0.01%), so the transition point changes so it is now sampling the previous bit?

    Is the only way around this to sample in the middle of a bit? And if so, don't you then need to sample a transition somewhere to get the phase right?

    But, as you say, you might sacrifice the highest frequency.

    Then there is the code that has to check the transmitter side. And I think you phase that with the Rx so it outputs bits in time with receiving them. That is a very cunning trick!

    This is quite a difficult problem if you want to run the Tx in parallel.

    I'm wondering, let's say you set up a delay 1/10th of the period of a bit. Start in a resting state with the line high. Sample the value. Check for bytes in the Tx buffer each cycle (is there time for that too??). If a transition occurs, wait half a bit period and then start the sampling.

    That would ensure it samples in the middle of the bit.

    I've got some code to do this in Z80 assembler from years ago so the memories of how to solve the problem are still buried somewhere in the tangled mess of neurons that is my brain.
  • KyeKye Posts: 2,200
    edited 2009-08-13 14:26
    Well, the problem is that when using waitcnt the code only runs at a certaint frequency.

    That said, I can only sample the line at 2x the baud rate. That is enough however to detect the start bit either at the being of the start bit or 1/2 of the way through the start bit.

    So, if the next bit is not exactly on time witht he first one then you have a problem because the driver will then sample on that reference point.

    So, try adding this piece of code in ...

    ' //////////////////////Receiver Setup/////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     receiverCounter,   #9                              ' Setup loop to receive the packet.
     
                            mov     buffer,            rate                            ' Waits 1/4 the baud rate. 250_000 BPS operation not possible
                            shr     rate,              #1                              '
                            sub     counter,           rate                            ' 230400 is still possible.
                            add     counter,           buffer                          '
                            waitcnt counter,           buffer                          '
    


    That should fix the problem. It ensures that you are sampling somewhere in the middle of each bit. The driver deos not care at what frequency it runs because it uses waitcnt to burn the extra time. So it does not become more accurate at lower frequencies.

    Try using a baud rate that is a perfect integer multiple of the clock. I'd had flawless result at 250000 bps. The maximum speed. I noticed that 230400 actually had a few corrupted bits on the hydra system. On the protobaord I've had no failures.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2009-08-13 14:27
    If I were you I would accept 2 stops bits and live with it. You'll spend ages trying to figure out what's wrong.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-13 14:34
    Kye, I've been studying your unaltered code some more and it is so close to working. I think I just need to understand it better.

    Ok, you test for the negative transition, start the counter and repeat 9x.

    Assuming it is roughly sampling in the middle of the bits, that should sample 8 bits. The 9th sample should put it in the middle of the stop bit, right?

    Now, do you just discard the value of the 9th sample which is the stopbit, right? Does REV do that somehow?

    Then - you have half a bit width to store everything and get back to the beginning of 'receiver' ready for the next transition.

    Can you explain how the
    jmpret receiverPC, transmiterPC ' Run some code.
    works?

    Are you jumping out and calling the whole transmit byte routine, or just one bit of it?

    I'm wondering if this would add more than half a bit width in the transmit code, and hence put the next sampling point too late for the negative transition?

    Just to reference this timing diagram again as it helps visualise things www.beyondlogic.org/serial/serial1.htm#40

    Actually, some even more basic questions.

    Is the 'waitcnt counter, rate' half or a full bit width?

    And
    waitcnt counter, rate ' Sync up with baud rate.

    if_z waitcnt counter, rate ' Adjust phase.

    where does the if_z come from and what does it do?

    Thanks heaps for the answers. I've got this working brilliantly on my N8VEM vb.net terminal program where I've added the tiny delays between each byte to emulate two stop bits. But it would be nice to have it working on generic terminal programs too.
  • KyeKye Posts: 2,200
    edited 2009-08-13 15:53
    I've gone through the piece of code and I can't see where the problem exist. The driver does take an extra bit period after it receives the final data bit to finish up house keeping task.

    This would be normally during the time the stop bit comes. The only thing the driver does oddly is to sample and start bit twice. The driver never inputs the stop bits. The Rev instruction throws away the start bit.

    The driver starts up sampling for the start bit again after the full stop bit period. I can't find this problem, sorry. You'll need to find it yourself.

    ...

    So the driver runs at 2x the baud rate. Thus each wait is half a bit width. All the waitcnt's with the if_z and stuff are to make sure the transmitter code is only run after 1 bit period passes. Trace the program execution from the test RXPin statements to see what I'm taking about.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-14 00:16
    Some more experiments and I think I can see a problem. Not sure about the solution yet.

    Ok, if delays are half a bit then the code starting at 'receive' will start somewhere between the beginning and half way through the start bit. It cycles 9 loops which should put it half way through the stop bit.

    Then it goes back to 'receiver'. In receiver there are two delays at the beginning so a full bit.

    If you have two stop bits, that puts it in the middle of the second stop bit and it will be ready to detect the next transition.

    BUT - if you have a continuous transmission with only one stop bit, the stop bit is actually also the next start bit. So it now finishes a bit late and ends up half way through the next start bit.

    So to test this theory out I modified the code so it returns and skips that 1 bit delay by jumping into the middle of the receiver code.
    receiver                rdlong  rate,              par                             ' Get new settings.  
                                                         
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                         
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
    
    rec2                    test    RXPin,             ina wz                          ' Wait for start bit.
    if_nz                   waitcnt counter,           rate                            '                        
    if_nz                   test    RXPin,             ina wc                          '         
    if_nz_and_c             jmp     #receiver                                          '
    
    ' //////////////////////Receiver Setup/////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     receiverCounter,   #9                              ' Setup loop to receive the packet.
    
    ' //////////////////////Receive Packet/////////////////////////////////////////////////////////////////////////////////////////
    
    receive                 test    RXPin,             ina wc                          ' Input bits. 
                            rcl     receiverBuffer,    #1                              '
    
                            waitcnt counter,           rate                            ' Sync up with baud rate.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
    
                            jmpret  receiverPC,        transmiterPC                    ' Run some code.
                                                                            
    if_nz                   waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            djnz    receiverCounter,   #receive                        ' Ready next bit.
                                                                           
    if_z                    waitcnt counter,           rate                            ' Adjust phase.
                                                                           
                            rev     receiverBuffer,    #24                             ' Reverse backwards bits.
    
    ' //////////////////////Update Packet//////////////////////////////////////////////////////////////////////////////////////////
       
                            rdbyte  receiverTail,      inputTailAddress                ' Update receiver tail.
                                                    
                            mov     buffer,            receiverHead                    ' Check if the buffer is full. 
                            sub     buffer,            receiverTail                    '
                            and     buffer,            #$FF                            ' 
                            cmp     buffer,            #255 wc                         '
    
    if_c                    mov     buffer,            inputBufferAddress              ' Set packet.
    if_c                    add     buffer,            receiverHead                    '
    if_c                    wrbyte  receiverBuffer,    buffer                          '
                                                    
    if_c                    add     receiverHead,      #1                              ' Update receiver head pointer.
    if_c                    and     receiverHead,      #$FF                            '                                                                  
    if_c                    wrbyte  receiverHead,      inputHeadAddress                '
    
    ' //////////////////////Repeat/////////////////////////////////////////////////////////////////////////////////////////////////
    
                            jmp     #rec2                                          ' Repeat.    
    
    



    Now, this does work better. Tested on Teraterm with 1 stop bit. It gets through about 12 packets before the number of packet errors goes >10 and xmodem fails.

    I think that is exactly what you would expect. If you are sending bytes individually, with longer delays between each byte, then it can resynch on each byte. But if the stream of data is more than one byte (xmodem is 132 bytes), and the sampling at the beginning of 'receiver' just happened to come just after the transition point (plus the tiny delay caused by sampling twice), then over the course of 132*9 bits I think the difference in clock rates could cause enough drift that the bits later in the packet get out of synch. xmodem has a checksum system so will reject these packets and ask for them to be resent.

    What I think needs to happen is that the code needs to resych on each byte and resynch more definitely in the middle of the bit. I think that might involve finer time slicing (maybe into 1/8ths) in the receiver code, so it is sampling the pin more frequently. Then when it detects the transition, just add in half a bit delay and head off into receive.

    Does this make sense? I'm just not sure how to write the finer timeslice code without upsetting any of the calls out to the transmitter code.
  • KyeKye Posts: 2,200
    edited 2009-08-14 01:41
    Good job. That would pretty much be an explination for driver.

    The trick you did however, will make the transmiter fail to work right. I would just reconmend you use two stop bits. That's what I tested the driver at.

    ...

    Try this. If you run the code at an integer divisor of the clkfreq you should have better results. Eg. (80_000_000 / 250_000BPS) = 320. Thus the driver has very little skew.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2009-08-14 02:07
    Man that is a problem with the code. And here I was thinking everything was fine. Well, there's not much I can do to fix the receiver with the way the code works. You would just need to sample the line more to receive more bytes in a row quickly.

    That said, more stop bits seem like the best solution. The driver runs in lockstep with the baud rate and because of this it is very tiny occupying only about 67 longs. But also it does not matter at what speed it runs as long as it can finish all task very quickly.

    So, if you want to make the driver sample the line more frequently you will reduce the maximum frequecny it can run at. Which reduces the maximum transmission frequency also. Addtionally more code will be needed.

    Sigh, if this driver were not full duplex everything would be simplier.

    So, the best solution is just to add more stop bits to give the driver a rest when it is receiving. 250_000 BPS is not actually the maximum speed. The driver can actually go much faster in different sernarios. I just decided to cap it there since that is the max freqeuncy a standard max232 can take.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • KyeKye Posts: 2,200
    edited 2009-08-14 02:25
    One more thing. the driver always waits one full stop bit period before starting to sample again. Your theory is not fully correct.
    Dr_Acula said...

    BUT - if you have a continuous transmission with only one stop bit, the stop bit is actually also the next start bit.
    Each byte should come as a 10 bit frame. If your stop bit is the next start bit then I most likely miss interpreted the serial protocool and thought that data was sent in frames and my driver completely ignores that. I can fix that however.

    This would more likely be the problem. Infact this would definately be the problem.

    I'll go research this right now... Was pretty sure that each byte should have a start bit and then a stop bit after it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-08-14 02:27
    James: What you have uncovered is definately a flaw with fdx code in general as it is the base of most of the code being used.

    For now, just use 2 stop bits until I get time to look at the code and try some other things. First up I will split the code into 2 cogs, one tx and 1 rx. That will not matter for ZiCog as we have cogs spare. Later I will see·if·I can combine back to 1 cog. However, remember, I want to run at 8MBs and pass status back and forth between props, so 2 cogs may be the way I have to go anyway. I·recall someone using the counters to transmit and that may be the way to go to fit it into a single cog.

    BTW, the stop bit is opposite polarity to the start bit.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBladeProp, RamBlade, TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80), MoCog (6809)
    · Search the Propeller forums (via Google)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-14 02:41
    Re my comment "BUT - if you have a continuous transmission with only one stop bit, the stop bit is actually also the next start bit. "

    Sorry, should rephrase that. The stop bit is the mark period that then leads into the next start bit.

    I think part of the problem is many descriptions of the waveform only have one byte. So

    en.wikipedia.org/wiki/Asynchronous_serial_communication

    10 bits. But as described in that article, you need to resynch on each high to low transition on the start bit for every byte. And I guess that means getting ready to resynch at least half way through the stop bit. Which as Kye says, might throw the Tx side out of synch...

    The full duplex is worth persevering with, as down the track it would be great to have several of these and if they only use one cog each.

    Post Edited (Dr_Acula) : 8/14/2009 3:34:53 AM GMT
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-14 03:14
    I think Kye might be right. Let's just use two stop bits.

    I can see the complexity in the Rx and Tx code when the Rx has to finish earlier than the Tx. You can't make the Tx stop bit any shorter, so the Tx and Rx code than has to be changed.

    But with two stop bits, it would add such an insignicant amount of time to file transfers.

    So, I thought of a plan. Add a bootup message to remind people to change the settings. The message will always go through because the Tx code is fine. 1 stop bit will be enough if the user is typing on the keyboard because there is a delay.

    So added a line to the spin code at bootup:
    UART.transmitCharacters(string("ZiCog v0.009 on the TriBladeProp v0.09x",13,10))
    UART.transmitCharacters(string("8 bit, parity=None, 2 stop bits, Flow control=None",13,10))

    I've saved that as the setting in my terminal programs.

    Next thing that is cool - using the board to improve itself. Debugging xmodem is a pain when you have to remove the sd card and remake an image. But now xmodem is working, we can send new versions with slightly different names via xmodem itself.

    I've been tweaking the variable msec in the code and recompiling on the PC using TASM. When xmodem starts up in receive mode it sends a NAK every few seconds. If it gets no reply after 10 tries it gives up. If you set the cycle time too short, there isn't enough time to go into the terminal menu and tell it what file you are sending. But too long, and you wait ages for the file transfer to start. I've tweaked it for this simulation so it checks every 4 seconds. So, average of only 2 seconds to wait for a transfer to start, but you have 40 seconds to put in the filename.

    And that works brilliantly in Teraterm (File/Transfer/Xmodem) and Hyperterminal too. BTW most windows installations have Hypterminal in the Start/Programs/Accessories menu.

    Message to Cluso: re However, remember, I want to run at 8MBs and pass status back and forth between props, so 2 cogs may be the way I have to go anyway. I recall someone using the counters to transmit and that may be the way to go to fit it into a single cog.

    That is a very fast speed? Is it needed? Just asking because even at 38400 baud for xmodem transfers, the biggest delay is not actually the transfer speed, but the read/write speed to the sd card. Any chance of speeding up the sd card transfers *please*?

    Post Edited (Dr_Acula) : 8/14/2009 3:37:54 AM GMT
  • KyeKye Posts: 2,200
    edited 2009-08-14 05:25
    **

    That is a very fast speed? Is it needed? Just asking because even at 38400 baud for xmodem transfers, the biggest delay is not actually the transfer speed, but the read/write speed to the sd card. Any chance of speeding up the sd card transfers *please*?

    **

    Using the new FSRW block driver underneath my file system maybe.

    **

    I spent some time making a half duplex version of this driver. I'm having problems getting it working with the FTDI driver however. More head bashing there as I have to keep the bits in different frames in synch while using a non sychronous protcool... (Bull****).

    Anyway, besides that fun. How should half duplex functionality work? For example. Should I try to receive a byte and then transmit a byte off and on for each frame? Or should I transmit all the bytes in a buffer before even thinking about receiving?

    I've already finished the base code to do this and I can get the speed up to about 1_000_000 MPBs but the spin interface will never reach that speed. Interested if you have any ideas about this. It will have the same interface.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-08-14 07:19
    Kye: I have just been looking at your SerialEngine code. It is similar to the FullDuplexSerial. However, the loop waiting for a received character is waiting a complete bit time. Unfortunately, your method cannot run full duplex because you cannot tie the transmit and receive character timing together. You have required this by using waitcnt. FDX does not do this, but rather samples the receive bit for a start.

    James: I think this problem has been introduced because the PC_keyboard.spin routine does not suffer from the above problem. If it still misses every second character, then there is another bug. I suggest since you have gone this deep, we should find the solution.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBladeProp, RamBlade, TwinBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: Micros eg Altair, and Terminals eg VT100 (Index) ZiCog (Z80), MoCog (6809)
    · Search the Propeller forums (via Google)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • KyeKye Posts: 2,200
    edited 2009-08-14 15:10
    My code does run at full duplex. That functionality I have tried out and it does work. The transmiter code always run at a complete bit time. The receiver code samples the line at half a bit time.

    The waitcnt, waits half a bit time. This gives the code enough time to jump in and out of the transmiter code while receiving.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-14 15:23
    Re Kye Anyway, besides that fun. How should half duplex functionality work? For example. Should I try to receive a byte and then transmit a byte off and on for each frame? Or should I transmit all the bytes in a buffer before even thinking about receiving?

    Well for the Zicog, it can be a lot simpler as you have the huge buffers. In fact, once a start bit comes in, you could go off and do receive code 100%, and just forget about Tx. Even receive an entire xmodem packet and not worry about Tx till there is a gap in the Tx. Just keep saving up the bytes in the Tx buffer.

    Hmm - but that won't work. What if you are half way through a Tx byte and a new Rx byte comes in. You still need the cunning time slicing bit by bit between Rx and Tx.

    And the dual uart in one cog is brilliant, because I have grand visions of adding more serial ports. Then you can do clever things like write a program to transfer one baud rate RS232 signal to a different baud rate signal. I don't know of anything that can do that easily (short of a PC).

    There has to be a cunning time slice solution to this. When I get a moment I might draw up the waveforms on a piece of paper. Sometimes the answer is easier to visualise that way.
  • KyeKye Posts: 2,200
    edited 2009-08-15 16:28
    Okay, I just rolled this out. Its a half duplex version of the driver.

    I tried a few 256 byte file transfers with it to stress the receiver and I had great results. I also reworked the transmiting nd receiving code so that the resoltuion for bit changes comes down to about (0.00000005) seconds so that the driver will transmit and receive better.

    I'll post a reworked version of the full duplex one soon also.

    ...

    Sadly I can't get above 250_000 BPS with this driver even though it can transmit at rates up to 1_000_000 BPS without crashing. I'm pretty sure the way I coded it is the best possible way using the propeller chip. Maybe the one instruction latency is too much. Not sure...

    Try baud rates above 250_000 BPS if you can.




    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-08-16 04:14
    Can't wait to get home and try this out. Thx++. As an aside, Kye, do you have a website where you have all your nifty code/objects in one place? Or are they on the obex (and search for your name or something?). I'd like to check out some of the other things you have written.
  • KyeKye Posts: 2,200
    edited 2009-08-16 04:28
    Look at the Obex. I have not posted much of what I have created.

    More will come in the future. I almost have the full duplex version working. The timing is really coming down to the wire however in clock cyles to get 250_000 BPS mode·working with no possibility for crashing.

    I already have 115200 BPS working and everything below. The new code is much more precise on control. No errors yet.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Nyamekye,
Sign In or Register to comment.