Open XuGuohui opened 9 years ago
Do it in the setup() function? Or duplicate the Arduino core and provide it with the boards.
Hi NicoHood,
It must be annoyed to maker to add this init code in the setup function every time he creates a new sketch, and some makers may forget to add this code. It is verbose to duplicate the Arduino core since we only make a modification in main.c. Even though we duplicate the core, how to merge the original Arduino core when install the boards using the board manager?
I finally resolve the issue by adding our custom main.cpp under the sub folder "variants
@XuGuohui
the PLL initialization in the Arduino Core seems correct:
void USBDevice_::attach()
{
[....]
#if F_CPU == 16000000UL
PLLCSR = 0x12; // Need 16 MHz xtal
#elif F_CPU == 8000000UL
PLLCSR = 0x02; // Need 8 MHz xtal
#endif
while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
;
may you explain why you need to set F_CPU
to 8Mhz when the external XTAL is 16? It would seem more logical to set F_CPU
to 16Mhz and let the core select the correct PLLCSR.
@cmaglie
First of all, when we design the hardware, we thought some users may hope to run their application at 16 MHz, which called over clock, so we have to solder the 16 MHz external crystal on the board. But most of time the CPU should run at 8 MHz to be stable. Therefore, we designed the bootloader to run at 8 MHz. If user want to run their application at 8 MHz, then the F_CPU is set to 8000000UL, then the USB stack select the PLLCSR as 0x02, treating the external crystal as 8 MHz, but actually the external crystal is 16 MHz. So we have to correct it after the USB stack initialization, i.e.
// As the F_CPU = 8000000UL, the USB core make the PLLCSR = 0x02
// But the external xtal is 16000000Hz, so correct it here.
PLLCSR |= 0x10; // Need 16 MHz xtal
while (!(PLLCSR & (1<<PLOCK))); // wait for lock pll
If user want to run their application at 16 MHz, then the F_CPU is set to 16000000UL, then the USB stack choose the right PLLCSR configuration. But our bootloader runs at 8 MHz, so we only need to make a division of the clock, i.e.
// The CPU clock in bootloader is 8MHz, change to 16MHz for sketches to run (i.e. overclock running at 3.3v).
CLKPR = 0x80;
CLKPR = 0;
That why we need to add some custom code after the USB stack initialization.
I see, F_CPU
may have a different value from the external crystal, usually the prescaler is set to a 1:1 factor so this is not a issue, but your board indeed have an unusual setup to allow over-clocking.
What about changing the USBDevice::attach() to something like:
// Default F_XOSC == F_CPU unless otherwise specified
#ifndef F_XOSC
#define F_XOSC F_CPU
#endif
#if F_XOSC == 16000000UL
PLLCSR = 0x12; // Need 16 MHz xtal
#elif F_XOSC == 8000000UL
PLLCSR = 0x02; // Need 8 MHz xtal
#endif
while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
this way you can set F_XOSC
via extra_flags
in boards.txt:
myboard.build.extra_flags={build.usb_flags} -DF_XOSC=16000000L
and all the other existing boards can continue to work as usual.
For the CLKPR
part I guess that there are no problems if you do the initialization before the USB Stack, right?
@cmaglie
First I remove our main.cpp under the variants folder and then add the code in the method USBDevice::attach()
as you mentioned above. Now the code looks like this:
_usbConfiguration = 0;
UHWCON = 0x01; // power internal reg
USBCON = (1<<USBE)|(1<<FRZCLK); // clock frozen, usb enabled
// Default F_XOSC == F_CPU unless otherwise specified
#ifndef F_XOSC
#define F_XOSC F_CPU
#endif
#if F_XOSC == 16000000UL
PLLCSR = 0x12; // Need 16 MHz xtal
#elif F_XOSC == 8000000UL
PLLCSR = 0x02; // Need 8 MHz xtal
#endif
//#if F_CPU == 16000000UL
// PLLCSR = 0x12; // Need 16 MHz xtal
//#elif F_CPU == 8000000UL
// PLLCSR = 0x02; // Need 8 MHz xtal
//#endif
while (!(PLLCSR & (1<<PLOCK))); // wait for lock pll
Then I add blendmicro8.build.extra_flags={build.usb_flags} -DF_XOSC=16000000UL
in the boards.txt. But it didn't compile the PLLCSR = 0x12
at all. It seams that the F_XOSC
flag didn't set.
I'd like to second the suggestion by cmagile on June 5, 2015. I use this modification with a 32U4 running on 3.3V with s a 16MHz clock input. F_CPU is divided down to 8MHz in the system clock prescaler, but the USB prescaler receives a 16MHz clock.
That code is now in the function USB_ClockEnable(). The clock input to the PLL prescaler does not have a consistent name on Atmel data sheets. On ATmega32U4 it is "PllPresc", on 8U2 and 16U2 it is "XTAL" and on AT90USB1286 it is "Source clock". Therefore a good name for the macro defining this frequency is not obvious. In each case however, it is the output of the main clock multiplexer, and is always applied to the PLL prescaler.
I think that "F_XOSC" would be okay or "F_XTAL" or "F_PLL_PRESCALER". The name isn't all that important however....I would jus tlike to see this change implemented in USBCore.cpp.
Please?
As an aside, the question has come up whether Atmel approves of running on 3.3V with an input clock of 16MHz. Clearly this is too fast for the entire MCU and the system clock prescaler must be used to reduce it to 8MHz or less.
It is less clear whether this is okay for the USB interface. I have not been able to get an answer from Atmel on this, but here is some evidence from the 32U4 data sheet that it might be okay.
First in section 6.9.2 regarding the system clock prescaler register:
The CKDIV8 Fuse determines the initial value of the CLKPS bits. If CKDIV8 is unprogrammed, the CLKPS bits will be reset to “0000”. If CKDIV8 is programmed, CLKPS bits are reset to “0011”, giving a division factor of 8 at start up. This feature should be used if the selected clock source has a higher frequency than the maximum frequency of the device at the present operating conditions. Note that any value can be written to the CLKPS bits regardless of the CKDIV8 Fuse setting. The Application software must ensure that a sufficient division factor is chosen if the selected clock source has a higher frequency than the maximum frequency of the device at the present operating conditions. The device is shipped with the CKDIV8 Fuse programmed.
Then in section 6.3 there is footnote 3 for table 6-3:
- If 8 MHz frequency exceeds the specification of the device (depends on VCC), the CKDIV8 Fuse can be programmed in order to divide the internal frequency by 8. It be ensured that the resulting divided clock meets the frequency specification of the device.
Hi all, We're making the 3-party boards add-on package for Arduino 1.6.4. Our board need to be re-configured must after the USB stack being initialized, or our configuration will be overrided by the USB stack. Just like this:
We don't hope that makers need to replace the main.cpp manually but just install our board by using the board manager. How could we achieve that? Now we can add our boards using the board manager successfully, but leave this issue unresolved.
Any ideas would be appreciated! Thanks in advance!