small modification to USBtoSerial causes failure

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

I can compile and run the MyUSB USBtoSerial demo.
Thanks Dean.
Thanks curtvm for suggesting the STK500 hookup.

When I add the following to the task list, it fails:

static unsigned char fred;

TASK(Fill_Task)
{
for(int j=BUFF_STATICSIZE-Tx_Buffer.Elements; j; --j, ++fred)
    { Buffer_StoreElement(&Tx_Buffer, fred); }
} // Fill_Task

I can no longer open the virtual port.
"ValueError: Cannot configure port, some setting was wrong."

The new task is made runnable when CDC_Task is.

Any idea what is happening?

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

Have you got a JTAG handy? If not, try adding in some serial debugging.

Does the device still enumerate, even if you cannot connect to the port?

Perhaps there's an error in my ringbuffer, causing it to write over other memory locations.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

abcminiuser wrote:
Have you got a JTAG handy? If not, try adding in some serial debugging.
I have it, but I'm not handy. I've never used JTAG.
When I get back to work, I'll see if I can add some
USART ouput that won't interfere with other code.
Quote:
Does the device still enumerate, even if you cannot connect to the port?
I'm not sure how to tell.
During execution, the device manager would go from saying
the port was functioning normally to saying it wasn't.
Quote:
Perhaps there's an error in my ringbuffer, causing it to write over other memory locations.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

The following code fails.
The device manager tells me I don't have a driver.
If I uncomment either ENTER or LEAVE in Fill_task,
it does what I want.
My python code gets the expected
data from the virtual serial port.
If it's ENTER I uncomment, it takes a while before
the device manager tells me that the virtual serial port
is functioning correctly and I can start reading it.

At the moment, FLIP is in one of its moods.
"Cannot open USB device."
Suggestions regarding that would be welcome also.
I can't close it without crashing the system.
Opening another instance didn't help either.
I hate FLIP.

As should be obvious, I've done some editing since Dean's copyright.

/*
             MyUSB Library
     Copyright (C) Dean Camera, 2008.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com

 Released under the LGPL Licence, Version 3
*/

/*
    Communications Device Class demonstration application.
    This gives a simple reference application for implementing
    a USB to Serial converter. Sent and recieved data on the
    serial port is communicated to the USB host.
    
    Before running, you will need to install the INF file that
    is located in the CDC project directory. This will enable
    Windows to use its inbuilt CDC drivers, negating the need
    for special Windows drivers for the device. To install,
    right-click the .INF file and choose the Install option.
*/

#include "USBtoSerial.h"


#include 
#include 

static int uart_putchar(char c, FILE *stream);

static FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, NULL,
                                             _FDEV_SETUP_WRITE);

static int
uart_putchar(char c, FILE *stream)
{
while ( !( UCSR1A & (1<<UDRE1)) ) {}

UDR1 = c;
return 0;
}

#define ENTER cli(); fprintf(&uart_stream, "%s here\n", __FUNCTION__); sei();
#define LEAVE cli(); fprintf(&uart_stream, "%s done\n", __FUNCTION__); sei();
#define emit_P(str) cli(); fputs_P(PSTR(str), &uart_stream); sei();


/* Project Tags, for reading out using the ButtLoad project */
BUTTLOADTAG(ProjName,     "MyUSB USB RS232 App");
BUTTLOADTAG(BuildTime,    __TIME__);
BUTTLOADTAG(BuildDate,    __DATE__);
BUTTLOADTAG(MyUSBVersion, "MyUSB V" MYUSB_VERSION_STRING);

TASK(Fill_Task) ;

/* Scheduler Task List */
TASK_LIST
{
    { Task: USB_USBTask          , TaskStatus: TASK_STOP },
    { Task: CDC_Task             , TaskStatus: TASK_STOP },
    { Task: Fill_Task            , TaskStatus: TASK_STOP },
};

/* Globals: */
CDC_Line_Coding_t LineCoding = { BaudRateBPS: 9600,
                                 CharFormat:  OneStopBit,
                                 ParityType:  Parity_None,
                                 DataBits:    8            };

RingBuff_t        Rx_Buffer;
RingBuff_t        Tx_Buffer;

volatile bool     Transmitting = false;

static unsigned char fred;

TASK(Fill_Task)
{
//---ENTER;
for(int j=BUFF_STATICSIZE-Tx_Buffer.Elements; j; --j, ++fred)
    { Buffer_StoreElement(&Tx_Buffer, fred); }
//---LEAVE;
} // Fill_Task


int main(void)
{
    /* Disable watchdog if enabled by bootloader/fuses */
    MCUSR &= ~(1 << WDRF);
    wdt_disable();

    /* Disable Clock Division */
    SetSystemClockPrescaler(0);

    /* Hardware Initialization */
    LEDs_Init();
    ReconfigureUSART();
    
    /* Ringbuffer Initialization */
    Buffer_Initialize(&Rx_Buffer);
    Buffer_Initialize(&Tx_Buffer);
    
    /* Indicate USB not ready */
    LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED3);
    
    /* Initialize Scheduler so that it can be used */
    Scheduler_Init();

    /* Initialize USB Subsystem */
    USB_Init();

    /* Scheduling - routine never returns, so put this last in the main function */
    Scheduler_Start();
}

EVENT_HANDLER(USB_Connect)
{
    /* Start USB management task */
    Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);

    /* Indicate USB enumerating */
    LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED4);
}

EVENT_HANDLER(USB_Disconnect)
{
    /* Stop running CDC and USB management tasks */
    Scheduler_SetTaskMode(Fill_Task, TASK_STOP);
    Scheduler_SetTaskMode(CDC_Task, TASK_STOP);
    Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);

    /* Indicate USB not ready */
    LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED3);
}

EVENT_HANDLER(USB_CreateEndpoints)
{
    /* Setup CDC Notification, Rx and Tx Endpoints */
    Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
                               ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
                               ENDPOINT_BANK_SINGLE);

    Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
                               ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
                               ENDPOINT_BANK_DOUBLE);

    Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
                               ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
                               ENDPOINT_BANK_DOUBLE);

    /* Indicate USB connected and ready */
    LEDs_SetAllLEDs(LEDS_LED2 | LEDS_LED4);

    /* Start CDC task */
    Scheduler_SetTaskMode(CDC_Task, TASK_RUN);
    Scheduler_SetTaskMode(Fill_Task, TASK_RUN);
}

EVENT_HANDLER(USB_UnhandledControlPacket)
{
    uint8_t* LineCodingData = (uint8_t*)&LineCoding;

    Endpoint_Ignore_Word();

    /* Process CDC specific control requests */
    switch (Request)
    {
        case GET_LINE_CODING:
            if (RequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
            {
                Endpoint_ClearSetupReceived();

                for (uint8_t i = 0; i < sizeof(LineCoding); i++)
                  Endpoint_Write_Byte(*(LineCodingData++));    
                
                Endpoint_Setup_In_Clear();
                while (!(Endpoint_Setup_In_IsReady()));
                
                while (!(Endpoint_Setup_Out_IsReceived()));
                Endpoint_Setup_Out_Clear();
            }
            
            break;
        case SET_LINE_CODING:
            if (RequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
            {
                Endpoint_ClearSetupReceived();

                while (!(Endpoint_Setup_Out_IsReceived()));

                for (uint8_t i = 0; i < sizeof(LineCoding); i++)
                  *(LineCodingData++) = Endpoint_Read_Byte();

                Endpoint_Setup_Out_Clear();

                ReconfigureUSART();

                Endpoint_Setup_In_Clear();
                while (!(Endpoint_Setup_In_IsReady()));
            }
    
            break;
        case SET_CONTROL_LINE_STATE:
            if (RequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
            {
                Endpoint_ClearSetupReceived();
                
                Endpoint_Setup_In_Clear();
                while (!(Endpoint_Setup_In_IsReady()));
            }
    
            break;
    }
}

TASK(CDC_Task)
{
ENTER;
    if (USB_IsConnected)
    {
        /* Select the Serial Rx Endpoint */
        Endpoint_SelectEndpoint(CDC_RX_EPNUM);
        
        if (Endpoint_ReadWriteAllowed())
        {
            /* Read the recieved data endpoint into the transmission buffer */
            while (Endpoint_BytesInEndpoint())
            {
                /* Wait until the buffer has space for a new character */
                //---emit_P("Waiting for Rx_Buffer\n");
                while (!((BUFF_STATICSIZE - Rx_Buffer.Elements)));
                //---emit_P("Rx_Buffer has room\n");
            
                /* Store each character from the endpoint */
                Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
            }
            
            /* Clear the endpoint buffer */
            Endpoint_FIFOCON_Clear();
        }
        
        /* Check if Rx buffer contains data */
        if (Rx_Buffer.Elements)
        {
            /* Initiate the transmission of the buffer contents if USART idle */
            if (!(Transmitting))
            {
                Transmitting = true;
                Serial_TxByte(Buffer_GetElement(&Rx_Buffer));
            }
        }

        /* Select the Serial Tx Endpoint */
        Endpoint_SelectEndpoint(CDC_TX_EPNUM);

        /* Check if the Tx buffer contains anything to be sent to the host */
        if (Tx_Buffer.Elements)
        {
            /* Wait until Serial Tx Endpoint Ready for Read/Write */
            //---emit_P("Waiting for Tx (IN) endpoint\n");
            while (!(Endpoint_ReadWriteAllowed()));
            //---emit_P("Tx endpoint available\n");
            
            /* Write the transmission buffer contents to the recieved data endpoint */
            while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE))
              Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
            
            /* Send the data */
            Endpoint_FIFOCON_Clear();    
        }
    }
LEAVE;
}

ISR(USART1_TX_vect)
{
    /* Send next character if avaliable */
    if (Rx_Buffer.Elements)
      UDR1 = Buffer_GetElement(&Rx_Buffer);
    else
      Transmitting = false;
}

ISR(USART1_RX_vect)
{
    /* Character recieved, store it into the buffer */
    //Buffer_StoreElement(&Tx_Buffer, UDR1);
    char dummy=UDR1;
}

void ReconfigureUSART(void)
{
    uint8_t ConfigMask = 0;

    /* Determine parity - non odd/even parity mode defaults to no parity */
    if (LineCoding.ParityType == Parity_Odd)
      ConfigMask = ((1 << UPM11) | (1 << UPM10));
    else if (LineCoding.ParityType == Parity_Even)
      ConfigMask = (1 << UPM11);

    /* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */
    if (LineCoding.CharFormat == TwoStopBits)
      ConfigMask |= (1 << USBS1);

    /* Determine data size - 5, 6, 7, or 8 bits are supported */
    if (LineCoding.DataBits == 6)
      ConfigMask |= (1 << UCSZ10);
    else if (LineCoding.DataBits == 7)
      ConfigMask |= (1 << UCSZ11);
    else if (LineCoding.DataBits == 8)
      ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10));
    
    /* Enable double speed, gives better error percentages at 8MHz */
    UCSR1A = (1 << U2X1);
    
    /* Enable transmit and receive modules and interrupts */
    UCSR1B = ((1 << TXCIE1) | (1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));

    /* Set the USART mode to the mask generated by the Line Coding options */
    UCSR1C = ConfigMask;
    
    /* Set the USART baud rate register to the desired baud rate value */
    UBRR1  = SERIAL_2X_UBBRVAL((uint16_t)LineCoding.BaudRateBPS);
}

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

Two changes since my previous post on this subject:
My computer put on a light show mentioned in another thread.
I'm programming with JTAG.
I got tired of system crashes from FLIP.

abcminiuser wrote:
Have you got a JTAG handy? If not, try adding in some serial debugging.

Does the device still enumerate, even if you cannot connect to the port?

According to the green lights, it enumerates.

I don't send anything to the virtual port,
so Rx_Buffer should remain empty.
The only side-effect I would expect from my
debugging macros is through the USART1_TX_vect ISR.
Transmitting is only used if Rx_Buffer is non-empty.

I'm missing something, but I don't know what.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

Of course! I'm an idiot - this is the second time I've missed this. It doesn't explain why adding the printf commands fix the problem, but I think that's just a side-effect.

The USB protocol has three different responses to a host's "get endpoint data" command: ACK, NACK and STALL.

ACK is ACKnowledge, and indicates that the endpoint is ready to transmit its contents.

NACK is No ACKnowledge, and indicates that the device received the command, but the endpoint is currently empty (no data to transmit).

STALL indicates that the endpoint received the command, but the endpoint is currently in a logical error condition. This is used to signal that the current data flow cannot continue because of a logical error (rather than a physical error such as data corruption).

What's missing however is a ACKC response, which indicates that the endpoint is currently full and that its data continues over to another packet. Instead, the USBIF decided that a full endpoint implicitly indicates this. That means that when you send your full endpoint - which you're doing - the host assumes that the transmission is continued over several packets, and so the low level drivers buffer the data. Since you always send full endpoints, the data "continues" forever, resulting in a timeout from the higher level drivers.

The fix would be to either a) send one less than the endpoint's packet size each time, or b) send an empty packet after each full packet to disable the buffering. The first non-full packet signals the end of a continued transmission, and released the reception buffer to the higher level drivers.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

abcminiuser wrote:
What's missing however is a ACKC response, which indicates that the endpoint is currently full and that its data continues over to another packet. Instead, the USBIF decided that a full endpoint implicitly indicates this. That means that when you send your full endpoint - which you're doing - the host assumes that the transmission is continued over several packets, and so the low level drivers buffer the data. Since you always send full endpoints, the data "continues" forever, resulting in a timeout from the higher level drivers.

The fix would be to either a) send one less than the endpoint's packet size each time, or b) send an empty packet after each full packet to disable the buffering. The first non-full packet signals the end of a continued transmission, and released the reception buffer to the higher level drivers.

Alas, that is not the problem.
I implemented (a). The following code works,
but if I #define INTRUDE , the result fails.
I made it as much like USBtoSerial as I could and still show the problem.
Doing a diff will show 30 insertions and only 2 replacements.
When reading from the virtual port,
the PC should get some extra A's-P's
if INTRUDE is #defined.
Though the green lights turn on,
the virtual port cannont be opened.
Sometimes the Device Manager says "Working properly",
sometimes "No driver found".
/* USBtoSerial demo from
             MyUSB Library
     Copyright (C) Dean Camera, 2008.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com

 Released under the LGPL Licence, Version 3
*/

/*
	Communications Device Class demonstration application.
	This gives a simple reference application for implementing
	a USB to Serial converter. Sent and recieved data on the
	serial port is communicated to the USB host.
	
	Before running, you will need to install the INF file that
	is located in the CDC project directory. This will enable
	Windows to use its inbuilt CDC drivers, negating the need
	for special Windows drivers for the device. To install,
	right-click the .INF file and choose the Install option.
*/

#include "USBtoSerial.h"

/* Project Tags, for reading out using the ButtLoad project */
BUTTLOADTAG(ProjName,     "MyUSB USB RS232 App");
BUTTLOADTAG(BuildTime,    __TIME__);
BUTTLOADTAG(BuildDate,    __DATE__);
BUTTLOADTAG(MyUSBVersion, "MyUSB V" MYUSB_VERSION_STRING);

#undef INTRUDE /**/
#ifdef INTRUDE
TASK(Fill_Task) ;
#endif

/* Scheduler Task List */
TASK_LIST
{
	{ Task: USB_USBTask          , TaskStatus: TASK_STOP },
	{ Task: CDC_Task             , TaskStatus: TASK_STOP },
	#ifdef INTRUDE
	{ Task: Fill_Task            , TaskStatus: TASK_STOP },
	#endif
};

/* Globals: */
CDC_Line_Coding_t LineCoding = { BaudRateBPS: 9600,
                                 CharFormat:  OneStopBit,
                                 ParityType:  Parity_None,
                                 DataBits:    8            };

RingBuff_t        Rx_Buffer;
RingBuff_t        Tx_Buffer;

volatile bool     Transmitting = false;

#ifdef INTRUDE
volatile unsigned char fred;
volatile unsigned char once;

TASK(Fill_Task)
{
if(!once) {
    once=1;
    for(int j=BUFF_STATICSIZE-Tx_Buffer.Elements; j> 1; --j, ++fred) {
        Buffer_StoreElement(&Tx_Buffer, 'A' + (fred & 0x0F));
    } // j
} // once
} // Fill_Task
#endif

int main(void)
{
	/* Disable watchdog if enabled by bootloader/fuses */
	MCUSR &= ~(1 << WDRF);
	wdt_disable();

	/* Disable Clock Division */
	SetSystemClockPrescaler(0);

	/* Hardware Initialization */
	LEDs_Init();
	ReconfigureUSART();
	
	/* Ringbuffer Initialization */
	Buffer_Initialize(&Rx_Buffer);
	Buffer_Initialize(&Tx_Buffer);
	
	/* Indicate USB not ready */
	LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED3);
	
	/* Initialize Scheduler so that it can be used */
	Scheduler_Init();

	/* Initialize USB Subsystem */
	USB_Init();

	/* Scheduling - routine never returns, so put this last in the main function */
	Scheduler_Start();
}

EVENT_HANDLER(USB_Connect)
{
	/* Start USB management task */
	Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);

	/* Indicate USB enumerating */
	LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED4);
}

EVENT_HANDLER(USB_Disconnect)
{
	/* Stop running CDC and USB management tasks */
	Scheduler_SetTaskMode(CDC_Task, TASK_STOP);
	#ifdef INTRUDE
	Scheduler_SetTaskMode(Fill_Task, TASK_STOP);
	#endif
	Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);

	/* Indicate USB not ready */
	LEDs_SetAllLEDs(LEDS_LED1 | LEDS_LED3);
}

EVENT_HANDLER(USB_CreateEndpoints)
{
	/* Setup CDC Notification, Rx and Tx Endpoints */
	Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT,
		                       ENDPOINT_DIR_IN, CDC_NOTIFICATION_EPSIZE,
	                           ENDPOINT_BANK_SINGLE);

	Endpoint_ConfigureEndpoint(CDC_TX_EPNUM, EP_TYPE_BULK,
		                       ENDPOINT_DIR_IN, CDC_TXRX_EPSIZE,
	                           ENDPOINT_BANK_DOUBLE);

	Endpoint_ConfigureEndpoint(CDC_RX_EPNUM, EP_TYPE_BULK,
		                       ENDPOINT_DIR_OUT, CDC_TXRX_EPSIZE,
	                           ENDPOINT_BANK_DOUBLE);

	/* Indicate USB connected and ready */
	LEDs_SetAllLEDs(LEDS_LED2 | LEDS_LED4);

	/* Start CDC task */
	Scheduler_SetTaskMode(CDC_Task, TASK_RUN);
	#ifdef INTRUDE
	Scheduler_SetTaskMode(Fill_Task, TASK_RUN);
	#endif
}

EVENT_HANDLER(USB_UnhandledControlPacket)
{
	uint8_t* LineCodingData = (uint8_t*)&LineCoding;

	Endpoint_Ignore_Word();

	/* Process CDC specific control requests */
	switch (Request)
	{
		case GET_LINE_CODING:
			if (RequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
			{
				Endpoint_ClearSetupReceived();

				for (uint8_t i = 0; i < sizeof(LineCoding); i++)
				  Endpoint_Write_Byte(*(LineCodingData++));	
				
				Endpoint_Setup_In_Clear();
				while (!(Endpoint_Setup_In_IsReady()));
				
				while (!(Endpoint_Setup_Out_IsReceived()));
				Endpoint_Setup_Out_Clear();
			}
			
			break;
		case SET_LINE_CODING:
			if (RequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
			{
				Endpoint_ClearSetupReceived();

				while (!(Endpoint_Setup_Out_IsReceived()));

				for (uint8_t i = 0; i < sizeof(LineCoding); i++)
				  *(LineCodingData++) = Endpoint_Read_Byte();

				Endpoint_Setup_Out_Clear();

				ReconfigureUSART();

				Endpoint_Setup_In_Clear();
				while (!(Endpoint_Setup_In_IsReady()));
			}
	
			break;
		case SET_CONTROL_LINE_STATE:
			if (RequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
			{
				Endpoint_ClearSetupReceived();
				
				Endpoint_Setup_In_Clear();
				while (!(Endpoint_Setup_In_IsReady()));
			}
	
			break;
	}
}

TASK(CDC_Task)
{
	if (USB_IsConnected)
	{
		/* Select the Serial Rx Endpoint */
		Endpoint_SelectEndpoint(CDC_RX_EPNUM);
		
		if (Endpoint_ReadWriteAllowed())
		{
			/* Read the recieved data endpoint into the transmission buffer */
			while (Endpoint_BytesInEndpoint())
			{
				/* Wait until the buffer has space for a new character */
				while (!((BUFF_STATICSIZE - Rx_Buffer.Elements)));
			
				/* Store each character from the endpoint */
				Buffer_StoreElement(&Rx_Buffer, Endpoint_Read_Byte());
			}
			
			/* Clear the endpoint buffer */
			Endpoint_FIFOCON_Clear();
		}
		
		/* Check if Rx buffer contains data */
		if (Rx_Buffer.Elements)
		{
			/* Initiate the transmission of the buffer contents if USART idle */
			if (!(Transmitting))
			{
				Transmitting = true;
				Serial_TxByte(Buffer_GetElement(&Rx_Buffer));
			}
		}

		/* Select the Serial Tx Endpoint */
		Endpoint_SelectEndpoint(CDC_TX_EPNUM);

		/* Check if the Tx buffer contains anything to be sent to the host */
		if (Tx_Buffer.Elements)
		{
			/* Wait until Serial Tx Endpoint Ready for Read/Write */
			while (!(Endpoint_ReadWriteAllowed()));
			
			/* Write the transmission buffer contents to the recieved data endpoint */
			while (Tx_Buffer.Elements && (Endpoint_BytesInEndpoint() < CDC_TXRX_EPSIZE-1))
			  Endpoint_Write_Byte(Buffer_GetElement(&Tx_Buffer));
			
			/* Send the data */
			Endpoint_FIFOCON_Clear();	
		}
	}
}

ISR(USART1_TX_vect)
{
	/* Send next character if avaliable */
	if (Rx_Buffer.Elements)
	  UDR1 = Buffer_GetElement(&Rx_Buffer);
	else
	  Transmitting = false;
}

ISR(USART1_RX_vect)
{
	/* Character recieved, store it into the buffer */
	Buffer_StoreElement(&Tx_Buffer, UDR1);
}

void ReconfigureUSART(void)
{
	uint8_t ConfigMask = 0;

	/* Determine parity - non odd/even parity mode defaults to no parity */
	if (LineCoding.ParityType == Parity_Odd)
	  ConfigMask = ((1 << UPM11) | (1 << UPM10));
	else if (LineCoding.ParityType == Parity_Even)
	  ConfigMask = (1 << UPM11);

	/* Determine stop bits - 1.5 stop bits is set as 1 stop bit due to hardware limitations */
	if (LineCoding.CharFormat == TwoStopBits)
	  ConfigMask |= (1 << USBS1);

	/* Determine data size - 5, 6, 7, or 8 bits are supported */
	if (LineCoding.DataBits == 6)
	  ConfigMask |= (1 << UCSZ10);
	else if (LineCoding.DataBits == 7)
	  ConfigMask |= (1 << UCSZ11);
	else if (LineCoding.DataBits == 8)
	  ConfigMask |= ((1 << UCSZ11) | (1 << UCSZ10));
	
	/* Enable double speed, gives better error percentages at 8MHz */
	UCSR1A = (1 << U2X1);
	
	/* Enable transmit and receive modules and interrupts */
	UCSR1B = ((1 << TXCIE1) | (1 << RXCIE1) | (1 << TXEN1) | (1 << RXEN1));

	/* Set the USART mode to the mask generated by the Line Coding options */
	UCSR1C = ConfigMask;
	
	/* Set the USART baud rate register to the desired baud rate value */
	UBRR1  = SERIAL_2X_UBBRVAL((uint16_t)LineCoding.BaudRateBPS);
}

Edit:
Replacing Fill_Task with the following produces the same effect:

volatile unsigned char fred;
volatile unsigned char once;

TASK(Fill_Task)
{
if(!once) {
    if(Tx_Buffer.Elements<=BUFF_STATICSIZE-3) {
        Buffer_StoreElement(&Tx_Buffer, 'A' + (fred & 0x0F));
        //once=1;
    }
} // once
} // Fill_Task

If I uncomment "once=1;", the code runs, but the "A" never shows up.
Edit:
According to debugging with AVR Studio,
it hangs in the GET_LINE_CODING case of USB_UnhandledControlPacket.
Endpoint_Setup_Out_IsReceived() never returns true.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

I think that I have discovered the problem.
Characters get put in TxBuffer before
the endpoint is ready to send them.
With other programs, data came from the PC after I typed in a command.
If I put in a delay, characters generated on board come through.
Presumably, I should wait for an event, but I'm not yet sure what event.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

Perhaps the host won't accept data until the SetLineCoding request has been issued. In fact I do see that as being a problem now that you've mentioned it; once the system is enumerated, the fill task then runs and (by virtue of the !(ReadWriteAllowed) loop) blocks until the data IN endpoint is ready. That would stop the SetLineCoding request from being processed by the USB task before the first data transmission.

Try enabling the fill task in the SetLineCoding request, so that it only starts after the line coding has been configured by the host.

- Dean :twisted:

(PS: Sorry for the delay in all this -- a man's work is never done! ;))

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Quote:

(PS: Sorry for the delay in all this -- a man's work is never done! )

...especially when there is a new kitten to play with.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

abcminiuser wrote:
Try enabling the fill task in the SetLineCoding request, so that it only starts after the line coding has been configured by the host.
Will do.
Thanks.
Quote:
(PS: Sorry for the delay in all this -- a man's work is never done! ;))
You response seemed timely to me,
especially since you don't work for me.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

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

Quote:

You response seemed timely to me,
especially since you don't work for me.

I check AVRFreaks many (many!) times a day, so generally the longest wait for a reply from me is the time that I am sleeping. This particular thread got away from me due to other commitments -- to me, a response time of over 24 hours is horrendous.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

abcminiuser wrote:
Try enabling the fill task in the SetLineCoding request, so that it only starts after the line coding has been configured by the host.
Alas, nyet.
It still has to wait another 18 ms, 17 is not sufficient.
It's not a busy wait. Fill_Task tests a timer.

@Lee: kitten==toy==? ?

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods