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