cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F103 USB Stall

gilbert
Associate II
Posted on October 02, 2013 at 00:41

I have an application that uses both USB (device) and I2C (master). Running either the USB or the I2C alone works fine, but when they are both running together about every 300 USB transfers results in a stall on ep1 OUT. This is strange in that the process is serial. That is, the host sends a USB msg (ep1 out) to the stm32; after reception the stm32 does a write of one byte on the I2C; and finally the stm32 sends a USB message (ep2 in) back to the host to indicate success/failure.

I used the VirtualCommPort example to start my USB code and I2CRoutines.c for my I2C code. As far as I can tell, when doing the I2C write interrupts are not touched. So how does the I2C code effect the USB?

Gil

#stm32
1 REPLY 1
gilbert
Associate II
Posted on October 02, 2013 at 02:30

It seems that the problem is coming from the code below. If I change this code to return a random byte (0x55), rather than reading the byte from the I2C hardware registers, USB does not stall.

        if ((NumByteToRead == 1) && bFrameStart && bFrameEnd)

        {

            Timeout = 0xFFFF;

            /* Send START condition */

            I2Cx->CR1 |= CR1_START_Set;

            /* Wait until SB flag is set: EV5  */

            while ((I2Cx->SR1&0x0001) != 0x0001)

            {

                if (Timeout-- == 0)

                    return Error;

            }

            /* Send slave address */

            /* Reset the address bit0 for read */

            SlaveAddress |= OAR1_ADD0_Set;

            Address = SlaveAddress;

            /* Send the slave address */

            I2Cx->DR = Address;

            /* Wait until ADDR is set: EV6_3, then program ACK = 0, clear ADDR

            and program the STOP just after ADDR is cleared. The EV6_3 

            software sequence must complete before the current byte end of transfer.*/

            /* Wait until ADDR is set */

            Timeout = 0xFFFF;

            while ((I2Cx->SR1&0x0002) != 0x0002)

            {

                if (Timeout-- == 0)

                    return Error;

            }

            /* Clear ACK bit */

            I2Cx->CR1 &= CR1_ACK_Reset;

            /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3

            software sequence must complete before the current byte end of transfer */

            __disable_irq();

            /* Clear ADDR flag */

            temp = I2Cx->SR2;

            /* Program the STOP */

            I2Cx->CR1 |= CR1_STOP_Set;

            /* Re-enable IRQs */

            __enable_irq();

            /* Wait until a data is received in DR register (RXNE = 1) EV7 */

            while ((I2Cx->SR1 & 0x00040) != 0x000040);

            /* Read the data */

            *pBuffer = I2Cx->DR;

            /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */

            while ((I2Cx->CR1&0x200) == 0x200);

            /* Enable Acknowledgement to be ready for another reception */

            I2Cx->CR1 |= CR1_ACK_Set;

        }