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
        }
}