Delay needed before setting USB0_CTL?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Delay needed before setting USB0_CTL?

572 Views
joeygouly
Contributor IV

Hi all,

I found a weird issue in my USB code. Actually it's the Teensy LC USB code, that I have modified to run on MKL27Z.

In my code, I had to add a 1 ms delay before setting USB0_CTL, otherwise my code doesn't seem to work.

Link to code: keyboard-firmware/usb_dev.c at 26740e5dda0d72eb0681a865d16cf2588b6e7670 · jgouly/keyboard-firmware ·...

Is there anything I need to "wait" for before setting this? Or anything that I'm missing?

Thanks,

Joey

Labels (1)
0 Kudos
2 Replies

339 Views
bobpaddock
Senior Contributor III

I believe the problem is in the lines that are commented out before those, the one 'undocumented bit' and the reset controller lines.

This is what I use:

void usb_init( void )

{

  debug_write_err( "USB_INT\n\r", 5 );

  /* Clock gate and USB clock source: */

    SIM_SOPT2 |= SIM_SOPT2_USBSRC_MASK;   // Set USB clock source to MKL25:(PLL/2) or MKL27:IRC48M clock.

#if( defined( MCU_MKL27Z4 ) )

    SIM_SCGC4 |= SIM_SCGC4_USBFS_MASK;    // Enable clock gate for USB

#else

    SIM_SCGC4 |= SIM_SCGC4_USBOTG_MASK;

#endif

    /*

     * USB Module Configuration.

     *

     * USBTRC0: USB Transceiver Control Register 0   *

     *

     * Reset USB Module.

     *   NOTE: USBRESET bit is always read as zero. Wait two USB clock cycles after setting this bit.

     *

     * Errata:

     *

     *  Description: The USBx_USBTCR0[USBRESET] bit is not properly

     *               synchronized.  In some cases using the bit can

     *               cause the USB module to enter an undefined state.

     *

     *  Workaround:  Do not use the USBx_USBTCR0[USBRESET] bit. If USB

     *               registers need to be written to their reset

     *               states, then write those registers manually

     *               instead of using the module reset bit.

     *

     *  Mask Set Errata for Mask 2N97F, Rev 23 JUL 2013.

     *

     * FIX ME:

     */

    USB0_USBTRC0 = USB_USBTRC0_USBRESET_MASK; /* Reset USB Module; "hardware bug workaround" */

    nop(); /* nop() may actually consume no time */

    nop();

    nop();

    nop();

    USB0_USBTRC0 |= 0x40; /* Asynchronous Resume Interrupt Enable / Attach ColdFireV1 USB core to bus */

    /*

     * Set address bits of the base address where the current Buffer

     * Descriptor Table (BDT) resides in system memory.

     * Must to be on 512 byte boundary.

     * D8 Bit is masked in BDT_PAGE_01.

     */

    USB0_BDTPAGE1 = ( (uint8_t)( (uint32_t) bdt >> 8U ) & 0xFEU );

    USB0_BDTPAGE2 =   (uint8_t)( (uint32_t) bdt >> 16U );

    USB0_BDTPAGE3 =   (uint8_t)( (uint32_t) bdt >> 24U );

    /*

     * Interrupt Enable register (USB0_INTEN)

     *

     * Setting any of these bits enables the respective interrupt

     * source in the ISTAT register.

     */

    USB0_INTEN  = 0x00;    /* Disable all IRQs, during configuration */

#if( defined( MCU_MKL25Z4 ) )

    /*

     * OTG Interrupt Control Register (USBx_OTGICR)

     *

     * Enables the corresponding interrupt status bits defined in the

     * OTG Interrupt Status Register.

     */

    USB0_OTGICR = 0x00;    /* Disable all OTG IRQs, during configuration */

#endif

    /*

     * Error Interrupt Enable register (USBx_ERREN)

     *

     * Contains enable bits for each of the error interrupt sources

     * within the USB module.  Setting any of these bits enables the

     * respective interrupt source in ERRSTAT. Each bit is set as soon

     * as the error conditions is detected. Therefore, the interrupt

     * does not typically correspond with the end of a token being

     * processed.

     */

    USB0_ERREN  = 0x00;    /* Disable all error IRQs, during configuration */

    /*

     * Interrupt Status register (USB0_ISTAT)

     *

     * Contains fields for each of the interrupt sources within the USB

     * Module.  Each of these fields are qualified with their respective

     * interrupt enable bits.  All fields of this register are logically

     * OR'd together along with the OTG Interrupt Status Register

     * (OTGSTAT) to form a single interrupt source for the processor's

     * interrupt controller.  After an interrupt bit has been set it may

     * only be cleared by writing a one to the respective interrupt bit.

     *

     * Clear any pending IRQs:

     */

#if( defined( MCU_MKL25Z4 ) )

    USB0_ISTAT     =

        USB_ISTAT_USBRST_MASK |

        USB_ISTAT_ERROR_MASK  |

        USB_ISTAT_SOFTOK_MASK |

        USB_ISTAT_TOKDNE_MASK |

        USB_ISTAT_SLEEP_MASK  |

        USB_ISTAT_RESUME_MASK |

        USB_ISTAT_ATTACH_MASK |

        USB_ISTAT_STALL_MASK;

#else

    USB0_ISTAT     =

        USB_ISTAT_USBRST_MASK |

        USB_ISTAT_ERROR_MASK  |

        USB_ISTAT_SOFTOK_MASK |

        USB_ISTAT_TOKDNE_MASK |

        USB_ISTAT_SLEEP_MASK  |

        USB_ISTAT_RESUME_MASK |

        USB_ISTAT_STALL_MASK;

#endif

    device_state_u8 = (uint8_t) POWER;

    /*

     * Enable just the reset interrupt.

     * Reset will enable the other interrupts when the bus is reset.

     */

    USB0_INTEN = USB_INTEN_USBRSTEN_MASK;

    /*

     * USB Control register (USBx_USBCTRL)

     *

     * 1:Weak pulldowns are enabled on D+ and D–.

     */

    USB0_USBCTRL = USB_USBCTRL_PDE_MASK;

    /*

     * Control register (USBx_CTL)

     *

     * Provides various control and configuration information for the

     * USB module.

     */

#if( defined( MCU_MKL25Z4 ) )

    USB0_CTL  =  USB_CTL_USBENSOFEN_MASK;       /* Module enable. StartOfFrame */

#else

    USB0_CONTROL = USB_CONTROL_DPPULLUPNONOTG_MASK;

    USB0_CTL1 =  USB_CTL1_USBEN_MASK;           /* Module enable */

#endif

    SIM_SOPT1 |= SIM_SOPT1_USBREGEN_MASK;       /* Enable USB regulator */

    /*

     * OTG Control register (USBx_OTGCTL)

     *

     * Controls the operation of VBUS and Data Line termination

     * resistors.

     */

#if( defined( MCU_MKL25Z4 ) )

    USB0_OTGCTL =  USB_OTGCTL_DPHIGH_MASK         /* D+ Data Line pullup resistor enable, starts enumeration */

                |  USB_OTGCTL_OTGEN_MASK;         /* The pull-up and pull-down controls in this register are used.*/

    enable_irq( INT_USB0 );

#else

    USB0_CTL0   =  USB_CTL0_DPHIGH_MASK;          /* D+ Data Line pullup resistor enable, starts enumeration */

    NVIC_EnableIRQ( INT_USB0 );

#endif

}

0 Kudos

339 Views
joeygouly
Contributor IV

Hm yes, I uncommenting those lines makes the code work.

diff --git a/src/target/kinetis/mkl27z/third_party/usb_dev.c b/src/target/kinetis/mkl27z/third_party/usb_dev.c index 2187900..1ab5421 100644 --- a/src/target/kinetis/mkl27z/third_party/usb_dev.c +++ b/src/target/kinetis/mkl27z/third_party/usb_dev.c @@ -983,7 +983,9 @@ void usb_init(void)  #endif          // reset USB module -       //USB0_USBTRC0 = USB_USBTRC_USBRESET; +#define USB0_USBTRC0           (*(volatile uint8_t  *)0x4007210C) // USB Transceiver Control Register 0 +#define USB_USBTRC_USBRESET            ((uint8_t)0x80) +       USB0_USBTRC0 = USB_USBTRC_USBRESET;         //while ((USB0_USBTRC0 & USB_USBTRC_USBRESET) != 0) ; // wait for reset to end          SIM_SOPT2 |= SIM_SOPT2_USBSRC_IRC48M; @@ -998,10 +1000,8 @@ void usb_init(void)         USB0_ERRSTAT = 0xFF;         USB0_OTGISTAT = 0xFF;  -       //USB0_USBTRC0 |= 0x40; // undocumented bit +       USB0_USBTRC0 |= 0x40; // undocumented bit  -       // FIXME: Remove this delay. -       cmsdelay(1);         // enable USB         USB0_CTL = USB_CTL_USBENSOFEN;         USB0_USBCTRL = 0;

However, a few things are still unclear:

Your code has:

Workaround:  Do not use the USBx_USBTCR0[USBRESET] bit

And then you just go on to using this bit:

  USB0_USBTRC0 = USB_USBTRC0_USBRESET_MASK;

So that seems odd!

Where can I find the current errata for new MKL27Z256VLH4s?

The MKL27Z document I have says:

USBx_USBTRC0

bit 6:

NOTE: Software must set this bit to 1b.

So that kinda confirms the need for "USB0_USBTRC0 |= 0x40; // undocumented bit", even though I don't seem to need that if I use my previous code.

0 Kudos