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