Page 1 of 1

Sending more than 8 bytes through usbFunctionWrite() fails

Posted: Sat Jul 10, 2010 9:40 pm
by Jurre
Hello there,

I'm working on a device that connects to my PC using V-USB. The hardware mainly consists of an ATmega162 and an external EEPROM. Now I want to write some data from my computer, to the EEPROM. For this, I want to be able to send data from my PC to the device in blocks of at least 64 bytes.

Naturally, I have enabled and configured usbFunctionWrite(). This are my usbFunctionSetup() and usbFunctionWrite() functions:

Code: Select all

SB_PUBLIC uchar usbFunctionSetup(uint8_t data[8])
{
   uint8_t      len = 0;

   packbuf->bmRequestType = data[0];
   packbuf->bRequest = data[1];
   packbuf->wValue = ((uint16_t)data[3] << 8) | data[2];
   packbuf->wIndex = ((uint16_t)data[5] << 8) | data[4];
   packbuf->wLength = ((uint16_t)data[7] << 8) | data[6];

   if(packbuf->bmRequestType & 0x80)
   {
      // Messages with USB_ENDPOINT_IN

      switch(packbuf->bRequest)
      {
      case MSG_READ_EEPROM:
         break;
      }
   } else
   {
      // Messages with USB_ENDPOINT_OUT

      switch(packbuf->bRequest)
      {
      case MSG_WRITE_EEPROM:
         if(packbuf->wLength)
         {
            len = 0xff;
            usb_buffer_init(packbuf->wLength);
         }

         snprintf(str, 40, "0x%x 0x%x 0x%x 0x%x", packbuf->bRequest, packbuf->wValue, packbuf->wIndex, packbuf->wLength);
         menu_add_msg(str);

         break;
      }
   }

   return len;
}

uchar usbFunctionWrite(unsigned char *data, uint8_t len)
{
   snprintf(str, 40, "%d %d", len, buf_bytes_remaining);
   menu_add_msg(str);

   if(buf_bytes_remaining == 0)
      return 1;

   PORTE = (PORTE & _BV(PE1)) ? PORTE & ~_BV(PE1) : PORTE | _BV(PE1);

   if(packbuf->bRequest != MSG_WRITE_EEPROM)
      return 1;

   if(len > buf_bytes_remaining)
      len = buf_bytes_remaining;

   buf_bytes_remaining -= len;

   for(uint16_t i = 0; i < len; i++)
   {
      rom_write_byte(rom_addr, data[i]);
      rom_addr++;
   }

   snprintf(str, 40, "Last write to %d", (rom_addr - 1));
   menu_add_msg(str);

   return (buf_bytes_remaining == 0);
}


If value contained in bRequest equals MSG_WRITE_EEPROM, the payload data will be written to the EEPROM. The repeated calls to snprintf() and menu_add_msg() are used to print debug information to an LCD. packbuf is a global pointer to my own usb_message structure, which is similar to but not entirely the same as usbRequest_t. buf_bytes_remaining is an 16-bit unsigned integer. On the host (my PC), I use the following code to send data to my device:

Code: Select all

ret = usb_control_msg(devh, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, MSG_WRITE_EEPROM, 0, 0, (char*)buf, (uint16_t)16, usb_timeout);

std::cout << ret << " " << usb_strerror() << std::endl;

buf, in this case, is an array containing only the values 0x12.

Anyway, on to the problem. As long as I send 8 bytes or less in buf this works perfectly. usbFunctionSetup() receives my setup data and takes the right actions, usbFunctionWrite() is called once and the correct data is written to the EEPROM. However, as soon as I try to send more than 8 bytes (9 bytes, for example) usbFunctionWrite() still gets called only once and so only 8 bytes are written to the EEPROM. In addition, on the host I get the following output: "-71 error sending control message: Protocol error". My debug output shows that usbFunctionWrite() is initially called with the right values, namely buf_bytes_remaining = 9 and len = 8.

Obviously, this isn't the right behaviour. Unfortunately I have no idea how to track down this error, let alone solve it. Therefore I am turning to you guys in hope of a possible solutions. Thanks in advance :)

Re: Sending more than 8 bytes through usbFunctionWrite() fails

Posted: Sun Jul 11, 2010 12:23 am
by Jurre
As usual, I solved my own problem right after posting it on a forum.

It turned out that I probably underestimated the time needed to write data to the EEPROM, as thinks are working perfectly when I take out my rom_write() call. So I probably have to store the data into RAM first and only write it to the EEPROM when a complete 64-byte page has been received.