Tricky problem using USB and UART with ATmega32U2

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am currently using the ATmega32U2 to communicate with a PC that send commands to a device connected over UART. My issue is that the Baud rate of the recorders are fixed at 115.2kBaud. Because the USB requires a 48MHz clock (a CPU clock of 8MHz with a 6x PLL) I have been switching to my internal clock for the USB communication and to my external clock of 1.8432MHz for UART. I have properly implemented the clock switching and can write from my PC to my recorders with no issue. My issue comes from when I want to the response from the recorders.

 

When I switch clocks as expected the USB becomes undetectable during this period. During initial debugging with this I was using Putty to read from the micro and sending commands from Cmd on windows. This works very well and most of the time I can read every response from the recorders correctly. When I try to use any method where I maintain the USB connection to read and write, such as Realterm,  is when I start to lose read capabilities. Even if I try to read the serial port with putty after the reading capabilities are lost from the other software I am unable to read anything from the USB. If I disconnect the USB and reconnect I can resume reading the port with no issue.

 

For my USB I am using the LUFA Class CDC demo as the main source of my USB code.  Below is my code to change the clocks between the internal clock and the external clock to switch between UART and USB.

void Switch_clock_Ext_2_RC(void)
{
	// Switch from external clock to internal clock
	CLKSEL0 |= (1 << RCE);
	while (!(CLKSTA & (1<<RCON)));
	CLKSEL0 &= ~(1 << CLKS);
	CLKSEL0 &= ~(1 << EXTE);
	PLLCSR |= (1 << PLLE);
}

void Switch_clock_RC_2_EXT(void)
{
	// Switch from Internal clock to external clock
	CLKSEL0 |= (1 << EXTE);
	while (!(CLKSTA & (1<<EXTON)));
	CLKSEL0 |= (1 << CLKS);
	CLKSEL0 &= ~(1 << RCE);
	PLLCSR &= ~(1 << PLLE);
}

 

Unfortunately I have tried just using UART with the internal clock of 8MHz and using the double speed clock U2X1=1 set at UBBR=8 but the 3.5% error rate ends up returning garbage message from the controllers.  I have tried to wait after reading from UART and send to USB after receiving a command from the PC also does not work. I am wondering if there is some sort of bit I need to reset to allow the USB to start sending messages again. Unfortunately I am constrained to using a clock below 8MHz for other reasons so I am trying to make it work using this clock switching method. There seems to be same way of making this work as the Putty disconnecting and reconnecting methodology seems to work under strict conditions. If anyone knows of better USB options using LUFA for my case please help point me in the right direction.

This topic has a solution.
Last Edited: Wed. Jul 10, 2019 - 07:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you can change the controller to xmega32A4U, everything will be easy to solve.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Use a 16MHz crystal and you won't have to switch - you can use

both the USB and USART at the same time.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wish I could switch the controller or go to a external clock of 16MHz or higher but due to power and time constraints I cannot make those hardware switches. Honestly both solutions would work and fix my issue immediately but I dont have enough time to spin a new board with a different micro on it and I am already pushing my power budget using the internal 8MHz clock. I am hoping to make things work with what I have and if I have enough time after this deadline I will likely change the micro.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

viciousvic wrote:
r or go to a external clock of 16MHz
But you already said:

viciousvic wrote:
my external clock of 1.8432MHz for UART
surely it's just a case of unsoldering that and putting a 16MHz in its place? To soncerve power either sleep or wind the clock down from 16Mhz using CLKPR when not required.

 

The alternative if you want to stick with intRC 8MHz might be to use an external 32.768kHz async clocking timer 2 then use this to calibrate the main clock for either USB or UART use.

Last Edited: Wed. Jul 10, 2019 - 04:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That is fair, I will just get a 16MHz clock and replace the current external I have. I will move around the power budget to make this work as this trivializes my USB issue. I just hope the 2.1% error is not nearly as bad as the 3.5% errors were.

 

I am not familiar enough with the async clocking timer to understand how to implement that but if that could allow me communicate over UART with some multiple of 115.2kHz than my concern with communication errors will be mitigated. For now I will try to get what have working as I wait for the 16MHz clock to come in.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I was able to get a temporary work around. I would simply disable the USB before switching clocks and re enable the USB after returning the clocks back.

 


		USB_Disable();
		Swith_clock_RC_2_EXT(); // switch clocks for UART
		_delay_ms(150);
		i=0;
		while (CmdString[i] !=0)
		{
					USART_Transmit(CmdString[i]); // send recorder specific command to recorders
					CmdString[i]=0;
					i++;
		}	
		USART_Transmit(0x0D);
		_delay_ms(150);
		USART_readin();
		_delay_ms(150);
		Swith_clock_Ext_2_RC(); // return to internal clock for USB communication
		USB_Init();

On my serial GUI after I send in the correct command and start UART communication I wait until the port is open again and immediately reconnect and everything resumes normally.