Wednesday, August 28, 2013

usb_test.c

/*
 **********************************************************************
 *name:         stmusb_test.c
 *author:       Samuel Igwe
 *date:         08/12/2013
 *description:  stm32 usb test code.
 **********************************************************************
 */
#include "IE_stm32.h"
#include "IE_tclib.h"
/*#include "usb_test.h"*/





/*
 **********************************************************************
 *mappings
 *PA0           = external wire jumpered to usb d+
 **********************************************************************
 */
#define USB_TEST_GPIO_PIN_USB                           STM32_GPIO_PIN_USB
#define USB_TEST_GPIO_PIN_DELAY                         5000
#define USB_TEST_GPIO_PIN_CONNECT_CHAR                  'c'
#define USB_TEST_GPIO_PIN_DISCONNECT_CHAR               'd'



/*
 **********************************************************************
 *macros
 **********************************************************************
 */
void    usb_test_user_connect(void);
#define STMUSB_SHOW_TIME(ptrString)                     \
        {                                               \
        stmlib_printf("%x\t", stm32_get_seconds);\
        stmlib_printf("%s\n", ptrString);               \
        }



/*
 **********************************************************************
 *description:  main() function
 *              this is where it all happens
 **********************************************************************
 */
int main()
{



/*
 **********************************************************************
 *stm32_init()     initialization ... must be called first
 *stm32_usb_init() initialization
 **********************************************************************
 */
stm32_init();
stm32_usb_init();
stm32_systick_hook_services(usb_test_user_connect);
stm32_usb_disconnect_pullup(USB_TEST_GPIO_PIN_USB);
stm32_timer_uS_delay(250000);
stm32_usb_connect_pullup(USB_TEST_GPIO_PIN_USB);


/*
 **********************************************************************
 *now loop forever
 **********************************************************************
 */
while(1)
        ;

return 0;
}





/*
 **********************************************************************
 *description:  used to check for rx value 'c'|'C' which is a trigger
 *              to call stm32_usb_connect_pullup()
 *inputs:       none
 **********************************************************************
 */
void    usb_test_user_connect(void)
{
volatile unsigned int wdTemp;



/*
 **********************************************************************
 *check the uart rx read status
 *retrieve the data
 **********************************************************************
 */
wdTemp  = (*PTR_STM32_UART1_SR);
if((wdTemp & STM32_UART_SR_RXNE) != STM32_UART_SR_RXNE)
        return;


wdTemp  = (*PTR_STM32_UART1_DR);
wdTemp &= 0x1ff;
switch(wdTemp)
        {
        case    USB_TEST_GPIO_PIN_CONNECT_CHAR:
                {
                tclib_printf("-------user-usb-connect----request------\n", 0);
                stm32_usb_connect_pullup(USB_TEST_GPIO_PIN_USB);
                break;
                }
        case    USB_TEST_GPIO_PIN_DISCONNECT_CHAR:
                {
                tclib_printf("-------user-usb-disconnect-request------\n", 0);
                stm32_usb_disconnect_pullup(USB_TEST_GPIO_PIN_USB);
                break;
                }
        default:
                break;
        }
}






IE_stm32_usbdev.h

/*
 **********************************************************************
 *name:         IE_stm32_usbdev.h
 *author:       Samuel Igwe
 *date:         08/27/2013
 *description:  IE_stm32_usbdev usb device header
 **********************************************************************
 */
#ifndef IE_STM32_USB_DEV
#define IE_STM32_USB_DEV



/*
 **********************************************************************
 *usb control and user endpoint (interrupt)
 **********************************************************************
 */
#define STMUSB_ENDP_CTRL_NUM                            0
#define STMUSB_ENDP_CTRL_SIZE                           8
#define STMUSB_ENDP_CTRL_MAX_SIZE                       64

#define STMUSB_ENDP_USER_NUM                            1
#define STMUSB_ENDP_USER_SIZE                           8
#define STMUSB_ENDP_INT_INTERVAL                        2



/*
 **********************************************************************
 *descriptor type
 **********************************************************************
 */
#define USBDEV_DESCR_TYPE_DEVICE                        1
#define USBDEV_DESCR_TYPE_CONFIGURATION                 2
#define USBDEV_DESCR_TYPE_STRING                        3
#define USBDEV_DESCR_TYPE_INTERFACE                     4
#define USBDEV_DESCR_TYPE_ENDPOINT                      5
#define USBDEV_DESCR_TYPE_DEV_QUALIFIER                 6
#define USBDEV_DESCR_TYPE_OTHER_SPEED_CONFIG            7
#define USBDEV_DESCR_TYPE_INTERFACE_POWER               8
#define USBDEV_DESCR_TYPE_OTG                           9
#define USBDEV_DESCR_TYPE_DEBUG                         10
#define USBDEV_DESCR_TYPE_INTERFACE_ASSOC               11



/*
 **********************************************************************
 *usb class code
 **********************************************************************
 */
#define USBDEV_CLASS_CODE_AUDIO                         0x01
#define USBDEV_CLASS_CODE_COMM                          0x02
#define USBDEV_CLASS_CODE_HID                           0x03
#define USBDEV_CLASS_CODE_PHYSICAL                      0x05
#define USBDEV_CLASS_CODE_IMAGE                         0x06
#define USBDEV_CLASS_CODE_PRINTER                       0x07
#define USBDEV_CLASS_CODE_STORAGE                       0x08
#define USBDEV_CLASS_CODE_HUB                           0x09
#define USBDEV_CLASS_CODE_DATA                          0x0a
#define USBDEV_CLASS_CODE_CARD                          0x0b
#define USBDEV_CLASS_CODE_SECURITY                      0x0d
#define USBDEV_CLASS_CODE_VIDEO                         0x0e
#define USBDEV_CLASS_CODE_PERSONAL                      0x0f
#define USBDEV_CLASS_CODE_AUDIO_VIDEO                   0x10
#define USBDEV_CLASS_CODE_DIAGNOSTIC                    0xdc
#define USBDEV_CLASS_CODE_WIRELESS                      0xe0
#define USBDEV_CLASS_CODE_APPLICATION                   0xfe
#define USBDEV_CLASS_CODE_VENDOR_SPECIFIC               0xff



/*
 **********************************************************************
 *usb requests
 **********************************************************************
 */
#define USBDEV_REQ_GET_STATUS                           0
#define USBDEV_REQ_CLEAR_FEATURE                        1
#define USBDEV_REQ_SET_FEATURE                          3
#define USBDEV_REQ_SET_ADDRESS                          5
#define USBDEV_REQ_GET_DESCRIPTOR                       6
#define USBDEV_REQ_SET_DESCRIPTOR                       7
#define USBDEV_REQ_GET_CONFIGURATION                    8
#define USBDEV_REQ_SET_CONFIGURATION                    9
#define USBDEV_REQ_GET_INTERFACE                        10
#define USBDEV_REQ_SET_INTERFACE                        11
#define USBDEV_REQ_SYNTH_FRAME                          12



/*
 **********************************************************************
 *transfer type request related #defines
 **********************************************************************
 */
#define USBDEV_CONFIG_DESC_ATTR_BUS                     (1 << 7)
#define USBDEV_CONFIG_DESC_ATTR_SELF                    (1 << 6)
#define USBDEV_CONFIG_DESC_ATTR_REMOTE_WAKE             (1 << 5)

#define USBDEV_ENDP_DESC_ADDR_DIR_IN                    (1 << 7)
#define USBDEV_ENDP_DESC_ADDR_DIR_OUT                   (0 << 7)

#define USBDEV_ENDP_DESC_ATTR_CTRL                      0
#define USBDEV_ENDP_DESC_ATTR_ISOCHRONOUS               1
#define USBDEV_ENDP_DESC_ATTR_BULK                      2
#define USBDEV_ENDP_DESC_ATTR_INTERRRUPT                3



/*
 **********************************************************************
 *8 byte setup packet offsets
 **********************************************************************
 */
#define USBDEV_SETUP_REQTYPE_OFFSET                     0
        #define USBDEV_SETUP_REQTYPE_DIR_H_TO_D         (0 << 7)
        #define USBDEV_SETUP_REQTYPE_DIR_D_TO_H         (1 << 7)
        #define USBDEV_SETUP_REQTYPE_DIR_MASK           (1 << 7)

        #define USBDEV_SETUP_REQTYPE_TYPE_STANDARD      (0 << 5)        
        #define USBDEV_SETUP_REQTYPE_TYPE_CLASS         (1 << 5)        
        #define USBDEV_SETUP_REQTYPE_TYPE_VENDOR        (2 << 5)        
        #define USBDEV_SETUP_REQTYPE_TYPE_RESERVED      (3 << 5)        
        #define USBDEV_SETUP_REQTYPE_TYPE_MASK          (3 << 5)        

        #define USBDEV_SETUP_REQTYPE_DEST_DEVICE        0
        #define USBDEV_SETUP_REQTYPE_DEST_INTERFACE     1
        #define USBDEV_SETUP_REQTYPE_DEST_ENDPOINT      2
        #define USBDEV_SETUP_REQTYPE_DEST_OTHER         3
        #define USBDEV_SETUP_REQTYPE_DEST_MASK          0x1f

#define USBDEV_SETUP_REQUEST_OFFSET                     1
#define USBDEV_SETUP_VALUE_OFFSET                       2
#define USBDEV_SETUP_INDEX_OFFSET                       4
#define USBDEV_SETUP_LENGTH_OFFSET                      6



/*
 **********************************************************************
 *string descriptors
 *offset 1 = manufacturers string
 *offset 2 = product string 
 *offset 3 = serial number
 *
 *swStrDescr below is an array of 4 of: pointer
 **********************************************************************
 **********************************************************************
 *string descriptor is unicode (16 bits)
 *string descriptor is 2*strlen(ptrDescStr)+2 bytes
 **********************************************************************
 */
static  unsigned        char    ptrStr0[]={
        (4),                                    /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_STRING,               /*string descriptor type*/
        0x9,                                    /*english code*/
        0x4};                                   /*english subcode*/

static  unsigned        char    ptrStr1[]={
        ((13 << 1)+2),                          /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_STRING,               /*string descriptor type*/
        'I',0,'g',0,'b',0,'o',0,' ',0,\
        'E',0,'m',0,'b',0,'e',0,'d',0,'d',0,'e',0,'d',0};

static  unsigned        char    ptrStr2[]={
        ((9 << 1)+2),                           /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_STRING,               /*string descriptor type*/
        'M',0,'y',0,' ',0,\
        'D',0,'e',0,'v',0,'i',0,'c',0,'e',0}; 

static  unsigned        char    ptrStr3[]={
        ((4 << 1)+2),                           /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_STRING,               /*string descriptor type*/
        '1',0,'2',0,'3',0,'4',0};

static  unsigned int    swUsbDevDescr[]={(unsigned int)ptrStr0,\
                                         (unsigned int)ptrStr1,\
                                         (unsigned int)ptrStr2,\
                                         (unsigned int)ptrStr3};



/*
 **********************************************************************
 *device descriptor
 **********************************************************************
 */
static  const   char    sbDevDescr[]={
        18,                                     /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_DEVICE,               /*device descriptor type*/
        0x10,                                   /*bcd usb version 1.1 = word*/
        0x01,
        0,                                      /*device class*/
        0,                                      /*device subclass*/
        0,                                      /*device protocol*/
        STMUSB_ENDP_CTRL_SIZE,
                                                /*max packet size*/
        0xde,                                   /*vendor id = word*/
        0xc0,

        0xed,                                   /*device id = word*/
        0xfe,

        0x0,                                    /*bcd device = word*/
        0x1,

        1,                                      /*manufacturer descriptor string*/
        2,                                      /*product      descriptor string*/
        3,                                      /*serial       descriptor string*/
        1};                                     /*number of configurations*/


/*
 **********************************************************************
 *configuration descriptor
 **********************************************************************
 */
static  const   char    sbConfDescr[]={
        9,                                      /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_CONFIGURATION,        /*configuration descriptor type*/
        (9+9+7+7),                              /*total lenght = word*/
        0,

        1,                                      /*number of interfaces*/
        1,                                      /*configuration value id*/
        0,                                      /*configuration descriptor string*/
        (USBDEV_CONFIG_DESC_ATTR_SELF | \
         USBDEV_CONFIG_DESC_ATTR_BUS),          /*bus attributes*/
        250,


        /*
         **************************************************************
         *interface descriptor
         **************************************************************
         */
        9,                                      /*byte length of descriptor*/
        USBDEV_DESCR_TYPE_INTERFACE,            /*interface descriptor type*/
        0,                                      /*interface number - zero based*/
        0,                                      /*alternate setting*/
        2,                                      /*number of endpoints*/
        USBDEV_CLASS_CODE_HID,                  /*human interface device*/

        0,                                      /*interface subclass*/
        0,                                      /*interface protocol*/
        0,                                      /*interface descriptor string*/


        /*
         **************************************************************
         *endpoint descriptor - input
         **************************************************************
         */
        7,                                      /*byte lenght of descriptor*/
        USBDEV_DESCR_TYPE_ENDPOINT,             /*endpoint descriptor type*/
        (USBDEV_ENDP_DESC_ADDR_DIR_IN |\
         STMUSB_ENDP_USER_NUM),                 /*endpoint in*/
        USBDEV_ENDP_DESC_ATTR_INTERRRUPT,       /*attributes*/
        STMUSB_ENDP_USER_SIZE,                  /*packet length = word*/
        0,
        STMUSB_ENDP_INT_INTERVAL,               /*interrupt interval*/


        /*
         **************************************************************
         *endpoint descriptor - output
         **************************************************************
         */
        7,                                      /*byte lenght of descriptor*/
        USBDEV_DESCR_TYPE_ENDPOINT,             /*endpoint descriptor type*/
        (USBDEV_ENDP_DESC_ADDR_DIR_OUT |\
         STMUSB_ENDP_USER_NUM),                 /*endpoint in*/
        USBDEV_ENDP_DESC_ATTR_INTERRRUPT,       /*attributes*/
        STMUSB_ENDP_USER_SIZE,                  /*packet length = word*/
        0,
        STMUSB_ENDP_INT_INTERVAL};              /*interrupt interval*/


#endif


Monday, August 26, 2013

IE_stm32_timer.h

/*
 **********************************************************************
 *name:         IE_stm32_timer.h
 *author:       Samuel Igwe
 *date:         08/27/2013
 *description:  Igbo Embedded stm32_timer header
 **********************************************************************
 */
#ifndef IE_STM32_TIMER
#define IE_STM32_TIMER


#define PTR_STM32_TIM2_BASE                             0x40000000 
#define PTR_STM32_TIM3_BASE                             0x40000400 
#define PTR_STM32_TIM4_BASE                             0x40000800 
#define PTR_STM32_TIM5_BASE                             0x40000c00 



/*
 **********************************************************************
 *timer #defines
 *basic timers 6 and 7 arent supported on the stm32f103. but general
 *purpose timers 2 through 5 are supported
 *
 *these timers are driven off a 36Mhz clock (sysclk / 2) which is the
 *maximum on the APB1 bus
 **********************************************************************
 **********************************************************************
 *control register 1
 **********************************************************************
 */
#define PTR_STM32_TIM2_CR1      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x0)
#define PTR_STM32_TIM3_CR1      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x0)
#define PTR_STM32_TIM4_CR1      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x0)
#define PTR_STM32_TIM5_CR1      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x0)
        #define STM32_TIM_CR1_CKD_MASK                  (0x3 << 8)
        #define STM32_TIM_CR1_CKD_TCK                   (0 << 8)
        #define STM32_TIM_CR1_CKD_2TCK                  (1 << 8)
        #define STM32_TIM_CR1_CKD_4TCK                  (2 << 8)

        #define STM32_TIM_CR1_ARPE                      (1 << 7)

        #define STM32_TIM_CR1_CMS_MASK                  (0x3 << 5)
        #define STM32_TIM_CR1_CMS_EDGE                  (0 << 5)
        #define STM32_TIM_CR1_CMS_MODE1                 (1 << 5)
        #define STM32_TIM_CR1_CMS_MODE2                 (2 << 5)
        #define STM32_TIM_CR1_CMS_MODE3                 (3 << 5)

        #define STM32_TIM_CR1_DIR_MASK                  (1 << 4)
        #define STM32_TIM_CR1_DIR_UP                    (0 << 4)
        #define STM32_TIM_CR1_DIR_DOWN                  (1 << 4)

        #define STM32_TIM_CR1_OPM                       (1 << 3)
        #define STM32_TIM_CR1_URS                       (1 << 2)
        #define STM32_TIM_CR1_UDIS                      (1 << 1)
        #define STM32_TIM_CR1_CEN                       (1 << 0)



/*
 **********************************************************************
 *control register 2
 **********************************************************************
 */
#define PTR_STM32_TIM2_CR2      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x4)
#define PTR_STM32_TIM3_CR2      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x4)
#define PTR_STM32_TIM4_CR2      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x4)
#define PTR_STM32_TIM5_CR2      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x4)
        #define STM32_TIM_CR2_MMS_TI1S                  (0x1 << 7)

        #define STM32_TIM_CR2_MMS_MASK                  (0x7 << 4)
        #define STM32_TIM_CR2_MMS_RESET                 (0x0 << 4)
        #define STM32_TIM_CR2_MMS_ENABLE                (0x1 << 4)
        #define STM32_TIM_CR2_MMS_UPDATE                (0x2 << 4)
        #define STM32_TIM_CR2_MMS_PULSE                 (0x3 << 4)

        #define STM32_TIM_CR2_CCDS                      (0x1 << 3)



/*
 **********************************************************************
 *dma interrupt enable register
 **********************************************************************
 */
#define PTR_STM32_TIM2_DIER     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0xc)
#define PTR_STM32_TIM3_DIER     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0xc)
#define PTR_STM32_TIM4_DIER     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0xc)
#define PTR_STM32_TIM5_DIER     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0xc)
        #define STM32_TIM_DIER_UDE                      (1 << 8)
        #define STM32_TIM_DIER_CC4IE                    (1 << 4)
        #define STM32_TIM_DIER_CC3IE                    (1 << 3)
        #define STM32_TIM_DIER_CC2IE                    (1 << 2)
        #define STM32_TIM_DIER_CC1IE                    (1 << 1)
        #define STM32_TIM_DIER_UIE                      (1 << 0)



/*
 **********************************************************************
 *status register
 **********************************************************************
 */
#define PTR_STM32_TIM2_SR       (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x10)
#define PTR_STM32_TIM3_SR       (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x10)
#define PTR_STM32_TIM4_SR       (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x10)
#define PTR_STM32_TIM5_SR       (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x10)
        #define STM32_TIM_SR_CC4IF                      (1 << 4)
        #define STM32_TIM_SR_CC3IF                      (1 << 3)
        #define STM32_TIM_SR_CC2IF                      (1 << 2)
        #define STM32_TIM_SR_CC1IF                      (1 << 1)
        #define STM32_TIM_SR_UIF                        (1 << 0)



/*
 **********************************************************************
 *event generation register
 **********************************************************************
 */
#define PTR_STM32_TIM2_EGR      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x14)
#define PTR_STM32_TIM3_EGR      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x14)
#define PTR_STM32_TIM4_EGR      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x14)
#define PTR_STM32_TIM5_EGR      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x14)
        #define STM32_TIM_EGR_CC4G                      (1 << 4)
        #define STM32_TIM_EGR_CC3G                      (1 << 3)
        #define STM32_TIM_EGR_CC2G                      (1 << 2)
        #define STM32_TIM_EGR_CC1G                      (1 << 1)
        #define STM32_TIM_EGR_UG                        (1 << 0)



/*
 **********************************************************************
 *capture/compare enable register
 **********************************************************************
 */
#define PTR_STM32_TIM2_CCER     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x20)
#define PTR_STM32_TIM3_CCER     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x20)
#define PTR_STM32_TIM4_CCER     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x20)
#define PTR_STM32_TIM5_CCER     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x20)
        #define STM32_TIM_CCER_CC4E                     (1 << 12)
        #define STM32_TIM_CCER_CC3E                     (1 << 8)
        #define STM32_TIM_CCER_CC2E                     (1 << 4)
        #define STM32_TIM_CCER_CC1E                     (1 << 0)



/*
 **********************************************************************
 *counter register
 **********************************************************************
 */
#define PTR_STM32_TIM2_CNT      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x24)
#define PTR_STM32_TIM3_CNT      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x24)
#define PTR_STM32_TIM4_CNT      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x24)
#define PTR_STM32_TIM5_CNT      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x24)



/*
 **********************************************************************
 *prescaler register
 **********************************************************************
 */
#define PTR_STM32_TIM2_PSC      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x28)
#define PTR_STM32_TIM3_PSC      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x28)
#define PTR_STM32_TIM4_PSC      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x28)
#define PTR_STM32_TIM5_PSC      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x28)



/*
 **********************************************************************
 *auto reload register
 **********************************************************************
 */
#define PTR_STM32_TIM2_ARR      (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x2c)
#define PTR_STM32_TIM3_ARR      (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x2c)
#define PTR_STM32_TIM4_ARR      (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x2c)
#define PTR_STM32_TIM5_ARR      (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x2c)



/*
 **********************************************************************
 *capture/compare register 1
 **********************************************************************
 */
#define PTR_STM32_TIM2_CCR1     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x34)
#define PTR_STM32_TIM3_CCR1     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x34)
#define PTR_STM32_TIM4_CCR1     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x34)
#define PTR_STM32_TIM5_CCR1     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x34)



/*
 **********************************************************************
 *capture/compare register 2
 **********************************************************************
 */
#define PTR_STM32_TIM2_CCR2     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x38)
#define PTR_STM32_TIM3_CCR2     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x38)
#define PTR_STM32_TIM4_CCR2     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x38)
#define PTR_STM32_TIM5_CCR2     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x38)



/*
 **********************************************************************
 *capture/compare register 3
 **********************************************************************
 */
#define PTR_STM32_TIM2_CCR3     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x3c)
#define PTR_STM32_TIM3_CCR3     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x3c)
#define PTR_STM32_TIM4_CCR3     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x3c)
#define PTR_STM32_TIM5_CCR3     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x3c)



/*
 **********************************************************************
 *capture/compare register 4
 **********************************************************************
 */
#define PTR_STM32_TIM2_CCR4     (volatile unsigned int *)(PTR_STM32_TIM2_BASE + 0x40)
#define PTR_STM32_TIM3_CCR4     (volatile unsigned int *)(PTR_STM32_TIM3_BASE + 0x40)
#define PTR_STM32_TIM4_CCR4     (volatile unsigned int *)(PTR_STM32_TIM4_BASE + 0x40)
#define PTR_STM32_TIM5_CCR4     (volatile unsigned int *)(PTR_STM32_TIM5_BASE + 0x40)



#endif

Saturday, August 24, 2013

bug in tclib_acquire_semaphore() and tclib_release_semaphore()

Turns out both functions were returning the value of the mutex instead of the compliment. strexb is a odd instruction code. It returns 0 when successful and 1 otherwise. But the function is setup to return 0 on error and 1 on success. In addition if a read (ldrexb) of the mutex returns it set to 1, I need to return 0 to the calling routine


/*
 *****************************************************************
 *description:  acquire semaphore
 *input:            char *ptrWord   = pointer to memory word
 *output:          0 on error 1 on success
 *void
 *tclib_acquire_semaphore(unsigned char *ptrWord)
 *****************************************************************
 */
.align  2
.global tclib_acquire_semaphore
/*
 *****************************************************************
 *r0 = ptrWord
 *****************************************************************
 */
.thumb_func
tclib_acquire_semaphore:
push    {r1-r2}


mov     r1, #1
mov     r2, r0

ldrexb  r0, [r2]                        /*get value*/
cmp     r0, #0
eorne   r0, #1
bne     tclib_get_mutex_exit

strexb  r0, r1, [r2]
eor     r0, #1
tclib_get_mutex_exit:
clrex

pop     {r1-r2}
mov     pc, lr



I also put the init routines inside stm32_init () and added a banner to to be printed to the terminal on power up. Now unto to USB firmware device development ...

bug in Vector Table Initialization

So after revisiting the program I realized that the errors were in a pattern that began with 0x2000 .... basically the address of RAM. It dawned on me that at the beginning the data in memory was fine ... so I single stepped to just after it got clobbered and that was in the stm32_nvic_init() function.

The problem was that I was initializing 256-2 vector table positions while only allocating space for 76. So I made the following changes

1) IE_stm32_ivt.S
.global stm32_ivt
.global stm32_ivt_end
.extern main
.equ    STM32_SRAM_BASE,0x20000000
.data
stm32_ivt:      .word   STM32_SRAM_BASE + (20 * 1024)
                .word   (main + 1)
                .skip   (14 * 4)
                .skip   (240 * 4)
stm32_ivt_end:
.text





2) IE_stm32.c
/*
 **********************************************************************
 *install handlers for all vector positions
 *skip positions 0 = thread stack and 1 = reset address
 *dont hardcode size of table - determine it with stm32_ivt and _end
 **********************************************************************
 */
ptrTemp = (volatile unsigned int *)STM32_NVIC_IVT_BASE;
wdTemp  = (&stm32_ivt_end - &stm32_ivt);
for(wdCount=2; wdCount<wdTemp; wdCount++)
        {
        if(wdCount <= 6)
                ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_fault_isr)\
                | 0x1);
        else
                {
                if(wdCount == 15)
                        ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_systick_isr)\
                        | 0x1);
                else
                        ptrTemp[wdCount] = ((unsigned int)(stm32_nvic_unknown_isr)\
                        | 0x1);
                }
        }





3) IE_stm32.ld
MEMORY  {
        STM32_RAM    : ORIGIN = 0x20000000,   LENGTH = (20480 - 1024)
        }


SECTIONS
        {
        .data :   
                {
                *(.data);
                } > STM32_RAM

        .text :   
                {
                *(.text);
                *(.rodata*);
                } > STM32_RAM

        .bss :
                {
                *(.bss);
                } > STM32_RAM
        }

Thursday, August 22, 2013

bug in compiler generated parameters passed to functions or just gdb' view of it?

Cant figure out why the compiler is passing invalid parameters to the tclib_printf() function. See gdb terminal interaction below. The asm dump looks fine to me

rombios@lenovo:~/PROJECTS/stm32$ arm-linux-gnueabi-gdb ./core_test.out
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-gnueabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
0x200003c8 in ?? ()
JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3)
JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1)
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x20000108 msp: 0x20005000
Reading symbols from /home/rombios/PROJECTS/stm32/core_test.out...done.

(gdb) l
25    /*
26     **********************************************************************
27     *initialization should start with:
28     *reset control clock registers
29     *general purpose input output registers
30     *universal asynchronous receiver transmitter registers
31     *nested vectored interrupt controller registers
32     **********************************************************************
33     */
34    stm32_rcc_cr_init();
(gdb)
35    stm32_gpio_init();
36    stm32_uart_init();
37    stm32_nvic_init();
38   
39    wdTemp = strSystick.dwSeconds;
40    while(1)
41        {
42        while(wdTemp == strSystick.dwSeconds)
43            ;
44   
(gdb)
45   
46        wdTemp = wdTemp;        /*dummy ins for breakpoint*/
47        tclib_printf("\r%d", wdTemp);
48        wdTemp = strSystick.dwSeconds;
49        }
50   
51    return 0;
52    }
53   
54   
(gdb) b 46
Breakpoint 1 at 0x20000e0a: file apps/core/core_test.c, line 46.
(gdb) load
Loading section .text, size 0xe54 lma 0x20000000
Loading section .data, size 0x130 lma 0x20000e54
Start address 0x20000dd9, load size 3972
Transfer rate: 64 KB/sec, 1986 bytes/write.
(gdb) c
Continuing.

Breakpoint 1, main () at apps/core/core_test.c:46
46        wdTemp = wdTemp;        /*dummy ins for breakpoint*/
(gdb) n
47        tclib_printf("\r%d", wdTemp);
(gdb) p wdTemp
$1 = 0
(gdb) s
tclib_printf (ptrString=0x0, wdValue=536874884) at tclib/IE_tclib.c:140
140    while ((*ptrString) != NULL)
(gdb) p strSystick
$2 = {dwMsTick = 0, dwSeconds = 1, dwMsTotal = 1000, ptrFunc = 0}
(gdb) 





20000e0a:       687b            ldr     r3, [r7, #4]
20000e0c:       607b            str     r3, [r7, #4]
20000e0e:       687b            ldr     r3, [r7, #4]
20000e10:       f640 6050       movw    r0, #3664       ; 0xe50
20000e14:       f2c2 0000       movt    r0, #8192       ; 0x2000
20000e18:       4619            mov     r1, r3
20000e1a:       f7ff f9a3       bl      20000164 <tclib_printf>
 




20000164 <tclib_printf>:
20000164:       b580            push    {r7, lr}
20000166:       b086            sub     sp, #24
20000168:       af00            add     r7, sp, #0
2000016a:       6078            str     r0, [r7, #4]
2000016c:       6039            str     r1, [r7, #0]
 













Makefile specified link order

Weird bug I encountered today and wasnt certain why changing the link order mattered but here is where the bug manifested itself and the latter correction:


 $(LD) -o $(APP)_test.out     $(LDFLAGS) reset.o   \
            core.o    \
             tclibS.o  \
             tclibC.o  \
            $(APP)_test.o
 
 
        $(LD) -o $(APP)_test.out        $(LDFLAGS) reset.o   \
                                                   tclibC.o  \
                                                   tclibS.o  \
                                                   core.o    \
                                                   $(APP)_test.o
 
 
Weird bug I encountered today and wasnt certain why changing the link order
The former results in a bug where global variables arent being updated. A breakpoint set in  stm32_nvic_systick_isr and single stepping with prints of strSystick structure shows that, the structure elements arent being updated (incremented). However a dump of the asm code (arm-linux-gnueabi-objdump -d core_test.out) shows the correct instructions.

Changing the linke order to the latter corrects the problem. I cant understand this. strSystick is defined in IE_stm32.h and as such would be in core.o which is sourced to IE_stm32.c. Thats also where the handler stm32_nvic_systick_isr resides so this isnt making sense.

 

IE_stm32.ld

/*
 ***********************************************************************
 *name:         IE_stm32.ld
 *author:       Samuel Igwe
 *date:         08/04/2013
 *description:  linker script that I have created for use in all stm32
 *              development related matters on this board
 *
 *              it took some time to set this up. the ld manual was 
 *              sadly inadequate. I must credit zilogic's "embedded 
 *              programming with the gnu toolchain" at 
 *              www.bravegnu.org/gnu-eprog-dist.pdf
 *              for clearing up issues related to loading the .data 
 *              section into its appropriate position in ram and 
 *              setting up the linker appropriately.
 *
 *              first this is the memory map I had decided on 
 *    
 *              0x2000 4fff             +++++++++++++++++++++++++++++++
 *                                      +            ram              +
 *              0x2000 0000             +++++++++++++++++++++++++++++++
 *                                      +                             +
 *              0x0001 ffff             +++++++++++++++++++++++++++++++
 *                                      +           flash             +
 *              0x0000 0000             +++++++++++++++++++++++++++++++
 *
 *
 *              my stm32f103 board is jumpered to boot from flash at 
 *              offset 0x2000 0000. the first 256*4 will be reserved 
 *              for the NVIC interrupt vector table and hopefull the
 *              last 512 bytes for the stack
 *
 *              adding the variable _loadaddr_data_section_ to the end
 *              of the .text along with the AT> directive places a copy
 *              of the .data right after .text but leaves the virtual
 *              addresses pointing at .data in ram
 *              
 *              in the assembler initialization file I can copy .data 
 *              from bottom of .text into .data in sram
 ***********************************************************************
 */
MEMORY  {
        STM32_RAM    : ORIGIN = 0x20000000,   LENGTH = (20480 - 1024)
        }


SECTIONS
        {
        .data :   
                {
                *(.data);
                } > STM32_RAM

        .text :   
                {
                *(.text);
                *(.rodata*);
                } > STM32_RAM

        .bss :
                {
                *(.bss);
                } > STM32_RAM
        }



Wednesday, August 14, 2013

"blx" and the .thumb_func gas directive

Encountered a major hard fault inside main().  Specifically the stm32_uart_init() functions call of tclib_memset().

under gdb, "layout asm" displayed the dis-assembly of the code and showed that instead of generating a "bl" instruction, the compiler was generating "blx" which implies a switch back to arm - which CANNOT happen on a cortex-m3

I had
-mthumb
-mno-thumb-interwork
-mcpu=cortex-m3

all set in CFLAGS.

Searching the net revealed the cause of it - a compiler "bug":
http://knowledgebase.nxp.com/showthread.php?t=674
tied to C functions calling assembly routines on a thumb ISA

The solution was to place the ".thumb_func" directive before any labels in the assembly source. This worked and got me passed this error ... but there are others ...


btw ".syntax unified" is needed to assemble my tclib.S asm source file with gcc

core_test.c

/*
 **********************************************************************
 *name:         core_test.c
 *author:       Samuel Igwe
 *date:         08/12/2013
 *description:  Igbo Embedded core_test.c source. goal is to test out 
 *              initialization
 *              uart
 *              systick timer
 *              interrupts
 *              tclib library
 *              all in preparation for usb "device" development
 **********************************************************************
 */
#include        "IE_tclib.h"
#include        "IE_stm32.h"





int     main()
{
volatile unsigned int wdTemp;

stm32_init();

wdTemp = stm32_get_seconds();
while(1)
        {
        while(wdTemp == stm32_get_seconds())
                ;


        tclib_printf("\r%d", wdTemp);
        wdTemp = stm32_get_seconds();
        }

return 0;
}






Monday, August 12, 2013

IE_stm32_usb.c

/*
 **********************************************************************
 *name:         IE_stm32_usb.c
 *author:       Samuel Igwe
 *date:         08/24/2013
 *description:  Igbo Embedded stm32.c usb source
 **********************************************************************
 */
#include        "IE_stm32.h"
#include        "IE_tclib.h"


/*
 **********************************************************************
 *#define functions for USB enumeration
 **********************************************************************
 */
void    stm32_usb_isr_control_in(void);
void    stm32_usb_isr_control_out(void);
void    stm32_usb_isr_user_in(unsigned int wdEndP);
void    stm32_usb_isr_user_out(unsigned int wdEndP);

void    stm32_usb_cancel_queued_IN_transfers(unsigned int wdEndP);
void    stm32_usb_dequeue_IN_transfers(unsigned int wdEndP);
void    stm32_usb_queue_IN_transfers(unsigned int  wdEndP,\
                                     unsigned char *ptrBuffer,\
                                     unsigned int  wdSize);
void    stm32_usb_set_epr_stat(unsigned int wdEndP,\
                               unsigned int wdNewStat,\
                               unsigned int wdOffset);

void    stm32_usb_clear_epr_ctr(unsigned int wdEndP,\
                                unsigned int wdMask);

void    stm32_usb_enable_endp(unsigned int wdEndP,\
                              unsigned int wdEndPType);

void    stm32_usb_set_epr_dtog(unsigned int wdEndP,\
                                        int wdNewStat,\
                               unsigned int wdOffset);




/*
 **********************************************************************
 *#define constants for USB enumeration
 **********************************************************************
 */
static  volatile unsigned int   wdUsbState, wdUsbAddr, wdUsbArgs;
struct  STR_USB_PKT_XFER{
                        unsigned char   *ptrCtrlBuf;
                        int     wdCtrlSize;

                        unsigned char   *ptrUserBuf;
                        int     wdUserSize;
                        }strUsbPktXfer;

#define STMUSB_DEVICE_CONFIGURED                (1 << 0)
#define STMUSB_DEVICE_IDLE                      0x0ff
#define USB_NVIC_IRQ_NUM                        20



/*
 **********************************************************************
 *description:  routine to properly set the EP_TYPE bits in the
 *              Endpoint register.
 *input:        unsigned int    wdEndP     = endpoint number
 *              unsigned int    wdEndPType = the following
 *                              STM32_USB_EPR_EP_TYPE_BULK
 *                              STM32_USB_EPR_EP_TYPE_CONTROL
 *                              STM32_USB_EPR_EP_TYPE_ISO
 *                              STM32_USB_EPR_EP_TYPE_INTERRUPT
 *output:       void
 *
 *note:         the CTR_RX and CTR_TX bits are governed by the rules
 *              1 = dont change 0 = clear
 **********************************************************************
 */
void    stm32_usb_enable_endp(unsigned int wdEndP,\
                              unsigned int wdEndPType)
{
unsigned int    wdTemp;

/*retrieve the current register value*/
wdTemp  = *(PTR_STM32_USB_EP0R + wdEndP);

/*invariants - values that will not modify these reg bits*/
wdTemp  &= ~(STM32_USB_EPR_STAT_TX_MASK  | \
             STM32_USB_EPR_STAT_RX_MASK  | \
            (STM32_USB_EPR_DTOG_TX       | STM32_USB_EPR_DTOG_RX));
wdTemp  |=  (STM32_USB_EPR_CTR_TX        | STM32_USB_EPR_CTR_RX);

/*set EndPType and number*/
wdTemp  |= (wdEndPType << STM32_USB_EPR_EP_TYPE_OFFSET);
wdTemp  |= wdEndP;

/*set the current register value*/
*(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP);
}





/*
 **********************************************************************
 *description:  routine to properly set the RX and TX STAT bits in the
 *              Endpoint register.
 *input:        unsigned int    wdEndP  = endpoint number
 *              unsigned int    wdMask  = the following
 *                              STM32_USB_EPR_CTR_RX
 *                              STM32_USB_EPR_CTR_TX
 *output:       void
 *
 *note:         the CTR_RX and CTR_TX bits are governed by the rules
 *              1 = dont change 0 = clear
 **********************************************************************
 */
void    stm32_usb_clear_epr_ctr(unsigned int wdEndP,\
                                unsigned int wdMask)
{
unsigned int    wdTemp;


/*retrieve the current register value*/
wdTemp  = *(PTR_STM32_USB_EP0R + wdEndP);

/*invariants - values that will not modify these reg bits*/
wdTemp  &= ~(STM32_USB_EPR_STAT_TX_MASK  | \
             STM32_USB_EPR_STAT_RX_MASK  | \
            (STM32_USB_EPR_DTOG_TX       | STM32_USB_EPR_DTOG_RX));
wdTemp  |=  (STM32_USB_EPR_CTR_TX        | STM32_USB_EPR_CTR_RX);

wdTemp  &= ~wdMask;

/*set the current register value*/
*(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP);
}





/*
 **********************************************************************
 *description:  routine to properly set or toggle the DTOG_RX | DTOG_TX
 *              bits of the Endpoint register.
 *input:        unsigned int    wdEndP     = endpoint number
 *              unsigned int    wdNewStat  = the following
 *                                      0  = set to 0
 *                                      1  = set to 1
 *                                     -1  = toggle
 *              unsigned int    wdOffset   = DTOG_RX or DTOG_TX STAT
 *                              STM32_USB_EPR_DTOG_RX_OFFSET
 *                              STM32_USB_EPR_DTOG_TX_OFFSET    
 *output:       void
 *                      
 *note:         the DTOG_RX and DTOG_TX bits are governed by the rules
 *              0 = dont change 1 = TOGGLE
 **********************************************************************
 */
void    stm32_usb_set_epr_dtog(unsigned int wdEndP,\
                               int wdNewStat,\
                               unsigned int wdOffset)
{
unsigned int    wdMask, wdTemp;

/*retrieve the current register value*/
wdMask  = *(PTR_STM32_USB_EP0R + wdEndP);
wdTemp  = wdMask;


/*wdMask has STAT position extracted*/
if(wdOffset == STM32_USB_EPR_DTOG_RX_OFFSET)
        wdMask &= STM32_USB_EPR_DTOG_RX; 
else
        wdMask &= STM32_USB_EPR_DTOG_TX; 


/*normalize then compute XOR of value and mask*/
wdMask >>= wdOffset;
if(wdNewStat != -1 && wdMask == wdNewStat)
        return;

if(wdNewStat == -1)
        wdNewStat = 1;

wdMask  ^= wdNewStat;
wdMask <<= wdOffset;

/*mask out non important bits*/
if(wdOffset == STM32_USB_EPR_DTOG_RX_OFFSET)
        wdMask &= STM32_USB_EPR_DTOG_RX; 
else
        wdMask &= STM32_USB_EPR_DTOG_TX; 


/*invariants - values that will not modify these reg bits*/
wdTemp  &= ~(STM32_USB_EPR_STAT_TX_MASK | \
             STM32_USB_EPR_STAT_RX_MASK | \
            (STM32_USB_EPR_DTOG_TX      | STM32_USB_EPR_DTOG_RX));
wdTemp  |=  (STM32_USB_EPR_CTR_TX       | STM32_USB_EPR_CTR_RX);

/*set user settings*/
wdTemp  |= wdMask;

/*update register*/
*(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP);
}





/*
 **********************************************************************
 *description:  routine to properly set the RX and TX STAT bits in the
 *              Endpoint register.
 *input:        unsigned int    wdEndP     = endpoint number
 *              unsigned int    wdNewStat  = the following
 *                              STM32_USB_EPR_STAT_RX_DISABLE
 *                              STM32_USB_EPR_STAT_TX_DISABLE
 *
 *                              STM32_USB_EPR_STAT_RX_STALL
 *                              STM32_USB_EPR_STAT_TX_STALL
 *
 *                              STM32_USB_EPR_STAT_RX_NAK
 *                              STM32_USB_EPR_STAT_TX_NAK
 *
 *                              STM32_USB_EPR_STAT_RX_VALID
 *                              STM32_USB_EPR_STAT_TX_VALID
 *              unsigned int    wdOffset   = RX or TX STAT
 *                              STM32_USB_EPR_STAT_RX_OFFSET
 *                              STM32_USB_EPR_STAT_TX_OFFSET    
 *output:       void
 *                      
 *note:         the RX_STAT and TX_STAT bits are governed by the rules
 *              0 = dont change 1 = TOGGLE
 *              A major error was not taking this into consideration
 **********************************************************************
 */
void    stm32_usb_set_epr_stat(unsigned int wdEndP,\
                               unsigned int wdNewStat,\
                               unsigned int wdOffset)
{
unsigned int    wdMask, wdTemp;

/*retrieve the current register value*/
wdMask  = *(PTR_STM32_USB_EP0R + wdEndP);
wdTemp  = wdMask;


/*wdMask has STAT position extracted*/
if(wdOffset == STM32_USB_EPR_STAT_RX_OFFSET)
        wdMask &= STM32_USB_EPR_STAT_RX_MASK; 
else
        wdMask &= STM32_USB_EPR_STAT_TX_MASK; 


/*normalize then compute XOR of value and mask*/
wdMask >>= wdOffset;
wdMask  ^= wdNewStat;
wdMask <<= wdOffset;

/*mask out non important bits*/
if(wdOffset == STM32_USB_EPR_STAT_RX_OFFSET)
        wdMask &= STM32_USB_EPR_STAT_RX_MASK; 
else
        wdMask &= STM32_USB_EPR_STAT_TX_MASK; 


/*invariants - values that will not modify these reg bits*/
wdTemp  &= ~(STM32_USB_EPR_STAT_TX_MASK | \
             STM32_USB_EPR_STAT_RX_MASK | \
            (STM32_USB_EPR_DTOG_TX      | STM32_USB_EPR_DTOG_RX));
wdTemp  |=  (STM32_USB_EPR_CTR_TX       | STM32_USB_EPR_CTR_RX);

/*set user settings*/
wdTemp  |= wdMask;

/*update register*/
*(PTR_STM32_USB_EP0R + wdEndP) = (wdTemp | wdEndP);
}





/*
 **********************************************************************
 *description:  tx transfer cancel routine
 *input:        unsigned int    wdEndP     = endpoint number
 *note:         called at post_reset and whenever the need arises
 **********************************************************************
 */
void
stm32_usb_cancel_queued_IN_transfers(unsigned int  wdEndP)
{
if(wdEndP == STMUSB_ENDP_USER_NUM)
        strUsbPktXfer.wdUserSize = -1;
else
        strUsbPktXfer.wdCtrlSize = -1;
}





/*
 **********************************************************************
 *description:  tx transfer dequeue routine
 *input:        unsigned int    wdEndP     = endpoint number
 *note:         be prepared to deal with zero length packets
 **********************************************************************
 */
void
stm32_usb_dequeue_IN_transfers(unsigned int  wdEndP)
{
unsigned char   *ptrBuf, **ptrPtrBuf;
int     *ptrCount, wdCount, wdEndPSize;


if(wdEndP == STMUSB_ENDP_USER_NUM)
        {
        ptrBuf    = strUsbPktXfer.ptrUserBuf;
        ptrPtrBuf = (unsigned char **)&strUsbPktXfer.ptrUserBuf;
        ptrCount  = &strUsbPktXfer.wdUserSize;

        wdCount   = *ptrCount;
        wdEndPSize= STMUSB_ENDP_USER_SIZE;
        }
else
        {
        ptrBuf    = (unsigned char *)strUsbPktXfer.ptrCtrlBuf;
        ptrPtrBuf = (unsigned char **)&strUsbPktXfer.ptrCtrlBuf;
        ptrCount  = &strUsbPktXfer.wdCtrlSize;

        wdCount   = *ptrCount;
        wdEndPSize= STMUSB_ENDP_CTRL_SIZE;
        }
                


/*check if xfer is >= 0, return if its -1*/
if(wdCount < 0)                         /*check xfer == -1 or xfer >=0 */
        return;
else
        {
        if(wdCount == 0)                /*should we generate a zero length packet*/
                {
                *ptrCount = -1;         /*end future xfers*/
                stm32_usb_endp_send_packet(wdEndP,\
                                           ptrBuf,\
                                           wdEndPSize,\
                                           0);
                }
        else
                {
                if(wdCount >= wdEndPSize)
                        wdCount = wdEndPSize;

                stm32_usb_endp_send_packet(wdEndP,\
                                           ptrBuf,\
                                           wdEndPSize,\
                                           wdCount);

                /*update variables*/
                *(ptrPtrBuf) = (unsigned char *)(ptrBuf + wdCount);
                *(ptrCount) -= wdCount;


                /*
                 *******************************************************
                 *prep for a zlp on the next interrupt if 
                 *this is the last transfer (wdCount == 0) and
                 *the transfer size matches the endpoint buffer size
                 *******************************************************
                 */
                if(wdCount == wdEndPSize && (*ptrCount) == 0)
                        ;               /*do nothing here zlp on next int*/
                else
                        {
                        if((*ptrCount) == 0)
                                (*ptrCount) = -1;
                        else
                                ;       /*do nothing transfer continues*/
                        }
                }
        }
}       





/*
 **********************************************************************
 *description:  tx transfer queue routine
 *input:        unsigned int    wdEndP     = endpoint number
 *              unsigned char   *ptrBuffer = pointer to buffer
 *              unsigned int    wdSize     = buffer size in bytes
 *notes:        store pointers to the global record. stores count of 
 *              records
 **********************************************************************
 */
void
stm32_usb_queue_IN_transfers(unsigned int  wdEndP,\
                             unsigned char *ptrBuffer,\
                             unsigned int  wdSize)
{
if(wdEndP == STMUSB_ENDP_USER_NUM)
        {
        strUsbPktXfer.ptrUserBuf = ptrBuffer;
        strUsbPktXfer.wdUserSize = wdSize;
        }
else
        {
        strUsbPktXfer.ptrCtrlBuf = ptrBuffer;
        strUsbPktXfer.wdCtrlSize = wdSize;
        }
}





/*
 **********************************************************************
 *description:  setup particular portA pin to an input, so its no
 *              longer driving the pin
 *input:        unsigned int wdPin = PAx pin number to use. it must be
 *              portA block pins ONLY
 *note:         this should be called inside the usb isr on RESET flag
 *implemented:  using three position jumper pin with all three wire
 *              wrapped linked - and a jumper from PAx to one of the
 *              positions
 **********************************************************************
 */
void    stm32_usb_connect_pullup(unsigned int wdPin)
{
volatile unsigned int wdTemp, wdMask;


wdTemp  = (*PTR_STM32_GPIO_A_CRL);
wdTemp &= ~(0x0f << (wdPin << 2));
wdMask  = ((STM32_GPIO_CNF_IN_FLOATING << 2) | \
            STM32_GPIO_MODE_INPUT_MODE) << (wdPin << 2);

(*PTR_STM32_GPIO_A_CRL)  = (wdMask | wdTemp);
}





/*
 **********************************************************************
 *description:  I am using PAX (external wire to Dplus pin on J6 facing
 *              the USB connector) to pull up the line to trigger the
 *              USB HOST enumeration. 
 *              setup PAX to generic output. pull it high 
 *input:        unsigned int wdPin = PAx pin number to use. it must be
 *              portA block pins ONLY
 **********************************************************************
 */
void    stm32_usb_disconnect_pullup(unsigned int wdPin)
{
volatile unsigned int wdTemp, wdMask;


(*PTR_STM32_GPIO_A_BSRR) = ((1 << wdPin) << 16);

wdTemp  = (*PTR_STM32_GPIO_A_CRL);
wdTemp &= ~(0x0f << (wdPin << 2));
wdMask  = ((STM32_GPIO_CNF_OUT_GEN_PUSH_PULL << 2) | \
            STM32_GPIO_MODE_OUTPUT_2MHZ) << (wdPin << 2);

(*PTR_STM32_GPIO_A_CRL)  = (wdMask | wdTemp);
}





/*
 **********************************************************************
 *description:  usb user out isr handler
 *input:        unsigned int wdEndP
 *
 *execute OUT transaction:COMMAND format is as follows:
 *      byte    0       = command
 *      byte    1       = length of data in bytes
 *      byte    2       = 0xed
 *      byte    3       = 0xfe
 *      byte    4       = 32bit address
 *      byte    5       = 
 *      byte    6       = 
 *      byte    7       = 
 **********************************************************************
 */
void    stm32_usb_isr_user_out(unsigned int wdEndP)
{
unsigned char   sbBuffer[STMUSB_ENDP_CTRL_MAX_SIZE + 1];
unsigned int    wdTemp, wdSize, *ptrEndP, *ptrAddr;
unsigned char   *ptrTemp;


/*
 **********************************************************************
 *handle usb endpoints. clear endpoint interrupts
 *first grab a snapshot of the interrupt status register
 **********************************************************************
 */
ptrEndP  = (unsigned int *)PTR_STM32_USB_EP0R;
ptrEndP += wdEndP;
wdTemp   = (*ptrEndP);
if(((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX) ||\
   ((wdTemp & STM32_USB_EPR_EA_MASK)!= wdEndP))
        return;
else
        {
        /*
         **************************************************************
         *receive data if available
         **************************************************************
         */
        wdSize = stm32_usb_endp_get_packet(wdEndP,\
                                           sbBuffer,\
                                           STMUSB_ENDP_USER_SIZE);
        stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_RX);
        }



#ifdef  DEBUG
wdTemp = (STMUSB_ENDP_CTRL_MAX_SIZE - wdSize);
ptrTemp = (unsigned char *)(sbBuffer + wdSize);
if(((wdSize << 1) + wdSize) < wdTemp)
        {
        unsigned int wdCount;
        for(wdCount=0; wdCount<wdSize; wdCount++)
                {
                wdTemp  = sbBuffer[wdCount];
                tclib_itoa(wdTemp,(unsigned char *) ptrTemp);

                ptrTemp += 2;
                (*ptrTemp) =' ';
                ptrTemp += 1;
                }
        
        *(ptrTemp - 1) = 0;
        tclib_printf("%s\n", (unsigned int)(sbBuffer + wdSize));
        }
#endif



/*
 **********************************************************************
 *process packet
 **********************************************************************
 */
tclib_memcpy((unsigned char *)&wdTemp, sbBuffer+4, sizeof(int));
ptrAddr = (unsigned char *)wdTemp;
if(sbBuffer[2] != 0xed || sbBuffer[3] != 0xfe)
        {
        tclib_printf("packet signature missing\n", 0);
        return;
        }



if(sbBuffer[0] == 0)                            /*IN*/
        {
        wdTemp = *ptrAddr;                      /*retrieve value*/

        wdTemp  = \
        stm32_usb_endp_send_packet(wdEndP,\
                                   (unsigned char *)&wdTemp,\
                                   STMUSB_ENDP_USER_SIZE,\
                                   sizeof(int));
        if(wdTemp != sizeof(int))
                {
                tclib_printf("isr_user_out: send_packet_error\n", 0);
                return;
                }               

        stm32_usb_cancel_queued_IN_transfers(wdEndP);

#ifdef  IGNORE
        /*wait until transfer is complete before continuing*/
        do
                {
                wdTemp  = *(PTR_STM32_USB_EP0R + wdEndP);
                wdTemp &= STM32_USB_EPR_CTR_TX;
                }while(wdTemp != STM32_USB_EPR_CTR_TX);
#endif
                                        
        /*clear TX interrupt*/
        stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_TX);
        }
else
        {
        if(sbBuffer[0] != 1)                    /*OUT*/
                return;

        wdTemp  = sbBuffer[1];
        wdTemp -= 8;                            /*subtract command packet*/
        wdSize -= 8;                            /*ditto*/
        if(wdSize != wdTemp)                    /*i need to get the data*/
                {
                /*wait until data is available before continuing*/
                do
                        {
                        wdTemp  = *(PTR_STM32_USB_EP0R + wdEndP);
                        wdTemp &= STM32_USB_EPR_CTR_RX;
                        }while(wdTemp != STM32_USB_EPR_CTR_RX);
                                        
        
                wdSize = stm32_usb_endp_get_packet(wdEndP,  \
                                                   sbBuffer,\
                                                   STMUSB_ENDP_USER_SIZE);
                /*clear RX interrupt*/
                stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_RX);

                if(wdSize >= sizeof(int))
                        tclib_memcpy((unsigned char *)&wdTemp, sbBuffer, sizeof(int));
                else
                        return;
                }
        else
                tclib_memcpy((unsigned char *)&wdTemp, sbBuffer+8, sizeof(int));


        /*set value*/
        *ptrAddr = wdTemp;
        }       
}





/*
 **********************************************************************
 *description:  usb user in isr handler
 *input:        unsigned int wdEndP
 **********************************************************************
 */
void    stm32_usb_isr_user_in(unsigned int wdEndP)
{
volatile unsigned int   *ptrTemp, wdTemp;


/*
 **********************************************************************
 *handle usb endpoints. clear endpoint interrupts
 *first grab a snapshot of the interrupt status register
 **********************************************************************
 */
ptrTemp  = PTR_STM32_USB_EP0R;
ptrTemp += wdEndP;
wdTemp   = (*ptrTemp);
if(((wdTemp & STM32_USB_EPR_CTR_TX) != STM32_USB_EPR_CTR_TX) ||\
   ((wdTemp & STM32_USB_EPR_EA_MASK)!= wdEndP))
        return;
else
        {
        /*
         **************************************************************
         *transmit data if available 
         **************************************************************
         */
        stm32_usb_dequeue_IN_transfers(wdEndP);
        stm32_usb_clear_epr_ctr(wdEndP, STM32_USB_EPR_CTR_TX);
        }
}





/*
 **********************************************************************
 *description:  usb control in isr handler
 **********************************************************************
 */
void    stm32_usb_isr_control_in(void)
{
volatile unsigned int   wdTemp;


/*
 **********************************************************************
 *handle usb endpoints. clear endpoint interrupts
 *first grab a snapshot of the interrupt status register
 **********************************************************************
 */
wdTemp = (*PTR_STM32_USB_EP0R);
if((wdTemp & STM32_USB_EPR_CTR_TX) != STM32_USB_EPR_CTR_TX)
        return;
else
        {
        /*
         **************************************************************
         *transmit data if available 
         *data toggle is set by caller to stm32_queue_IN_transfers to 1
         *subsequent toggles are done by the hardware
         **************************************************************
         */
        stm32_usb_dequeue_IN_transfers(0);
        stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX);
        }
}





/*
 **********************************************************************
 *description:  usb control out isr handler
 *output:       none
 **********************************************************************
 */
void    stm32_usb_isr_control_out(void)
{
unsigned char   sbBuffer[STMUSB_ENDP_CTRL_MAX_SIZE + 1];
unsigned char   *ptrTemp;
volatile unsigned int   wdTemp, wdSize, wdIndex, wdType;


/*
 **********************************************************************
 *handle usb endpoints. clear endpoint interrupts
 *first grab a snapshot of the interrupt status register
 **********************************************************************
 */
wdTemp = (*PTR_STM32_USB_EP0R);
#ifdef  IGNORE
if(((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX) ||\
   ((wdTemp & STM32_USB_EPR_SETUP)  != STM32_USB_EPR_SETUP))
#endif
if((wdTemp & STM32_USB_EPR_CTR_RX) != STM32_USB_EPR_CTR_RX)
        return;
else
        {
        /*
         **************************************************************
         *receive data if available
         **************************************************************
         */
        wdSize = stm32_usb_endp_get_packet(0,       \
                                           sbBuffer,\
                                           STMUSB_ENDP_CTRL_MAX_SIZE);
        stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_RX);
        }


#ifdef  DEBUG
if(wdSize >= 8)
        {
        wdTemp = (STMUSB_ENDP_CTRL_MAX_SIZE - wdSize);
        ptrTemp = (unsigned char *)(sbBuffer + wdSize);
        if(((wdSize << 1) + wdSize) < wdTemp)
                {
                unsigned int wdCount;
                for(wdCount=0; wdCount<wdSize; wdCount++)
                        {
                        wdTemp  = sbBuffer[wdCount];
                        tclib_itoa(wdTemp, (unsigned char *)ptrTemp);

                        ptrTemp += 2;
                        (*ptrTemp) =' ';
                        ptrTemp += 1;
                        }
        
                *(ptrTemp - 1) = 0;
                tclib_printf("%s\n", (unsigned int)(sbBuffer + wdSize));
                }
        }
#endif



/*
 **********************************************************************
 *evaluate SETUP command packet
 **********************************************************************
 */
wdTemp  = sbBuffer[USBDEV_SETUP_REQTYPE_OFFSET];
if((wdTemp & USBDEV_SETUP_REQTYPE_DIR_MASK) == USBDEV_SETUP_REQTYPE_DIR_H_TO_D)
        {                                               /*these are SET commands*/
        switch(sbBuffer[USBDEV_SETUP_REQUEST_OFFSET])
                {
                case    USBDEV_REQ_SET_ADDRESS:
                        {                             
                        /*return ZLP = zero length packet, before enabling dev*/
                        stm32_usb_set_epr_dtog(0,\
                                               1,\
                                               STM32_USB_EPR_DTOG_TX_OFFSET);

                        wdTemp  = \
                        stm32_usb_endp_send_packet(0,\
                                                   (unsigned char *)&wdTemp,\
                                                   STMUSB_ENDP_CTRL_SIZE,\
                                                   0);
                        if(wdTemp != 0)
                                {
                                tclib_printf("isr_control_out: send_packet_error\n", 0);
                                return;
                                }               


                        /*wait until transfer is complete before setting address*/
                        do
                                {
                                wdTemp  = *(PTR_STM32_USB_EP0R + 0);
                                wdTemp &= STM32_USB_EPR_CTR_TX;
                                }while(wdTemp != STM32_USB_EPR_CTR_TX);
                                        

                        /*clear TX interrupt*/
                        stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX);


                        /*alert user and set the bus address*/
                        wdTemp  = sbBuffer[USBDEV_SETUP_VALUE_OFFSET];
                        (*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | wdTemp);
                        tclib_printf("usb device address = %x\n", wdTemp);
                        break;
                        }
                case    USBDEV_REQ_SET_CONFIGURATION:
                        {
                        /*return ZLP = zero length packet*/
                        stm32_usb_set_epr_dtog(0,\
                                               1,\
                                               STM32_USB_EPR_DTOG_TX_OFFSET);

                        wdTemp = \
                        stm32_usb_endp_send_packet(0,\
                                                   (unsigned char *)&wdTemp,\
                                                   STMUSB_ENDP_CTRL_SIZE,\
                                                   0);
                        if(wdTemp != 0)
                                {
                                tclib_printf("isr_control_out: send_packet_error\n", 0);
                                return;
                                }               

                        break;
                        }
                case    USBDEV_REQ_SET_FEATURE:         /*not supported*/
                case    USBDEV_REQ_SET_INTERFACE:       /*not supported*/
                case    USBDEV_REQ_CLEAR_FEATURE:       /*not supported*/
                case    USBDEV_REQ_SET_DESCRIPTOR:      /*not supported*/
                default:
                        {
                        break;
                        }
                }
        }
else
        {                                               /*these are GET* commands*/
        switch(sbBuffer[USBDEV_SETUP_REQUEST_OFFSET])
                {
                case    USBDEV_REQ_GET_DESCRIPTOR:
                        {
                        wdType   = (sbBuffer[(USBDEV_SETUP_VALUE_OFFSET + 1)] & 0x0ff);
                        wdIndex  = (sbBuffer[USBDEV_SETUP_VALUE_OFFSET]       & 0x0ff);
                        wdSize   = (sbBuffer[USBDEV_SETUP_LENGTH_OFFSET]      & 0x0ff);


                        /*
                         *********************************************
                         determine descriptor type
                         *********************************************
                         */
                        switch(wdType)
                                {
                                case    USBDEV_DESCR_TYPE_DEVICE:
                                        {
                                        ptrTemp = (unsigned char *)sbDevDescr;
                                        break;
                                        }
                                case    USBDEV_DESCR_TYPE_CONFIGURATION:
                                        {
                                        ptrTemp = (unsigned char *)sbConfDescr;
                                        break;
                                        }
                                case    USBDEV_DESCR_TYPE_STRING:
                                        {
                                        wdTemp  = swUsbDevDescr[wdIndex];
                                        ptrTemp = (unsigned char *)wdTemp;
                                        break;
                                        }
                                default:
                                        {
                                        tclib_printf("unsupported descriptor type = %x\n", wdType);
                                        break;
                                        }
                                }



                        
                        stm32_usb_set_epr_dtog(0,\
                                               1,\
                                               STM32_USB_EPR_DTOG_TX_OFFSET);

                        stm32_usb_queue_IN_transfers(0,\
                                                     (unsigned char *)ptrTemp,\
                                                     wdSize);
                        stm32_usb_dequeue_IN_transfers(0);
                        break;
                        }
                case    USBDEV_REQ_GET_STATUS:
                        {
                        wdTemp = 0;
                        stm32_usb_set_epr_dtog(0,\
                                               1,\
                                               STM32_USB_EPR_DTOG_TX_OFFSET);

                        wdTemp = \
                        stm32_usb_endp_send_packet(0,\
                                                   (unsigned char *)&wdTemp,\
                                                   STMUSB_ENDP_CTRL_SIZE,\
                                                   2);
                        if(wdTemp != 2)
                                {
                                tclib_printf("isr_control_out: send_packet_error\n", 0);
                                return;
                                }               

                        break;
                        }
                case    USBDEV_REQ_GET_CONFIGURATION:
                        {
                        wdTemp = 0;
                        stm32_usb_set_epr_dtog(0,\
                                               1,\
                                               STM32_USB_EPR_DTOG_TX_OFFSET);

                        wdTemp = \
                        stm32_usb_endp_send_packet(0,\
                                                   (unsigned char *)&wdTemp,\
                                                   STMUSB_ENDP_CTRL_SIZE,\
                                                   1);
                        if(wdTemp != 1)
                                {
                                tclib_printf("isr_control_out: send_packet_error\n", 0);
                                return;
                                }               

                        break;
                        }
                case    USBDEV_REQ_SYNTH_FRAME:     /*doesnt apply*/
                case    USBDEV_REQ_GET_INTERFACE:   /*doesnt apply*/
                default:
                        {
                        break;
                        }
                }
        }
}





/*
 **********************************************************************
 *description:  first stage usb isr handler
 **********************************************************************
 */
void    stm32_usb_isr(void)
{
volatile unsigned int   wdIrqStat, wdEndP;


/*
 **********************************************************************
 *is this a RESET interrupt?
 *handle it. re-initialize the usb endpoint sub-system
 **********************************************************************
 */
wdIrqStat = (*PTR_STM32_USB_ISTR);
if((wdIrqStat & STM32_USB_ISTR_RESET) == STM32_USB_ISTR_RESET)
        {
        wdUsbState = STM32_USB_ISTR_RESET;
        (*PTR_STM32_USB_ISTR) = ~wdUsbState;

        /*disable interrupts */
        asm("cpsid i");

#ifdef  DEBUG
(*PTR_STM32_TIM3_CNT) =0;
#endif
        stm32_usb_post_reset_setup(STMUSB_ENDP_USER_NUM,\
                                   STM32_USB_EPR_EP_TYPE_BULK,
                                   STMUSB_ENDP_USER_SIZE);
#ifdef  DEBUG
wdUsbState = (*PTR_STM32_TIM3_CNT);
#endif

        /*enable interrupts anew*/
        asm("cpsie i");

#ifdef  DEBUG
        tclib_printf("--------RESET----------- %duS\n", wdUsbState);
#else
        tclib_printf("--------RESET----------- \n", 0);
#endif

        wdUsbState = 0;
        }



/*
 **********************************************************************
 *is this a CORRECT TRANSFER interrupt?
 *handle it. process the data
 **********************************************************************
 */
wdIrqStat = (*PTR_STM32_USB_ISTR);
if((wdIrqStat & STM32_USB_ISTR_CTR)   == STM32_USB_ISTR_CTR)
        {
        wdEndP   = (wdIrqStat & STM32_USB_ISTR_EP_ID_MASK);
        wdEndP >>= STM32_USB_ISTR_EP_ID_OFFSET;


        /*
         **************************************************************
         *control endpoint can go in either direction = IN or OUT
         *        its complexity requires a function that handles a 
         *        a state machine
         *user    endpoint can go in either direction = IN or OUT
         *        this is simple data exchange nothing more
         **************************************************************
         */
        switch((wdIrqStat & STM32_USB_ISTR_DIR_MASK))
                {
                case    STM32_USB_ISTR_DIR_IN:
                        {
                        if(wdEndP == 0)
                                stm32_usb_isr_control_in();
                        else
                                stm32_usb_isr_user_in(wdEndP);

                        break;
                        }
                case    STM32_USB_ISTR_DIR_OUT:
                        { 
                        stm32_usb_cancel_queued_IN_transfers(0);
                        if(wdEndP == 0)
                                stm32_usb_isr_control_out();
                        else
                                stm32_usb_isr_user_out(wdEndP);
                        
                        break;
                        }
                }
        }
}





/*
 **********************************************************************
 *description:  usb initialization function
 *note:         setup the usb function then setup the endpoint for 
 *              control (0) and user endpoint (interrupt for now)
 **********************************************************************
 */
void    stm32_usb_init(void)
{
volatile unsigned int   wdTemp;

        
/*
 **********************************************************************
 *clear out record
 **********************************************************************
 */
tclib_memset((unsigned char *)&strUsbPktXfer, -1, sizeof(strUsbPktXfer));


/*
 **********************************************************************
 *now setup the usb interface
 **********************************************************************
 */
wdTemp  = STM32_USB_CNTR_CTRM;
wdTemp |= STM32_USB_CNTR_RESETM;
//wdTemp |= STM32_USB_CNTR_SUSPM;
#ifdef  ISOCHRONOUS
        wdTemp |= STM32_USB_CNTR_SOFM;
#endif

(*PTR_STM32_USB_CNTR) = wdTemp;

stm32_usb_pre_reset_setup(STMUSB_ENDP_USER_NUM,\
                          STM32_USB_EPR_EP_TYPE_BULK,
                          STMUSB_ENDP_USER_SIZE);

wdTemp  = ~(STM32_USB_ISTR_RESET | STM32_USB_ISTR_SUSP);
(*PTR_STM32_USB_ISTR) = wdTemp;

stm32_nvic_install_isr(USB_NVIC_IRQ_NUM, (unsigned int)stm32_usb_isr);
}





/*
 **********************************************************************
 *description:  usb routine to be executed after host bus initiated 
 *              reset
 *inputs:       unsigned int    wdUserEndPNum = user endpoint number
 *              unsigned int    wdUserEndPType= endpoint type
 *                              STM32_USB_EPR_EP_TYPE_BULK
 *                              STM32_USB_EPR_EP_TYPE_CONTROL
 *                              STM32_USB_EPR_EP_TYPE_ISO
 *                              STM32_USB_EPR_EP_TYPE_INTERRUPT
 *              unsigned int    wdUserEndPSize= 8,16,32,64 etc
 *note:         crucial to call stm32_usb_clear_epr_cnt to clear rx and
 *              tx SPURIOUS interrupts!!!
 **********************************************************************
 */
void    stm32_usb_post_reset_setup(unsigned int wdUserEndPNum,\
                                   unsigned int wdUserEndPType,\
                                   unsigned int wdUserEndPSize)
{
stm32_usb_set_epr_dtog(0,\
                       0,\
                       STM32_USB_EPR_DTOG_RX_OFFSET);
stm32_usb_set_epr_dtog(0,\
                       1,\
                       STM32_USB_EPR_DTOG_TX_OFFSET);
stm32_usb_set_epr_stat(0,\
                       STM32_USB_EPR_STAT_RX_VALID,\
                       STM32_USB_EPR_STAT_RX_OFFSET);
stm32_usb_set_epr_stat(0,\
                       STM32_USB_EPR_STAT_TX_NAK,\
                       STM32_USB_EPR_STAT_TX_OFFSET);
stm32_usb_cancel_queued_IN_transfers(0);
stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_RX);
stm32_usb_clear_epr_ctr(0, STM32_USB_EPR_CTR_TX);
stm32_usb_enable_endp(0, STM32_USB_EPR_EP_TYPE_CONTROL);

                       
stm32_usb_set_epr_stat(wdUserEndPNum,\
                       STM32_USB_EPR_STAT_RX_VALID,\
                       STM32_USB_EPR_STAT_RX_OFFSET);
stm32_usb_set_epr_stat(wdUserEndPNum,\
                       STM32_USB_EPR_STAT_TX_NAK,\
                       STM32_USB_EPR_STAT_TX_OFFSET);
stm32_usb_cancel_queued_IN_transfers(wdUserEndPNum);
stm32_usb_clear_epr_ctr(wdUserEndPNum, STM32_USB_EPR_CTR_RX);
stm32_usb_clear_epr_ctr(wdUserEndPNum, STM32_USB_EPR_CTR_TX);
stm32_usb_enable_endp(wdUserEndPNum, wdUserEndPType);

/*set and enable device addr*/
(*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | 0);
}





/*

 **********************************************************************
 *description:  usb routine to be executed before host bus initiated 
 *              reset
 *inputs:       unsigned int    wdUserEndPNum = user endpoint number
 *              unsigned int    wdUserEndPType= endpoint type
 *                              STM32_USB_EPR_EP_TYPE_BULK
 *                              STM32_USB_EPR_EP_TYPE_CONTROL
 *                              STM32_USB_EPR_EP_TYPE_ISO
 *                              STM32_USB_EPR_EP_TYPE_INTERRUPT
 *              unsigned int    wdUserEndPSize= 8,16,32,64 etc
 **********************************************************************
 */
void    stm32_usb_pre_reset_setup(unsigned int wdUserEndPNum,\
                                  unsigned int wdUserEndPType,\
                                  unsigned int wdUserEndPSize)
{
volatile unsigned int   *ptrTemp, wdLclPktAddr;


/*set usb buffer table address*/
(*PTR_STM32_USB_BTABLE) = 0;                    /*offset ?*/

/*clear out all packet buffer memory*/
tclib_memset((unsigned char *)PTR_STM32_USB_EPRAM, 0, 0x200);

/*initialize control endpoint first - calculate pk buffer local addr*/
ptrTemp      = (volatile unsigned int *)PTR_STM32_USB_EPRAM;
wdLclPktAddr = ((8 * 8) + 0);                   /*offset ?*/

/*control endp*/
wdLclPktAddr = stm32_usb_build_endp_descriptors(0,\
                                     STM32_USB_EPR_EP_TYPE_CONTROL,\
                                     STMUSB_ENDP_CTRL_SIZE,\
                                     (unsigned int *)ptrTemp,\
                                     wdLclPktAddr);
stm32_usb_enable_endp(0, STM32_USB_EPR_EP_TYPE_CONTROL);

/*user chosen endp*/
ptrTemp     += (4 * STMUSB_ENDP_USER_NUM);
wdLclPktAddr = stm32_usb_build_endp_descriptors(wdUserEndPNum,\
                                     wdUserEndPType,\
                                     wdUserEndPSize,\
                                     (unsigned int *)ptrTemp,\
                                     wdLclPktAddr);
stm32_usb_enable_endp(wdUserEndPNum, wdUserEndPType);

/*finally set and enable device addr*/
(*PTR_STM32_USB_DADDR) = ((STM32_USB_DADDR_EF) | 0);


/*cancel all transfers*/
stm32_usb_cancel_queued_IN_transfers(0);
stm32_usb_cancel_queued_IN_transfers(wdUserEndPNum);
}





/*
 **********************************************************************
 *description:  usb routine to build a particular endpoints descriptors
 *
 *inputs:       unsigned int    wdEndPNum = endpoint number
 *              unsigned int    wdEndPType= endpoint type
 *                              STM32_USB_EPR_EP_TYPE_BULK
 *                              STM32_USB_EPR_EP_TYPE_CONTROL
 *                              STM32_USB_EPR_EP_TYPE_ISO
 *                              STM32_USB_EPR_EP_TYPE_INTERRUPT
 *              unsigned int    wdEndPSize= 8,16,32,64 etc
 *output:       wdLclPktAddr    = usb local packet address
 *NOTE:         packet descriptor size must be pktsize+2 to account for
 *              the two byte crc the host writes
 **********************************************************************
 */
int     stm32_usb_build_endp_descriptors(unsigned int wdEndPNum,\
                                         unsigned int wdEndPType,\
                                         unsigned int wdEndPSize,\
                                         unsigned int *ptrDescAddr,\
                                         unsigned int wdLclPktAddr)
{
volatile unsigned int   wdTemp;


/*set tx buffer addr*/
(*ptrDescAddr++) =  wdLclPktAddr;
wdLclPktAddr    +=  wdEndPSize;


/*set tx count*/
(*ptrDescAddr++) =  wdEndPSize;


/*adjust wdEndPSize to account for extra 2 bytes of crc*/
/*set rx buffer addr*/
wdEndPSize      +=  2;
(*ptrDescAddr++) =  wdLclPktAddr;
wdLclPktAddr    +=  wdEndPSize;


if(wdEndPSize >= 64)
        {
        wdTemp  = STM32_USB_COUNT_RX_BL_SIZE_32BYTE;
        wdTemp |= ((wdEndPSize >> 6) << STM32_USB_COUNT_RX_NUM_BLOCK_OFFSET);
        }
else
        {
        wdTemp  = STM32_USB_COUNT_RX_BL_SIZE_2BYTE;
        wdTemp |= ((wdEndPSize >> 1) << STM32_USB_COUNT_RX_NUM_BLOCK_OFFSET);
        }


/*set rx count*/
(*ptrDescAddr++) = wdTemp;

return wdLclPktAddr;
}





/*
 **********************************************************************
 *description:  usb endpoint send packet routine
 *
 *inputs:       unsigned int    wdEndPNum = endpoint number
 *              unsigned int    wdEndPSize= 8,16,32,64 etc
 *                      char    *ptrBuffer= pointer to buffer
 *              unsigned int    wdBytelen = byte length
 *output:       number of bytes sent on success -1 on error (timeout)
 *note:         clears CTR_TX flag
 **********************************************************************
 */
int    stm32_usb_endp_send_packet(unsigned int  wdEndPNum,\
                                  unsigned char *ptrBuffer,\
                                  unsigned int  wdEndPSize,\
                                  unsigned int  wdBytelen)
{
volatile unsigned int   wdTemp, *ptrTemp, wdCount, *ptrDst, wdSize;
unsigned short  int     *ptrSrc;


ptrSrc = (unsigned short int *)ptrBuffer;
if(wdBytelen > wdEndPSize)
        wdCount = wdEndPSize;
else
        wdCount = wdBytelen;


wdSize = wdCount;
/*
 **************************************************************
 *copy the data into the buffer - retrieve address
 *update transmission count 
 *now enable transmission control reg - retrieve value
 *prepare for transmission - set status bits
 **************************************************************
 */
ptrTemp  = (volatile unsigned int *)PTR_STM32_USB_EPRAM;
ptrTemp += (4 * wdEndPNum);

wdTemp   = (*ptrTemp);
wdTemp   = (PTR_STM32_USB_EPRAM + (wdTemp << 1));

ptrTemp += 1;                   /*tx count descriptor*/
(*ptrTemp) = wdCount;
        

ptrDst = (unsigned int *)wdTemp;
while(wdCount > 0)
     {
     *(ptrDst++)     = (int)(*(ptrSrc++));
     if(wdCount >= 2)
        wdCount -= 2;
     else
        wdCount -= 1;
     }


/*
 **********************************************************************
 *prepare for new transmission at a later time, set valid bits
 **********************************************************************
 */
stm32_usb_set_epr_stat(wdEndPNum,\
                       STM32_USB_EPR_STAT_TX_VALID,\
                       STM32_USB_EPR_STAT_TX_OFFSET);
 
return wdSize;
}





/*
 **********************************************************************
 *description:  usb endpoint get packet routine
 *
 *inputs:       unsigned int    wdEndPNum = endpoint number
 *                      char    *ptrBuffer= pointer to buffer
 *              unsigned int    wdBytelen = byte length
 *output:       int                       = size of data posted
 *note:         clears CTR_RX flag
 **********************************************************************
 */
int     stm32_usb_endp_get_packet(unsigned int  wdEndPNum,\
                                  unsigned char *ptrBuffer,\
                                  unsigned int  wdBytelen)
{
volatile unsigned int   wdTemp, *ptrTemp, wdCount, wdSize ,*ptrSrc;
unsigned short    int   *ptrDst;


/*
 **********************************************************************
 *get byte size
 *copy over data
 **********************************************************************
 */
ptrTemp  = (volatile unsigned int *)PTR_STM32_USB_EPRAM;
ptrTemp += (4 * wdEndPNum);
ptrTemp += 2;

wdTemp   = (*ptrTemp);
wdTemp   = (PTR_STM32_USB_EPRAM + (wdTemp << 1));
wdCount  = *(ptrTemp +1);
wdCount &= STM32_USB_COUNT_RX_MASK;
wdSize   = wdCount;

if(wdCount > wdBytelen)
        wdCount = wdBytelen;

ptrSrc = (unsigned int *)wdTemp;
ptrDst = (unsigned short int *)ptrBuffer;
while(wdCount > 0)
        {
        *(ptrDst++)      = (short int)(*(ptrSrc++));
        if(wdCount >= 2)
                wdCount -= 2;
        else
                wdCount -= 1;
        }


/*
 **********************************************************************
 *prepare for new reception at a later time, set valid bits
 **********************************************************************
 */
stm32_usb_set_epr_stat(wdEndPNum,\
                       STM32_USB_EPR_STAT_RX_VALID,\
                       STM32_USB_EPR_STAT_RX_OFFSET);
 
return wdSize;
}





Saturday, August 10, 2013

my style.txt file from 2001

So I found my style.txt file from 2001. It was basically a document I put together defining or clarifying the style I would use in developing software - from variable names to indentation.


Pulled from the way back machine. For the most part I have adhered to this convention all these years and its served me well.

Samuel Igwe     
Last Modified: April 6,2001

REVISION OF CODING STYLE
************************
C language and ASM
******************


HEADER (header and function):
*****************************
all source files (.asm,.c etc) must have a header that defines its purpose
all functions must have a header that defines its purpose as well.
this header takes the following form
source module header
/************************************************************************
module:  ...
date:  ...
description: ... 
************************************************************************/

function header
/************************************************************************
description: ... 
input:  ...
output:  ...
************************************************************************/

FOR .asm replase /* with ;* or ;-
note header top and bottom must start from one end of the screen and end in 
the other sort of enclosing the function/procedure or header


VARIABLES:
**********
variables must begin with the following prefixes then the first char capital
by=char,byte
sb=char array
wd=short int,word
sw=short int array
dw=long,double word
sd=long array
qw=quad word
ptr=pointer
str=structure
un=union

examples of variable names are byChar,wdCount,dwValue,ptrToken, etc


FUNCTION and PROCEDURES (definitions):
**************************************
function names must begin with the prefix "func" followed by an underbar and 
then the name of the function. 

examples of function names are func_get_key, func_init_registers

FOR .asm this convention maybe broken in the case of modules that serve as
library files (cg=color graphics module). the keyboard library procedures 
would begin with kb_ the video vga_ etc etc


#DEFINE and #EQUATES:
*********************
the name of constants defined using the #define prefix must be capitalized
for asm, macro names must be capitalized along with equates defined with the
.equ directive.

examples are #define MAX_STRING_LENGTH 256
      .equ    BOOTSTART  0


POINTERS (definitions):
***********************
all pointer definitions must begin with the prefix "ptr" followed by the name
of the pointer. values passed to functions as pointers must be named
ptrVariable name even if the original definition was not of a pointer but of
an array or variable.

examples are ptrToken, ptrChar


AESTETHICS:
***********
it is far easier to modify code when its appearance pleases the eye and is
found understandable. in keeping with this belief, code must be formatted
and indented well.
examples
if=the STATEMENT portion for "if" and "else" MUST be indented (tab)
while=same as above
do while etc etc

this rule applied double to ASM  -- blocks of code and loops MUST be indented
well -- this rule is sacrosant!!! 

Thursday, August 8, 2013

Makefile

CC     = arm-linux-gnueabi-gcc
LD     = arm-linux-gnueabi-ld
OBJCPY = arm-linux-gnueabi-objcopy
APP    = usb
#APP   = core

#CFLAGS = -g -c -Wall -nostdlib -mcpu=cortex-m3 -mlittle-endian -mthumb  -I core/include -I tclib \
#         -mabi=atpcs -O0 -DDEBUG
CFLAGS = -g -c -Wall -nostdlib -mcpu=cortex-m3 -mlittle-endian -mthumb  -I core/include -I tclib \
         -mabi=atpcs -DDEBUG 
LDFLAGS= -nostdlib -e main  -Map flash.map -L linker -T IE_stm32.ld --cref 

all:
        make stm32_core
        make app
        make clean
        

stm32_core:
        $(CC) -o reset.o     $(CFLAGS)  core/src/IE_stm32_ivt.S
        $(CC) -o tclibS.o    $(CFLAGS)  tclib/IE_tclib.S
        $(CC) -o tclibC.o    $(CFLAGS)  tclib/IE_tclib.c
        $(CC) -o usbdev.o    $(CFLAGS)  core/src/IE_stm32_usb.c
        $(CC) -o core.o      $(CFLAGS)  core/src/IE_stm32.c



app:
        $(CC) -o $(APP)_test.o          $(CFLAGS)  apps/$(APP)/$(APP)_test.c 
        $(LD) -o $(APP)_test.out        $(LDFLAGS) reset.o   \
                                                   core.o    \
                                                   tclibS.o  \
                                                   tclibC.o  \
                                                   usbdev.o  \
                                                   $(APP)_test.o

clean:
        rm -f reset.o
        rm -f core.o
        rm -f tclibS.o
        rm -f tclibC.o
        rm -f usbdev.o
        rm -f $(APP)_test.o
     

binimage: 
        $(OBJCPY) -O binary flash.out flash.bin



Monday, August 5, 2013

IE_tclib.S

/*
 *****************************************************************
 *name:         tclib.S
 *author:       Samuel Igwe
 *date:         08/04/2013
 *description:  my thumb2 library. asm optimized generic routines
 *
 *notes:        from ARM technical reference manual
 *              instructions are conditional
 *              eq/ne (eq = 0, ne = not 0)
 *              ge/gt/le/lt
 *              memory addressing formats ldr(s)/str
 *              pre-index with writeback   ldr r0, [r1,#4]!
 *                              data = mem[base+offset] 
 *                      base addr reg= base+offset
 *              pre-index                  ldr r0, [r1,#4]
 *                              data = mem[base+offset]
 *                      base addr reg= not updated
 *              post-index                 ldr r0, [r1],#4
 *                              data = mem[base]
 *                      base addr reg= base+offset 
 *
 *              #4 above could be replaced by another register
 *****************************************************************
 */





.thumb
.text
.syntax unified

.align  2
.global tclib_cinit
.thumb_func
.equ    SRAM_TOP, (0x20000000 + (20*1024))
tclib_cinit:
ldr     sp, =SRAM_TOP
mov     pc, lr



/*
 *****************************************************************
 *description:  software divider. meanth to be called from asm
 *              takes 
 *inputs:       r0 = dividend
 *              r1 = divisor
 *outputs:      r0 = quotient
 *              r1 = remainder
 *output:       0 on error 1 on success
 *****************************************************************
 */
.align  2
.global tclib_softdiv
.thumb_func
tclib_softdiv:
push    {r2, lr}

mov     r2, r0                                  /*put r0 in r2*/
mov     r0, #0                                  /*zero out quotient*/

tclib_softdiv_loop:
cmp     r2, r1
blt     tclib_softdiv_exit
sub     r2, r2, r1
add     r0, r0, #1
b tclib_softdiv_loop

tclib_softdiv_exit:
mov     r1, r2                                  /*r1 remainder*/

pop     {r2, lr}
mov     pc, lr





/*
 *****************************************************************
 *description:  acquire semaphore
 *input:        char *ptrWord   = pointer to memory word
 *output:       0 on error 1 on success
 *void
 *tclib_acquire_semaphore(unsigned char *ptrWord)
 *****************************************************************
 */
.align  2
.global tclib_acquire_semaphore
/*
 *****************************************************************
 *r0 = ptrWord
 *****************************************************************
 */
.thumb_func
tclib_acquire_semaphore:
push    {r1-r2}


mov     r1, #1
mov     r2, r0

ldrexb  r0, [r2]                        /*get value*/
cmp     r0, #0
eorne   r0, #1
bne     tclib_get_mutex_exit

strexb  r0, r1, [r2]
eor     r0, #1

tclib_get_mutex_exit:
clrex

pop     {r1-r2}
mov     pc, lr





/*
 *****************************************************************
 *description:  release semaphore
 *input:        char *ptrWord   = pointer to memory word
 *output:       0 on error 1 on success
 *void
 *tclib_release_semaphore(unsigned char *ptrWord)
 *****************************************************************
 */
.align  2
.global tclib_release_semaphore
/*
 *****************************************************************
 *r0 = ptrWord
 *****************************************************************
 */
.thumb_func
tclib_release_semaphore:
push    {r1-r2}


mov     r1, #0
mov     r2, r0

ldrexb  r0, [r2]                        /*get value*/
cmp     r0, #0
eorne   r0, #1
beq     tclib_release_mutex_exit

strexb  r0, r1, [r2]
eor     r0, #1

tclib_release_mutex_exit:
clrex

pop     {r1-r2}
mov     pc, lr





/*
 *****************************************************************
 *description:  sets a string buffer to a certain value
 *input:        char *ptrString =pointer to string
 *              int  wdValue    =value
 *              int  wdSize     =maximum length of string
 *void
 *tclib_memset(unsigned char *ptrString, int wdValue, int wdSize)
 *{
 *while ((wdSize--) >0)
 *       *(ptrString++) = (char)wdValue;
 *}
 *****************************************************************
 */
.align  2
.global tclib_memset
/*
 *****************************************************************
 *r0 = ptrString
 *r1 = wdValue
 *r2 = wdSize
 *r3 = scratch
 *****************************************************************
 */
.thumb_func
tclib_memset:
push    {r0-r3, lr}

mov     r3, r1, lsl #8
orr     r1, r1, r3                      /*put byte into word*/
mov     r3, r1, lsl #16
orr     r1, r1, r3                      /*put word into dword*/

/*
 *****************************************************************
 *the instructions below
 orr     r1, r1, lsl #8                 
 orr     r1, r1, lsl #16
 *
 *generate the error
 tclib/tclib.S: Assembler messages:
 tclib/tclib.S:203: Error: garbage following instruction -- `orr r1,r1,lsl#8'
 tclib/tclib.S:204: Error: garbage following instruction -- `orr r1,r1,lsl#16'
 *under arm-linux-gnueabi-gcc version 4.4.5
 *so I revised it to the instructions above this comment
 *****************************************************************
 */

andS    r3, r0, #0x3                    /*determine dword alignment*/
beq     tclib_memset_loop               /*take action if aligned*/


        tclib_memset_align:
        strb    r1, [r0], #1            /*store one byte - autoincr*/
        subS    r2, r2, #1              /*decrement counter*/
        popeq   {r0-r3, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        andS    r3, r0, #0x3            /*determine dword alignment*/
        bne     tclib_memset_align


        tclib_memset_loop:              /*optimization*/
        cmp     r2, #4                  /*r2 >= 4*/
        blt     tclib_memset_align
                                        /*else*/
        str     r1, [r0], #4            /*dword*/
        subS    r2, #4                  /*decrement counter*/
        bne     tclib_memset_loop      
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/




/*
 *****************************************************************
 *description:  copy from source to destination buffer
 *input:        char *ptrDstStr =pointer to dst string
 *              char *ptrSrcStr =pointer to src string
 *              int  wdSize     =max length of string
 *void
 *tclib_memcpy(unsigned char *ptrDstStr,\
 *              unsigned char *ptrSrcStr, \
 *              int wdSize)
 *{
 *while ((wdSize--) >0)
 *       *(ptrDstStr++) = *(ptrSrcStr++);
 *}
 *****************************************************************
 */
.align  2
.global tclib_memcpy
/*
 *****************************************************************
 *r0 = ptrDst
 *r1 = ptrSrc
 *r2 = wdSize
 *r3 = scratch
 *****************************************************************
 */
.thumb_func
tclib_memcpy:
push    {r0-r3, lr}

andS    r3, r0, #0x3                    /*check if dst aligned*/                        
bne     tclib_memcpy_bcopy
andS    r3, r1, #0x3                    /*check if src aligned*/
bne     tclib_memcpy_bcopy


        tclib_memcpy_loop:              /*optimization*/
        cmp     r2, #4                  /*check if size >= 4*/
        blt     tclib_memcpy_bcopy
                                        /*else*/
        ldr     r3, [r1], #4            /*get from src*/
        str     r3, [r0], #4            /*put in   dst*/
        subS    r2, #4                  /*decrement counter*/
        bne     tclib_memcpy_loop
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/


        tclib_memcpy_bcopy:
        ldrb    r3, [r1], #1            /*get from src*/
        strb    r3, [r0], #1            /*put in   dst*/
        subS    r2, #1                  /*decrement counter*/
        bne     tclib_memcpy_bcopy
        pop     {r0-r3, lr}             /*exit*/
        mov     pc, lr                  /*exit*/





/*
 *****************************************************************
 *description:  ascii to integer
 *input:        char *ptrAscStr =pointer to string
 *output:       int             =value
 *int
 *tclib_atoi(unsigned char *ptrAscStr)
 *{
 *unsigned char     *ptrTemp;
 *volatile int wdValue,wdWeight,wdTemp;
 *
 *wdValue =0;
 *wdWeight=1;
 *ptrTemp =ptrAscStr;
 *
 *while ((*ptrTemp) != NULL)
 *       ptrTemp++;
 *
 *while ((--ptrTemp) >= ptrAscStr)
 *       {
 *       wdTemp = *ptrTemp;
 *       if (wdTemp >= '0' && wdTemp <='9')
 *               wdTemp-= '0';
 *       else
 *               {
 *               if (wdTemp >='a' && wdTemp <='f')
 *                       {
 *                       wdTemp-= 'a';
 *                       wdTemp+= 10;
 *                       }
 *               else
 *                       {
 *                       if (wdTemp >= 'A' && wdTemp <= 'F')
 *                               {
 *                               wdTemp-= 'A';
 *                               wdTemp+= 10;
 *                               }
 *                       else
 *                               return 0;
 *                       }
 *               }
 *
 *       wdValue  += wdTemp * wdWeight;
 *       wdWeight<<= 4;
 *       }
 *
 *return wdValue;
 *}
 *****************************************************************
 */
.align  2
.global tclib_atoi
/*
 *****************************************************************
 *r0 = ptrString
 *returns r0
 *r1 = r0 - address
 *r2 = scratch - wdValue
 *r3 = scratch - wdWeight
 *r4 = scratch
 *****************************************************************
 */
.thumb_func
tclib_atoi:
push    {r1-r4, lr}

mov     r1, r0                          /*to be return value*/
bl      tclib_strlen                    /*of strlen()*/
cmp     r0, #0                          /*is it zero?*/
pop     {r1-r4, lr}
moveq   pc, lr

mov     r3, #1                          /*init wdWeight*/
mov     r2, #0                          /*zero out*/


        tclib_atoi_loop:
        subS    r0, r0, #1              /*decrement loop*/
        movlt   r0, r2                  /*copy out arg when done*/
        poplt   {r1-r4, lr}
        movlt   pc, lr

        ldrb    r4, [r1,r0]             /*preindex without update*/
        and     r4, r4, #0x0ff          /*clear upper bits*/

        cmp     r4, #'0'
        movlt   r0, #0                  /*zero out before exiting*/
        poplt   {r1-r4, lr}             /*exit if less than '0'*/
        movlt   pc, lr                  /*exit*/

        cmp     r4, #'9'
        bgt     tclib_atoi_lcase
        sub     r4, r4, #'0'
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4          /*adjust 16^x*/
        b       tclib_atoi_loop


        tclib_atoi_lcase:
        cmp     r4, #'a'
        blt     tclib_atoi_ucase
        cmp     r4, #'f'
        movgt   r0, #0                  /*zero out before exiting*/
        popgt   {r1-r4, lr}             /*exit if greater than 'f'*/
        movgt   pc, lr                  /*exit*/

        sub     r4, r4, #'a'
        add     r4, r4, #10
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4
        b       tclib_atoi_loop

                
        tclib_atoi_ucase:
        cmp     r4, #'A'
        movlt   r0, #0                  /*zero out before exiting*/
        poplt   {r1-r4, lr}
        movlt   pc, lr

        cmp     r4, #'F'
        movgt   r0, #0                  /*zero out before exiting*/
        popgt   {r1-r4, lr}             /*exit if greater than 'F'*/
        movgt   pc, lr                  /*exit*/

        sub     r4, r4, #'A'
        add     r4, r4, #10
        mla     r2, r4, r3, r2          /*r2=(r3*r4)+r2*/
        mov     r3, r3, lsl #4
        b       tclib_atoi_loop
        




/*
 *****************************************************************
 *description:  integer to ascii. convert nibbles
 *input:        int     wdValue     =value
 *              char    *ptrAscStr  =pointer to string
 *void
 *tclib_itoa(int wdValue, unsigned char *ptrAscStr)
 *{
 *volatile int wdIndex,wdTemp;
 *
 *if (wdValue < 0)
 *       wdIndex =8;
 *else
 *       {
 *       if (wdValue < (1 << 8))
 *               wdIndex =2;
 *       else
 *               {
 *               if (wdValue < (1 << 16))
 *                       wdIndex =4;
 *               else
 *                       {
 *                       if (wdValue < (1 << 24))
 *                               wdIndex =6;
 *                       else
 *                               wdIndex =8;
 *                       }
 *               }
 *       }
 *
 *ptrAscStr[wdIndex--] =NULL;
 *while (wdIndex >=0)
 *       {
 *       wdTemp   = wdValue;
 *       wdTemp  &= 0x0f;
 *       wdValue>>= 4;
 *
 *       if (wdTemp >=0 && wdTemp < 10)
 *               ptrAscStr[wdIndex--] = wdTemp +'0';
 *       else
 *               {
 *               wdTemp -=10;
 *               ptrAscStr[wdIndex--] = wdTemp +'A';     
 *               }
 *       }
 *}
 *****************************************************************
 */
.align  2
.global tclib_itoa
/*
 *****************************************************************
 *r0 = value
 *r1 = ptrString
 *r2 = scratch - index
 *r3 = scratch
 *r4 = 1
 *****************************************************************
 */
.thumb_func
tclib_itoa:
push    {r0-r4, lr}

mov     r4, #1
mov     r3, r4, lsl #8                  /*(wdValue< (1<<8))*/
cmp     r0, r3
movlo   r2, #2
blo     tclib_itoa_prep_loop

mov     r3, r4, lsl #16                 /*(wdValue< (1<<16))*/
cmp     r0, r3
movlo   r2, #4
blo     tclib_itoa_prep_loop

mov     r3, r4, lsl #24                 /*(wdValue< (1<<24))*/
cmp     r0, r3
movlo   r2, #6
movhs   r2, #8


tclib_itoa_prep_loop:
add     r1, r1, r2                      /*setup addresses*/
mov     r3, #0
strb    r3, [r1],#-1                    /*nullify string*/


        tclib_itoa_loop:
        sub     r2, r2, #1              /*decrement counter*/
        cmp     r2, #0
        poplt   {r0-r4, lr}             /*exit*/
        movlt   pc, lr                  /*exit*/

        mov     r3, r0                  /*save r0 temporarily*/
        mov     r0, r0, lsr #4          /*new value to work on*/
        and     r3, r3, #0x0f           /*nibble*/

        cmp     r3, #10                 /*prepare to adjust*/
        addlt   r3, r3, #'0'
        subge   r3, r3, #10
        addge   r3, r3, #'A'
        
        strb    r3, [r1],#-1            /*store with auto-decr*/
        b       tclib_itoa_loop





/*
 *****************************************************************
 *description:  word swap
 *input:        int wdValue = value 
 *output:       int
 *int
 *tclib_word_swap(int wdValue)
 *{
 *unsigned int dwTemp;
 *
 *(dwTemp = 0;
 *dwTemp|= (wdValue << 24) & 0xff000000;
 *dwTemp|= (wdValue << 8 ) & 0x00ff0000;
 *dwTemp|= (wdValue >> 24) & 0x0ff;
 *dwTemp|= (wdValue >> 8 ) & 0x0ffff;
 *
 *return dwTemp;
 *}
 *****************************************************************
 */
.align  2
.global tclib_swap
/*
 *****************************************************************
 *r0 = value
 *returns r0 = word swapped value
 *r1 = scratch
 *r2 = scratch
 *r3 = 0x0ff
 *****************************************************************
 */
.thumb_func
tclib_swap:
push    {r1, lr}

mov     r1, r0                          /*safe keep - r0 = return*/
rev     r0, r1                          /*theres a single thumb ins*/
                                        /*for this now*/
pop     {r1, lr}                        /*exit*/
mov     pc, lr                          /*exit*/





/*
 *****************************************************************
 *description:  byte swap
 *input:        int wdValue = value 
 *output:       int
 *int
 *tclib_byte_swap(int wdValue)
 *{
 *unsigned int dwTemp;
 *
 *dwTemp = 0;
 *dwTemp|= (wdValue << 8 ) & 0xff00;
 *dwTemp|= (wdValue >> 8 ) & 0x0ff;
 *
 *return dwTemp;
 *}
 *****************************************************************
 */
.align  2
.global tclib_bswap
/*
 *****************************************************************
 *r0 = value
 *returns r0 = byte swapped value
 *r1 = scratch
 *r2 = scratch old value
 *****************************************************************
 */
.thumb_func
tclib_bswap:
push    {r1, lr}

mov     r1, r0
rev     r0, r1                          /*save original value*/
mov     r0, r0, lsl #16

pop     {r1, lr}                        /*exit*/
mov     pc, lr                          /*exit*/
 




/*
 *****************************************************************
 *description:  string len computation function
 *inputs:       char *ptrStrSrc
 *output:       int  = lenght of string
 *int
 *tclib_strlen(unsigned char *ptrStrSrc)
 *{
 *unsigned int wdCount;
 *for (wdCount=0; ptrStrSrc[wdCount]!=NULL; wdCount++)
 *      ;
 *
 *return wdCount;
 *}
 *****************************************************************
 */
.align  2
.global tclib_strlen
/*
 *****************************************************************
 *r0 = ptrString
 *returns r0 = byte length
 *r1 = ptrString
 *r2 = scratch
 *****************************************************************
 */
.thumb_func
tclib_strlen:
push    {r1-r2, lr}

mov     r1, r0                          /*put pointer in r1*/
mov     r0, #0                          /*zero out r0*/


        tclib_strlen_loop:
        ldrb    r2, [r1], #1            
        andS    r2, r2, #0x0ff          /*clear lower bits*/
            
        addne   r0, r0, #1              /*track strlen results*/

        popeq   {r1-r2, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        b       tclib_strlen_loop              





/*
 *****************************************************************
 *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*/

        ldrb    r4, [r2], #1
        andS    r4, r4, #0x0ff          /*clear upper bits*/

        cmp     r3, r4
        addeq   r0, r0, #1              /*track strcmp results*/
        beq     tclib_strcmp_cmp_zero
        popne   {r1-r4, lr}             /*exit*/
        movne   pc, lr                  /*exit*/
        
        
        tclib_strcmp_cmp_zero:
        orrS    r4, r3, r4              /*are both zero?*/
        moveq   r0, #0                  /*return 0*/

        popeq   {r1-r4, lr}             /*exit*/
        moveq   pc, lr                  /*exit*/

        b       tclib_strcmp_loop





.end