Monday, September 28, 2015

Phase 2: waste not want not

Its funny because I am involved in a bunch of projects and I cycle through them as time permits. Just recently got back to EGWU ... I had already written the uart code and monitor program but couldnt reliable test it until I had fixed my voltage regulation problem.

THE PROBLEM IS THAT THE 5V AND 3.3V REGULATORS ARE STILL RUNNING INCREDIBLY HOT. SO MUCH SO I COULDNT KEEP A THUMB ON IT FOR LONGER THAN A SECOND

alas there is NO immediate fix other than a more sensible redesign (perhaps with TO-220 parts and heatsinks and larger copper pour area or with switching regulators). Ill deal with that in the next revision of the design and layout.

Last week my office tossed out two p4 PC's and I salvaged their power supplies. I figured Id use them to generate 5v and 3.3v reliably so I can get on with firmware and fpga development.

This evening I removed the 3.3v and 5v regulators (ams1117 parts) and soldered in 1 pin headers for 5v, 3.v and gnd at the P2/P3/P31 test points. Thus the wisdom in adding those test points during the layout.

Then I went online and grabbed the pin out for the 20 pin ATX motherboard power connector and dug into the PSU box with cutters and my soldering iron.

NOTE: the green wire must be grounded for the power supply to turn on. its designated PS/ON . ALSO some pin positions have both large and small wires - both must be connected to together for the PSU to work.

The color coding is simple
black  = common ground
green  = PS/ON (must be connected to ground)
red      = +5v
orange = +3.3v

Thats all I need, pics below.






Next post resumes software/firmware development

Friday, September 11, 2015

Phase 2: component replacement on backup board

So I have two boards at home. One populated with test points inserts and the other without. I have been using the latter, but I needed to probe some signals and mothballed it for now to use the other one.

So, I found a short on the former that was causing eratic behavior ... and something in excess of 4 volts on the output of the 3.3v regulator. Why that hadnt damaged all my 3.3v chips I shall never know.

Further analysis revealed the AMS1117 3.3v regulator was damaged and I figured that the DC adapter connector may have contributed to this. I had already replaced it once so I tore it out as well.

Used the hot air gun to replace the SOT* regulator and my soldering iron to replace the DC adapter. I had damaged the pad and trace to VCC_in on the
connector that I ran a wire through to the two regulators (3.3v and 5v) fed by VCC_in

Then used the continuity tester to verify the 3.3v regulator wasnt shorted between two pins

Pcb layout and component/solder side pics below.










Note to self:
be wary of multi voltage (aka Universal AC/DC) adapters. Two of the three I have (Electrix - UL certified) were producing incorrect output voltages for the various switch settings. At switch setting 9v ... dc meter read 12.7v. A the setting of 12v it was reading out 17.1v on my dmm

DITCH the stupid universal AC/DC adapters!!!
Stick with the 7.5v/1.5A regulated wall adapters I stocked specifically for this project

Tuesday, September 8, 2015

Phase 2: There and back again

the problem was really openocd 0.9.0 (and also 0.8.0) both of which are flaky with the JLINK and OLIMEX Jtag tiny adapters. I tested this on the olimex_stm32_h103.cfg board. on the other hand, openocd 0.7.0 had no issues, with either the ft2232 or the ftdi configuration files.

Oddly enough 0.7.0 was what I was using a few years ago when I was developing firmware for the stm32 series

so I rebuilt it this afternoon and thats what I am going to be using going forward:
sudo ./configure --enable-ftdi --enable-ft2232_libftdi --enable-ioutil --enable-jlink --enable-usbprog


also here is a copy of the /etc/udev/rules.d/99-openocd.rules
This makes running openocd with sudo privileges unnecessary. Note that the user has to be a member of group "plugdev" in order to use this

# Copy this file to /etc/udev/rules.d/

ACTION!="add|change", GOTO="openocd_rules_end"
SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end"

# Please keep this list sorted by VID:PID

# opendous and estick
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="664", GROUP="plugdev"

# Original FT232/FT245 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"

# Original FT2232 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"

# Original FT4232 VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev"

# Original FT232H VID:PID
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="664", GROUP="plugdev"

# DISTORTEC JTAG-lock-pick Tiny 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="664", GROUP="plugdev"

# TUMPA, TUMPA Lite
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="664", GROUP="plugdev"

# XDS100v2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="664", GROUP="plugdev"

# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca1", MODE="664", GROUP="plugdev"

# TI/Luminary Stellaris Evaluation Board FTDI (several)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"

# TI/Luminary Stellaris In-Circuit Debug Interface FTDI (ICDI) Board
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev"

# egnite Turtelizer 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"

# Section5 ICEbear
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"

# Amontec JTAGkey and JTAGkey-tiny
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="664", GROUP="plugdev"

# TI ICDI
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="664", GROUP="plugdev"

# STLink v1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="664", GROUP="plugdev"

# STLink v2
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="664", GROUP="plugdev"

# STLink v2-1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="664", GROUP="plugdev"

# Hilscher NXHX Boards
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="664", GROUP="plugdev"

# Hitex STR9-comStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="664", GROUP="plugdev"

# Hitex STM32-PerformanceStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev"

# Amontec JTAGkey-HiSpeed
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="664", GROUP="plugdev"

# IAR J-Link USB
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0102", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0103", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0104", MODE="664", GROUP="plugdev"

# J-Link-OB (onboard)
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE="664", GROUP="plugdev"

# Raisonance RLink
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="664", GROUP="plugdev"

# Debug Board for Neo1973
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="664", GROUP="plugdev"

# Olimex ARM-USB-OCD
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"

# Olimex ARM-USB-OCD-TINY
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"

# Olimex ARM-JTAG-EW
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="664", GROUP="plugdev"

# Olimex ARM-USB-OCD-TINY-H
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev"

# Olimex ARM-USB-OCD-H
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002b", MODE="664", GROUP="plugdev"

# USBprog with OpenOCD firmware
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="664", GROUP="plugdev"

# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="664", GROUP="plugdev"

# Marvell Sheevaplug
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"

# CMSIS-DAP compatible adapters
ATTRS{product}=="*CMSIS-DAP*", MODE="664", GROUP="plugdev"

LABEL="openocd_rules_end"

Monday, September 7, 2015

Phase 2: Adjustment to openocd and gdb scripts related to various clock and delay values

So this is basically a deviation from my default script. I was dealing with remotetimeout and communication errors with the microcontroller and ft2232 USB-jtag interface (MPSSE) that I decided to modify the clock and delay parameters for openocd ... with rather conservative values. and to set the remotetimeout under gdb to 3 seconds.

Here are the changed files

/home/rombios/.gdbinit
set history filename ~/.gdb_history
set history save
target remote localhost:3333
set remotetimeout 3000
monitor reset halt
#load


egwu_board.cfg
# egwu_board.cfg

set WORKAREASIZE 0x10000
source [find target/egwu_target_1788.cfg]


egwu_interface_usb.cfg
#
# embedded projects openocd usb adapter v3
#
# http://shop.embedded-projects.net/index.php?module=artikel&action=artikel&id=14
#
interface ftdi
ftdi_vid_pid 0x0403 0x6010
#ftdi_channel     0
#ftdi_layout_init 0x1000 0x3d1b
#working ftdi_layout_init 0x0008 0x000b
ftdi_layout_init 0x1000 0x3d0b
ftdi_layout_signal nTRST -data 0x0010


egwu_target_1788.cfg
# egwu_target_1788.cfg
set CHIPNAME lpc1788
set CPUTAPID 0x4ba00477
set CPURAMSIZE 0x10000
set CPUROMSIZE 0x80000

# CCLK is the core clock frequency in KHz

set CCLK 24000
source [find target/egwu_target_17xx.cfg];
#cortex_m reset_config sysresetreq
cortex_m reset_config trst_only


egwu_target_17x.cfg
# egwu_target_17xx.cfg

if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
error "_CHIPNAME not set. Please do not include lpc17xx.cfg directly, but the specific chip configuration file (lpc1751.cfg, lpc1764.cfg, etc)."
}

# After reset the chip is clocked by the ~4MHz internal RC oscillator.
# When board-specific code (reset-init handler or device firmware)
# configures another oscillator and/or PLL0, set CCLK to match; if
# you don't, then flash erase and write operations may misbehave.
# (The ROM code doing those updates cares about core clock speed...)
#
# CCLK is the core clock frequency in KHz
if { [info exists CCLK] } {
set _CCLK $CCLK
} else {
set _CCLK 24000
}

if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
error "_CPUTAPID not set. Please do not include lpc17xx.cfg directly, but the specific chip configuration file (lpc1751.cfg, lpc1764.cfg, etc)."
}

if { [info exists CPURAMSIZE] } {
  set _CPURAMSIZE $CPURAMSIZE
} else {
error "_CPURAMSIZE not set. Please do not include lpc17xx.cfg directly, but the specific chip configuration file (lpc1751.cfg, lpc1764.cfg, etc)."
}

if { [info exists CPUROMSIZE] } {
  set _CPUROMSIZE $CPUROMSIZE
} else {
error "_CPUROMSIZE not set. Please do not include lpc17xx.cfg directly, but the specific chip configuration file (lpc1751.cfg, lpc1764.cfg, etc)."
}

jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME

# The LPC17xx devices have 8/16/32kB of SRAM In the ARMv7-M "Code" area (at 0x10000000)
$_TARGETNAME configure -work-area-phys 0x10000000 -work-area-size $_CPURAMSIZE

# The LPC17xx devies have 32/64/128/256/512kB of flash memory, managed by ROM code
# (including a boot loader which verifies the flash exception table's checksum).
# flash bank <name> lpc2000 <base> <size> 0 0 <target#> <variant> <clock> [calc checksum]
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME lpc2000 0x0 $_CPUROMSIZE 0 0 $_TARGETNAME \
lpc1700 $_CCLK calc_checksum

# Run with *real slow* clock by default since the
# boot rom could have been playing with the PLL, so
# we have no idea what clock the target is running at.
adapter_khz  50
#adapter_khz 1000

# delays on reset lines
adapter_nsrst_assert_width 100
adapter_nsrst_delay 100

jtag_ntrst_assert_width 100
jtag_ntrst_delay 100

$_TARGETNAME configure -event reset-init {
mww 0x400FC040 0x01
mww 0xe000ed08 0x10000000
}

# perform a soft reset
#cortex_m reset_config sysresetreq
cortex_m reset_config trst_only

Tuesday, August 25, 2015

Phase 2: Resolution to crystal bias capacitor issue

I had been using the internal 12Mhz RC because the external crystal wasnt working. And by working I mean:

per lpc1778 manual:
with the appropriate bias caps CX1 and CX2, setting bits 4 (oscillator range select) and 5 (main oscillator enable) of the System Control and Status register should return read only bit 6 (oscillator status) as ready.

This wasnt happening and I thought perhaps it was because I chose 12pf for bias caps from an earlier crystal selection before I bought the 24Mhz versions on ebay.

The datasheet says using capacitor values 18pf or 39pf depending on crystal load capacitance. I ordered 18pf and 39pf 0603's on ebay. And replaced the 12pf on the board ... TO NO AVAIL


With phase 2 nearing completion (and me needing a precise crystal clock source for the SDRAM controller/USB interface and FPGA) I decided to revisit the schematic and noticed that I had shorted XTAL1 pin to ground via 0ohm resistor R13. Why I put that in the design I dont know ... and I have to go to storage to find the notebooks I made notes on when I designed this board.



What I do know is that it doesnt belong there. So I brought out my hot air tool and removed R13





Then I launched GDB to see if the oscillator status changes after I enable the logic driver and sure enough it does.


(gdb) monitor reset halt
JTAG tap: lpc1788.cpu tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Only resetting the Cortex-M core, use a reset-init event handler to reset any peripherals or configure hardware srst support.
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
(gdb) monitor mdw 0x400fc1a0
0x400fc1a0: 00000009
(gdb) monitor mww 0x400fc1a0 0x39
(gdb) monitor mdw 0x400fc1a0
0x400fc1a0: 00000079


I removed R13 on the other spare EGWU board with CX1/CX2 bias caps of 12pf and tested it and it worked as well.

The next few days will be devoted to debugging UARTIO code and writing the YModem transfer code  ... before delving in the SDRAM controller

Phase 2: Code posting guidelines

select all    (text)
select font = times
leave text  =large

this prevents wrap around

Phase 2: IE_egwu_uartio

/*
 *****************************************************************
 *name:         IE_egwu_uartio.h
 *author:       Samuel Igwe
 *date:         08/25/2015
 *description:  IE_egwu_uartio header.
 *****************************************************************
 */
#ifndef IE_EGWU_UARTIO_H
#define IE_EGWU_UARTIO_H

    #include "chip.h"
    #include "chip_lpc177x_8x.h"
    #include "uart_17xx_40xx.h"
    #include "IE_tclib.h"
    #include "IE_egwu_setup.h"

    #define     EGWU_UART_BUF_SIZE              80

    #define     ASCII_BS                        8
    #define     ASCII_TAB                       9
    #define     ASCII_LF                        10
    #define     ASCII_CR                        13
    #define     ASCII_ESC                       27
    #define     ASCII_SPACE                     32
    #define     ASCII_DEL                       127



    struct      STR_UART_BUFFER {
        volatile unsigned int   wdTopMutex,  wdTopIndex;
        volatile unsigned int   wdBotMutex,  wdBotIndex;
        volatile unsigned int   *ptrUsrIndex,*ptrUsrMutex;

        volatile unsigned int   *ptrDmaMutex;

        volatile unsigned char  sbTopBuf[EGWU_UART_BUF_SIZE+1];
        volatile unsigned char  sbBotBuf[EGWU_UART_BUF_SIZE+1];
        volatile unsigned char  *ptrUsrBuf;
        }strUartTxBuf;



    /*
     *********************************************************
     *routines
     *********************************************************
     */
    char uartio_getch(void);
    char uartio_getc(void);
    int  uartio_gets(char *ptrString, int wdSize);
    int  uartio_tx_flush(void);

    void setup_uartio(void);
    void uartio_putc(char byByte);
    void uartio_dma_isr(void);
    void uartio_puts(char *ptrString, int wdStrlen);
    void uartio_printf(char *ptrString, int wdValue);
    void test_determine_fractional_divider_values(void);

#endif 
 
 
 
 
 
 
/*
 *****************************************************************
 *name:         IE_egwu_uartio.c
 *author:       Samuel Igwe
 *date:         08/25/2015
 *description:  uartio support functions. sets up call 
 *              back array of functions for dealing with gpdma
 *              channel interrupts
 *****************************************************************
 */
#ifndef IE_EGWU_UARTIO_C
#define IE_EGWU_UARTIO_C

#include "IE_egwu_uartio.h"




/*
 *****************************************************************
 *description:  initialization routine
 *              dont forget to initialize ptrDmaMutex
 *****************************************************************
 */
void
setup_uartio(void)
{
    tclib_memset((unsigned char *)&strUartTxBuf, 0, sizeof(strUartTxBuf));

    strUartTxBuf.ptrUsrBuf  = strUartTxBuf.sbTopBuf;
    strUartTxBuf.ptrUsrIndex= &strUartTxBuf.wdTopIndex;
    strUartTxBuf.ptrUsrMutex= &strUartTxBuf.wdTopMutex;
    strUartTxBuf.ptrDmaMutex= &strUartTxBuf.wdTopMutex;
}





/*
 *****************************************************************
 *description:  getch routine. non blocking read
 *output:       0 on error or valid char
 *****************************************************************
 */
char
uartio_getch(void)
{
    volatile unsigned int wdTemp;

    wdTemp = Chip_UART_ReadLineStatus(EGWU_ONBOARD_UART);
    if((wdTemp & UART_LSR_RDR) == 0)
        return 0;
    else
        {
        wdTemp = Chip_UART_ReadByte(EGWU_ONBOARD_UART);
        return wdTemp;
        }
}





/*
 *****************************************************************
 *description:  getc routine. 
 *output:       valid char
 *****************************************************************
 */
char
uartio_getc(void)
{
    volatile unsigned int wdTemp;

    do
        {
        wdTemp  = Chip_UART_ReadLineStatus(EGWU_ONBOARD_UART);
        wdTemp &= UART_LSR_RDR;
        }while(wdTemp == 0);

    wdTemp = Chip_UART_ReadByte(EGWU_ONBOARD_UART);
    return wdTemp;
}





/*
 *****************************************************************
 *description:  putc routine. 
 *input:        char    byByte
 *****************************************************************
 */
void
uartio_putc(char byByte)
{
    volatile unsigned int wdTemp;

    Chip_UART_SendByte(EGWU_ONBOARD_UART, byByte);
    do
        {
        wdTemp  = Chip_UART_ReadLineStatus(EGWU_ONBOARD_UART);
        //wdTemp &= (UART_LSR_TEMT | UART_LSR_THRE);
        wdTemp &= UART_LSR_TEMT;
        }while(wdTemp != UART_LSR_TEMT);

}





/*
 *****************************************************************
 *description:  gets routine. 
 *inputs:       char    *ptrString
 *              int     wdSize
 *output:       int     string length
 *note:         echo back typed characters
 *****************************************************************
 */
int
uartio_gets(char *ptrString, int wdSize)
{
    volatile unsigned char wdByte;
    volatile unsigned int  wdStrlen = 0;


    while(wdSize > 0)
        {
        wdByte = uartio_getc();
        switch(wdByte)
                {
                case    ASCII_CR:
                case    ASCII_ESC:
                        {
                        *(ptrString + wdStrlen) = 0;
                        return wdStrlen;
                        }
                case    ASCII_BS:
                        {
                        if(wdStrlen > 0)
                                {
                                uartio_putc(ASCII_BS);
                                wdStrlen--;             
                                }
                        break;
                        }
                case    ASCII_DEL:
                        {
                        *(ptrString + wdStrlen) = 0;
                        break;
                        }
                default:
                        {
                        *(ptrString + wdStrlen) = wdByte;
                        uartio_putc(wdByte);    
                        wdStrlen++;
                        wdSize--;
                        break;
                        }
                }
        }

    *(ptrString + wdStrlen) = 0;
    return wdStrlen;
}




/*
 *****************************************************************
 *description:  uartio dma isr
 *note:         a) clear index
 *              b) swap pointers
 *              c) release mutex
 *****************************************************************
 */
void
uartio_dma_isr(void)
{
    tclib_release_semaphore((unsigned int *)(strUartTxBuf.ptrDmaMutex));
}





/*
 *****************************************************************
 *description:  uartio tx flush routine.  can be called by timer
 *              (systick) isr as well as uartio_puts()
 *
 *notes:        check strUartTxBuf.ptrUsrIndex != 0
 *              a) attempt to acquire the mutex
 *              b) if unsuccessful return -1
 *              c) if successful proceed
 *              d) request dma channel
 *              e) call nvic_dma_hook_isr_to_chan()
 *              f) program dma to generate int on complete
 *              g) set ptrUsr* pointers to the other half buffers
 *              h) clear *ptrIndex to 0
 *              i) return 0
 *
 *              j) dont NOT busy poll in this routine since it is 
 *                 called both by uartio_puts() and the systick 
 *                 handler every 1mS
 *              k) to prevent race condition of dual dma channels
 *                 writing to uart tx ... examine ptrDmaMutex in
 *                 uartio_tx_flush
 *              l) uartio_tx_flush should return 0 on success -1
 *                 otherwise
 *****************************************************************
 */
int
uartio_tx_flush(void)
{
    volatile unsigned int wdTemp, wdChan;

    if(*(strUartTxBuf.ptrUsrIndex) == 0)
        return 0;

    /*check to see if a dma is in operation*/
    if(*(strUartTxBuf.ptrDmaMutex) != 0)
        return -1;

    if((tclib_acquire_semaphore((unsigned int *)strUartTxBuf.ptrUsrMutex)) == 0)
        return -1;
    else
        strUartTxBuf.ptrDmaMutex = strUartTxBuf.ptrUsrMutex;


    wdChan = Chip_GPDMA_GetFreeChannel(LPC_GPDMA, 0);
    gpdma_hook_chan_isr(wdChan, uartio_dma_isr);
    

    /*
     *************************************************************
     *program dma controller
     *************************************************************
     */
    LPC_GPDMA->INTTCCLEAR         = (1 << wdChan);
    LPC_GPDMA->INTERRCLR          = (1 << wdChan);

    LPC_GPDMA->CH[wdChan].SRCADDR = (unsigned int)strUartTxBuf.ptrUsrBuf;
    LPC_GPDMA->CH[wdChan].DESTADDR= (unsigned int)&LPC_UART1->THR;
    LPC_GPDMA->CH[wdChan].LLI     = 0;

    wdTemp  = (*strUartTxBuf.ptrUsrIndex);
    wdTemp |= GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_1);
    wdTemp |= GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_1);
    wdTemp |= GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_BYTE);
    wdTemp |= GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_BYTE);
    wdTemp |= GPDMA_DMACCxControl_SI;
    wdTemp |= GPDMA_DMACCxControl_I;
    LPC_GPDMA->CH[wdChan].CONTROL = wdTemp;

    wdTemp  = GPDMA_DMACCxConfig_DestPeripheral(GPDMA_CONN_UART1_Tx);
    wdTemp |= GPDMA_DMACCxConfig_TransferType(GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA);
    wdTemp |= GPDMA_DMACCxConfig_IE;
    wdTemp |= GPDMA_DMACCxConfig_ITC;
    wdTemp |= GPDMA_DMACCxConfig_E;
    LPC_GPDMA->CH[wdChan].CONFIG  = wdTemp;

    wdTemp  = GPDMA_DMACConfig_E;
    LPC_GPDMA->CONFIG = wdTemp;


    *(strUartTxBuf.ptrUsrIndex) = 0;
    if(strUartTxBuf.ptrUsrIndex == &strUartTxBuf.wdTopIndex)
        {
        strUartTxBuf.ptrUsrBuf  = strUartTxBuf.sbBotBuf;
        strUartTxBuf.ptrUsrIndex= &strUartTxBuf.wdBotIndex;
        strUartTxBuf.ptrUsrMutex= &strUartTxBuf.wdBotMutex;
        }
    else
        {
        strUartTxBuf.ptrUsrBuf  = strUartTxBuf.sbTopBuf;
        strUartTxBuf.ptrUsrIndex= &strUartTxBuf.wdTopIndex;
        strUartTxBuf.ptrUsrMutex= &strUartTxBuf.wdTopMutex;
        }
          
    return 0;
}





/*
 *****************************************************************
 *description:  puts routine. 
 *inputs:       char *ptrString = pointer to string
 *              int  wdLen      = number of characters to print 
 *****************************************************************
 */
void
uartio_puts(char *ptrString, int wdLen)
{
    volatile unsigned int  **ptrMutex, **ptrIndex, wdTemp;
    volatile unsigned char **ptrBuf;

    ptrMutex = &(strUartTxBuf.ptrUsrMutex);
    ptrIndex = &(strUartTxBuf.ptrUsrIndex);
    ptrBuf   = &(strUartTxBuf.ptrUsrBuf);

    do
        {
        wdTemp = tclib_acquire_semaphore((unsigned int *)*ptrMutex);
        }while(wdTemp == 0);


    while((wdLen--) >= 0)
        {
        if((**ptrIndex) != EGWU_UART_BUF_SIZE)
                {
                *((*ptrBuf) + (**ptrIndex)) = *ptrString;

                ptrString++;
                (**ptrIndex)++;
                }
        else
                {
                tclib_release_semaphore((unsigned int *)*ptrMutex);

                while(uartio_tx_flush() !=0)
                        ;
                
                do
                        {
                        wdTemp = tclib_acquire_semaphore((unsigned int *)*ptrMutex);
                        }while(wdTemp == 0);
                }
        }

    tclib_release_semaphore((unsigned int *)*ptrMutex);
}



     

/*
 *****************************************************************
 *description:  printf routine. 
 *inputs:       char *ptrString = null terminated string        
 *              int   wdValue   = %d/%x value
 *****************************************************************
 */
void
uartio_printf(char *ptrString, int wdValue)
{
    volatile unsigned int  wdOffset, wdTemp;
    volatile char byChar, *ptrBase, sbTemp[20+1];

    ptrBase = ptrString;
    wdOffset= 0; 
    while(*(ptrBase + wdOffset) !=0)
        {
        byChar = *(ptrBase + wdOffset);
        switch(byChar)
                {
                case    '%':
                        {
                        if(wdOffset > 0)
                                {
                                uartio_puts((char *)ptrBase, (wdOffset-1));
                                ptrBase += wdOffset;
                                wdOffset = 0;
                                }
        
                        ptrBase++;
                        wdOffset = 0;
                        if(*(ptrBase + wdOffset) == 0)
                                return;

                        byChar = *(ptrBase + wdOffset);
                        ptrBase++;
                        switch(byChar)
                                {
                                case    'd':
                                case    'x':
                                        {
                                        tclib_itoa((unsigned int)wdValue, (unsigned char *)sbTemp);
                                        wdTemp = tclib_strlen((unsigned char *)sbTemp);
                                        uartio_puts((char *)sbTemp, wdTemp);
                                        break;
                                        }
                                case    'c':
                                        {
                                        ptrBase--;
                                        *(ptrBase) = (unsigned char)wdValue;
                                        wdOffset++;
                                        break;
                                        }
                                case    's':
                                        {
                                        wdTemp = tclib_strlen((unsigned char *)wdValue);
                                        uartio_puts((char *)wdValue, wdTemp);
                                        break;
                                        }
                                default:
                                        {
                                        wdOffset++;
                                        break;
                                        }
                                }

                        break;
                        }
                default:
                        {
                        wdOffset++;
                        break;
                        }
                }


        }
        if(wdOffset > 0)
                uartio_puts((char *)ptrBase, wdOffset);
}





/*
 ***********************************************************************
 description:   fractional divider test routine. used to tweak the uart
                baud rate clock
 notes:         for this to work - put a paper clip between pin 2(rx) 
                and pin 3(tx) of the serial cable. which effectively 
                creates a loop back.
                then set a break point where the "if" test of the data
                read back evaluates as true
 ***********************************************************************
 */
void
test_determine_fractional_divider_values(void)
{
    volatile unsigned int wdTemp, wdCount, wdErrorFlag;
    volatile unsigned int wdMulVal, wdDivAddVal;
    const    int          wdTestVal='0';


        
    /*
     *******************************************************************
     cycle through the 14 x 15 fractional divider values
     reset RX fifo
     wait 1mS after setting fractional dividers

     write and read back three values in succession
     turn on flag if any error
   
     evaluate results
     *******************************************************************
     */
    for(wdMulVal = 1; wdMulVal <= 15; wdMulVal++)
        {
        for(wdDivAddVal = 0; wdDivAddVal <= 15; wdDivAddVal++)
                {
                wdTemp  = (wdMulVal << 4);
                wdTemp |=  wdDivAddVal;
                EGWU_ONBOARD_UART->FDR = wdTemp;
                timer_delay_mS(1);              
                EGWU_ONBOARD_UART->FCR |= UART_FCR_RX_RS;


                for(wdCount = 0, wdErrorFlag = 0; wdCount < 3; wdCount++)
                        {
                        uartio_putc(wdTestVal + wdCount);
                        //if((uartio_getc()) != (wdTestVal + wdCount))
                        //      wdErrorFlag++;
                        }


                if(wdErrorFlag == 0)
                        {
                        uartio_putc(wdMulVal);
                        uartio_putc(wdDivAddVal);
                        }
                }
        }



    /*
     *******************************************************************
     flash bi-LED in a sequence every 500mS
     *******************************************************************
     */
    do
        {
        wdTemp++;
        gpio_set_lpc_biled(wdTemp);
        timer_delay_mS(1000);
        }while(0);
}





#endif