I am trying to implement a UART based on the TI app note: Implementation of a Software UART on TMS320C54x Using General-Purpose I/O Pins The receive part works great but I cannot figure out why the transmit does not work. I am using Hyperterm to verify everything but it does not receive anything after I call the transmit function. Any ideas? |
************************************************************ *This program is a s/w UART for the C54x using the BIO and * *XF, I/O pins, a hardware interrupt, and a timer. * *The device operates in full-duplex mode and supports * *up to 16 data bits, 1 or 2 stop bits, and parity (even or * *odd). * * * *Written by: Adrienne Prahler Jaffe * *Modified: 3/10/99 * *Three function calls are available in this program, * *setup, transmit and transmit_delay. * *Functions being made c-callable * ************************************************************ .global _timer_isr, _transmit, _transmit_delay, _setup, _hw_int0, _tx_datapass .global _rcv_datapass, _UART_reg, _parity_value, _one, _UART_count, _tx_datalo .global _rcv_datalo .global _newData ****************** MAIN SHELL ********************************** .mmregs ; allow addressing of memory registers by name .bss _temp,1 ; .bss _newData,1; .bss _UART_reg,1 ; location of status register flags .bss _rcv_datalo,1 ; rcv location .bss rcv_datahi,1 ; rcv location .bss _tx_datalo, 1 ; tx_data location .bss tx_datahi, 1 ; tx_data location .bss _UART_count,1 ; counter .bss _one, 1 ; constant location .bss _tx_datapass, 1 ; where transmit data is put for transmission .bss _rcv_datapass, 1 ; where receive data is stored ; (striped of stop, start, parity) .bss _parity_value,1 ; parity value location ; if total #1's in dataword even then ; lsb = 0, odd lsb = 1 .bss parity_bit, 1 ; parity_bit value ****************Added for debugging******************************* .bss _data_storage, 330, 1 ; where receive data is stored ****************************************************************** **********************Timer information************************** * timer interrupt rate (baud rate)= 1/(clkout*(TDDR+1)*(PRD+1))* * TDDR is timer divide down ratio, 4 bits * * PRD is the timer period register, 16 bits * * * * Knowing the desired baud rate and clkout of device, the values* * of TDDR and PRD can be determined. * * In this example, the TDDR is set to 1, if that is changed, the* * values of tcr_timer_go needs to be changed so the lower 4 bits* * are the desired values. * * * * The program uses two timer rates, one for a half bit time and * * one for a whole bit time. The value calculated for the PRD * * in the above equation is for the whole bit time. * ***************************************************************** whole_bit_time .set 1706d ; set whole bit time assuming 32.768MHZ (set by jumpers) ; and 9600 baud half_bit_time .set 853d ; set half bit time assuming 32.768MHz ; and 9600 baud tcr_setup .set 0000000000010000b ; setup tcr values, stop timer tcr_timer_go .set 0000000001100001b ; tcr register values for ; timer start *************variables set for operation of UART***************** * UART_reg: * *___15-5__________4__________3_______2_______1_______0____ * *|reserved| parity error | delay | uart | tx | rcv | * *--------------------- * *RCV * * 0 = not receiving data * * 1 = receiving data * *TX * * 0 = no data to transmit * * 1 = data waiting to be transmitted * *UART * * 0 = not busy transmitting * * 1 = actively transmitting * *Delay * * 0 = not delayed * * 1 = delayed * *Parity error * * 0 = nothing wrong * * 1 = error occurred * ***************************************************************** data_bits .set 8 ; number of data bits being transferred stop .set 1 ; number of stop bits, 1 or 2 start_bits .set 1 ; number of start bits parity .set 0 ; if 0, no parity ; if 1, odd parity ; if 2, even parity .if parity != 0 ; if parity set then reserve a bit spot par_bits .set 1 parity_or .set 01b<<data_bits+start_bits .else par_bits .set 0 .endif ************Setting up stopbit formatting values****************** .if stop=2 ;if 2 stop bits then set up this value for formatting stop_or .set 011b<<data_bits+par_bits+start_bits ; setting up for formatting data .elseif stop=1 ; if 1 stop bit set up this value for formatting stop_or .set 01b<<data_bits+par_bits+start_bits ; setting up for formatting data .else .emsg "ERROR, must specify the number of stop bits to be 1 or 2" .endif **********Parity Routines**************************************** .if parity > 2 .emsg "ERROR, the parity value must correspond to no parity, even parity or odd parity!" .endif .if parity !=0 ; if parity set .if data_bits+par_bits+start_bits> N_par .set 32 .elseif data_bits+par_bits+start_bits>=9 N_par .set 16 .elseif data_bits+par_bits+start_bits>=5 N_par .set 8 .elseif data_bits+par_bits+start_bits>=3 N_par .set 4 .elseif data_bits+par_bits+start_bits=2 N_par .set 2 .elseif data_bits+par_bits+start_bits=1 N_par .set 1 .endif .endif *******************Main Program*********************** .text ******dummy main program to call UART setup and a delayed transmit****** start: nop call _setup nop nop call _transmit_delay nop loop: nop ; looping nop nop b loop nop nop ************setup UART************************** _setup: rsbx cpl ; enable direct addressing mode ld #_UART_reg, DP ; setup DP for direct addressing RSBX INTM ; enable global interrupts RSBX SXM ; turn off sign extension mode, the UART must ; operate with this setting! st #1, @_one ; create a Smem location with value 1 stored st #9h, *(IMR) ; enable interrupt (timer and hw_int) st #0, @_UART_reg ; initialize data locations st #0, @_tx_datalo st #0, @tx_datahi st #0, @_newData ; initialize data locations **************Added for debugging************** stm #100, bk ; load circular buffer size ssbx xf ; set xf high nop nop nop nop stm #_data_storage, ar3 ; setup auxiliary register for ; receive data st #8bh, @_tx_datapass ; load data into tx_datapass ************************************************ ssbx cpl rete ; return to main program ************Timer ISR for UART************************** _timer_isr: pshm st0 ; context save pshm AL pshm AH pshm AG rsbx cpl ; set cpl=0 for assembly functions ld #_UART_reg, DP ; setup DP for direct addressing rcv: bitf *(_UART_reg), #1h ; test rcv flag nop nop bc tx, ntc ; if rcv not set then branch to tx cmpm @_UART_count, #0h ; is count = 0? nop nop bc exit_now, nbio, tc ; if count = 0 and bio =1 then exit now! ; not a VALID start bit! cc timerwhole, bio, tc ; setup timer for whole bit if count=0 ; bio=0 bc tx, bio, tc ; after time set up branch to tx routine ld @_UART_count, T ; load counter into T register ; used for offset since data received ; lsb first. ld @_rcv_datalo, A ; load rcv_data add @rcv_datahi, 16, A xc 1, nbio ; if bio pin high then add @_one, TS, A ; add one shifted by bit position(count) stl A, @_rcv_datalo ; store rcv data in memory location sth A, @rcv_datahi tx: bitf @_UART_reg, #4h ; test UART flag nop nop bc exit_norm, ntc ; if not transmitting then just exit bitf @_tx_datalo, #1h ; what is lsb? ld @_tx_datalo, A ; load tx_data add @tx_datahi, 16, A xc 1, tc ; if lsb=1 set xf=1 ssbx xf xc 1, ntc rsbx xf ; if lsb=0 set xf=0 stl A, -1, @_tx_datalo ; store low portion of tx out with shift ; right of one sth A, -1, @tx_datahi ; store hi portion of tx out with shift ; right of one *******************Exit Routines from timer isr****************** * Normal exit routine * * Invalid start bit detected * * End of rcv data routine * * End of tx data routine * ***************************************************************** *********Normal Exit routine************************************* exit_norm: cmpm @_UART_count, #stop+start_bits+par_bits+data_bits-1 ;test if final bit nop nop cc exit_final, tc ; if final bit exit Addm #1, @_UART_count ; update counter restore: ssbx cpl ; reset cpl=1 for c program popm AG ; restore accumulator A contents and status popm AH popm AL popm ST0 timer_end: rete ; return to main program nop nop *********Invalid start bit************************************ exit_now: bitf @_UART_reg, #4h ; What is UART bit set to? stm #tcr_setup, TCR ; stop timer by writing a 1 to tss in tcr xorm #1h, @_UART_reg ; reset RCV flag xc 2, tc ; if this was a delayed tx and uart=1 xorm #0ah, @_UART_reg ; reset txdelay bit, and uart bit! st #9h, *(IMR) ; enable int0 and timer interrupts (timer ; stopped) b restore ; exit routine nop nop *************Final Bit exit Routine exit_final: bitf @_UART_reg, #1h ; check rcv bit ld @_rcv_datalo, A add @rcv_datahi, A cc end_rcv_routine, tc nop nop bitf @_UART_reg, #4h ; check uart bit stm #tcr_setup, TCR ; stop timer by writing a 1 to tss in tcr nop xc 2, tc xorm #6h, @_UART_reg ; reset TX and UART flags ldm IFR, A ; load interrupts pending nop nop and #1h, A ; get rid of int0 pending interrupts stlm A, IFR ; clear all pending interrupts st #9h, *(IMR) ; enable int0 (timer still active but stopped) call _transmit_delay ; loop back with a transmit delay call nop nop ret ; restore saved registers nop nop ******************end rcv data routine*********************** end_rcv_routine: formatting xor #stop_or, A ; get rid of stop bits ******************Parity Bit Routine******************** ** only compiled if parity set at compile time ** ******************************************************** .if parity != 0 call parity_calc ; does this match with the ; type of parity expected? bitf @_parity_value, #1h ; check parity value ld @_rcv_datalo, A ; load rcv_data to edit out parity, add @rcv_datahi, 16, A ; stop, start stl A, -(start_bits+data_bits), @parity_bit ; store parity bit ;to lsb in parity_bit .if parity = 1 ; if odd parity & paritycalc is 0 cc parity_error, ntc ; then call error .elseif parity = 2 ; if even parity & parity bit is 1 cc parity_error, tc ; then call error .endif bitf @parity_bit, #1h ; check parity bit value xor #stop_or, A ; get rid of stop bits nop xc 2, tc ; if parity bit=1 then get rid of it xor #parity_or, A nop .endif ********************************************************** stl A, -start_bits, @_rcv_datapass ; put unformatted data word ; in rcv location ********************Added for debugging****************************** stl A, -start_bits, @_tx_datapass ; load tx data with just ; received data ;stl A, -start_bits, *AR3+% ; error checking routine ; putting data into a ; memory location so it can ; be checked later ********************************************************************** xorm #1h, @_UART_reg ; reset RCV flag st #1, @_newData ; new data flag ret nop nop ************************ Timer setups********************** timerhalf: stm #tcr_setup, TCR ; stop timer by writing a 1 to tss in tcr stm #half_bit_time, PRD ; load timer period stm #tcr_timer_go,TCR ; start timer ret timerwhole: stm #tcr_setup, TCR ; stop timer by writing a 1 to tss in tcr stm #whole_bit_time, PRD ; load timer period stm #tcr_timer_go,TCR ; start timer ret ***************Parity calculation routine***************** ** only compiled if parity set at compile time ** ********************************************************** parity_calc: .if parity != 0 .if N_par = 32 xor A, 16, A .endif .if N_par >= 16 xor A, 8, A .endif .if N_par>= 8 xor A,4, A .endif .if N_par>=4 xor A, 2, A .endif .if N_par>=2 xor A, 1,A stl A, -N_par+1, @_parity_value ; load parity status ; into lsb .endif ret nop nop .endif ********************Parity error routine************************* parity_error: xorm #10h, @_UART_reg ;set parity error flag ret *****************Transmit Routine******************************** * Data passed in mem location tx_datapass * * The routine will check if the tx flag is set and wait until * * the tx flag is reset so transmit data won't be overwritten * * before it is sent. If it is a delayed transmit the routine * * will just format the data and return to the main program until* * the next receive interrupt occurs. If it is a transmit the * * registers for transmit and the timer are setup and started. * * * * If a transmit is started, then the device can not receive. * * Full-duplex operation occurs only when a transmit delayed is * * called since there is only one timer. * ***************************************************************** _transmit: pshm AL ; context save since Accumulator A used pshm AH pshm AG pshm ST0 rsbx cpl ; enable direct addressing mode ld #_UART_reg, DP ; set DP for addressing busy: BITF *(_UART_reg), #4h ; What is UART_flag set to? nop nop BC busy, tc ; if UART=1 then can not overwrite data tx_set BITf @_UART_reg, #2h ; What is TX_flag set to? nop nop BC tx_set, tc ; if tx = 1 then can not overwrite data xorm #2h, @_UART_reg ; if tx = 0 set TX=1 format: *******************Parity formatting of tx data*********** ** only compiled if parity set at compile time ** ********************************************************** .if parity != 0 ld @_tx_datapass, A ; load temp data for parity check call parity_calc ; calculate parity_value .endif ********************************************************** ld @_tx_datapass, start_bits, A ; load temp data (offset by ; start_bit) nop ;stl A,-1, *AR3+% ; added for debugging add #stop_or, A ; add stop bits **********************Add parity bit********************** ** only compiled if parity set at compile time ** ********************************************************** .if parity != 0 bitf @_parity_value, #1h ; check parity value nop nop .if parity = 1 xc 2, ntc add #1h, start_bits+data_bits, A ; add a 1 to make ; odd parity ; add #parity_or, A ; add a 1 to make ; odd parity .elseif parity =2 xc 2, tc add #1h, start_bits+data_bits, A ; add a 1 to make ; even parity ; add #parity_or, A ; add a 1 to make ; even parity .endif .endif ********************************************************* bitf @_UART_reg, #8h ; is this a delayed transmit? sth A,@tx_datahi ; store out data for transmit stl A,@_tx_datalo ;stl A, *AR3+% ; added for debugging ; return to user program if delayed td_end: bc tx_end, tc ; transmit - wait for rcv interrupt nop nop waiting: BITf @_UART_reg, #1h ; what is RCV flag? nop nop BC waiting, tc ; if recieving have to wait until done ; can insert user program if desired st #8h, *(IMR) ; disable hw_int0, timer enabled call timerwhole ; setup timer for 1 bit and start xorm #4h, @_UART_reg ; set UART=1, going to transmit st #0, @_UART_count ; initialize UART_count tx_end: ssbx cpl ; reset cpl=1 popm st0 ; restore contents and status popm ag popm ah popm al t_end ret _transmit_delay: xorm #8h, *(_UART_reg) ; enable delay bit (this is a ; delayed tx) B _transmit nop nop *********************Receive routine************************************* *This is the hw_int routine that will be executed when a start * *bit is detected. The routine checks the status of transmit and starts * *the timer for a half bit time so the program can be sure a true start * *bit not a glitch was detected. It also resets the counter, and * *receive data locations. * * * *If the device is finishing a transmit routine, the TX and UART flags * *will be reset. If the transmit_delay flag is set, the routine will * *setup for a transmit during the receive. * ************************************************************************* _hw_int0: pshm st0 ; context save rsbx cpl ; enable direct addressing mode ld #_UART_reg, DP ; setup DP for addressing bitf *(_UART_reg), #8h ; is txd set? call timerhalf ; setup and start time for half bit xc 2, tc ; if delayed transmit xorm #0ch, @_UART_reg ; reset TXD bit and set UART bit end: ST #0, @_UART_count ; initialize UART counter st #8h, *(IMR) ; disable int0 st #0, @_rcv_datalo st #0, @rcv_datahi xorm #1h, @_UART_reg ; set RCV flag = 1 ; return with timer enabled ssbx cpl popm st0 ; context restore hw_end: rete |
|
UART with GPIO pins
Started by ●October 10, 2003
Reply by ●October 10, 20032003-10-10
Lucy- > I am trying to implement a UART based on the TI app note: > > Implementation of a Software UART on TMS320C54x Using General-Purpose I/O Pins > > The receive part works great but I cannot figure out why the > transmit does not work. I am using Hyperterm to verify > everything but it does not receive anything after I call the > transmit function. Any ideas? Is Hyperterminal set for Hardware Flow Control or Software Flow Control (XON/XOFF)? You might try Software to take your CTS, RTS, etc. lines out of the equation. Sometimes when you get one direction working and not the other the issue is the handshake lines. -Jeff |