Shop OBEX P1 Docs P2 Docs Learn Events
Known error(s) of UART example TUT40 in Programming the SX Microcontroller — Parallax Forums

Known error(s) of UART example TUT40 in Programming the SX Microcontroller

FrasseFrasse Posts: 11
edited 2006-11-17 09:21 in General Discussion
Hi,

I have recently bought the book Programming the SX Microcontroller by Gunther Daubach.
My special interest, just now, is the UART implementation described in tutorial TUT40.
Has anyone else had problems with getting this to run cleanly?
I have used the sourcecode, downloaded from the Parallax site so there should not be any typos.
I have found one error myself in both the printed version and the downloaded code (if my math is correct) and that is in the values for various baud rates.
For 9600 baud the value for start_delay should read 32 + 16 + 1 instead of the shown 16+8+1.
I have however tried the program using different baudrates and none seem to work.
At reset it will produce garbage output, seemingly at random.
By commenting out the call get_byte in the main program loop, it will stop the seemingly random output and instead, after each reset, it will provide an output with some similarities of the expected hello string, but with a majority of the characters garbled.
Apart from altering the value for start_delay for the 9600 baud setting, my only change is that the VP is connected to a MAX232 driver circuit. As this will invert the signals I have tried removing the negation of the signal in the movb tx_pin,/tx_low.6 statement but this does not make any visual difference. Any and all help would be appreciated.

Regards
Frasse

Comments

  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2006-11-15 17:28
    Frasse,

    unfortunately, there is a typo in my book text and in the TUT40.SRC code. You are right, for 9600 Baud, the definition of start_delay must read 32+16+1 instead of 16+8+1 (which is the definition for 19,200 Baud).

    Besides this, I'm using a similar code in many of my own applications without having problems. For a step-by-step start, I'd recommend that you first test the transmitter code, i.e. comment out the receiver code in the ISR, as the transmitter is the easier part.

    When you have attached a MAX232, make sure that the SX pin driving the MAX232 transmitter input is initialized to high at reset. Tthis will let the MAX 232 output a negative (idle) signal on the associated TxOut pin. In the ISR, don't invert tx_low.6, as shown in line 12 of TUT40.SRC. When setting up for transmitting, like shown in send_byte (lines 32, ff. in TUT40.SRC), don't invert the byte to be sent (i.e. comment out the "not w" instruction at line 35), and simply clear tx_low, instead of setting bit 7, as shown in line 37.

    For a first test, I would let the main program run in a loop, checking tx_count. When tx_count holds zero, the transmitter is no longer busy, so you can prepare it to send a new character. Move some ASCII code into tx_high (e.g. $41 for 'A'), clear tx_low, and finally set tx_count to #10.. Then re-enter the loop waiting for tx_count to reach 0. This should send out a continouous string of characters. When you have connected the MAX 232 to a PC's COM port, you should be able to verify this with HyperTerminal, or any other terminal program.

    This is the way how I test serial output from the SX, and I hope it works for you as well.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • FrasseFrasse Posts: 11
    edited 2006-11-15 22:40
    Gunther (sorry can't find the umlaut on my keyboard)

    Thanks for your tips on faultfinding the UART VP.

    I did as you told me, stripped down the code to a bare minimum. Then I removed the inversion of the character to be sent to compensate for the inversion made by the MAX232. (I am sticking to setting the bit 7 of tx_low as I did not understand the reasoning for clearing the byte altogether.)
    I wrote a small main routine to set up the input parameters required for the transmit routine and tried it out. No luck.
    I tried some alterations, like clearing tx_low altogether, checking the code for the umpteenth time but to no avail.

    However, depending on what value I load into tx_high, I either get a character (not the correct one, but still) repeated at fast pace.
    Negating the value loaded into tx_high, (incorporating a not w after initial character definition) will only give me spurious characters (not the anticipated one) and only after a reset.

    I'm totally dumbfounded by this.

    Can I ask you to have a look at the program which is attached to this post? I would be ever so greatful.

    Best regards
    Frasse
  • FrasseFrasse Posts: 11
    edited 2006-11-15 23:09
    Gunther,

    I found the problem of my stripped transmit routine!
    I forgot to set the return value before issuing the retiw in the interrupt routine.
    I also found out that it is necessarry to do a not w for the character value before loading it into tx_high and then in the interrupt routine send the inverted value by using movb tx_pin, /tx_low.6 (as it said in the original program) despite me using an inverting RS-232 driver.

    Anyway, this is it for tonight, I'll continue with the receiver routine tomorrow, now that I got something to work with.

    Once again, thanks for your help!

    Best regards
    Frasse
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2006-11-16 11:36
    Frasse,

    ok, you found one important bug by yourself - the missing initialization of w before the RETIW instruction. This caused RTCC to be modified by whatever was in w, so the ISR timing was definitely wrong.

    Now let's look at the voltage levels. When you pull a MAX232 Tin line low, the assoviated Tout line goes to a positive level (approx. +9V), and when you pull the input high, the output goes to a negative Level (-9V). The idle state on an RS-232 line is the negative level. So when you connect an SX output pin to a MAX232 Tin pin, the SX pin should be set to high for idle (see line 14 in the code sample).

    Each transmission must begin with a start bit, i.e. the RS-232 line must go to positive level for one bit period, i.e. the SX pin must go low for the start bit (see the diagram at the beginning of the code sample). The start bit is followed by eight data bits. Note that they are in "reverse order", i.e. bit 0 first, bit 7 last. Bit 7 must be followed by at least one stop bit, i.e. the RS-232 line must go to negative level, so the SX pin must go high.

    To serialize the data, you would use a shift register in hardware. Here, we use SX registers, and rotate instructions to perform this task. The SX registers are 8 bits wide, i.e. wide enough to hold the data bits to be transmitted but each serial character actually contains 10 bits (the start bit, 8 data bits, and the stop bit). The UART VP code handles this quite tricky (the original code was written by Chip Gracey, who is a real specialist in writing "tricky" but compact and fast code smile.gif ).

    Important for the serialization are the two TxHigh and TxLow registers AND the carry flag. If you look at line 11 in the code sample, you see that bit 6 in TxLow is transferred to the SX output pin. IOW, TxLow.6 is our "UART output". Before TxLow.6 is copied to the output pin, there are three important instructions in lines 7, 8, an 9: In line 7, the carry flag is set - as you will see, this becomes our stop bit later. Next TxHigh is rotated right, i.e. the carray flag is moved into TxHigh.7, and TxHigh.0 (i.e. data bit 0) is moved into the carry flag. As the carry flag was set before, TxHigh.7 is set now. Next, TxLow is rotated right. So, TxLow.7 is moved into TxLow.6, and the carry flag (i.e. data bit 0) is moved into TxLow.7 As TxLow was cleared in the main program, TxLow.7 was 0 before the rotate right, so TxLow.6 is low now. (BTW, it does not matter if you clear TxLow in the main program, or if you do a clrb TxLow.7, as only bits 7 and 6 in TxLow are of importance here).

    After the two rotates, TxLow.6 is copied to the output pin, so it goes low then. Eight more rotate rights are neccessary to shift the eight data bits from TxHigh through TxLow.6, and to output them. After these eight rotate rights, the former TxHigh.7 bit that was set on the first rotate rights for the start condition has "arrived" in TxLow.7. The final rotate rights move it into TxLow.6, our "output bit", so the output pin will go high for the stop bit. This is why it is so important to set the carry flag in line 7. Although it is not neccessary to set the carry flag before each rotate, it does not harm if it is done in order to simplify the code.

    In the original UART code, Chip used "negative logic", i.e. movb TxDpin, /TxLow.6 to output the bits. In order to get the right polarity for the start bit and the data bits, you must setb TxLow.7, and move the inverted data byte into TxHigh in this case, when preparing the transmitter. In order to get the stop bit right, it is also neccessary to clear the carry flag in line 7 instead of setting it.

    I have copied the code snippets, below, from one of my applications that make use of a MAX232:

    ; 19,200 Baud @ 50 MHz system clock
    
    BaudBit           = 4
    IntPeriod         = 163
    
                        ORG 0
    ISR
    
       bank  Serial
    
    ;              Data Bits
    ;          0 1 2 3 4 5 6 7 
    ;  _____   _ _ _ _ _ _ _ _ _
    ;       |_|_|_|_|_|_|_|_|_|
    ;        ^                 ^ 
    ;        |                 |
    ;      Start             Stop
    
    :Transmit
        clrb  TxDividePC.BaudBit                     ; 1 clear xmit timing count flag
        inc   TxDivide                               ; 2 only execute the transmit routine
        stz                                          ; 3 set zero flag for test
        snb   TxDivide.BaudBit                       ; 4 every 2^baud_bit interrupt
         test  TxCount                               ; 5 are we sending?
        jz    :ExitInt                               ; 6 if not, go to next VP
        stc                                          ; 7 Yes, ready stop bit
        rr    TxHighPC                               ; 8 and shift to next bit
        rr    TxLowPC                                ; 9
        dec   TxCount                                ;10 decrement bit counter
        movb  TXDpin, TxLow.6                        ;11 output next bit
        
    :ExitInt
        mov     w, #-IntPeriod                       ;12
        retiw                                        ;13
        
    
    Main
    
    ; Initializations go here...
    
        setb    TxDpin                              ;14 Make sure that TxD is idle      
        
    ; Sample to send an endless stream of "X"es     
        
    :Loop       
        bank    Serial                              ;15
        mov     TxHigh, #'X'                        ;16
        clr     TxLow                               ;17
        mov     TxCount, #10                        ;18
    :WaitTx
        test    TxCount                             ;19
        sz                                          ;20
          jmp   :WaitTx                             ;21
        jmp     :Loop                               ;22
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
  • FrasseFrasse Posts: 11
    edited 2006-11-16 19:41
    Gunther,

    Thanks a lot for your very lucid and in depth explanation of the UART transmitter with driver problem I had.
    It now works like a charm with both transmitter and receiver.
    I am now back to the book to learn some more of the good stuff you put in there.

    Keep the good work up!

    Regards
    Frasse
  • Guenther DaubachGuenther Daubach Posts: 1,321
    edited 2006-11-17 09:21
    Frasse,

    I'm glad to hear that your code now works as expected. BTW, I found a typo in the sample code I had posted last time: The little graphic at the beginning of the code showed nine data bits (0...8) instead of eight (0...7) as it should be. In the meantime, I have edited the post to fix it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Greetings from Germany,

    G
Sign In or Register to comment.