Friday, November 1, 2013

added IN transfer queing/dequeing routines in IE_stm32_usb.c

void    stm32_usb_cancel_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);



/*
 **********************************************************************
 *#define constants for USB enumeration
 **********************************************************************
 */
struct  STR_USB_PKT_XFER{
                        unsigned char   *ptrCtrlBuf;
                        int     wdCtrlSize;

                        unsigned char   *ptrUserBuf;
                        int     wdUserSize;
                        }strUsbPktXfer;
 
 
 
/*
 **********************************************************************
 *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_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*/
                else
                        (*ptrCount) = -1;
                }
        }
}       





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




Friday, October 4, 2013

modification to using external pin to control the USB D+ line/pin

So I decided to abandon using the jumper switch. It suffers from mechanical bounce and that is a major problem going forward debugging wize. Cant have the usb host mis-interpreting connects and disconnects. Besides I wanted a purely software solution since that will allow me to debug this remotely without having to stand in front of the board pushing and holding the pushbutton switch-hack I used previous to this.

My solution?
The realization that the external pin ALONE does not produce enough current to drive the USB D+ pin high. So my work around was to take a 3 position jumper and tie all three leads together - and plug it into J6 effectively driving D+ to vcc by DEFAULT.

Then connect one of the jumper positions to pin PA0. Now when the software loads it calls stm32_usb_disconnect_pullup() which sets PA0 as an output and pulls it down to ground (0). then later when the user presses "c" on the terminal I call stm32_usb_connect_pullup() which sets PA0 as in input and floating - which drives D+ back up to VCC. This results seen on my Total Phase USB Sniffer is as I expected!!!

Clever?
Yeah ... thats me


/*
 **********************************************************************
 *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);
} 
 
 
 
 
 
 
 

Thursday, October 3, 2013

bug fixes 10-02-13

1. the size of the receiver packet buffer must be packet size + 2 bytes to account for the 2 bytes of crc the usb controller slave will read. when there is no space for it it will send a STALL to the host


/*
 **********************************************************************
 *description:  usb routine to enable a particular endpoint
 *
 *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_endp_enable(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;


/*set rx and tx status bits*/
wdTemp  = (STM32_USB_EPR_STAT_RX_VALID << STM32_USB_EPR_STAT_RX_OFFSET);
wdTemp |= (wdEndPType << STM32_USB_EPR_EP_TYPE_OFFSET);
wdTemp |= (STM32_USB_EPR_STAT_TX_NAK   << STM32_USB_EPR_STAT_TX_OFFSET);
wdTemp |= wdEndPNum;

/*these bits be written as 1 to not clear*/
wdTemp |= (STM32_USB_EPR_CTR_RX|STM32_USB_EPR_CTR_TX);
*(PTR_STM32_USB_EP0R + wdEndPNum) = wdTemp;


return wdLclPktAddr;
} 
 
 
 
2. the access of the packet buffer in stm32_usb_get/send_packet() must be made as words even though only the two bytes are relevant


 
/*
 **********************************************************************
 *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:       0 on success -1 on error (timeout)
 **********************************************************************
 */
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;
volatile unsigned int   wdFlag=FALSE, wdZlp=FALSE;
unsigned short int  *ptrSrc;


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


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

        /*
         **************************************************************
         *adjust wdBytelen before starting data xfer
         **************************************************************
         */
        wdBytelen -= wdCount;
        if(wdBytelen == 0 && (wdCount == wdEndPSize))
                wdZlp = TRUE;
        else
                wdZlp = FALSE;

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


        ptrTemp  = PTR_STM32_USB_EP0R;
        ptrTemp += wdEndPNum;
        wdTemp   = (*ptrTemp);

        /*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);
        /*user settings*/
        wdTemp  |=  (STM32_USB_EPR_STAT_TX_VALID << \
                     STM32_USB_EPR_STAT_TX_OFFSET);
        (*ptrTemp) = wdTemp;

 
        /*
         **************************************************************
         *continue until done (do it for 1ms then bail on error)
         *wait for CTR_TX to be set
         *clear it and restart
         **************************************************************
         */
        wdCount  =  10;
        do
                {
                stm32_timer_uS_delay(100);
                wdCount--;

                wdTemp   = (*PTR_STM32_USB_ISTR);
                if((wdTemp & STM32_USB_ISTR_RESET) == STM32_USB_ISTR_RESET)
                        {
                        wdFlag = TRUE;
                        break;
                        }

                wdTemp   = (*ptrTemp);
                #ifdef  IGNORE_FOR_NOW
                if((wdTemp & STM32_USB_EPR_CTR_RX) == STM32_USB_EPR_CTR_RX)
                        {
                        wdFlag = TRUE;
                        break;
                        }
                #endif

                }while(((wdTemp & STM32_USB_EPR_CTR_TX) == 0) &&\
                        (wdCount > 0));
        

        /*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);
        /*user settings*/
        wdTemp  &= ~(STM32_USB_EPR_CTR_TX);
        (*ptrTemp) = wdTemp;
        }


/*
 **********************************************************************
 *should we send a zlp ?
 **********************************************************************
 */
if(wdZlp == TRUE)
        {
        ptrTemp    = (volatile unsigned int *)PTR_STM32_USB_EPRAM;
        ptrTemp   += (4 * wdEndPNum);
        ptrTemp   += 1;                 /*tx count descriptor*/
        (*ptrTemp) = 0;
        
        ptrTemp  = PTR_STM32_USB_EP0R;
        ptrTemp += wdEndPNum;
        wdTemp   = (*ptrTemp);

        /*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);
        /*user settings*/
        wdTemp  |=  (STM32_USB_EPR_STAT_TX_VALID << \
                     STM32_USB_EPR_STAT_TX_OFFSET);
        (*ptrTemp) = wdTemp;
        }

return 0;
}





/*
 **********************************************************************
 *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
 **********************************************************************
 */
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 transmission at a later date
 *set valid bits
 **********************************************************************
 */
ptrTemp  = PTR_STM32_USB_EP0R;
ptrTemp += wdEndPNum;
wdTemp   = (*ptrTemp);


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

return wdSize;
}




 
 
 

Friday, September 27, 2013

sync errors (with usb sniffer) resolved to j6 jumper switch

After discovering that FRES bit of the USB Control Register isnt useful as a software disconnect/connect. I tied one of the header pins to PA12 - USB D+ and used the user 'c' and 'd' values on the uart to connect (set as output and pullup) and disconnect(set as input floating) ...

Unfortunately other that RESET, no USB transactions were taking place. My usb sniffer showed sync errors.

Last night I decided to test a theory - which is that the internal pullup/pulldown wasnt driving the pin/line hard enough. I decided to remove the header wire between PA0 and PA12 and just insert the jumper on J6 after initialization. Immediately communication started flowing between the host and my board as seen on my beagle USB sniffer.

The jumper pulls PA12 to vcc (3.3v).

I even tested using PA12 to do the work PA0 was meant to do. To no avail. Finally I decided I needed a momentary switch plugged into J6 - for now while I am debugging my firmware. Normal operation would have firmware running shortly after usb power plugin

I salvaged this switch from the front panel of an old PC I had laying around and it serves its purpose well. Here is the output from the TotalPhase Beagle USB sniffer and a picture of the board and push button switch.






Wednesday, September 4, 2013

usb irq to systick irq preemption issue resolved

Ok so this bug was pretty interesting. Basically upon branching into the USB isr I call tclib_printf() to print a message to the serial port. tclib_printf would stall trying to retrieve a mutex lock held by the SysTick isr.  A dump of the core registers indicated the USB interrupt was executing and SysTick was pending but it would never hand over. Deadlock.

Now I know that the Cortex-m3 core NVIC controller implements priority based preemption and I felt that leaving the default settings in place and since SysTick was at a lower position in the vector table than Usb it would automatically pre-empt.

Thats not the case. Some googling and a reread of the Cortex-m3 r1p1 manual cleared things up.

Basically only the first three interrupts (fault, nmi, reset) are automatically locked in with a priority that is non configurable. The other positions in the exception table (position <= 15) and external interrupts of peripherals(position >16) are configurable. And here the kicker:

In order for an Irq to preempt the currently executing Irq, its priority must be greater (smaller number) than that of the currently executing Irq. Meaning if they have identical priorities (as they did because I never bothered to change the default power up settings) then Systick will never preempt Usb.

Once I discovered this - I made a quick change to verify before putting in a permanent fix in both stm32_nvic_init() and stm32_nvic_install_isr(). Now I can see usb interaction while the SysTick handler' keep-alive-LED-blink continues to run.

before
/*set the priority low (high number) so as not to conflict with systick*/
wdByteIdx = (wdIrqNum / 4);
ptrTemp   = PTR_STM32_NVIC_INTP_BASE;
ptrTemp  += wdByteIdx;
(*ptrTemp)= 0xffffffff;


after
/*set the priority low (high number) so as not to conflict with systick*/
wdByteIdx = (wdIrqNum / 4);
wdBitIdx  = (wdIrqNum % 4);

wdTemp    = (wdIrqNum >> 4);            /*build prio from irqnum*/
if(wdTemp == 0)
        wdTemp++;

ptrTemp   = PTR_STM32_NVIC_INTP_BASE;
ptrTemp  += wdByteIdx;
(*ptrTemp)= ((wdTemp << 4) << (wdBitIdx << 8)); /*bits [7:4] of prio*/


Now to start debugging USB communication. I may need to fish out my USB sniffer.

+-++-++-++-+ +-++-++-++-++-++-++-++-+ +-++-++-++-++-++-++-++-++-+
|I||g||b||o| |E||m||b||e||d||d||e||d| |C||o||r||t||e||x||-||m||3|
+-++-++-++-+ +-++-++-++-++-++-++-++-+ +-++-++-++-++-++-++-++-++-+
-------user-usb-connect-request---------
--------RESET-----------
-------user-usb-disconnect-request------
-------user-usb-connect-request---------
--------RESET-----------


rombios@lenovo:~/FOR_NBOX$ dmesg
[59112.279114] usb 1-3.4: new full speed USB device number 60 using ehci_hcd
[59112.352119] usb 1-3.4: device descriptor read/64, error -32
[59112.526134] usb 1-3.4: device descriptor read/64, error -32
[59112.700189] usb 1-3.4: new full speed USB device number 61 using ehci_hcd
[59112.774164] usb 1-3.4: device descriptor read/64, error -32
[59112.949177] usb 1-3.4: device descriptor read/64, error -32
[59113.123905] usb 1-3.4: new full speed USB device number 62 using ehci_hcd
[59113.526020] usb 1-3.4: device not accepting address 62, error -32
[59113.599118] usb 1-3.4: new full speed USB device number 63 using ehci_hcd
[59114.001029] usb 1-3.4: device not accepting address 63, error -32
[59114.001150] hub 1-3:1.0: unable to enumerate USB device on port 4


Tuesday, September 3, 2013

using google drive to store file for upload

https://docs.google.com/file/d/0Bw6D8nqb-AYzZFJ4dl90TVdzeEU/edit?usp=sharing

click on google drive link above ... create folder ... upload file ... click on file name ... select share ... change from private to anyone with a link ... take url link to downloads

file above is a snapshot of my stm32 build directory as of 0903 and its password protected

https://docs.google.com/file/d/0Bw6D8nqb-AYzZFJ4dl90TVdzeEU/edit?usp=sharing

unsupported timers and usb connect

Discovered that timers 5 ,6  and 7 arent supported on low density stm32 devices like the one I have - stm32f103. So now I am using timer 2 for implementing uS and mS Delays. The stm32_timer_uS_delay() routine is posted below.





/*
 **********************************************************************
 *description:  delay wdUs ticks
 *input:        unsigned int wdUs = number of uS ticks to delay for
 *note:         use timer2. its tied to a 36Mhz reference (PCLK1)
 **********************************************************************
 */
void    stm32_timer_uS_delay(unsigned int wdUs)
{
volatile unsigned int wdTemp, wdPr;

if(wdUs > 1000000)
        wdUs = 1000000;


/*adjust preload counter if greater than 1000*/
if(wdUs > 1000)
        {
        wdUs /= 1000;
        wdPr  = 36000;
        }
else
        wdPr  = 36;



/*
 **********************************************************************
 *disable timer
 *clear status
 *clear interrupt enable reg
 *clear control reg 2
 *then
 *setup prescaler value
 *setup autoreload (for count up)
 *clear the status register' UIF bit
 *then set control reg 1 OPM + CEN
 *finally
 *loop on status register checking UIF
 **********************************************************************
 */
(*PTR_STM32_TIM2_CR1) = 0;
(*PTR_STM32_TIM2_SR)  = 0;
(*PTR_STM32_TIM2_DIER)= 0;
(*PTR_STM32_TIM2_CR2) = 0;

(*PTR_STM32_TIM2_PSC) = wdPr;
(*PTR_STM32_TIM2_ARR) = wdUs;
(*PTR_STM32_TIM2_SR)  = STM32_TIM_SR_UIF;

wdTemp  = STM32_TIM_CR1_OPM;
wdTemp |= STM32_TIM_CR1_CEN;
(*PTR_STM32_TIM2_CR1) = wdTemp;

do
        {
        wdTemp  = (*PTR_STM32_TIM2_SR);
        wdTemp &= STM32_TIM_SR_UIF;
        }while(wdTemp != STM32_TIM_SR_UIF);
}






So the issue of bus enumeration (beginning with RESET) became an issue this weekend. On the stm32f103 board D+ is tied to vcc via jumper J6. This is optional. I dont like this setup because during debugging I like the freedom to connect and disconnect the usb device. This necessitates pulling D+ high to connect and pulling it low later to disconnect.

I wanted a means to do this in software and the stm32 core doesnt appear to have the software CONNECT feature I found on the nxp lpc2378. So I decided to tack a jumper wire between PA0 (user headers) and D+. This allows me to setup PortA and pin 0 as an output and drive it high when I am ready to initiate the host to usb enumeration process.

Clever right?
I thought so too ... routine for me

I wrote stm32_usb_connect_pullup() and stm32_usb_disconnect_pullup() to realize this. They are meanth to be called in usb_test.c/main() after stm32_init() and stm32_usb_init()




/*
 **********************************************************************
 *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_connect_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);
wdMask  = ((STM32_GPIO_CNF_OUT_GEN_PUSH_PULL << 2) | \
            STM32_GPIO_MODE_OUTPUT_10MHZ) << (wdPin << 2);

(*PTR_STM32_GPIO_A_CRL)  = (wdMask | wdTemp);

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





/*
 **********************************************************************
 *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
 **********************************************************************
 */
void    stm32_usb_disconnect_pullup(unsigned int wdPin)
{
volatile unsigned int wdTemp, wdMask;


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

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