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
 

Phase 2: IE_egwu_setup

/*
 ****************************************************************************
 *name:         IE_egwu_setup.h
 *author:       Samuel Igwe
 *date:         06/30/2015
 *description:  pll/clock/iopin initialization
 ****************************************************************************
 */
#ifndef IE_EGWU_SETUP_H
#define IE_EGWU_SETUP_H
    #include "chip.h"
    #include "chip_lpc177x_8x.h"
    #include "gpdma_17xx_40xx.h"
    #include "IE_egwu_uartio.h"

   /*
    *************************************************************************
    *#defines
    *************************************************************************
    */
    #define     EGWU_ONBOARD_UART               LPC_UART1
    #define     EGWU_UART_BAUD_RATE             115200
    #define     LPC177X_NUM_INT                 40
    #define     LPC177X_PREEMPT_PRIO_GROUP      2
    #define     EGWU_CPU_CLK_RATE               120000000
    #define     EGWU_CPU_OSC_RATE               24000000
    #define     EGWU_SYSTICK_RATE               (EGWU_CPU_CLK_RATE/1000)

    #define     LPC177X_SRAM_BASE               0x10000000


    #define     LPC_BILED_PORT                  1
    #define     LPC_BILED_PIN1                  23
    #define     LPC_BILED_PIN2                  24

    #define     LPC_LED_PORT                    1
    #define     LPC_LED_PIN                     8

    #define     EGWU_NVIC_USER_BILED_MASK       0x1
    #define     EGWU_NVIC_FAULT_BILED_MASK      0x2



    struct      STR_EGWU_SYSTICK        {
        volatile unsigned int wdSeconds;
        volatile unsigned int wdTicks;
        }strSysTick;


    #define     MINIMUM_PERIPHERAL_IRQ_PRIORITY 3
    enum        egwu_int_pl     {
        USB_INT_PL=MINIMUM_PERIPHERAL_IRQ_PRIORITY,
        UART_INT_PL,
        DMA_INT_PL,
        GPIO_INT_PL,
        WD_INT_PL};


    extern      int     EGWU_IVT;
    const       uint32_t OscRateIn;

    void        (*ptrGpDmaUserIsr[GPDMA_NUMBER_CHANNELS])(void);
    unsigned int wdEnableGpDmaInt;


   /*
    *************************************************************************
    *routines
    *************************************************************************
    */
    void        setup_pll(void);
    void        setup_nvic(void);
    void        setup_gpio(void);
    void        setup_uart(void);

    void        nvic_systick_isr(void);
    void        nvic_fault_isr(void);
    void        nvic_user_isr(void);

    void        gpio_set_lpc_biled(unsigned int wdLedMask);

    void        setup_gpdma(void);
    void        nvic_dma_isr(void);
    void        gpdma_hook_chan_isr(int  wdChannel,\
                                       void (*ptrFunc)(void));  
    void        gpdma_unhook_chan_isr(int wdChannel);
    void        timer_delay_mS(int wdMs);

#endif 
 
 
 
 
 
 
/*
 ****************************************************************************
 *name:         IE_egwu_setup.c
 *author:       Samuel Igwe
 *date:         06/30/2015
 *description:  pll/clock/iopin initialization
 ****************************************************************************
 */
#ifndef IE_EGWU_SETUP_C
#define IE_EGWU_SETUP_C

#include "IE_egwu_setup.h"





/*
 ****************************************************************************
 *description:  pll/clock.
 *inputs:       none
 *note:         main pll (0)        m=5        p=1    
 *                              pllin=24  pllout=120  fcco=240  
 *               alt pll (1)        m=2        p=2
 *                              pllin=24  pllout48    fcco=192
 *
 *              the condition pllin  = 1 < 25Mhz and fcco = 156 -> 320 has 
 *              has been satisfied
 *              cpu = 120Mhz
 *              emc =  60Mhz
 *              gpio=  40Mhz
 *
 *              when using the internal oscillator aim for 120Mhz as well
 *              main pll (0)        m=10       p=1
 *                              pllin=12  pllout=120  fcco=240
 ****************************************************************************
 */
void
setup_pll(void)
{
    /*
     ************************************************************************
     *switch to using default clock source
     ************************************************************************
     */
    Chip_Clock_SetMainPLLSource(SYSCTL_PLLCLKSRC_IRC);
    Chip_Clock_SetCPUClockSource(SYSCTL_CCLKSRC_SYSCLK);
    Chip_Clock_DisablePLL(SYSCTL_MAIN_PLL, SYSCTL_PLL_ENABLE);
    Chip_Clock_DisablePLL(SYSCTL_USB_PLL,  SYSCTL_PLL_ENABLE);


    /*
     ************************************************************************
     *use the internal rc clock for phase 1 and 2, while await replacement
     *caps for the crystal oscillator driver
     ************************************************************************
     */
#ifdef  EXT_CLK
    Chip_Clock_SetCrystalRangeHi();
    Chip_Clock_EnableCrystal();

    if((Chip_Clock_IsCrystalEnabled()) == TRUE)
        Chip_Clock_SetCPUClockSource(SYSCTL_CCLKSRC_MAINPLL);

    Chip_Clock_SetupPLL(SYSCTL_MAIN_PLL, 5, 1);
    Chip_Clock_SetupPLL(SYSCTL_USB_PLL,  2, 2);

    Chip_Clock_EnablePLL(SYSCTL_MAIN_PLL, SYSCTL_PLL_ENABLE);
    Chip_Clock_EnablePLL(SYSCTL_USB_PLL,  SYSCTL_PLL_ENABLE);
#else
    Chip_Clock_SetupPLL(SYSCTL_MAIN_PLL, 10, 1);
    Chip_Clock_EnablePLL(SYSCTL_MAIN_PLL, SYSCTL_PLL_ENABLE);
#endif


    /*
     ************************************************************************
     *delay a bit to let the logic do its thing
     ************************************************************************
     */
    while(Chip_Clock_IsMainPLLLocked() == 0)
        ;

#ifdef  EXT_CLK
    Chip_Clock_SetMainPLLSource(SYSCTL_PLLCLKSRC_MAINOSC);
    while(Chip_Clock_IsUSBPLLLocked() == 0)
        ;
#endif


    /*
     ************************************************************************
     *resume initialization
     ************************************************************************
     */
    Chip_Clock_SetCPUClockDiv(1);
    Chip_Clock_SetCPUClockSource(SYSCTL_CCLKSRC_MAINPLL);

#ifdef  EXT_CLK
    Chip_Clock_SetUSBClockDiv(1);
    Chip_Clock_SetUSBClockSource(SYSCTL_USBCLKSRC_USBPLL);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_USB);
#endif

    Chip_Clock_SetPCLKDiv(3);


    /*
     ************************************************************************
     *enable all the peripherals
     ************************************************************************
     */
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_TIMER0);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_TIMER1);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_UART0);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_UART1);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_RTC);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_EMC);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_I2C0);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_I2C1);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_I2C2);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SSP0);
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SSP1);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_USB);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_GPDMA);

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_GPIO);


    /*
     ************************************************************************
     *enable emc and clkout
     ************************************************************************
     */
    Chip_Clock_SetEMCClockDiv(SYSCTL_EMC_DIV2); 
    Chip_Clock_SetCLKOUTSource(SYSCTL_CLKOUTSRC_MAINOSC, 3);
    Chip_Clock_EnableCLKOUT();
}





/*
 ****************************************************************************
 *description:  configure nvic
 *inputs:       none
 *notes:        assume vector table is the global "ivt"
 *              skip stack and reset positions
 *              default isrs
 *              nvic_fault_isr()
 *              nvic_systic_isr()
 *              nvic_user_isr()
 ****************************************************************************
 */
void
setup_nvic(void)
{
    volatile unsigned int wdTemp, *ptrTemp;
    volatile int wdCount;


    ptrTemp = (volatile unsigned int *)&EGWU_IVT;
    for(wdCount = 2; wdCount < (LPC177X_NUM_INT + 16); wdCount++)
        {
        if(wdCount < 15)                        /*faults*/
                wdTemp  = (int) nvic_fault_isr;
        else
                {
                switch(wdCount)
                        {
                        case    15:             /*systick*/
                                wdTemp  = (int) nvic_systick_isr;
                                break;
                        case    42:             /*dma*/
                                wdTemp  = (int) nvic_dma_isr;
                                break;
                        default:
                                wdTemp  = (int) nvic_user_isr;
                                break;
                        }
                }

        wdTemp |= 1;                            /*thumb - mandatory*/
        *(ptrTemp + wdCount) = wdTemp;
        }


    /*
     ************************************************************************
     *selecting nvic priority group 2  (there are 32 pre-rempt priority 
     *levels on the lpc17xx)
     *[7:3]     = preempt priority field (5 bits)
     *[2:0]     = sub priority field     (3 bits)
     *
     *this allows me to allocate 32 interrupt priority levels thought I doubt
     *Id use that many interrupts in this project but one never knows
     *
     *for now set interrupts (system handler priority)
     *4 + 5 + 6   to priority level 0
     *11+14       to priority level 1
     *15 (systick)to priority level 2
     *(peripherals interrupt)
     *26 (dma)    to priority level 3
     *interrupts 1 through 3 are fixed (reset to fault)
     *set to rest to maximum priority (0xff)
     ************************************************************************
     */
    NVIC_SetPriorityGrouping(LPC177X_PREEMPT_PRIO_GROUP);
    for (wdCount = MemoryManagement_IRQn; wdCount < (LPC177X_NUM_INT); wdCount++)
        {
        switch(wdCount)
                {
                case    UsageFault_IRQn:
                        wdTemp = NVIC_EncodePriority(LPC177X_PREEMPT_PRIO_GROUP, 0, 0);
                        break;
                case    SVCall_IRQn:
                case    PendSV_IRQn:
                        wdTemp = NVIC_EncodePriority(LPC177X_PREEMPT_PRIO_GROUP, 1, 0);
                        break;
                case    SysTick_IRQn:
                        wdTemp = NVIC_EncodePriority(LPC177X_PREEMPT_PRIO_GROUP, 2, 0);
                        break;
                case    DMA_IRQn:
                        wdTemp = NVIC_EncodePriority(LPC177X_PREEMPT_PRIO_GROUP, 3, 0);
                        break;
                default:
                        wdTemp = NVIC_EncodePriority(LPC177X_PREEMPT_PRIO_GROUP, 9, 0);
                        break;
                }

        NVIC_SetPriority(wdCount, wdTemp);
        }


    /*
     ************************************************************************
     *setup systick timer for 1mS tick
     *configure variables
     ************************************************************************
     */
    strSysTick.wdSeconds = 0;
    strSysTick.wdTicks   = 0;
    SysTick_Config(EGWU_CPU_CLK_RATE/1000);


    /*
     ************************************************************************
     *cpu synchronization
     ************************************************************************
     */
    asm("dsb");
    asm("isb");


    /*
     ************************************************************************
     *enable mem/bus/usage fault interrupts
     ************************************************************************
     */
    wdTemp  = SCB_SHCSR_MEMFAULTENA_Msk;
    wdTemp |= SCB_SHCSR_BUSFAULTENA_Msk;
    wdTemp |= SCB_SHCSR_USGFAULTENA_Msk;
    SCB->SHCSR = wdTemp;


    /*
     ************************************************************************
     *remap vector table
     *enable interrupts on the processor level
     ************************************************************************
     */
    SCB->VTOR = LPC177X_SRAM_BASE;
    asm("cpsie i");
}





/*
 ****************************************************************************
 *description:  gpio configuration
 *inputs:       none
 *note:         mapping is as follows
 *              p0[00] - p0[01] =       fx4     =uart0
 *              p0[02] - p0[11] =       fx2     =sspi + i2c
 *              p0[12] - p0[13] =       fx1     =usb
 *              p0[15] - p0[18] =       fx2     =spi
 *              p0[23] - p0[25] =       fx1     =adc
 *              p0[26]          =       fx2     =dac
 *              p0[30]          =       fx0     =gpio1
 *              p0[31]          =       fx1     =usb
 *
 *              p1[02] - p1[10] =       fx0     =gpio
 *              p1[11] - p1[12] =       fx3     =pwm
 *              p1[14]          =       fx0     =gpio
 *              p1[18] - p1[19] =       fx0     =gpio3 and gpio4
 *              p1[23] - p1[24] =       fx0     =gpio (bi-led anode)
 *              p1[27]          =       fx4     =clkout
 *              p1[30] - p1[31] =       fx1     =usb
 *
 *              p2[00] - p[01]  =       fx1     =uart1
 *
 *              p2[10]          =       fx0     =isp_mode (dont use)
 *              p2[11]          =       fx1     =gbl_int
 *
 *              p2[14] - p2[31] =       fx1     =emc
 *
 *              p3[00] - p3[31] =       fx0     =emc
 *
 *              p4[00] - p4[31] =       fx0     =emc
 *
 *              p5[00] - p5[01] =       fx0     =emc
 ****************************************************************************
 */
void
setup_gpio(void)
{
    volatile unsigned int wdCount;


    /*
     ************************************************************************
     *port 3 and port 4 to function 1 and port 2 (14-31)
     ************************************************************************
     */
    for(wdCount = 0; wdCount < 32; wdCount++)
        {
        Chip_IOCON_PinMuxSet(LPC_IOCON, 3, wdCount, IOCON_FUNC1);
        Chip_IOCON_PinMuxSet(LPC_IOCON, 4, wdCount, IOCON_FUNC1);
        if(wdCount >= 14)
                Chip_IOCON_PinMuxSet(LPC_IOCON, 2, wdCount, IOCON_FUNC1);
        }


    /*
     ************************************************************************
     *port 0
     ************************************************************************
     */
    for(wdCount = 0; wdCount < 32; wdCount++)
        {
        if(wdCount <= 1)
                Chip_IOCON_PinMuxSet(LPC_IOCON, 0, wdCount, IOCON_FUNC4);
        else
                {
                if((wdCount >= 6  && wdCount <= 11) ||
                   (wdCount >= 15 && wdCount <= 18) ||
                   (wdCount == 26))
                        Chip_IOCON_PinMuxSet(LPC_IOCON, 0, wdCount, IOCON_FUNC2);
                else
                        {
                        if((wdCount >= 12 && wdCount <= 13) ||
                           (wdCount >= 23 && wdCount <= 25) ||
                           (wdCount == 31))
                                Chip_IOCON_PinMuxSet(LPC_IOCON, 0, wdCount, IOCON_FUNC1);
                        else
                                {
                                if(wdCount == 30)
                                        Chip_IOCON_PinMuxSet(LPC_IOCON, 0, wdCount, IOCON_FUNC0);
                                }
                        }
                }
        }


    /*
     ************************************************************************
     *port 1
     ************************************************************************
     */
    for(wdCount = 0; wdCount < 32; wdCount++)
        {
        if((wdCount >= 2  && wdCount <= 10) ||
           (wdCount >= 18 && wdCount <= 19) ||
           (wdCount >= 23 && wdCount <= 24) ||
           (wdCount == 14))
                Chip_IOCON_PinMuxSet(LPC_IOCON, 1, wdCount, IOCON_FUNC0);
        else
                {
                if(wdCount >= 11 &&  wdCount <= 12)
                        Chip_IOCON_PinMuxSet(LPC_IOCON, 1, wdCount, IOCON_FUNC3);
                else
                        {
                        if(wdCount  >= 30 && wdCount <= 31)
                                Chip_IOCON_PinMuxSet(LPC_IOCON, 1, wdCount, IOCON_FUNC1);
                        else
                                {
                                if(wdCount == 27)
                                        Chip_IOCON_PinMuxSet(LPC_IOCON, 1, wdCount, IOCON_FUNC4);
                                }
                        }
                }
        }


    /*
     ************************************************************************
     *port 2
     ************************************************************************
     */
    for(wdCount = 0; wdCount < 14; wdCount++)
        {
        if(wdCount <= 1)
                Chip_IOCON_PinMuxSet(LPC_IOCON, 2, wdCount, IOCON_FUNC2);
        else
                {
                if(wdCount >= 14)
                        Chip_IOCON_PinMuxSet(LPC_IOCON, 2, wdCount, IOCON_FUNC1);
                }
        }


    /*
     ************************************************************************
     *set direction for ports configured as gpio
     ************************************************************************
     */
    //Chip_GPIO_SetPinDIRInput(LPC_GPIO, 0, 30);
    Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, 30);

    for(wdCount =0; wdCount < 32; wdCount++)
        {
        switch(wdCount)
                {
                case    2:
                case    5:
                case    9:
                case    10:
                case    14:
                        {
                        Chip_GPIO_SetPinDIRInput(LPC_GPIO, 1, wdCount);
                        break;
                        }
                case    3:
                case    4:
                case    6:
                case    7:
                case    8:
                case    18:
                case    19:
                case    23:
                case    24:
                        {
                        Chip_GPIO_SetPinDIROutput(LPC_GPIO, 1, wdCount);
                        break;
                        }
                }
        }
}





/*
 ****************************************************************************
 *description:  uart configuration
 *inputs:       none
 *notes:        using 40Mhz peripheral clock (cpuclock/3) to derive 115200 baud
 ****************************************************************************
 */
void
setup_uart(void)
{
    volatile unsigned int wdTemp;


    /*
     ************************************************************************
     *governing formula is as follows:
     *Uart(baudrate) =  PCLK (40Mhz)/16 x (256 x DLM) + DLL x (1 + DivVal/MulVal)
     *constraints
     *                  1 <= MulVal     <= 15
     *                  0 <= DivAddVal  <= 14
     *                  DivAddVal       <  MulVal
     *[for 115200]
     ************************************************************************
     *115200 = 40Mhz/16 x [(256 x DLM) + DLL x (1 + D/M)
     *115200 = 40Mhz/16 x DLest
     *DLest  = 21.7
     *FRest  = 1.5
     ************************************************************************
     *DLest  = INT(40Mhz/(16 x 115200 x FRest)
     *FRest  = 40Mhz/(16 x 115200 x DLest)
     ************************************************************************
     *DLest  = INT(14.46) = 14
     *FRest  = 1.55
     ************************************************************************
     *this satisfies the condition 1.1 < Frest < 1.9
     *DL     = INT(40Mhz/(16 x 115200 x 1.55) = 14
     *DL*FR  = 14 x 1.55 =  21.7
     ************************************************************************
     *from the table
     *DivAdd = 5
     *MulVal = 9
     * 
     *determined later that the values 6/7 work best for this osc and board
     ************************************************************************
     *[for 9600]
     ************************************************************************
     *9600   = 40Mhz/16 x [(256 x DLM) + DLL x (1 + D/M)
     *9600   = 40Mhz/16 x DLest
     *DLest  = 260.41
     *FRest  = 1.5
     ************************************************************************
     *DLest  = INT(40Mhz/(16 x 9600 x FRest)
     *FRest  = 40Mhz/(16 x 9600 x DLest)
     ************************************************************************
     *DLest  = INT(173.61) = 173
     *FRest  = 1.505
     ************************************************************************
     *this satisfies the condition 1.1 < Frest < 1.9
     *DL     = INT(40Mhz/(16 x 9600 x 1.505) = 173.03
     *DL*FR  = 173 x 1.505 =  260.365
     ************************************************************************
     *from the table
     *DivAdd = 5
     *MulVal = 9
     ************************************************************************
     */
#if (EGWU_UART_BAUD_RATE == 115200)
    Chip_UART_EnableDivisorAccess(EGWU_ONBOARD_UART);
    Chip_UART_SetDivisorLatches(EGWU_ONBOARD_UART, 14, 0);
    Chip_UART_DisableDivisorAccess(EGWU_ONBOARD_UART);


    /*
     ************************************************************************
     *8-N-1
     ************************************************************************
     */
    wdTemp  = UART_LCR_WLEN8;
    wdTemp |= UART_LCR_SBS_1BIT;
    wdTemp |= UART_LCR_PARITY_DIS;
    Chip_UART_ConfigData(EGWU_ONBOARD_UART, wdTemp);

    EGWU_ONBOARD_UART->FDR = (UART_FDR_MULVAL(7) | UART_FDR_DIVADDVAL(6)); 
#else
    Chip_UART_EnableDivisorAccess(EGWU_ONBOARD_UART);
    Chip_UART_SetDivisorLatches(EGWU_ONBOARD_UART, 173, 0);
    Chip_UART_DisableDivisorAccess(EGWU_ONBOARD_UART);


    /*
     ************************************************************************
     *8-N-1
     ************************************************************************
     */
    wdTemp  = UART_LCR_WLEN8;
    wdTemp |= UART_LCR_SBS_1BIT;
    wdTemp |= UART_LCR_PARITY_DIS;
    Chip_UART_ConfigData(EGWU_ONBOARD_UART, wdTemp);

    //EGWU_ONBOARD_UART->FDR = (UART_FDR_MULVAL(1) | UART_FDR_DIVADDVAL(0)); 
    #ifdef      DIVADDVAL
        EGWU_ONBOARD_UART->FDR = (UART_FDR_MULVAL(MULVAL) | UART_FDR_DIVADDVAL(DIVADDVAL)); 
    #else
        EGWU_ONBOARD_UART->FDR = (UART_FDR_MULVAL(9) | UART_FDR_DIVADDVAL(5)); 
    #endif
#endif


    /*
     ************************************************************************
     *reset RX and TX blocks and enable fifos
     ************************************************************************
     */
    wdTemp  = UART_FCR_FIFO_EN;
    wdTemp |= UART_FCR_RX_RS;
    wdTemp |= UART_FCR_TX_RS;
    wdTemp |= UART_FCR_TRG_LEV1;
    wdTemp |= UART_FCR_DMAMODE_SEL;
    Chip_UART_SetupFIFOS(EGWU_ONBOARD_UART, wdTemp);

    Chip_UART_TXEnable(EGWU_ONBOARD_UART);
 

    /*
     ************************************************************************
     *enable interrupts
     ************************************************************************
     */
    wdTemp  = UART_IER_RBRINT;
    Chip_UART_IntEnable(EGWU_ONBOARD_UART, wdTemp);
}



 

/*
 ****************************************************************************
 *description:  nvic systic handler
 *inputs:       none
 *note:         toggle P1[8] = 190 uC led used as heartbeat monitor
 ****************************************************************************
 */
void
nvic_systick_isr(void)
{
    volatile unsigned int wdTemp;

    strSysTick.wdTicks++;
    if(strSysTick.wdTicks == 1000)
        {
        strSysTick.wdTicks = 0;
        strSysTick.wdSeconds++;

        //wdTemp = Chip_GPIO_GetPinState(LPC_GPIO1, LPC_LED_PORT, LPC_LED_PIN);
        //Chip_GPIO_SetPinState(LPC_GPIO1, LPC_LED_PORT, LPC_LED_PIN, wdTemp);

        wdTemp = (((LPC_GPIO1->PIN) >> LPC_LED_PIN) & 0x1);
        wdTemp ^= 0x1;
        if(wdTemp == 0)
                (LPC_GPIO1->CLR) = (1 << LPC_LED_PIN);  
        else
                (LPC_GPIO1->SET) = (1 << LPC_LED_PIN);  

        uartio_tx_flush();
        }
}





/*
 ****************************************************************************
 *description:  nvic fault handler
 *inputs:       none
 ****************************************************************************
 */
void
nvic_fault_isr(void)
{
    gpio_set_lpc_biled(EGWU_NVIC_FAULT_BILED_MASK);
}





/*
 ****************************************************************************
 *description:  nvic user handler
 *inputs:       none
 ****************************************************************************
 */
void
nvic_user_isr(void)
{
    gpio_set_lpc_biled(EGWU_NVIC_USER_BILED_MASK);
}





/*
 ****************************************************************************
 *description:  set the bi-led connected to the LPC
 *inputs:       unsigned int wdLedMask = led mask only lower two bits matter
 ****************************************************************************
 */
void
gpio_set_lpc_biled(unsigned int wdLedMask)
{
    wdLedMask &= 0x3;

    Chip_GPIO_SetPinState(LPC_GPIO, LPC_BILED_PORT, LPC_BILED_PIN1, wdLedMask);
    Chip_GPIO_SetPinState(LPC_GPIO, LPC_BILED_PORT, LPC_BILED_PIN2, (wdLedMask >> 1));
}





/*
 *****************************************************************
 *description:  configure the gpdma peripheral
 *              set array of pointers to int to 0 then init gpdma
 *****************************************************************
 */
void
setup_gpdma(void)
{
    volatile unsigned int wdCount;

    for(wdCount=0; wdCount < GPDMA_NUMBER_CHANNELS; wdCount++)
        *(ptrGpDmaUserIsr + wdCount) = 0;

    wdEnableGpDmaInt = 0;
    Chip_GPDMA_Init(LPC_GPDMA);
}





/*
 *****************************************************************
 *description:  channel isr call back
 *****************************************************************
 */
void
nvic_dma_isr(void)
{
    volatile unsigned int wdCount;

    for(wdCount=0; wdCount <GPDMA_NUMBER_CHANNELS; wdCount++)
        {
        if((Chip_GPDMA_Interrupt(LPC_GPDMA, wdCount) == SUCCESS) &&\
                ptrGpDmaUserIsr[wdCount] != NULL)
                ptrGpDmaUserIsr[wdCount]();
        }
}





/*
 *****************************************************************
 *description:  hook channel ISR
 *inputs:       int  wdChannel        = 0 to GPDMA_NUMBER_CHANNELS 
 *              void (*ptrFunc)(void) = pointer to callback function
 *****************************************************************
 */
void
gpdma_hook_chan_isr(int  wdChannel, \
                    void (*ptrFunc)(void))
{
    if(ptrGpDmaUserIsr[wdChannel] == NULL)
        {
        ptrGpDmaUserIsr[wdChannel] = ptrFunc;
        wdEnableGpDmaInt++;

        NVIC_EnableIRQ(DMA_IRQn);
        }
}





/*
 *****************************************************************
 *description:  unhook channel ISR
 *input:        int  wdChannel        = 0 to GPDMA_NUMBER_CHANNELS 
 *****************************************************************
 */
void
gpdma_unhook_chan_isr(int wdChannel)
{
    if(wdChannel >= GPDMA_NUMBER_CHANNELS)
        return;

    ptrGpDmaUserIsr[wdChannel] = 0;
    wdEnableGpDmaInt--;
    if(wdEnableGpDmaInt == 0)
        NVIC_DisableIRQ(DMA_IRQn);
}





/*
 *****************************************************************
 *description:  mS delay using TIMER0
 *input:        int  wdMs = number of milliseconds to delay
 *note:         peripheral clock is 40Mhz
 *****************************************************************
 */
void
timer_delay_mS(int wdMs)
{
    volatile unsigned int wdTemp;
    
    Chip_TIMER_Reset(LPC_TIMER0);
    Chip_TIMER_Disable(LPC_TIMER0);
    Chip_TIMER_PrescaleSet(LPC_TIMER0, 40000);
    Chip_TIMER_SetMatch(LPC_TIMER0, 0, wdMs);
    Chip_TIMER_StopOnMatchEnable(LPC_TIMER0, 0);

    Chip_TIMER_Enable(LPC_TIMER0);
    do
        {
        wdTemp = Chip_TIMER_ReadCount(LPC_TIMER0);
        }while(wdTemp != wdMs);

}





#endif
 

Sunday, August 9, 2015

Phase 2: Overview

modifications to IE_setup.c/.h and uartio.c/.h

the goal is to create buffered and unbuffered version of the various input and output routines that involve the uart. dma will manage one half of the swinging buffer while user is interacting with the other.

in addition create a means to implement the xmodem protocol towards the end. I actually implemented xmodem completely in mc6800 assembly years ago so doing so in C should be too tasking.



IE_setup.c
create
egwu_setup_gpdma
           generic gpdma configuration routines
egwu_nvic_gpdma_isr
           call table for all 8 channels using pointer to void function
egwu_dma_hook_channel_isr
            add user isr to call table above
egwu_dma_unhook_channel_isr
            remove user isr from call table above



IE_uartio.c
create
egwu_uartio_fflush
           uses dma transfer to clear out one half of the tx swinging buffer
egwu_uartio_tx_dma_isr
           user isr to hook unto gpdma isr call table (for any of 8 channels)
egwu_uartio_printf/putc
           printf will be buffered
           putc will be unbuffered
egwu_uartio_getc/getch/gets
           for now gets will be unbuffered but that might change
           getc and getch will be unbuffered with the latter simply looking at the
           rx fifo flag and returning a code indicating presence or absence of a
           key/character