6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Jul 12, 2024 4:52 am

All times are UTC




Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Problematic UART
PostPosted: Fri Jun 09, 2017 4:28 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
So... the UART on my SBC works beautifully.

Except for one teeny tiny problem.

It won't change baud rate. For the longest time I thought it was just plain busted, but I finally hooked up an oscilloscope to it and discovered that its running at a baud rate of 14375. As soon as I switched the terminal emulator on the PC to that baud rate, works perfectly.

I cannot for the life of me figure out why I can't set the baud rate. As best as I (and one my lecturers) can tell I'm following the datasheet to the letter, but regardless of what divisor I write into the divisor latches, nothing changes. Every other aspect of the UART is working perfectly as best as I can tell, so I don't think I managed to zap it with ESD as I wouldn't expect ESD problems to manifest so specifically.

The UART I'm using is an NXP SC16C550BIB48 (datasheet). You can see how its wired in using the schematic etc Here.

I'm copying in the complete source code below just in case the problem is in a far off region I hadn't considered, but the directly relevant setup code is the block underneath the "; Initial setup of the UART" comment. Please excuse my sawdust, this is literally the in-development-code I have right now exactly as it is.

uarttest.asm
Code:
; FPGA-6502 Test Computer Test BIOS#2
; UART Test.
; Copyright (C) Nicholas Parks Young, 2017. All Rights Reserved.
; Version 20170601
;

   INCLUDE "definitions.asm"
   INCLUDE "wozprint.asm"

  CODE
RstHandler:
    ; Just arrived here from a RESET condition. The following is known:
    ; Status Register P:  NF=?, VF=?, 5F=1, BF=1, DF=0, IF=1, ZF=?, CF=?
    ; Program Counter PC: RSTHandler
    ; All other flags and registers are undefined. We must define them.
   
    ; Define all the undefined things.
    STZ     biosStatus      ; Reset BIOS status bits - in particular bit 0, which indicates successful initialisation.
    SEI                   ; Disable Interrupts -> IF=1
    CLD                   ; Disable Decimal mode -> DF=0
    LDX    #$FF           ; Set X=FF
    TXS                   ; Copy X to S -> S=FF
    INX                   ; Increment X -> X=0
    TXA                   ; Copy X to A -> A=0
    TAY                   ; Copy A to Y -> Y=0, NF=0, ZF=1
    CLC                   ; Clear Carry flag -> CF=0
    CLV                   ; Clear Overflow flag -> VF=0
    ; Processor is now in the following known state:
    ; P: NF=0, VF=0, 5F=1, BF=1, DF=0, IF=1, ZF=1, CF=0
    ; A=0
    ; S=FF
    ; X=0
    ; Y=0
   
    ; Initial setup of the VIA.
    LDA     #$FF            ; Ensure all interrupt flags are cleared.
    STA     VIA_IFR
    LDA     #IER_CLEAR|INT_T2|INT_CB1|INT_CB2|INT_CA1|INT_CA2|INT_SR
    STA     VIA_IER         ; Ensure all interrupts we're not currently using are disabled.
    LDA     #IER_SET|INT_T1
    STA     VIA_IER         ; Ensure the interrupts we are using are enabled.
   
    STZ     VIA_PCR         ; Set all Cxx pins to input/negative-edge.
   
    LDA     #%10111111      ; Setup port B - everything is an output except SPIMISO...
    STA     VIA_DDRB
    LDA     #%00011100      ; Set initial output states for Port B. ~SPICSx lines are inactive(high)
    STA     VIA_ORB         ; For SERDir (bit7), LOW is output, HIGH is input.
   
    LDA     #$FF            ; Set port A direction register to all outputs
    STA     VIA_DDRA
    STZ     VIA_ORA         ; Set port A outputs to all low
   
    LDA     #T1_CONTI|T2_TIMED|SR_DISABLED|NOLATCH_PB_CB1|NOLATCH_PA_CA1
    STA     VIA_ACR         ; Set Timer 1 to generate interrupts as specified by T1 Latches.

    LDA     #$40            ; 0x9C40 = 40000. Note little-endian as timing starts on write to VIA_T1CH.
    STA     VIA_T1CL        ; T1 is set to generate interrupts at PHI2/Latches intervals. Effectively
    LDA     #$9C            ; I'll get a T1 interrupt every 40/20ms (for 1MHz/2MHz respectively)
    STA     VIA_T1CH
   
    ; Initial setup of the UART
    STZ     biosCharsRcvd   ; Clear the characters received counter.
    STZ     biosCharsRcvd+1
   LDA     #$83          ; Enable access to DLL/DLM, set parity to off, set word length to 8 bits, 1 stop bit.
    STA     UART_LCR
   LDA     #12             ; Set DLL/DLM to 12(decimal). This divisor gives 9600 baud with 1.8432MHz crystal.
   STA     UART_DLL
    STZ     UART_DLM      
   LDA     #$03          ; Disable access to DLL/DLM, set parity to off, set word length to 8 bits, 1 stop bit.
   STA     UART_LCR
   LDA     #$23          ; Set Auto-RTS/CTS to On, DTR = active.
   STA     UART_MCR
   LDA     #$01          ; Enable FIFOs. Must be done before setting other FCR bits.
   STA     UART_FCR
   LDA     #$C7          ; FIFO Trigger level = 14 bytes, DMA Mode = off. Reset FIFOs.
   STA     UART_FCR
   LDA     #$09          ; Enable interrupt on FIFO trigger level and MSR change.
   STA     UART_IER

   SMB0    <biosStatus     ; We've finished setting up, so we can set the "setup" status flag
    CLI                     ; Enable interrupts.

?BusyWait:
    WAI                     ; Wait for an interrupt to happen
    JMP     ?BusyWait       ; After interrupt has been serviced, go back to waiting.
   
NmiHandler:

    ; If the "setup" status bit is clear, skip NMI routine.
    BBR0    <biosStatus, ?HandlerEnd
   
    ; If the DCD/DSR active bit is clear, skip NMI routine.
    ;BBR1    <biosStatus, ?HandlerEnd
   
    ; Wait until the UART TX FIFO is completely cleared, just in case.
    ; To do this, check LSR[6] -> V Flag -> 0 = TX FIFO Not Empty.
?BusyWait:
    ;BIT     UART_LSR        ; Copy LSR[6] into V Flag
    ;BVC     ?BusyWait       ; If V Flag is clear (which is true if the TX FIFO is non-empty), go to ?BusyWait

    PHA                     ; Preserve A
   
   ; Print number of chars received to the UART.
    LDA     biosCharsRcvd+1 ; Load High Byte First (little-endian)
    JSR     PrintHex        ; Print hex bytes
    LDA     biosCharsRcvd   ; Load Low Byte Second
    JSR     PrintHex        ; Print hex bytes

    PLA                     ; Restore A

?HandlerEnd:
    RTI

IrqHandler:
    PHA             ; Save accumulator
    PHX             ; Save X
   
    ; Check if interrupt came from VIA T1.
    LDA     VIA_IFR         ; Get the Interrupt Flag Register from the VIA.
    BIT     #IFR_IRQACTIVE|INT_T1    ; Mask the IFR so that ZF=0 if Timer1 triggered the interrupt.
    BEQ     ?UartIrq        ; If ZF=1 its not the VIA's T1, so next we'll check the UART.

; Interrupt came from VIA T1.
?ViaIrqTimer1:
    LDA     VIA_ORA         ; Get current state of output port A
    EOR     #%00000001      ; Flip bit 0
    STA     VIA_ORA         ; Put it back.
    LDA     #$FF            ; Clear the interrupt from the VIA's IFR register.
    STA     VIA_IFR         ; I'm clearing all the flags even though it should only be T1, just in case.
    JMP     ?IrqHandlerEnd  ; Job done.

; Interrupt came from the UART (probably)   
?UartIrq:

   ; Jump to the appropriate handler given the UART's ISR status.
   LDA     UART_ISR
   AND     #$0F   ; Mask out the four high bits which we're not interested in.
   ASL     A      ; Shift one left because addresses are 2 bytes, not one.
   TAX       
   JMP     (?UartIrqJumpTable, X)
   KDATA
     ?UartIrqJumpTable:
     dw  ?UartMsrChangeHandler       ; ISR[3:0] = 0000 = MSR has changed
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 0001 = No UART Interrupt
     dw  ?UartTransmitterEmptyHandler   ; ISR[3:0] = 0010 = Transmitter FIFO is Empty
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 0011 = No UART Interrupt
     dw  ?UartDataFullHandler          ; ISR[3:0] = 0100 = Receiver FIFO is Full.
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 0101 = No UART Interrupt
     dw  ?UartDataReceivedHandler      ; ISR[3:0] = 0110 = Some data has been received
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 0111 = No UART Interrupt
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1000 = Invalid
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1001 = No UART Interrupt
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1010 = Invalid
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1011 = No UART Interrupt
     dw  ?UartDataTimeoutHandler      ; ISR[3:0] = 1100 = Data in Receiver FIFO and timeout period elapsed
     dw  ?IrqHandlerEnd             ; ISR[3:0] = 1101 = No UART Interrupt
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1110 = Invalid
     dw  ?IrqHandlerEnd            ; ISR[3:0] = 1111 = No UART Interrupt
   ENDS

; MSR status has changed. Investigate DSR & DCD state.
?UartMsrChangeHandler:
   LDA     #$A0         
   CMP     UART_MSR      ; ZF=1 if both DSR and DCD are "low".
    BNE     ?SkipBitSet     ; If ZF=0 (DSR or DCD inactive) branch then skip the bit set
   SMB1    <biosStatus     ; If ZF=1 then set bit 1 of biosStatus to indicate DSR&DCD are active.
?SkipBitSet:
    BEQ     ?SkipBitReset   ; If ZF=1 branch skip the bit clear
    RMB1    <biosStatus     ; If ZF=0 then clear bit 1 of biosStatus to indicate DSR&DCD are inactive.
?SkipBitReset:
   JMP     ?UartIrq       ; Keep repeating until all UART interrupts are serviced.

; Received some data that is to be processed.
?UartDataFullHandler:
?UartDataTimeoutHandler:
   LDA     #$01         ; Set ZF=0 if LSR[0] = 1; ZF=1 if LSR[0] = 0.
   BIT     UART_LSR      
   BEQ       ?IrqHandlerEnd   ; If ZF=1 then LSR=0 so no data -> skip to end.
   
   CLC                   ; Add 1 to character counter (16-bit little-endian)
   LDA     #$01
   ADC     biosCharsRcvd   ; Low byte has one added
    STA     biosCharsRcvd   ; Store result back
   LDA     #$00            ; Add the carry result flag to the high byte
   ADC     biosCharsRcvd+1
    STA     biosCharsRcvd+1 ; Store the resulting high byte back
   
    ; Echo the char
   LDA     UART_RHR      ; Copy received byte from RX FIFO into RegA.
    ; If DSR/DCD are inactive, skip to end dropping the received char.
   ; BBR1    <biosStatus, ?IrqHandlerEnd
   STA     UART_THR      ; Echo byte back by writing to TX FIFO

   JMP     ?UartIrq         ; Keep repeating until all UART interrupts are serviced.
   
?UartTransmitterEmptyHandler:   ; Not used, interrupt should be disabled. Fall through to end.
?UartDataReceivedHandler:      ; Not used, interrupt should be disabled. Fall through to end.
?IrqHandlerEnd:
    PLX             ; Restore X
    PLA             ; restore accumulator
    RTI             ; return from interrupt
   
  ENDS
   
BIOSVECT SECTION OFFSET BIOSVCT_BASE
    dw  NmiHandler
    dw  RstHandler
    dw  IrqHandler
  ENDS

  END


definitions.asm
Code:
; FPGA-6502 Test Computer Test BIOS#2
; Common Definitions & Setup
; Copyright (C) Nicholas Parks Young, 2017. All Rights Reserved.
; Version 20170531

  SPACES ON                 ; Fix stupid comments behaviour
  CHIP W65C02S              ; This is designed for the WDC W65C02S
  LONGA OFF                 ; As we're using the W65C02S, Long Accumulator is not possible
  LONGI OFF                 ; As we're using the W65C02S, Long Immediates are not possible
  CASE ON                   ; Make sure everything is case sensitive
  CHKIMMED OFF              ; Allow immediate values to be truncated
  EXTERNS OFF               ; Make sure that we need to explicitly declare XREFs
  RADIX 10                  ; Use Decimal by default
  BIT7 OFF                  ; Do not set the 7th bit for ASCII bytes.
  SQUOTE OFF                ; Require a closing quote for string literals.
  TWOCHAR OFF               ; Do not convert two letter short codes into ASCII bytes. Counter-intuitive.
  ARGCHK ON                 ; Verify number of arguments to macro calls.
  MACFIRST OFF              ; Don't allow macro names to override opcode, directive or section names.
  PL 61                     ; Page length for Listing is 61 lines
  PW 132                    ; Page width for Listing is 132 characters
  TOP 0                     ; Insert no extra blank lines on each page of a listing.
  ASCLIST ON                ; Make sure complete data is shown in listing.
 
; Define the various regions of the address for the FPGA-6502 Test Computer.
; Use these to define sections, etc.
PAGEZERO_BASE equ $0        ; Page zero is 0 to 0xFF (256 bytes)
PAGEZERO_SIZE equ 256
HWSTACK_BASE  equ $100      ; Hardware Stack is 0x100 to 0x1FF (256 bytes)
HWSTACK_SIZE  equ 256
SWSTACK_BASE  equ $200      ; Software Stack is 0x200 to 0x2FF (256 bytes)
SWSTACK_SIZE  equ 256
BIOSRAM_BASE  equ $300       ; RAM Space reserved for BIOS (768 bytes)
BIOSRAM_SIZE  equ 768
RAM_BASE      equ $600      ; General Purpose RAM is 0x600 to 0x3FFF (14.5KiB)
RAM_SIZE      equ 14848
CARTROM_BASE  equ $4000     ; Cartridge ROM is 0x4000 to 0xBFFF (32KiB)
CARTROM_SIZE  equ 32768
VIAREG_BASE   equ $C000     ; VIA I/O device registers 0xC000 to 0xC00F
VIAREG_SIZE   equ 16
UARTREG_BASE  equ $C400     ; UART I/O device registers 0xC400 to 0xC407
UARTREG_SIZE  equ 8
BIOSROM_BASE  equ $E000     ; BIOS ROM is 0xE000 to 0xFEFF
BIOSROM_SIZE  equ 8186
BIOSVCT_BASE  equ $FFFA     ; BIOS Routine Vectors. Note: Interrupt Vectors are at 0xFFFA to 0xFFFF
BIOSVCT_SIZE  equ 6         ; Note: this is physically a part of the BIOS ROM

; VIA registers
; see datasheet for W65C22S:
; http://www.westerndesigncenter.com/wdc/documentation/w65c22.pdf
VIAREG SECTION REF_ONLY
  ORG VIAREG_BASE
VIA_ORB                     ; Output Register for Port B (write)
VIA_IRB     db              ; Input Register for Port B (read)
VIA_ORA                     ; Output Register for Port A (write)
VIA_IRA     db              ; Input Register for Port A (read)
VIA_DDRB    db              ; Data Direction Register for Port B
VIA_DDRA    db              ; Data Direction Register for Port A
VIA_T1CL    db              ; Timer 1 Low-Order Latches (write); Timer 1 Low-Order Counter (read)
VIA_T1CH    db              ; Timer 1 High-Order Counter
VIA_T1LL    db              ; Timer 1 Low-Order Latches
VIA_T1LH    db              ; Timer 1 High-Order Latches
VIA_T2CL    db              ; Timer 2 Low-Order Latches (write); Timer 2 Low-Order Counter (read)
VIA_T2CH    db              ; Timer 2 High-Order Counter
VIA_SR      db              ; Shift Register
VIA_ACR     db              ; Auxiliary Control Register
VIA_PCR     db              ; Peripheral Control Register
VIA_IFR     db              ; Interrupt Flag Register
VIA_IER     db              ; Interrupt Enable Register
VIA_ORA_NH                  ; Output Register for Port A (write), No Handshake
VIA_IRA_NH  db              ; Input Register for Port A (read), No Handshake
  ENDS

; VIA Constants
CB2_IN_NEG        equ %000<<5     ; PCR - Input-negative active edge on CB2
CB2_IN_NEG_IND    equ %001<<5     ; PCR - Independent interrupt input-negative edge on CB2
CB2_IN_POS        equ %010<<5     ; PCR - Input-positive active edge on CB2
CB2_IN_POS_IND    equ %011<<5     ; PCR - Independent interrupt input-positive edge on CB2
CB2_OUT_HANDSHAKE equ %100<<5     ; PCR - Handshake Output on CB2
CB2_OUT_PULSE     equ %101<<5     ; PCR - Pulse output on CB2
CB2_OUT_LOW       equ %110<<5     ; PCR - Low output on CB2
CB2_OUT_HIGH      equ %111<<5     ; PCR - High output on CB2
CB1_NEG           equ %0<<4       ; PCR - Negative active edge on CB1
CB1_POS           equ %1<<4       ; PCR - Positive active edge on CB1
CA2_IN_NEG        equ %000<<1     ; PCR - Input-negative active edge on CA2
CA2_IN_NEG_IND    equ %001<<1     ; PCR - Independent interrupt input-negative edge on CA2
CA2_IN_POS        equ %010<<1     ; PCR - Input-positive active edge on CA2
CA2_IN_POS_IND    equ %011<<1     ; PCR - Independent interrupt input-positive edge on CA2
CA2_OUT_HANDSHAKE equ %100<<1     ; PCR - Handshake Output on CA2
CA2_OUT_PULSE     equ %101<<1     ; PCR - Pulse output on CA2
CA2_OUT_LOW       equ %110<<1     ; PCR - Low output on CA2
CA2_OUT_HIGH      equ %111<<1     ; PCR - High output on CA2
CA1_NEG           equ %0          ; PCR - Negative active edge on CA1
CA1_POS           equ %1          ; PCR - Positive active edge on CA1
T1_TIMED          equ %00<<6      ; ACR - Timed interrupt each time T1 is loaded.
T1_CONTI          equ %01<<6      ; ACR - Continuous interrupts on T1.
T1_TIMED_ONESHOT  equ %10<<6      ; ACR - Timed interrupt each time T1 is loaded, with one shot output on PB7
T1_CONTI_SQUAREW  equ %11<<6      ; ACR - Continuous interrupts on T1, with square wave output on PB7
T2_TIMED          equ %0<<5       ; ACR - Timed interrupt on T2
T2_COUNT_PB6      equ %1<<5       ; ACR - Decrement T2 on negative pulse on PB6
SR_DISABLED       equ %000<<2     ; ACR - Shift Register disabled
SR_IN_T2          equ %001<<2     ; ACR - Shift in under control of T2
SR_IN_PHI2        equ %010<<2     ; ACR - Shift in under control of System Clock
SR_IN_CB1         equ %011<<2     ; ACR - Shift in under control of External Clock on CB1
SR_OUT_T2_FREE    equ %100<<2     ; ACR - Shift out free running at T2 rate
SR_OUT_T2_CTRL    equ %101<<2     ; ACR - Shift out under control of T2
SR_OUT_PHI2       equ %110<<2     ; ACR - Shift out under control of System Clock
SR_OUT_CB1        equ %111<<2     ; ACR - Shift out under control of External Clock on CB1
LATCH_PA_CA1      equ %1          ; ACR - Enable latching input data on Port A on CA1 active transition
LATCH_PB_CB1      equ %1<<1       ; ACR - Enable latching input data on Port B on CB1 active transition
NOLATCH_PA_CA1    equ %0          ; ACR - Disable latching input data on Port A on CA1 active transition
NOLATCH_PB_CB1    equ %0<<1       ; ACR - Disable latching input data on Port B on CB1 active transition
IER_CLEAR         equ %0<<7       ; IER - Disable corresponding interrupts:
                                  ; e.g. IER_CLEAR|INT_T1|INT_T2 will disable T1 and T2 interrupts.
IER_SET           equ %1<<7       ; IER - Enable corresponding interrupts:
                                  ; e.g. IER_SET|INT_T1|INT_T2 will disable T1 and T2 interrupts.
IFR_IRQACTIVE     equ %1<<7       ; IFR - Bit is set if any triggered but uncleared interrupts in VIA
INT_T1            equ %1<<6       ; IFR/IER - Bit corresponding to Timer 1 interrupt
INT_T2            equ %1<<5       ; IFR/IER - Bit corresponding to Timer 2 interrupt
INT_CB1           equ %1<<4       ; IFR/IER - Bit corresponding to CB1 interrupt
INT_CB2           equ %1<<3       ; IFR/IER - Bit corresponding to CB2 interrupt
INT_SR            equ %1<<2       ; IFR/IER - Bit corresponding to Shift Register interrupt
INT_CA1           equ %1<<1       ; IFR/IER - Bit corresponding to CA1 interrupt
INT_CA2           equ %1          ; IFR/IER - Bit corresponding to CA2 interrupt

; UART registers
UARTREG SECTION REF_ONLY
  ORG UARTREG_BASE
UART_DLL                    ; Baud Rate Divisor Latch, LSB (only when LCR[7]=1)
UART_RHR                    ; Receive Holding Register (read)
UART_THR    db              ; Transmit Holding Register (write)
UART_DLM                    ; Baud Rate Divisor Latch, MSB (only when LCR[7]=1)
UART_IER    db              ; Interrupt Enable Register
UART_ISR                    ; Interrupt Status Register (read)
UART_FCR    db              ; FIFO Control Register (write)
UART_LCR    db              ; Line Control Register
UART_MCR    db              ; Modem Control Register
UART_LSR    db              ; Line Status Register (read)
UART_MSR    db              ; Modem Status Register (read)
UART_SPR    db              ; Scratchpad Register
  ENDS

; UART Constants
  ; To Do.
 
; SPI Registers
  ; To Do

; SPI Constants
  ; To Do

; SER Registers
  ; To Do

; SER Constants
SER_READ    equ %1<<7
SER_WRITE   equ %0<<7
  ; To Do.

; Non-hardware numbers.
CART_SIG_VAL  equ   $55AA
CART_SIG_LOC  equ   CARTROM_BASE
CART_SIG_SIZ  equ   2
 
  PAGE0
biosCharsRcvd       dw  ; 16-bit counter for number of received characters.
biosStatus          db  ; Bitfield for internal status flags
                        ; bit 0: 1 = Setup complete
                        ; bit 1: 1 = DSR/DCD active
  ENDS


wozprint.asm
Code:
; Adapted from code in the Apple 1 WOZ Monitor source:
; http://www.sbprojects.com/projects/apple1/wozmon.txt

;-------------------------------------------------------------------------
;  Subroutine to print a byte in A in hex form (destructive)
;-------------------------------------------------------------------------

PrintHex:       PHA                     ; Save A for LSD
                LSR
                LSR
                LSR                     ; MSD to LSD position
                LSR
                JSR     ?PRHEX          ; Output hex digit
                PLA                     ; Restore A

; Fall through to print hex routine

;-------------------------------------------------------------------------
;  Subroutine to print a hexadecimal digit
;-------------------------------------------------------------------------

?PRHEX:         AND     #%00001111      ; Mask LSD for hex print
                ORA     #"0"            ; Add "0"
                CMP     #"9"+1          ; Is it a decimal digit?
                BCC     ?ECHO           ; Yes! output it
                ADC     #6              ; Add offset for letter A-F

; Fall through to print routine

;-------------------------------------------------------------------------
;  Subroutine to print a character to the terminal
;-------------------------------------------------------------------------

?ECHO           STA     UART_THR        ; Output character.
                RTS

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Fri Jun 09, 2017 5:55 pm 
Offline

Joined: Thu Mar 03, 2011 5:56 pm
Posts: 280
14375 is what you'd get if you supplied a divisor of 8 (dll=8 , dmm=0)... do you see any indication that data bit 2 is not connected to the UART?

Alternatively, could it be that you need to allow the UART a few idle cycles after changing the LCR setting (by adding a few NOPs in you init code)?


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Fri Jun 09, 2017 6:16 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
Only some suggestions (where I would looking):
- the crystal is running at its nominal frequency (UART pin 15)?
- assemblers output against input ?
- (EP)ROM dump = assembly ?

edit(1):
if s.th. with DB7 isn't ok, you can't set LCR7 => can't change baudrate. Can you transmit s.th. with bit 7 set to your terminal and check what you get?


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Fri Jun 09, 2017 7:19 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
GaBuZoMeu wrote:
the crystal is running at its nominal frequency (UART pin 15)?

Yep, first thing I checked.

Quote:
assemblers output against input ?
(EP)ROM dump = assembly ?

Not specifically checked these, but I'd be surprised in both cases. In the former case I'm using the WDC official assembler, in the latter because I would expect problems writing the EEPROM to manifest more significantly than this relatively minor issue and my ROM Programmer automatically verifies writes on the fly.

GaBuZoMeu wrote:
if s.th. with DB7 isn't ok, you can't set LCR7 => can't change baudrate. Can you transmit s.th. with bit 7 set to your terminal and check what you get?

Interestingly, I do have a bug where the print that happens on NMI sometimes has the highest bit set on printed characters, for no apparent reason. Perhaps I need to investigate how good the connections are on DB7....

rwiker wrote:
14375 is what you'd get if you supplied a divisor of 8 (dll=8 , dmm=0)... do you see any indication that data bit 2 is not connected to the UART?

I think if it weren't the ASCII output characters would also be garbage. Nevertheless when I check DB7 I'll double check all of the databus.

rwiker wrote:
Alternatively, could it be that you need to allow the UART a few idle cycles after changing the LCR setting (by adding a few NOPs in you init code)?

I had the same thought too, but I havn't actually tried it yet as the datasheet doesn't say that it needs a delay.

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Fri Jun 09, 2017 8:22 pm 
Offline
User avatar

Joined: Wed Mar 01, 2017 8:54 pm
Posts: 660
Location: North-Germany
If you have a flakey DB7 connection, check for bend pins first, then socket (on precision sockets the inlet may be missing) and then for poor solder connection or broken copper trace. For the latter two bend your pcb while measuring the impedance - a haircut is very difficult to locate under solder resist. And a "cold" solder connection may work fine for a while under certain circumstances.

WDC assembler: Even an official program may have inofficial errors ;) I didn't encounter one so far, but who knows.. :)


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Fri Jun 09, 2017 9:44 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
GaBuZoMeu wrote:
WDC assembler: Even an official program may have inofficial errors ;) I didn't encounter one so far, but who knows.. :)


Oh I know, I have encountered one. The whole "won't accept BBS0" thing.

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Sat Jun 10, 2017 2:29 pm 
Offline

Joined: Mon Jan 09, 2017 3:50 pm
Posts: 39
I've a bunch of working 16C550 code (for Z80 and 6502) at my github repo https://github.com/ancientcomputing/rc2014/tree/master/source. For 6502, look for under the 6502/monitor folder.

There's code to enable the AFC as well. Setting the baudrate itself is very straightforward.

As suggested by others, check the actual clock that you are generating from the crystal (why I always use an external oscillator :)). Rather than looking at the data lines, I would also look at the address lines. If you are successfully sending/receiving characters, the data lines are probably okay (excepting maybe D7). But bad addr lines may not allowing you to access the appropriate registers.

_________________
Blog: http://ancientcomputing.blogspot.com/
GitHub: https://github.com/ancientcomputing


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Sat Jun 10, 2017 2:35 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
bluesky6 wrote:
I've a bunch of working 16C550 code (for Z80 and 6502) at my github repo https://github.com/ancientcomputing/rc2014/tree/master/source. For 6502, look for under the 6502/monitor folder.

There's code to enable the AFC as well. Setting the baudrate itself is very straightforward.

As suggested by others, check the actual clock that you are generating from the crystal (why I always use an external oscillator :)). Rather than looking at the data lines, I would also look at the address lines. If you are successfully sending/receiving characters, the data lines are probably okay (excepting maybe D7). But bad addr lines may not allowing you to access the appropriate registers.


I shall have a nosey at your code.
The clock is definitely oscillating at 1.8342MHz, as its meant to. I have double and triple checked this.
If the address lines were preventing me from accessing the DLL/DLM registers, it would also be preventing me from accessing THR/RHR - In other words I wouldn't be able to send or receive any characters at all.

EDIT: your initialization code, at least insofar as the divisor latch is concerned, is identical to mine with one exception: You set only LCR[7] initially whereas I set LCR[7] and LCR[0:1] and then clear LCR[7] afterwards. Maybe LCR[7] has to be set on its own?

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Sat Jun 10, 2017 3:05 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3366
Location: Ontario, Canada
Alarm Siren wrote:
If the address lines were preventing me from accessing the DLL/DLM registers, it would also be preventing me from accessing THR/RHR - In other words I wouldn't be able to send or receive any characters at all.

You're almost certainly right, but assumptions like this do need to be treated with caution. It's amazing some of the fluky sh*t that can happen and take you by surprise -- stuff that "shouldn't" work but does. That's the voice of experience talking. :| It's noteworthy that you have a new piece of hardware, and a problem presents which has you stumped. Something has gotten missed, so you need to be careful about saying, "It can't be ___ because it seems to me that ___ !" I'd look for independent evidence -- an additional test, perhaps.

ETA: Continuity tests are one way to check those address & data lines. Or you can temporarily add a connection from the UART /Chip-Select input to the CPU's RDY input. The system will stall on the first access to the UART, and at your leisure you can then examine the state of each UART pin to verify that the access is being received as intended. This won't rule out an intermittent connection, however. Really a Logic Analyzer (attached to the UART itself) is a better way to see that the access is being properly received.

Good luck, and keep us posted!

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Mon Nov 27, 2017 8:07 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
*sigh* Spent the entire day fiddling with this, and I've ruled out almost everything I could think of but still no solution.

  • All address and data lines plus R/W have good continuity
  • The logic levels on the busses are good (infact if anything they're a teeny bit high)
  • I have confirmed using a logic analyser that the software is being correctly executed - i.e. the software is doing the correct writes to the correct addresses in the right order
  • The software itself has been scaled back to the absolute bare minimum to test the problem, and I have checked it against similar code used in the RC2014 codebase, and they're pretty much identical so there's no hidden gotchas there.
  • CS line is going low at at the right times

However, the chip is stuck at Divisor 8 which gives a baud rate of 14400. It doesn't specify in the datasheet what the default baud rate is, but I suspect that this is the reset default and my writes are simply not reaching the divisor registers.

I have two remaining theories:
  • The chip is busted, in a strange and weirdly specific way. This will be difficult to test as removing an LQFP48 chip is going to be a pain, and I don't have a spare so I'll need to order one.
  • I have not specifically tested WE/RE (as opposed to R/W)
  • I'm confident the setup times for the UART are met, but I have not specifically checked the hold times, though I would be surprised if this were the issue.

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Tue Nov 28, 2017 12:11 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8263
Location: Midwestern USA
Alarm Siren wrote:
*sigh* Spent the entire day fiddling with this, and I've ruled out almost everything I could think of but still no solution...The chip is busted

A defective device is not unheard of. Do you have another one to try out?

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Tue Nov 28, 2017 1:04 am 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
No, unfortunately not. I will have to order one if I want to try swapping it out.

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Wed Nov 29, 2017 2:53 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3366
Location: Ontario, Canada
Alarm Siren wrote:
the software is doing the correct writes to the correct addresses in the right order
Okay, all the correct stuff is happening. Are we sure incorrect (like a rogue write) isn't happening? Just a theory, but worth considering. All it takes is a glitch, not a proper, full-duration write. For example did we attend to that question of whether the NAND that generates /WE to the UART is qualified by the PHI2 CPU output or (as recommended by WDC) qualified by the PHI0 input to the CPU? I'm only guessing about the source of a glitch. But (depending on various factors) such a thing could easily be missed by the logic analyzer.

Quote:
All address and data lines plus R/W have good continuity
What about Vcc and Gnd; did they get checked already? I'm embarrassed to say that's something I got tripped up on just the other day. :oops: All I can say is it's amazing how well a chip can work sometimes with no Vcc connection! :shock:

One needs to be careful about ruling stuff out. There are lots of situations where yer gonna wanna say, "it can't be ___ because if that were the case then ___." I'm not saying deductive reasoning should be abandoned. Just be careful not to put all your trust there. ("It can't be a missing Vcc connection because if that were the case then the whole chip would be inoperative.") This is just one instance of "stuff that shouldn't work but does," and I've been threatened and/or bitten by it in many different forms. :|

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Wed Nov 29, 2017 8:29 am 
Offline

Joined: Sun Apr 10, 2011 8:29 am
Posts: 597
Location: Norway/Japan
Quote:
All I can say is it's amazing how well a chip can work sometimes with no Vcc connection!
Yeah, as the ARM folks (Wilson & co) found when they tested their new chip.. it worked fine, but didn't draw any current.
ARM first test


Top
 Profile  
Reply with quote  
 Post subject: Re: Problematic UART
PostPosted: Wed Nov 29, 2017 3:56 pm 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
Dr Jefyll wrote:
Okay, all the correct stuff is happening. Are we sure incorrect (like a rogue write) isn't happening? Just a theory, but worth considering. All it takes is a glitch, not a proper, full-duration write. For example did we attend to that question of whether the NAND that generates /WE to the UART is qualified by the PHI2 CPU output or (as recommended by WDC) qualified by the PHI0 input to the CPU? I'm only guessing about the source of a glitch. But (depending on various factors) such a thing could easily be missed by the logic analyzer.


I would only be able to check for a spurious /WE transition with a more capable scope than I have access to, but the /CE line is working fine, so if /WE is going spuriously going low it must be doing it whilst /CE is also low. /WE and /RE are qualified by PHI0.

Dr Jefyll wrote:
What about Vcc and Gnd; did they get checked already?


The Power rails themselves are good, though I've not explicitly checked continuity right up to the UART pin. I'll add that to me list of things to do.

Tor wrote:
it worked fine, but didn't draw any current.


Yes, one of the technicians at the Uni have a similar story. They were developing some kind of measurement system that went inside a gas canister. For safety reasons it wasn't allowed to draw more than a few microamps. Plugged it in? drawing 50x the limit. Couldn't figure it out. Turns out the Vcc line was broken and it was running off leakage current, which for some reason meant it drew all that extra current. Red faces all around!

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron