LUFA question - USB to Serial example project

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

Hello all AVR freaks,

First of all, congratulations on LUFA! Great job!!

So, I am working in a project at my university which I have to read the signal from a sensor that uses SENT protocol (Single Edge Nibble Transmission). This means that I have to measure the time between the falling edges of the sensor's output square wave. And of course: I have to send the time measured to the pc right after every measurement (before the next falling edge).

I installed the LUFA extension for Studio 6.2 and am using the "USB to Serial converter" example. It works almost perfect, except for one problem. The data I have to send is between 3 and 4 bytes. If the USB 2.0 has a speed of 12Mbit/s, it means that every bit takes ~83ns (and I measured it to confirm). 4bytes = 32bits = 2656ns. My first question is: how many and which are the other bytes of every message? I would say it is not only my data in the message, or?

My second question would be: the time between the falling edges that I have to measure can vary from 10 to 900 microseconds"¦ from 900 to 100 microseconds, everything works perfect. I get the complete data at the terminal (1byte: msg number and 3 other bytes with data). But when I start to decrease the time, like to 80 or 50 microseconds, then some messages are lost and even repeated"¦ The more I decrease, the worse it gets.
I would like to know if I can send messages faster than the 100 microseconds that I am getting now, and what I have to change in the project to accomplish that.

One thing I was concerned was about the CDC_Device_USBTask(&VirtualSerial_CDC_Interface); and USB_USBTask(); in the main loop. I am actually not using USB task anymore, just the CDC device task. But what I did was to use a second timer to count ~24ms, and then it would call this task. I thought calling the CDC device task every time in the main loop was slowing it down, but it actually didn't make that much difference. I have already tried changing other stuff too, but no success so far"¦

I hope you guys can help me!

Thank you very much and hope to hear from you soon!

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

Quote:

My first question is: how many and which are the other bytes of every message? I would say it is not only my data in the message, or?

You need to get either

a) the USB standard: http://www.usb.org/developers/do...

or

b) a good primer on USB - probably something by Jan Axelson: http://janaxelson.com/usb.htm

or

better still, both.

There's a whole lot more to USB than UART so don't just expect to see your data bytes with a few surrounding bits.

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

Hello Clawson, thanks for your reply!

Yes, I can find out which the other bytes are… That’s fine… :)

But I am still having the problem measuring the time between the falling edges lower as 100 microseconds. Do you perhaps know what I could try? Even maybe another solution (instead of the USB to Serial example project)?

Thanks again!

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

So, I’ve found part of the problem…

As I was trying to send every message as fast as possible, I set that data of the message to 4 bytes (that’s the number of bytes I have to send)… But there is much more bytes in one message… So I set the message data to a much higher number, like 128 or 256 bytes… this way I am sending more measurements in one message, which also works for me… But I still have can’t reach the speed I would like… But I will continue trying here…

Thanks anyway!

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

Quote:

So I set the message data to a much higher number, like 128 or 256 bytes…

Surely the "best" value is the size of the endpoint for that transmission channel? Probably 64 in fact.

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

I was changing the size of the buffer in this line:

/** Underlying data buffer for \ref USARTtoUSB_Buffer, where the stored bytes are located. */
static uint8_t USARTtoUSB_Buffer_Data[256];

I thought this buffer was the data buffer of the complete message (just the Data part, without Sync, CRC, etc).
But I think this doesn’t change the size of the data inside the message… When I measure with the oscilloscope, the complete message usually takes ~16 microseconds, which means ~ 24bytes… And it doesn’t matter if the buffer size is 256, or 4, etc…

Where can I actually change the size of the data inside the message? Could this be the solution to my problem?

My idea is: if sending the message with only 4 bytes of data is not fast enough (because it takes too long to send everything), I thought that I could increase the data bytes in my message, then I could reach the speed I need… Like this: I get the interruption of a falling edge, read the timer and put the data to the buffer. Don’t send the message yet. Get a new falling edge, same procedure. Then, whenever the data of the message is full, then the message would be sent… This way I could “read” all the fallings edges, without losing them because they are happening too fast…

I will post here the main code, maybe it helps…

At the end of the code, there is the ISR when there is a falling edge. Read the timer and add to the buffer.

#include "USBtoSerial.h"

uint16_t period;
uint8_t periodL, periodH, msg_number=0, periodextra=0;

FILE USBSerialStream;

/** Circular buffer to hold data from the host before it is sent to the device via the serial port. */
static RingBuffer_t USBtoUSART_Buffer;

/** Underlying data buffer for \ref USBtoUSART_Buffer, where the stored bytes are located. */
static uint8_t      USBtoUSART_Buffer_Data[256]; 

/** Circular buffer to hold data from the serial port before it is sent to the host. */
static RingBuffer_t USARTtoUSB_Buffer;

/** Underlying data buffer for \ref USARTtoUSB_Buffer, where the stored bytes are located. */
static uint8_t      USARTtoUSB_Buffer_Data[256]; 

/** LUFA CDC Class driver interface configuration and state information. This structure is
 *  passed to all CDC Class driver functions, so that multiple instances of the same class
 *  within a device can be differentiated from one another.
 */
USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
	{
		.Config =
			{
				.ControlInterfaceNumber         = INTERFACE_ID_CDC_CCI,
				.DataINEndpoint                 =
					{
						.Address                = CDC_TX_EPADDR,
						.Size                   = CDC_TXRX_EPSIZE,
						.Banks                  = 1,
					},
				.DataOUTEndpoint                =
					{
						.Address                = CDC_RX_EPADDR,
						.Size                   = CDC_TXRX_EPSIZE,
						.Banks                  = 1,
					},
				.NotificationEndpoint           =
					{
						.Address                = CDC_NOTIFICATION_EPADDR,
						.Size                   = CDC_NOTIFICATION_EPSIZE,
						.Banks                  = 1,
					},
			},
	};


/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void)
{
	SetupHardware();

	RingBuffer_InitBuffer(&USBtoUSART_Buffer, USBtoUSART_Buffer_Data, sizeof(USBtoUSART_Buffer_Data));
	RingBuffer_InitBuffer(&USARTtoUSB_Buffer, USARTtoUSB_Buffer_Data, sizeof(USARTtoUSB_Buffer_Data));
	
	/* Create a regular character stream for the interface so that it can be used with the stdio.h functions */
	CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream);

	GlobalInterruptEnable();
	

	for (;;)
	{
		
		/* Only try to read in bytes from the CDC interface if the transmit buffer is not full */
		if (!(RingBuffer_IsFull(&USBtoUSART_Buffer)))
		{
			int16_t ReceivedByte = CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);

			/* Store received byte into the USART transmit buffer */
			if (!(ReceivedByte < 0))
			  RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte);
		}

		uint16_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);
		if (BufferCount)
		{
			Endpoint_SelectEndpoint(VirtualSerial_CDC_Interface.Config.DataINEndpoint.Address);

			/* Check if a packet is already enqueued to the host - if so, we shouldn't try to send more data
			 * until it completes as there is a chance nothing is listening and a lengthy timeout could occur */
			if (Endpoint_IsINReady())
			{
				/* Never send more than one bank size less one byte to the host at a time, so that we don't block
				 * while a Zero Length Packet (ZLP) to terminate the transfer is sent if the host isn't listening */
				uint8_t BytesToSend = MIN(BufferCount, (CDC_TXRX_EPSIZE - 1));

				/* Read bytes from the USART receive buffer into the USB IN endpoint */
				while (BytesToSend--)
				{
					/* Try to send the next byte of data to the host, abort if there is an error without dequeuing */
					if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
											RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError)
					{
						break;
					}

					/* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */
					RingBuffer_Remove(&USARTtoUSB_Buffer);
				}
			}
		}

		/* Load the next byte from the USART transmit buffer into the USART */
		if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer)))
		  Serial_SendByte(RingBuffer_Remove(&USBtoUSART_Buffer));
		  
		  

		CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
		//USB_USBTask();
		
	}
}

/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
#if (ARCH == ARCH_AVR8)
	/* Disable watchdog if enabled by bootloader/fuses */
	MCUSR &= ~(1 << WDRF);
	wdt_disable();

	/* Disable clock division */
	clock_prescale_set(clock_div_1);
#endif

	/* Hardware Initialization */
	//LEDs_Init();
	USB_Init();
	LED_CONFIG;
	INT_init();
	TIMER1_init();
	
}


/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
	bool ConfigSuccess = true;

	ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);

	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}

/** Event handler for the library USB Control Request reception event. */
void EVENT_USB_Device_ControlRequest(void)
{
	CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
}

/** ISR to manage the reception of data from the serial port, placing received bytes into a circular buffer
 *  for later transmission to the host.
 */
ISR(USART1_RX_vect, ISR_BLOCK)
{
	uint8_t ReceivedByte = UDR1;

	if (USB_DeviceState == DEVICE_STATE_Configured)
	  RingBuffer_Insert(&USARTtoUSB_Buffer, ReceivedByte);
}

/** Event handler for the CDC Class driver Line Encoding Changed event.
 *
 *  \param[in] CDCInterfaceInfo  Pointer to the CDC class interface configuration structure being referenced
 */
void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
{
	uint8_t ConfigMask = 0;

	switch (CDCInterfaceInfo->State.LineEncoding.ParityType)
	{
		case CDC_PARITY_Odd:
			ConfigMask = ((1 << UPM11) | (1 << UPM10));
			break;
		case CDC_PARITY_Even:
			ConfigMask = (1 << UPM11);
			break;
	}

	if (CDCInterfaceInfo->State.LineEncoding.CharFormat == CDC_LINEENCODING_TwoStopBits)
	  ConfigMask |= (1 << USBS1);

	switch (CDCInterfaceInfo->State.LineEncoding.DataBits)
	{
		case 6:
			ConfigMask |= (1 << UCSZ10);
			break;
		case 7:
			ConfigMask |= (1 << UCSZ11);
			break;
		case 8:
			ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10));
			break;
	}

	/* Must turn off USART before reconfiguring it, otherwise incorrect operation may occur */
	UCSR1B = 0;
	UCSR1A = 0;
	UCSR1C = 0;

	/* Set the new baud rate before configuring the USART */
	UBRR1  = SERIAL_2X_UBBRVAL(CDCInterfaceInfo->State.LineEncoding.BaudRateBPS);

	/* Reconfigure the USART in double speed mode for a wider baud rate range at the expense of accuracy */
	UCSR1C = ConfigMask;
	UCSR1A = (1 << U2X1);
	UCSR1B = ((1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));
}



ISR(TIMER1_OVF_vect) { // timer1 overflow
	
	periodextra++;
	
}


ISR(INT0_vect){
	
	period=TCNT1;
	TCNT1=0;
		
	msg_number++;
	periodL = period;
	periodH = period>>8;
	
	RingBuffer_Insert(&USARTtoUSB_Buffer, msg_number);
	
	RingBuffer_Insert(&USARTtoUSB_Buffer, periodextra);
	
	RingBuffer_Insert(&USARTtoUSB_Buffer, periodH);
	
	RingBuffer_Insert(&USARTtoUSB_Buffer, periodL);
	
	periodextra=0;

}

void INT_init() {
	EICRA=0x02; //1<<ISC0; //Set Pin change IT for INT0 to falling edge
	EIMSK=0x01; //1<<INT0; //Enable INT0 interrupt
}

void TIMER1_init() {
	TIMSK1 = (1<<TOIE1);		//enable timer overflow interrupt for Timer1
	TCNT1=0;			//Init Timer1
	TCCR1B = (1<<CS00);		//Set prescaler to clk/1
}

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

Quote:
Where can I actually change the size of the data inside the message?

I found out where I can change this…

It is in this line, inside the “descriptors.h”

		/** Size in bytes of the CDC data IN and OUT endpoints. */
		#define CDC_TXRX_EPSIZE 16