Tuesday, August 25, 2015

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
 

No comments:

Post a Comment