## LUFA question - USB to Serial example project

7 posts / 0 new
Author
Message

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!

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.

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!

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!

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.

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                 =
{
.Size                   = CDC_TXRX_EPSIZE,
.Banks                  = 1,
},
.DataOUTEndpoint                =
{
.Size                   = CDC_TXRX_EPSIZE,
.Banks                  = 1,
},
{
.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)))
{

/* Store received byte into the USART transmit buffer */
}

uint16_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);
if (BufferCount)
{

/* 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 */
{
/* 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,
{
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));

}
}

/** 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);

}

/** 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)
{

if (USB_DeviceState == DEVICE_STATE_Configured)
}

/** 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)
{

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

if (CDCInterfaceInfo->State.LineEncoding.CharFormat == CDC_LINEENCODING_TwoStopBits)

switch (CDCInterfaceInfo->State.LineEncoding.DataBits)
{
case 6:
break;
case 7:
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 */
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
}


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