Monday, December 28, 2015

Phase 3: MPU

Per the ARM cortex r1p1 technical reference manual, the cortex-M3 includes (optional) MPU (which the ST32 cores do not have but the LPC cores do). This memory protection unit has 8 regions.

I plan on only using 4 of these regions.
region 0 will span the block of the default memory map designated "code" and "data". That would be 0x0000 0000 to 0x3fff ffff. The attributes will be:
strongly ordered
executable
cached

region 1 will span the block of the default memory map designated "peripherals". That would be 0x4000 0000 to 0x5fff ffff.  The attributes will be:
strongly ordered
non executable
non buffered
non cached

region 2 will be identical to region 0 in attributes, but will span the block of the default memory map designated "external ram". That would be the space for both SRAM and SDRAM or 0x6000 0000 to 0x9fff ffff.

finally
region 3 will be identical to region 1 in attributes, but will span the block of the default memory map designated "external devices". That would be span 0xa000 0000 to 0xdfff ffff

I needed to do this because the default memory map on the lpc1778 will allow read and write access to SDRAM block but not execution (code loading).
Worked out most of the details on paper and code will be in IE_egwu_setup.c. Here is a snippet below


    #define     EGWU_MPU_REGION_0_BASE          0x00000000
    #define     EGWU_MPU_REGION_0_ATTR          0x0302003B

    #define     EGWU_MPU_REGION_1_BASE          0x40000000
    #define     EGWU_MPU_REGION_1_ATTR          0x13040039

    #define     EGWU_MPU_REGION_2_BASE          0x60000000
    #define     EGWU_MPU_REGION_2_ATTR          0x0302003B

    #define     EGWU_MPU_REGION_3_BASE          0x40000000
    #define     EGWU_MPU_REGION_3_ATTR          0x1304003D
 
 
 
 
 
/*
 *****************************************************************
 *description:  configure the memory protection unit
 *              
 *note:         of the 8 regions I will setup 4 as below. regions
 *              0 and 2 are identical in attributes are as regions
 *              1 and 3
 *
 *              executable ram attributes:
 *              0000 0011 0000 0010 0000 0000 0011 1011
 *              peripheral device attributes:
 *              0001 0011 0000 0100 0000 0000 0011 1101
 *
 *              region 0 = internal ram (0x0000 0000 - 0x4000 0000)
 *                         strongly ordered, cache, executable
 *
 *              region 1 = int periphs  (0x4000 0000 - 0x6000 0000)
 *                         strongly ordered, non execute, non cache
 *
 *              region 2 = external ram (0x6000 0000 - 0xa000 0000)
 *                         strongly ordered, cache, executable
 *
 *              region 3 = ext periphes (0xa000 0000 - 0xf000 0000)
 *                         strongly ordered, non execute, non cache
 *
 *              disable interrupts while doing this
 *              and
 *              execute "dsb" and "isb" before exiting
 *****************************************************************
 */
void
setup_mpu(void)
{
    volatile unsigned int wdTemp, wdCount;
 
    wdTemp   = MPU->TYPE;
    wdTemp  &= MPU_TYPE_DREGION_Msk;
    wdTemp >>= MPU_TYPE_DREGION_Pos;
    if(wdTemp != 8)
        return;
    else
        {
        asm("cpsid i");
        MPU->CTRL = 0;
        }

    for(wdCount = 0; wdCount < 8; wdCount++)
        {
        MPU->RNR = wdCount;
        switch(wdCount)
                {
                case    0:
                        {
                        wdTemp = (EGWU_MPU_REGION_0_BASE & MPU_RBAR_ADDR_Msk);  
                        MPU->RBAR = wdTemp;
                        MPU->RASR = EGWU_MPU_REGION_0_ATTR;
                        break;
                        }
                case    1:
                        {
                        wdTemp = (EGWU_MPU_REGION_1_BASE & MPU_RBAR_ADDR_Msk);  
                        MPU->RBAR = wdTemp;
                        MPU->RASR = EGWU_MPU_REGION_1_ATTR;
                        break;
                        }
                case    2:
                        {
                        wdTemp = (EGWU_MPU_REGION_2_BASE & MPU_RBAR_ADDR_Msk);  
                        MPU->RBAR = wdTemp;
                        MPU->RASR = EGWU_MPU_REGION_2_ATTR;
                        break;
                        }
                case    3:
                        {
                        wdTemp = (EGWU_MPU_REGION_3_BASE & MPU_RBAR_ADDR_Msk);  
                        MPU->RBAR = wdTemp;
                        MPU->RASR = EGWU_MPU_REGION_3_ATTR;
                        break;
                        }
                default:
                        break;
                }
        }

    MPU->CTRL = MPU_CTRL_ENABLE_Msk;
    asm("isb");
    asm("dsb");
    asm("cpsie i");
}



 

Phase 3: Overview

On the agenda:
1. setting up the Memory Protection Unit

2. configuring the External Memory Controller for SDRAM and SRAM access

3. debugging my Xmodem function and using it to retrieve files from the host written into SDRAM
    note: consider adding a cksum calculation routine in the monitor program that can be accessed with the command "cksum base_addr length"

4. verilog code for the lattice XP2 fpga to implement address decode and glue logic. Ill know this works when I can control LEDs D4-D7 connected to the FPGA  but through the LPC1778. I have already started re-reading "A Verilog HDL Primer" by J Bhasker.


5. its also at this point that I want to put in support for LPC1778 access to the cypress USB controller - through the lattice XP2 fpga.

6. this is all after I verify that I can download bit streams to the lattice part from the ft2232

Friday, December 25, 2015

Phase 2: Complete

Finally!!!
Took long enough

Lets see ... the bug fixes I made were all related to either solving a race condition where in (calls to uartio_tx_flush while DMA channel 0 has the mutex to the first swinging buffer half ... has the potential to configure DMA channel 1 for the second swinging buffer half - corrupting the tx output and handshaking operation in uartio_dma_isr() that clears the DmaMutex)

Took some time to see and correct that. Honestly all this could have been avoided if I stuck with the backup plan of not using DMA to offload uart tx and instead using the systick handler and polled I/O

But I have no regrets because ultimately I want to be able to dump data and debug messages as fast  as possible without burdening the main processor and DMA is always the way to go.  Having the entire process interrupt driven is added icing on the cake.

The only other issue was formatting the output of various monitor_assist_() routines. The results from minicom are shown below.

Another issue I tackled and may have to revisit is the problems I often have loading code with openocd/arm-none-eabi-gdb. I chose conservative values for CCLK/adapter_khz keeping in mind that although I initialize the lpc1788 to run off the external 24Mhz clock through the PLL to generate a 120Mhz cpu clock, it powers up with the 12Mhz RC clock enabled ... and that should be what openocd parameters should be set to.

CCLK should be 12000
adapter_khz should be 1/6th of that or less ... 500 to 2000

..ie........
..ieieie....
..ie........
..ieieie....
..ie........    Igbo Embedded
..ieieie....    EGWU v1,1 (c) 2015
..ie........    Samuel Igwe


egwu-> mdw 0x10000000 0x30
10000000:       10010000  10001E0D  10000D91  10000D91  10000D91  10000D91  10000D91  10000D91  
10000020:       10000D91  10000D91  10000D91  10000D91  10000D91  10000D91  10000D91  10000D29  
10000040:       10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  
10000060:       10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  
10000080:       10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  10000D9D  
100000A0:

egwu-> mdw 0x10000000 
10000000:       10010000  

egwu-> mdh 0x10000000 0x30
10000000:       0000  1001  1E0D  1000  0D91  1000  0D91  1000  
10000010:       0D91  1000  0D91  1000  0D91  1000  0D91  1000  
10000020:       0D91  1000  0D91  1000  0D91  1000  0D91  1000  
10000030:       0D91  1000  0D91  1000  0D91  1000  0D29  1000  
10000040:       0D9D  1000  0D9D  1000  0D9D  1000  0D9D  1000  
10000050:

egwu-> mdh 0x10000000 
10000000:       0000  

egwu-> mdb 0x10000000 0x30
10000000:       00  00  01  10  0D  1E  00  10  
10000008:       91  0D  00  10  91  0D  00  10  
10000010:       91  0D  00  10  91  0D  00  10  
10000018:       91  0D  00  10  91  0D  00  10  
10000020:       91  0D  00  10  91  0D  00  10  
10000028:

egwu-> mdb 0x10000000
10000000:       00  

egwu-> mww 0x20000000 0xc0defeed
C0DEFEED
egwu-> mww 0x20000000 0xa5015a02
A5015A02
egwu-> mdw 0x20000000 4
20000000:       A5015A02  BEB2400C  22916148  0010C3C9  

egwu-> mww 0x2000004 0xc0defeed
..ie........
..ieieie....
..ie........
..ieieie....
..ie........    Igbo Embedded
..ieieie....    EGWU v1,1 (c) 2015
..ie........    Samuel Igwe


egwu-> mww 0x20000004 0xc0defeed
C0DEFEED
egwu-> mdw 0x20000000 4
20000000:       A5015A02  C0DEFEED  22916148  0010C3C9 



Saturday, December 19, 2015

Phase 2: my script files for openocd 0.9.0

alias openocd_ftdi='openocd -s /home/rombios/DEVEL/EGWU/openocd/scripts -f interface/ftdi/egwu_interface_usb.cfg -f board/egwu_board.cfg'
alias openocd_olimex='openocd -s /home/rombios/DEVEL/EGWU/openocd/scripts -f interface/ftdi/olimex-jtag-tiny.cfg -f board/egwu_board.cfg'
alias openocd_jlink='openocd -f interface/jlink.cfg -f board/olimex_stm32_h103.cfg'
 
 
# egwu_board.cfg

set WORKAREASIZE 0x10000
source [find target/egwu_target_1788.cfg] 
 
 
 
 
 
#
# embedded projects openocd usb adapter v3
# egwu_interface_usb.cfg (ftdi)
# 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_init        0x0008 0x000b
ftdi_layout_signal      nTRST -data 0x0010
 
 
 
 
 
# 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 120000
source [find target/egwu_target_17xx.cfg];
#cortex_m reset_config sysresetreq
cortex_m reset_config trst_only 
 
 
 
 
 
# egwu_target_17xx.cfg

adapter_khz 2000

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  250

# delays on reset lines
adapter_nsrst_assert_width      500
adapter_nsrst_delay             500

jtag_ntrst_assert_width         500
jtag_ntrst_delay                500

$_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 
 
 
  

Phase 2: transition from arm-linux-gnueabi* toolset to arm-none-eabi* toolset

https://community.freescale.com/thread/313490 sums it up well :

arm-none-eabi - This tool chain targets for ARM architecture, has no vendor, does not target an operating system and complies with the ARM EABI.
arm-none-linux-gnueabi - This toolchain targets the ARM architecture, has no vendor, creates binaries that run on the Linux operating system, and uses the GNU EABI. It is used to target ARM-based Linux systems.


The former favors my design as there is no operating system running on EGWU.
Also there were some issues with faults tied to instructions generated by the latter toolset.

Its funny that the moment I switched my Makefile environment variables over, I got errors on my thumb2 C library tclibC.S related to NOT using the IT block of conditional instructions. I have since read up and remedied that mistake.

As an aside:
arm-linux-gnueabi-gcc -v
Using built-in specs.
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/arm-linux-gnueabi/include/c++/4.4.5 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --disable-sjlj-exceptions --enable-checking=release --program-prefix=arm-linux-gnueabi- --includedir=/usr/arm-linux-gnueabi/include --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabi --with-headers=/usr/arm-linux-gnueabi/include --with-libs=/usr/arm-linux-gnueabi/lib
Thread model: posix
gcc version 4.4.5 (Debian 4.4.5-8)





arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-none-eabi/4.8/lto-wrapper
Target: arm-none-eabi
Configured with: ../gcc-4.8.4/configure --build=x86_64-linux-gnu --prefix=/usr --includedir='/usr/lib/include' --mandir='/usr/lib/share/man' --infodir='/usr/lib/share/info' --sysconfdir=/etc --localstatedir=/var --disable-silent-rules --libexecdir='/usr/lib/lib/gcc-arm-none-eabi' --disable-maintainer-mode --disable-dependency-tracking --enable-languages=c,c++ --prefix=/usr/lib --infodir=/usr/share/doc/gcc-arm-none-eabi/info --mandir=/usr/share/man --htmldir=/usr/share/doc/gcc-arm-none-eabi/html --pdfdir=/usr/share/doc/gcc-arm-none-eabi/pdf --bindir=/usr/bin --libexecdir=/usr/lib --libdir=/usr/lib --with-system-zlib --enable-multilib --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-libstdc++-v3 --disable-nls --disable-shared --disable-threads --disable-tls --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-none-eabi --with-gnu-as --with-gnu-ld --with-headers=no --without-newlib --with-pkgversion=4.8.4-1+11-1 --without-included-gettext --with-multilib-list=armv6-m,armv7-m,armv7e-m,armv7-r INHIBIT_LIBC_CFLAGS=-DUSE_TM_CLONE_REGISTRY=0 AR_FOR_TARGET=arm-none-eabi-ar AS_FOR_TARGET=arm-none-eabi-as LD_FOR_TARGET=arm-none-eabi-ld NM_FOR_TARGET=arm-none-eabi-nm OBJDUMP_FOR_TARGET=arm-none-eabi-objdump RANLIB_FOR_TARGET=arm-none-eabi-ranlib READELF_FOR_TARGET=arm-none-eabi-readelf STRIP_FOR_TARGET=arm-none-eabi-strip
Thread model: single
gcc version 4.8.4 20141219 (release) (4.8.4-1+11-1)



Phase 2: Command Interpreter

After 5 hours straight debugging ... I have a rudimentary command interpreter in place. Most notably I had to change my tclib_strcmp routine in IE_tclib.S. Other files such as IE_egwu_monitor/IE_egwu_uartio and even IE_egwu_setup in the "core" subdirectory underwent changes.

What stuck out what a bug in the UART swinging buffer and the mutex shared between the user program and the DMA Engine's ISR that releases that resource. Anyway ... I have it all squared away. Once I debug the memory peek and poke command (mdx and mwx) I can transition to phase 3

time for some much needed sleep

/*
 *****************************************************************
 *description:  string comparison 
 *inputs:       char *ptrStrSrc=string 1
 *              char *ptrStrDst=string 2
 *              int  wdCount   =number of characters to compare 
 *output:       int = 0 on success failing index on error
 *int
 *tclib_strcmp(unsigned char *ptrStrSrc,\
 *             unsigned char *ptrStrDst,\
 *             int wdCount)
 *{
 *unsigned int wdIndex;
 *
 *for(wdIndex=0; wdIndex <wdCount; wdIndex++)
 *      {
 *      if (ptrStrSrc[wdIndex] == NULL || \
 *           ptrStrDst[wdIndex] == NULL || \
 *          (ptrStrSrc[wdIndex] - ptrStrDst[wdIndex]) !=0)
 *              return wdIndex;
 *      }
 *
 *return 0;          
 *}
 *****************************************************************
 */
    .align  2
    .global tclib_strcmp
/*
 *****************************************************************
 *r0 = ptrDst
 *r1 = ptrSrc
 *returns r0 strcmp value
 *r1 = src1
 *r2 = src2
 *r3 = scratch
 *r4 = scratch
 *r0 = cmp
 *****************************************************************
 */
    .thumb_func
    tclib_strcmp:
    push    {r1-r4, lr}

    mov     r2, r0                      /*save src1 in r2*/
    mov     r0, #0                      /*zero out r0*/


        tclib_strcmp_loop:
        ldrb    r3, [r1], #1            
        andS    r3, r3, #0x0ff          /*clear upper bits*/
        orrS    r3, r3, #0              /*end of string?*/
        beq     tclib_strcmp_exit

        ldrb    r4, [r2], #1
        andS    r4, r4, #0x0ff          /*clear upper bits*/
        orrS    r4, r4, #0              /*end of string?*/
        beq     tclib_strcmp_exit

        cmp     r4, r3
        it      EQ
        beq     tclib_strcmp_loop
                                        /*else*/
        ite     HI
        addhi   r0, r0, #1              /*track strcmp results*/
        subls   r0, r0, #1              /*ditto*/

        itt     NE
        popne   {r1-r4, lr}             /*exit*/
        movne   pc, lr                  /*exit*/
        
        
        tclib_strcmp_exit:
        itt     EQ
        popeq   {r1-r4, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        b       tclib_strcmp_loop
 
 
 
 
Finally this is what the command interpreter output looks like under minicom 
 
..ie........ 
..ieieie.... 
..ie........ 
..ieieie.... 
..ie........ Igbo Embedded 
..ieieie.... EGWU v1.1 (c) 2015 
..ie........ Samuel Igwe


egwu-> help
go address           :  jump to address  
ldusb address        :  load file to address using USB  
ldxmodem address     :  load file to address using xmodem+serial port  
help                 :  display command table  
mdb|mdh|mdw addr len :  display byte|word|dword at address         
mwb|mwh|mww addr val :  write byte|word|dword to address         
reset                :  reset the lpc17
egwu-> mdb 0x10000000
invalid or non existent address

egwu-> reset 

Wednesday, December 16, 2015

Phase 2: main

/*
 ***********************************************************************
 *name:         Samuel Igwe
 *date:         07/04/2015
 *description:  main ... what else
 *              phase 1:        system initialization
 *                              led + timer
 *              phase 2:        the above with 
 *                              uart communication 115200
 *                              simple monitor program 
 *              phase 3:        the above with
 *                              fpga setup in order to control LED's 
 *                              enabling static and dram memory controller
 *              phase 4:        the above with
 *                              usb host support in place for gamepads
 *                              /mouse/keyboards        
 *              phase 5:        the above with
 *                              extended fpga support for usb controller
 *                              glue logic. 
 ***********************************************************************
 */
#include "IE_egwu_setup.h"
#include "IE_egwu_uartio.h"
#include "IE_egwu_monitor.h" 
 
 
 
 
/*
 ***********************************************************************
 *name:         Samuel Igwe
 *date:         07/04/2015
 *description:  main ... what else
 *              phase 1:        system initialization
 *                              led + timer
 *              phase 2:        the above with 
 *                              uart communication 115200
 *                              simple monitor program 
 *              phase 3:        the above with
 *                              fpga setup in order to control LED's 
 *                              enabling static and dram memory controller
 *              phase 4:        the above with
 *                              usb host support in place for gamepads
 *                              /mouse/keyboards        
 *              phase 5:        the above with
 *                              extended fpga support for usb controller
 *                              glue logic. 
 ***********************************************************************
 */
#include "main.h"



int
main(void)
{
    volatile unsigned int wdTemp, *ptrTemp;
    //const           int wdGpio=18, wdTestVal='0';
    //asm ("ldr sp, =0x10008000");
    
    /*stack setup ... to help determine stack issues*/
    //ptrTemp = (volatile unsigned int *)(0x10000000 + 32768 - 4);
    //for(wdTemp = 0; wdTemp <1024; wdTemp++)
    //*(ptrTemp--) = 0xc0defeed;
                

    setup_pll();
    setup_nvic();
    setup_gpio();

    setup_gpdma();
    setup_uart();
    setup_uartio();
        
    gpio_set_lpc_biled(0);
    wdTemp ='0';
    while(1)
        {
        //uartio_printf("%s\n", ptrBanner);

        monitor_execution(&strCmdline);
#ifdef  IGNORE
        wdTemp = strSysTick.wdSeconds;
        uartio_printf("%d\r", wdTemp);
        //      (LPC_GPIO1->SET) = (1 << wdGpio); 

        uartio_putc(wdTemp);
        wdTemp++;
        //uartio_putc('\r');
        if(wdTemp  == '9')
                {
                uartio_putc(13);
                uartio_putc(10);
                wdTemp = '0';
                }

        timer_delay_mS(1000);
        //      (LPC_GPIO1->CLR) = (1 << wdGpio); 
#endif
        }
}





 

Tuesday, December 8, 2015

Phase 2: Revisiting the MAX232E overheating problem

Often after power up and code execution ... with the UART producing output ... Id touch the level converter and it will burn to the touch ... like really really hot. I have had this problem since I began setting up UART communication

Google turned up the following hits:
http://www.avrfreaks.net/forum/max232-heating-hell
http://www.electro-tech-online.com/threads/max232-gets-overheated.107364/

And rereading the documentation for the MAX232E indicates that (pg 9)

**********

The unused drivers’ inputs on the MAX205E–MAX208E,MAX211E, MAX213E, and MAX241E can be left unconnected because 400kΩ pull up resistors to VCC are included on-chip. Since all drivers invert, the pull up resistors force the unused drivers’ outputs low. The MAX202E, MAX203E, and MAX232E do not have pull up resistors on the transmitter inputs.
***********************

Seems the the floating input TX2? maybe be picking up stray noise or getting amplified through the op-amp


So going forward I should either
a) connect together the TTL TX1 and TX2 inputs
b) tied the TTL TX* inputs to a pullup resistor ?
c) replace the MAX232E SMD with MAX232 SIP where this problem doesnt exist

So for now I connected the two TX* inputs and pulled it up to VCC via a ~260k resistor. For the DB9-ttl-rs232 adapter external circuit I simply soldered a wire between TX1_in and TX2_in



Friday, December 4, 2015

Phase 2: IE_egwu_monitor

/*
 *****************************************************************
 *name:         IE_egwu_monitor.h
 *author:       Samuel Igwe
 *date:         12/03/2015
 *description:  IE_egwu_monitor program/command interpreter header.
 *****************************************************************
 */
#ifndef IE_EGWU_MONITOR_H
#define IE_EGWU_MONITOR_H

    #include "chip.h"
    #include "chip_lpc177x_8x.h"
    #include "uart_17xx_40xx.h"
    #include "IE_egwu_uartio.h"


    /*
     *************************************************************
     *support variables
     *************************************************************
     */
    enum        {
        MON_ERROR_CMD=0,
        MON_ERROR_ADDRESS,
        MON_ERROR_TOKEN,
        MON_ERROR_COMMANDS};

    enum        {
        MON_CMD_GO=0,
        MON_CMD_HELP,
        MON_CMD_LDUSB,
        MON_CMD_LDXMODEM,
        MON_CMD_MDB,
        MON_CMD_MDH,
        MON_CMD_MDW,
        MON_CMD_MWB,
        MON_CMD_MWH,
        MON_CMD_MWW,
        MON_CMD_RESET,
        NUM_MONITOR_COMMANDS};


    union       UN_ADDR {
        volatile unsigned int   *ptrInt;
        volatile unsigned short *ptrShort;
        volatile unsigned char  *ptrChar;
        }unAddr;

        
    struct MONITOR_CMDLINE      {
        volatile int wdCmd;
        volatile int wdAddr;
        volatile int wdOpSize;
        volatile int wdVallen;
        }strCmdline;

        
    /*
     *************************************************************
     *routines
     *************************************************************
     */
    void monitor_assist_reset(struct MONITOR_CMDLINE *ptrStrCmdline);
    void monitor_assist_go(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_assist_ldxmodem(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_assist_ldusb(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_assist_mwx(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_assist_mdx(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_assist_help(struct MONITOR_CMDLINE  *ptrStrCmdline);
    void monitor_execution(struct MONITOR_CMDLINE *ptrStrCmdline);
    void monitor_flag_error(int wdErrorNum);
    
    int  monitor_parse_cmdline(unsigned char *ptrCmdString, struct MONITOR_CMDLINE *ptrStrCmdline);
    int  monitor_get_next_token(unsigned char *ptrSrc, unsigned char *ptrDst, int DstSize);
    int  monitor_search_table(unsigned char *ptrString, char *ptrTable[], int wdSize);
  

#endif 
 
 
 
 
 
 
/*
 *****************************************************************
 *name:         IE_egwu_monitor.c
 *author:       Samuel Igwe
 *date:         12/03/2015
 *description:  monitor program/command interpreter and support 
 *              functions. 
 *****************************************************************
 */
#ifndef IE_EGWU_MONITOR_C
#define IE_EGWU_MONITOR_C

#include "IE_egwu_monitor.h"

    void (*ptrMonCmdFuncTable[NUM_MONITOR_COMMANDS])(struct \
                              MONITOR_CMDLINE *ptrStrCmdline) ={
        monitor_assist_go,
        monitor_assist_help,
        monitor_assist_ldusb,
        monitor_assist_ldxmodem,
        monitor_assist_mdx,
        monitor_assist_mdx,
        monitor_assist_mdx,
        monitor_assist_mwx,
        monitor_assist_mwx,
        monitor_assist_mwx,
        monitor_assist_reset};


    char *ptrMonErrorStrings[] = {
        "\r\ncommand error",
        "\r\ninvalid or non existent address",
        "\r\ntoken error"};


    char *ptrMonCmdStrings[] = {
        "go",
        "help",
        "ldusb",
        "ldxmodem",
        "mdb",
        "mdh",
        "mdw",
        "mwb",
        "mwh",
        "mww",
        "reset"};


    char *ptrBanner = {
       "\r\n..ie........\
        \r\n..ieieie....\
        \r\n..ie........\
        \r\n..ieieie....\
        \r\n..ie........\tIgbo Embedded\
        \r\n..ieieie....\tEGWU v1,1 (c) 2015\
        \r\n..ie........\tSamuel Igwe\n\n"};


    char *ptrPrompt = "\r\negwu-> ";


    char *ptrMonUsage = {
        "\r\ngo address           :\t jump to address\
         \r\nldusb address        :\t load file to address using USB\
         \r\nldxmodem address     :\t load file to address using xmodem+serial port\
         \r\nhelp                 :\t display command table\
         \r\nmdb|mdh|mdw addr len :\t display byte|word|dword at address\
         \r\nmwb|mwh|mww addr val :\t write byte|word|dword to address\
         \r\nreset                :\t reset the lpc1778\n\n"};



/*
 *****************************************************************
 *description:  monitor executioner
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *note:         clear screen
 *              print banner
 *              loop:
 *                      get string
 *                      call monitor_parse_string()
 *                      check result != -1
 *                      take action
 *                      loop loop
 *............
 *..ie........
 *..ieieie....
 *..ie........
 *..ieieie....
 *..ie........
 *..ie........
 *..ieieie....
 *..ie........
 *............
 *****************************************************************
 */
void
monitor_execution(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    volatile unsigned int wdTemp;
    unsigned char     sbTemp[80+1];


    uartio_printf("%s", (unsigned int)ptrBanner);
    while(1)
        {
        tclib_memset((unsigned char *)ptrStrCmdline, 0, sizeof(struct MONITOR_CMDLINE));
        uartio_printf("%s", (unsigned int)ptrPrompt);

        if((uartio_gets((char *)sbTemp, 80)) < 4)
                continue;

        wdTemp = monitor_parse_cmdline(sbTemp, ptrStrCmdline);
        if(wdTemp >= MON_CMD_GO && wdTemp <= MON_CMD_RESET)
                ptrMonCmdFuncTable[wdTemp](ptrStrCmdline);
        }       


     
    
}
 



/*
 *****************************************************************
 *description:  "reset" command
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_reset(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    uartio_printf("\n\rpreparing to reset board \n", 0);
    timer_delay_mS(1000);
    /*NVIC_SystemReset();
      asm ("ldr r0, =0x10000004");
      asm ("mov pc, [r0]"); Error: r15 not allowed here -- `mov pc,[r0]'
      */

    /*do something with a register write to the FPGA that resets the
      entire system ... although this is only useful for rom code
      for now just jump to main*/ 

      main();
}
 




/*
 *****************************************************************
 *description:  "go" command
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_go(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    unsigned int wdTemp = ptrStrCmdline->wdAddr;
    
    uartio_printf("preparing to jump to address %x\n", wdTemp);
    timer_delay_mS(1000);

//    asm ("ldr r0, =wdTemp");
    asm ("ldr sp, =0x10010000");
    asm ("mov pc, r0");

}





/*
 *****************************************************************
 *description:  "ldxmodem" command
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_ldxmodem(struct MONITOR_CMDLINE *ptrStrCmdline)
{
}





/*
 *****************************************************************
 *description:  "ldusb" command
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_ldusb(struct MONITOR_CMDLINE *ptrStrCmdline)
{
}





/*
 *****************************************************************
 *description:  "mwb/mwh/mww" commands
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_mwx(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    unsigned int wdTemp;
    union    UN_ADDR *ptrAddr = &unAddr;

    ptrAddr->ptrInt = (volatile unsigned int *)ptrStrCmdline->wdAddr;
    if(ptrStrCmdline->wdOpSize == 1)
        {
        *ptrAddr->ptrChar = ptrStrCmdline->wdVallen;
        wdTemp = *ptrAddr->ptrChar;
        }
    else
        {
        if(ptrStrCmdline->wdOpSize == 2)
                {
                *ptrAddr->ptrShort = ptrStrCmdline->wdVallen;
                wdTemp = *ptrAddr->ptrShort;
                }
        else
                {
                *ptrAddr->ptrInt = ptrStrCmdline->wdVallen;
                wdTemp = *ptrAddr->ptrInt;
                }
        }

        uartio_printf("\n\r%x", wdTemp);
}





/*
 *****************************************************************
 *description:  "mdb/mdh/mdw" commands
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_mdx(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    volatile unsigned int wdRow, wdMaxRow, wdTemp, wdValPerRow = 8;
    volatile unsigned int wdCol, wdMaxCol, wdLastCol;
    volatile union    UN_ADDR *ptrAddr = &unAddr;


    if(ptrStrCmdline->wdAddr== 0)
        {
        monitor_flag_error(MON_ERROR_ADDRESS);
        return;
        }
    else
        ptrAddr->ptrInt = (volatile unsigned int *)ptrStrCmdline->wdAddr;

     
    if(ptrStrCmdline->wdVallen == 0)
        ptrStrCmdline->wdVallen++;

    wdMaxRow = (ptrStrCmdline->wdVallen)/wdValPerRow;
    if(wdMaxRow == 0)
        wdMaxRow++;

    wdLastCol= (ptrStrCmdline->wdVallen)%16;

    for(wdRow = 0; wdRow < wdMaxRow; wdRow++)
        {
        uartio_printf("\r\n%x:\t", (unsigned int)ptrAddr->ptrInt);

        if(wdRow == (wdMaxRow - 1))
                wdMaxCol = wdLastCol;
        else
                wdMaxCol = wdValPerRow;

        for(wdCol = 0; wdCol < wdMaxCol; wdCol++)
                {
                if(ptrStrCmdline->wdOpSize == 1)
                        {
                        wdTemp = *ptrAddr->ptrChar;
                        ptrAddr->ptrChar++;
                        wdTemp &= 0x0ff;
                        }
                else
                        {
                        if(ptrStrCmdline->wdOpSize == 2)
                                {
                                wdTemp = *ptrAddr->ptrShort;
                                ptrAddr->ptrShort++;
                                wdTemp &= 0x0ffff;
                                }
                        else
                                {
                                wdTemp = *ptrAddr->ptrInt;
                                ptrAddr->ptrInt++;
                                }
                        }


                switch(ptrStrCmdline->wdOpSize)
                        {
                        case    4:
                                {
                                uartio_printf("%x", ((wdTemp >> 24)&0x0ff));
                                uartio_printf("%x", ((wdTemp >> 16)&0x0ff));
                                wdTemp &= 0x0ffff;
                                /*slide down to code below*/
                                }
                        case    2:
                                {
                                uartio_printf("%x", ((wdTemp >>  8)&0x0ff));
                                wdTemp &= 0x0ff;
                                /*slide down to code below*/
                                }
                        case    1:
                                {
                                uartio_printf("%x  ",(wdTemp));
                                break;
                                }
                        default:
                                {
                                }
                        }
                }

        }

        uartio_printf("\n", 0);
}





/*
 *****************************************************************
 *description:  "help" command
 *inputs:       struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *****************************************************************
 */
void
monitor_assist_help(struct MONITOR_CMDLINE *ptrStrCmdline)
{
    uartio_printf("%s", (unsigned int)ptrMonUsage);
}





/*
 *****************************************************************
 *description:  command line parsing routine
 *inputs:       char   *ptrString     = pointer to input string
 *              struct MONITOR_CMDLINE *ptrStrCmdline = pointer to
 *                                      cmdline structure
 *output:       int                   = 0 on success 
 *****************************************************************
 */
int
monitor_parse_cmdline(unsigned char   *ptrString,\
                      struct MONITOR_CMDLINE *ptrStrCmdline)
{
    int  wdTemp, wdArgCnt = 0;
    unsigned char sbToken[80+1];


    tclib_memset((unsigned char *)ptrStrCmdline, 0, sizeof(struct MONITOR_CMDLINE));
    ptrStrCmdline->wdCmd = -1;          /*0 is a valid cmd index*/

    while(1)
        {
        if((wdTemp = monitor_get_next_token(ptrString, sbToken, 80))  == 0)
                return (ptrStrCmdline->wdCmd);
                
        wdArgCnt++;
        switch(wdArgCnt)
                {
                case    1:      /*command*/
                        {
                        if((wdTemp = monitor_search_table(sbToken, ptrMonCmdStrings, NUM_MONITOR_COMMANDS)) == -1)
                                {
                                monitor_flag_error(MON_ERROR_CMD);
                                return -1;
                                }
                
                        ptrStrCmdline->wdCmd = wdTemp;
                        switch(wdTemp)
                                {
                                case    MON_CMD_HELP:
                                case    MON_CMD_RESET:
                                        {
                                        ptrStrCmdline->wdOpSize = 0;
                                        break;
                                        }
                                case    MON_CMD_MDB:
                                case    MON_CMD_MWB:
                                        {
                                        ptrStrCmdline->wdOpSize = 1;
                                        break;
                                        }
                                case    MON_CMD_MDH:
                                case    MON_CMD_MWH:
                                        {
                                        ptrStrCmdline->wdOpSize = 2;
                                        break;
                                        }
                                case    MON_CMD_MDW:
                                case    MON_CMD_MWW:
                                case    MON_CMD_GO:
                                case    MON_CMD_LDXMODEM:
                                case    MON_CMD_LDUSB:
                                default:
                                        {
                                        ptrStrCmdline->wdOpSize = 4;
                                        break;
                                        }
                                }
                        break;
                        }
                case 2:                 /*address*/
                        {
                        if(sbToken[1] == 'x' || sbToken[1] == 'X')
                                ptrStrCmdline->wdAddr = tclib_atoi(sbToken+2);
                        else
                                ptrStrCmdline->wdAddr = tclib_atoi(sbToken);
                        break;
                        }
                case 3:                 /*value or length*/
                        {
                        if(sbToken[1] == 'x' || sbToken[1] == 'X')
                                ptrStrCmdline->wdVallen = tclib_atoi(sbToken+2);
                        else
                                ptrStrCmdline->wdVallen = tclib_atoi(sbToken);
                        break;
                        }
                default:
                        {
                        monitor_flag_error(MON_ERROR_TOKEN);
                        return -1;
                        }
                }
        }

    if(wdArgCnt < 4)
        return ptrStrCmdline->wdCmd;
    else
        return -1;
}





/*
 *****************************************************************
 *description:  token extraction routine
 *inputs:       char *ptrSrc  = pointer to input string
 *              char *ptrDst  = pointer to destination buffer
 *              int   wdSize  = size of destination buffer
 *output:       int           = string length on success or 0
 *operation:    a) scan through ptrSrc extracting a string
 *              b) see a non space char extract into ptrDst and
 *                 replace with space (convert to lower)
 *              c) when space or NULL is encountered exit
 *              d) return 0 on error or string lenght on success
 *****************************************************************
 */
int
monitor_get_next_token(unsigned char *ptrSrc,\
                       unsigned char *ptrDst,\
                       int   wdSize)
{
    int  wdCount;
    char byValue;
    while(((*ptrSrc) != 0) && (*(ptrSrc) == ' '))
        ptrSrc++;

    if((*ptrSrc) == 0)
        return 0;

    //for(wdCount = 0; ((*ptrSrc) != 0 && (*ptrSrc) != ' '); wdCount++)
    for(wdCount = 0; wdCount <wdSize; wdCount++)
        {
        if((*ptrSrc) == 0 || (*ptrSrc) == ' ')
                break;

        byValue = (*ptrSrc);
        *(ptrSrc++) = ' ';

        if(byValue >='A' && byValue <='Z')
                {
                byValue  =('Z'- byValue);
                byValue += 'a';
                }

        *(ptrDst++) = byValue;
        }

    (*ptrDst) = 0;

    return wdCount;
}





/*
 *****************************************************************
 *description:  error routine
 *inputs:       int wdErrorNum = index into error table
 *****************************************************************
 */
void
monitor_flag_error(int wdErrorNum)
{
    unsigned int wdAddr;

    if(wdErrorNum >= MON_ERROR_COMMANDS)
        return;
    else
        wdAddr = (unsigned int)ptrMonErrorStrings[wdErrorNum];

    uartio_printf("%s\n", wdAddr);
}





/*
 *****************************************************************
 *description:  table search routine 
 *inputs:       char *ptrString  = pointer to input string
 *              char *ptrTable[] = pointer to MonCmdStrings table
 *              int   wdSize     = NUM_MONITOR_COMMANDS
 *output:       int              = enum index into *ptrMonCmdStrings
 *****************************************************************
 */
int
monitor_search_table(unsigned char *ptrString,\
                     char *ptrTable[],\
                     int   wdSize)
{
    short wdTop    = wdSize - 1;
    short wdMiddle = 0;
    short wdBottom = 0;
    short wdResult = 0;

    while(wdBottom <= wdTop)
        {
        wdMiddle   = (wdTop + wdBottom);
        wdMiddle >>= 1;
        wdResult = tclib_strcmp(ptrString, (unsigned char *)ptrTable[wdMiddle]);
        if(wdResult == 0)
                return wdMiddle;

        if(wdResult < 0)
                wdTop = (wdMiddle - 1);
        else
                wdBottom = (wdMiddle + 1);
        }

    return -1;
}



#endif
 

Thursday, December 3, 2015

Phase 2: UART the one

Finally resolved.

Modified test_determine_fractional_divider_values() to not read back the values and instead just write 0, 1, and 2 followed by the current MULVAL and DIVADDVAL values. I saw several times where it appeared ("012") under minicom so once again I dumped the data to a file

stty raw
cat >/tmp/serial.dat </dev/ttyS0
hexdump /tmp/serial.dat

Got back the following:

0000200 c0e0 4416 0327 fe0f 24c0 e6ce 40b6 fe18
0000210 6c80 8c1c 806c f823 4c80 8c3c 804c f04c
0000220 c800 c678 361c 0660 00ff f0d8 380c 0032
0000230 c0e0 e098 7818 e666 9880 18e0 98c3 3006
0000240 e07e c038 8738 0638 0060 aab4 4c82 0c15
0000250 2b88 e108 a458 144b 90ff 962c f880 3130
0000260 0632 7005 7271 0606 8d60 6626 e0d0 1ae0
0000270 2364 0460 34c0 7347 b073 c006 8e24 c4c4
0000280 16c0 80fc 1c6c 8c8c 2780 80f8 384c 8c8c
0000290 7080 00f0 78c8 1e42 6038 fc0e c800 84f0
00002a0 c338 f800 00c0 e098 7818 0086 80fe eab4
00002b0 0482 0c55 a128 e08d 5648 c11c 2498 48d2
00002c0 b0fc 9999 f890 3130 0732 7006 7271 0707
00002d0 8560 7626 e118 0ae0 f424 82b0 16c0 8c23
00002e0 220f c0f0 c624 f2e2 8360 24c0 c48e c0e4
00002f0 fc38 6c80 8c1c 80ec f87b 4c80 8c38 80cc
0000300 f07c cc00 6378 3e0e c060 2aa4 04c2 1955
0000310 d52c f848 42c8 c110 a458 248b 98ff 1624
0000320 fc50 b130 88b2 3086 3231 0708 7170 0872
0000330 6008 2685 5886 e0e1 240b 1004 e0c1 6412
0000340 0423 fe17 34c0 7347 1081 c007 8e24 04c6
0000350 0720 2cc0 cc8e 810c f83c 6c80 8c1c 030c
0000360 f07e 6ab4 1482 10d5 b56c fe01 2b88 e114
0000370 9658 1211 a418 5433 90fe 562c fc68 3130
0000380 0932 3007 3231 0809 7170 0972 6019 2685
0000390 8896 60f0 260b d096 e0c1 641a 06a3 fe18
00003a0 16c0 3127 9633 c0f0 c624 12e2 e020 24c0
00003b0 c48e 8124 fc3f 2aa4 14c2 0055 356c ff28
00003c0 aba8 f891 52c8 c218 a458 24cb 98ff 9624
00003d0 fc60 99b0 4599 30f0 3231 080a 3130 0a32


Randomly chose one occurance of 3130 0732 xx06. This amounts to a MULVAL of 7 and a DIVADDVAL of 6.

Then i modified IE_setup.c's setup_uart() with the above fractional divide values then main.c to write out 0's non stop. This produced the following output under minicom (using the db8 external ttl-rs232 adapter).

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000


Occasionally, it would deteriorate and when I checked the output of RX (null modem) on a scope I saw the signal attenuated to between 0 and 3v but squeezing the max232 chip fixed it ... which means its probably a solder issue (now that the fractional divider value has been found).

Ill fix up the mainboard db9 connector and use that. I might even wire it up in a null modem (swap RX and TX) so I can stick with the straight through serial cable I am using ...