[DONE] DualCDC associate new SerialUSBDriver

ChibiOS public support forum for all topics not covered by a specific support forum.

Moderators: RoccoMarco, lbednarz, utzig, tfAteba, barthess

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

[DONE] DualCDC associate new SerialUSBDriver

Postby etmatrix » Mon Apr 22, 2013 9:04 pm

After the test of DualCDC with STM32F4 with low success, in waiting for solution of the bug, I trying my firmware DualCDC with PIC32MX.
Without changes in source code, but only in Makefile I tried to compile, my old test DualCDC for PIC32MX, and compile without problems, ChibiOS is great for this.
My device is detected in my linux system with 2 ttyACM, so my descriptor was correct, but I have a doubt: how can I associate new ttyACM at SerialUSBDriver?
In my example there is a SerialUSBDriver SDU1 and I can read and write with first ttyACM, but I don't know how to create a new SerialUSBDriver.
I should be associate new endpoints, but I don't understand if is possible with latest ChibiOS 2.5.2

Thank you

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

Re: DualCDC associate new SerialUSBDriver

Postby etmatrix » Mon Apr 22, 2013 9:11 pm

I give me a first reply alone, I think I need to rewrite ./os/hal/src/serial_usb.c for manage multiple SerialUSBDriver. There are static definition of endpoints.

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: DualCDC associate new SerialUSBDriver

Postby Giovanni » Mon Apr 22, 2013 9:15 pm

Good point, it appears to not be possible, descriptor numbers should be associated to the configuration structure instead of being statically configured.
I will look into this, I already planned to rework the serial_usb driver.

Giovanni

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

Re: [TODO] DualCDC associate new SerialUSBDriver

Postby etmatrix » Tue Apr 23, 2013 9:08 pm

I tried to develop a patch, very expiremental. Works but is not perfect. I added a field (Endpoint Data) in SerialUSBDriver, so endpoint data is not static.
In my test I create 2 shell one for each serial, with different commands.
First serial has problem in receive data, I receveid data only after I sent data, second serial is ok.
After some tests about five minutes, first serial stop to work and second serial is yet ok.

Code: Select all

diff --git a/os/hal/include/serial_usb.h b/os/hal/include/serial_usb.h
index cdde81e..abdcb7a 100644
--- a/os/hal/include/serial_usb.h
+++ b/os/hal/include/serial_usb.h
@@ -111,7 +111,8 @@ typedef struct {
   uint8_t                   ob[SERIAL_USB_BUFFERS_SIZE];                    \
   /* End of the mandatory fields.*/                                         \
   /* Current configuration data.*/                                          \
-  const SerialUSBConfig     *config;
+  const SerialUSBConfig     *config;                                        \
+  uint8_t                   iEpData;

 /**
  * @brief   @p SerialUSBDriver specific methods.
diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c
index 7b7d255..d2bf4c3 100644
--- a/os/hal/src/serial_usb.c
+++ b/os/hal/src/serial_usb.c
@@ -123,18 +123,18 @@ static void inotify(GenericQueue *qp) {
   /* If there is in the queue enough space to hold at least one packet and
      a transaction is not yet started then a new transaction is started for
      the available space.*/
-  maxsize = sdup->config->usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize;
-  if (!usbGetReceiveStatusI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP) &&
+  maxsize = sdup->config->usbp->epc[sdup->iEpData]->out_maxsize;
+  if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->iEpData) &&
       ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize)) {
     chSysUnlock();

     n = (n / maxsize) * maxsize;
     usbPrepareQueuedReceive(sdup->config->usbp,
-                            USB_CDC_DATA_AVAILABLE_EP,
+                            sdup->iEpData,
                             &sdup->iqueue, n);

     chSysLock();
-    usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP);
+    usbStartReceiveI(sdup->config->usbp, sdup->iEpData);
   }
 }

@@ -152,16 +152,16 @@ static void onotify(GenericQueue *qp) {

   /* If there is not an ongoing transaction and the output queue contains
      data then a new transaction is started.*/
-  if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP) &&
+  if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->iEpData) &&
       ((n = chOQGetFullI(&sdup->oqueue)) > 0)) {
     chSysUnlock();

     usbPrepareQueuedTransmit(sdup->config->usbp,
-                             USB_CDC_DATA_REQUEST_EP,
+                             sdup->iEpData,
                              &sdup->oqueue, n);

     chSysLock();
-    usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP);
+    usbStartTransmitI(sdup->config->usbp, sdup->iEpData);
   }
 }

@@ -255,9 +255,9 @@ void sduConfigureHookI(USBDriver *usbp) {
   chnAddFlagsI(sdup, CHN_CONNECTED);

   /* Starts the first OUT transaction immediately.*/
-  usbPrepareQueuedReceive(usbp, USB_CDC_DATA_AVAILABLE_EP, &sdup->iqueue,
-                          usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize);
-  usbStartReceiveI(usbp, USB_CDC_DATA_AVAILABLE_EP);
+  usbPrepareQueuedReceive(usbp, sdup->iEpData, &sdup->iqueue,
+                          usbp->epc[sdup->iEpData]->out_maxsize);
+  usbStartReceiveI(usbp, sdup->iEpData);
 }

 /**
@@ -360,7 +360,7 @@ void sduDataReceived(USBDriver *usbp, usbep_t ep) {

   /* Writes to the input queue can only happen when there is enough space
      to hold at least one packet.*/
-  maxsize = usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize;
+  maxsize = usbp->epc[sdup->iEpData]->out_maxsize;
   if ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize) {
     /* The endpoint cannot be busy, we are in the context of the callback,
        so a packet is in the buffer for sure.*/


main.c

Code: Select all

  SDU1.iEpData = 1;
  SDU2.iEpData = 3;

  /*
   * Initializes a serial-over-USB CDC driver.
   */
  sduObjectInit(&SDU1);
  sduStart(&SDU1, &serUsbCfg);
  sduObjectInit(&SDU2);
  sduStart(&SDU2, &serUsbCfg);


Maybe 2 shell command is a problem, I will test with only one shell.

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: [TODO] DualCDC associate new SerialUSBDriver

Postby Giovanni » Tue Apr 23, 2013 9:48 pm

Hi,

The endpoint number(s) should go in the configuration structure, except for that it looks good.

Giovanni

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

Re: [TODO] DualCDC associate new SerialUSBDriver

Postby etmatrix » Thu Apr 25, 2013 9:00 am

Hi Giovanni,

new patch

Code: Select all

diff --git a/os/hal/include/serial_usb.h b/os/hal/include/serial_usb.h
index cdde81e..955a641 100644
--- a/os/hal/include/serial_usb.h
+++ b/os/hal/include/serial_usb.h
@@ -92,6 +92,7 @@ typedef struct {
    * @brief   USB driver to use.
    */
   USBDriver                 *usbp;
+  uint8_t                   endpdata;
 } SerialUSBConfig;

 /**
diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c
index 7b7d255..90dea4d 100644
--- a/os/hal/src/serial_usb.c
+++ b/os/hal/src/serial_usb.c
@@ -123,18 +123,18 @@ static void inotify(GenericQueue *qp) {
   /* If there is in the queue enough space to hold at least one packet and
      a transaction is not yet started then a new transaction is started for
      the available space.*/
-  maxsize = sdup->config->usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize;
-  if (!usbGetReceiveStatusI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP) &&
+  maxsize = sdup->config->usbp->epc[sdup->config->endpdata]->out_maxsize;
+  if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->endpdata) &&
       ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize)) {
     chSysUnlock();

     n = (n / maxsize) * maxsize;
     usbPrepareQueuedReceive(sdup->config->usbp,
-                            USB_CDC_DATA_AVAILABLE_EP,
+                            sdup->config->endpdata,
                             &sdup->iqueue, n);

     chSysLock();
-    usbStartReceiveI(sdup->config->usbp, USB_CDC_DATA_AVAILABLE_EP);
+    usbStartReceiveI(sdup->config->usbp, sdup->config->endpdata);
   }
 }

@@ -152,16 +152,16 @@ static void onotify(GenericQueue *qp) {

   /* If there is not an ongoing transaction and the output queue contains
      data then a new transaction is started.*/
-  if (!usbGetTransmitStatusI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP) &&
+  if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->endpdata) &&
       ((n = chOQGetFullI(&sdup->oqueue)) > 0)) {
     chSysUnlock();

     usbPrepareQueuedTransmit(sdup->config->usbp,
-                             USB_CDC_DATA_REQUEST_EP,
+                             sdup->config->endpdata,
                              &sdup->oqueue, n);

     chSysLock();
-    usbStartTransmitI(sdup->config->usbp, USB_CDC_DATA_REQUEST_EP);
+    usbStartTransmitI(sdup->config->usbp, sdup->config->endpdata);
   }
 }

@@ -255,9 +255,9 @@ void sduConfigureHookI(USBDriver *usbp) {
   chnAddFlagsI(sdup, CHN_CONNECTED);

   /* Starts the first OUT transaction immediately.*/
-  usbPrepareQueuedReceive(usbp, USB_CDC_DATA_AVAILABLE_EP, &sdup->iqueue,
-                          usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize);
-  usbStartReceiveI(usbp, USB_CDC_DATA_AVAILABLE_EP);
+  usbPrepareQueuedReceive(usbp, sdup->config->endpdata, &sdup->iqueue,
+                          usbp->epc[sdup->config->endpdata]->out_maxsize);
+  usbStartReceiveI(usbp, sdup->config->endpdata);
 }

 /**
@@ -360,7 +360,7 @@ void sduDataReceived(USBDriver *usbp, usbep_t ep) {

   /* Writes to the input queue can only happen when there is enough space
      to hold at least one packet.*/
-  maxsize = usbp->epc[USB_CDC_DATA_AVAILABLE_EP]->out_maxsize;
+  maxsize = usbp->epc[sdup->config->endpdata]->out_maxsize;
   if ((n = chIQGetEmptyI(&sdup->iqueue)) >= maxsize) {
     /* The endpoint cannot be busy, we are in the context of the callback,
        so a packet is in the buffer for sure.*/


for definition of SerialUSBConfig become:

Code: Select all

const SerialUSBConfig serUsbCfg = {
  &USBD1,
  1         // endpoint data
};

const SerialUSBConfig serUsbCfg2 = {
  &USBD1,
  3         // endpoint data
};


I have the same problem with first serial in flush data when there are 2 serials.
With 2 CDC without initialize the second serial (sduObjectInit and sduStart), the first serial works very well. So I think my simple patch don't make problems to previuos version of USB CDC Serial.

Thank you

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: [TODO] DualCDC associate new SerialUSBDriver

Postby Giovanni » Sun Apr 28, 2013 2:14 pm

Hi,

I made changes to the Serial_USB driver along those lines, I had to specify all three endpoints because it is not guaranteed that IN and OUT can have the same number and the interrupt endpoints has to be specified too.

Please verify if the changes indeed fix your problems.

Giovanni

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

Re: [DONE] DualCDC associate new SerialUSBDriver

Postby etmatrix » Mon Apr 29, 2013 9:00 pm

Hi Giovanni,

thank you for your update. I still have problems with flush data on first serial.
I tried to disable the second serial and all work very well.
Sure with your patch serial usb work in all custom implementations.

User avatar
Giovanni
Site Admin
Posts: 14444
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1074 times
Been thanked: 921 times
Contact:

Re: [DONE] DualCDC associate new SerialUSBDriver

Postby Giovanni » Mon Apr 29, 2013 10:01 pm

Hi,

I am not sure to understand the problem with the flush data, could you give an example?

Giovanni

etmatrix
Posts: 46
Joined: Sun Oct 21, 2012 10:05 pm

Re: [DONE] DualCDC associate new SerialUSBDriver

Postby etmatrix » Tue Apr 30, 2013 6:01 pm

In my test source code I have

Code: Select all

sduObjectInit(&SDU1);
sduStart(&SDU1, &serUsbCfg);
sduObjectInit(&SDU2);
sduStart(&SDU2, &serUsbCfg2);

On SDU1 there is attached the shell. When I open the serial port with my program (minicom for linux or hyperterminal for windows) I expect a prompt of the shell, but for get it I need to send data with ENTER key. When I send the command info, this return many rows, I need to send many ENTER key for get all the output. I think there is a problem in flush data. In my shell there is the command write, I took the source from your testhal. In my example this command write on SDU2, and work very well.
I attached 2 shell. The shell on SDU2 works, I got data without send ENTER key, as it should be normally, the shell on SDU1 has problem with flush.
The problem is not on SDU1 but on the first call to sduObjectInit/sduStart. I think the second call to sduObjectInit/sduStart overwrite something.
With this code

Code: Select all

sduObjectInit(&SDU2);
sduStart(&SDU2, &serUsbCfg2);
sduObjectInit(&SDU1);
sduStart(&SDU1, &serUsbCfg);

The shell on SDU1 works very well, but the command write doesn't work (1° test), the shell on SDU2 (2° test) has problem with flush data.
If you have some board with PIC32 I can give you my simple test project. I can't test on STM32 because there is the problem on descriptor length.

Thank you


Return to “General Support”

Who is online

Users browsing this forum: No registered users and 22 guests