EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: DELTA67 on November 04, 2024, 08:10:23 pm

Title: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: DELTA67 on November 04, 2024, 08:10:23 pm
Hi all,
I'm experimenting with USB on the STM32F103C8 as I've mentionned in this thread:
https://www.eevblog.com/forum/microcontrollers/weird-stm32f103-usb-module (https://www.eevblog.com/forum/microcontrollers/weird-stm32f103-usb-module)!!/
With your help (thanks ataradov, pcprogrammer, ... and others) I can now control a LED via control transfer or send/receive data via simple bulk transfer.
The only problem however, is when the size of the config descriptor is EVEN, the device can't be enumerated!! I've  to add an extra dummy byte in order to get things working. No problem with other descriptors if they are even.
Now I'm struggling with double buffered IN endpoint. Only one buffer can be sent to the host.
Here's how I do it:

1- EP1 descriptor:
Code: [Select]
  0x07,   // bLength
  0x05,   // bDescriptorType: Endpoint
  0x81,   // bEndpointAddress: (1IN)
  0x02,   // bmAttributes: Bulk
  0x08,   // wMaxPacketSize: 8 bytes
  0x00,
  0x00,    // bInterval:

2- EP1 initialization:
Code: [Select]
	...............
Addr += 64;
BTable[1].TX_ADDR = Addr; // TX0_ADDR
BTable[1].TX_COUNT = 0; // TX0_COUNT
Addr += 64; //
BTable[1].RX_ADDR = Addr; // TX1_ADDR
BTable[1].RX_COUNT = 0; // TX1_COUNT

// at startup the Application owns TX1BUF
USB->EPR[1] = EP_DTOG_RX | EP_KIND | EP_TX_VALID | 1;

fill(tx0buf, BTable[1].TX_ADDR);  // copy  tx0buf[] to TX0_ADDR in PMA
fill(tx1buf, BTable[1].RX_ADDR);  // copy  tx1buf[] to TX1_ADDR in PMA
BTable[1].TX_COUNT = 8; // TX0_COUNT  
BTable[1].RX_COUNT = 8; // TX1_COUNT
3- EP1 transfer complete interrupt handler:
to toggle the DTOG_RX bit I declared a pointer to it in the bitband region:
Code: [Select]
#define BITBAND_PERIPH(address, bit) ((uint32_t *)(0x42000000 + (((uint32_t)address) - 0x40000000) * 32 + (bit) * 4))
volatile uint32_t* bb_DTOGRX = BITBAND_PERIPH(&(USB->EPR[1]), 14);

and the handler:
Code: [Select]
	if(EP == 1){
if(USB->EPR[1] & EP_CTR_TX){
USB->EPR[1] = EP_BULK | EP_KIND |  1;  //Reset the CTR TX bit
*bb_DTOGRX = 1; //toggle DTOG_RX  by bitbanding
}
}

4- The host application:
   a 10 times for() loop doing usb_bulk_read() from the device.
 
 I expected to see    tx0buf[] then tx1buf[] then tx0buf[] ...etc, but I get only the contents of tx0buf[] once then the device stops responding.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: ataradov on November 04, 2024, 10:16:15 pm
For the descriptor length - it is likely your size calculations are wrong when copying the data, so you are not copying the last byte. Although it is strange that it happens when it is even.

For the other issue. I have never used double buffered endpoints, but I'm 99.9% sure USB controller will not work with bit-band region. It barely works with regular register access.

Just toggle it manually. It is stupid complicated to figure out all combination of bits to not accidentally clear something else, but it is doable.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: pcprogrammer on November 05, 2024, 06:38:25 am
and the handler:
Code: [Select]
  if(EP == 1)
  {
    if(USB->EPR[1] & EP_CTR_TX)
    {
      USB->EPR[1] = EP_BULK | EP_KIND |  1;   //Reset the CTR TX bit
      *bb_DTOGRX = 1;                         //toggle DTOG_RX  by bitbanding
    }
  }

If the intent is to actually toggle the bit, setting it  to one won't work. Exor with 1 should work.

Code: [Select]
  *bb_DTOGRX ^= 1;  //toggle DTOG_RX  by bitbanding

On a side not, there is a button in the editor to list code, which works better than using the quote button. It is the one marked with the # symbol, right next to the quote button.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: ataradov on November 05, 2024, 07:01:02 am
This bit is toggled by writing one to it. The issue is that this register is the stupidest thing I've seen in my entire life as far as registers concerned. It is a mine fiend of bits that are cleared by writing one, writing 0 or toggled by writing one. So, you have to come up with creative masks to not mess up the bits you don't want to mess up.

If controller supported toggling from bit-band region, it would be cool. But given how shit the design is to begin with, I really doubt it.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 07:06:59 am
Thanks ataradov and pcprogrammer.
For the descriptor length - it is likely your size calculations are wrong when copying the data, so you are not copying the last byte.
Here's how I copy RAM to PMA:
Code: [Select]
uint16_t*	txbuf;    // transmit buffer pointer.
uint16_t l2tx;              // bytes still need to be send.
//=================================================
void RAM2PMA(uint8_t EPn){
uint32_t i;
uint8_t count = l2tx <= 8 ? l2tx : 8;
uint32_t* dest = (PMA_BASE + BTable[EPn].TX_ADDR * 2);
BTable[EPn].TX_COUNT = count;
for (i = 0; i<(count+1)/2; i++) *dest++ = *txbuf++;
l2tx -= count;
setValid(EPn, TX);
}

//=================================================
void sendData(uint8_t EPn, uint16_t* data, uint16_t length){
if(length > SETUPPACKET->wLength) l2tx = SETUPPACKET->wLength;
else l2tx = length;
txbuf = data;
RAM2PMA(EPn);
}

Just toggle it manually.

I tried it this way but it did'nt work:
Code: [Select]
void togl_DTOG_RX(uint8_t EPn){
register uint16_t val = USB->EPR[EPn];         // Read Current EP stat
USB->EPR[EPn] = (val ^1<<14) & 0xCF8F; // Toggle DTOG_RX
}
Have you a working code please?

there is a button in the editor to list code, which works better than using the quote button.

DONE!
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 08:45:32 am
Frome here:
https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/memory-model/optional-bit-banding
We can read:
Quote
The memory map has two 32-MB alias regions that map to two 1-MB bit-band regions:
    * Accesses to the 32-MB SRAM alias region map to the 1-MB SRAM bit-band region.
    * Accesses to the 32-MB peripheral alias region map to the 1-MB peripheral bit-band region.

The USB periheral base address is 0x40005C00, so it's included in the 1-MB peripheral bit-band region, No?
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 12:20:54 pm
.... With your help (thanks ataradov, pcprogrammer, ... and others) I can now control a LED ....
Yes, they are great, especially ataradov.

Your question about double buffering doesn't make sense, because there is a system gap between packets, during which time you will take the buffer.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 12:39:48 pm
there is a system gap between packets, during which time you will take the buffer.
Can you explain please?
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 12:47:18 pm
Can you explain please?
We are dealing with a slow USB FS, the buffer size is 64 bytes. When transferring in any direction with any degree of buffering on the oscilloscope you will always see gaps, sufficient in time to rewrite 64 bytes 10 times anywhere, which negates the meaning of the buffering itself.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: pcprogrammer on November 05, 2024, 02:58:57 pm
Can you explain please?
We are dealing with a slow USB FS, the buffer size is 64 bytes. When transferring in any direction with any degree of buffering on the oscilloscope you will always see gaps, sufficient in time to rewrite 64 bytes 10 times anywhere, which negates the meaning of the buffering itself.

You are dealing with a 1ms interval between packages, so indeed with bulk transfer on 12Mbit/s double buffering does not add anything useful. Only when the host ups the frequency of fetching packages does it help, and for this you need a dedicated host driver.

I have done so for a project, but switched to isochronous mode to make it work.

@DELTA67, I will search for the latest version of my code tomorrow. It is on another machine, and I have to dig it up.

Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: pcprogrammer on November 05, 2024, 03:06:08 pm
This bit is toggled by writing one to it. The issue is that this register is the stupidest thing I've seen in my entire life as far as registers concerned. It is a mine fiend of bits that are cleared by writing one, writing 0 or toggled by writing one. So, you have to come up with creative masks to not mess up the bits you don't want to mess up.

If controller supported toggling from bit-band region, it would be cool. But given how shit the design is to begin with, I really doubt it.

Ah yes, that is the "invariant value" thing. Forgot about that.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 03:27:59 pm
... I have done so for a project, but switched to isochronous mode to make it work. ...
This will work in point-to-point conditions. Any USB hub between devices will give a minimum 50 µS gap between FS packets, if we count on this gap, our device will work both directly and through the hub equally. Especially considering that many SBCs obviously have a hub, and laptops have a limited number of USB sockets.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 03:42:32 pm
I will search for the latest version of my code tomorrow. It is on another machine, and I have to dig it up.
Ok, thanks in advance.
Have you any solution for teh EVEN size of config desc problem? I've tried your code in the previous thread with no success.
If you can, please,  try the bulk double buffering transfer, just for learning purpose, this will help us all here.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 03:52:44 pm
.... If you can, please,  try the bulk double buffering transfer, just for learning purpose, this will help us all here.
For educational purposes, it is better to read how this is organized on the FX2 chip in descriptions from 20 years ago.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 03:59:14 pm
it is better to read how this is organized on the FX2 chip in descriptions from 20 years ago.
We are working with the STM32F103. It's USB module it's a little bit complicated.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 04:04:42 pm
We are working with the STM32F103. It's USB module it's a little bit complicated.
Is FS harder than HS? OK.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: pcprogrammer on November 05, 2024, 04:20:24 pm
I will search for the latest version of my code tomorrow. It is on another machine, and I have to dig it up.
Ok, thanks in advance.
Have you any solution for teh EVEN size of config desc problem? I've tried your code in the previous thread with no success.
If you can, please,  try the bulk double buffering transfer, just for learning purpose, this will help us all here.

About the even size of the descriptor problem I have to look at my and your code and refresh my memory as to what is needed and why if might fail.

For the bulk double buffering I'm not sure if I tried it with my own host driver. I did a lot of testing to get a continuous stream of data from the F103 into the host computer. With the CH340 host driver it did not work with bulk transfer, double buffered or not. The remaining bandwidth on the channel was never filled by the host. That is why I switched to isochronous mode.

The host driver I wrote is only for Linux and I had to install it with modprobe, if I remember correctly, on every startup to be able to use it.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 04:25:58 pm
For the bulk double buffering I'm not sure if I tried it with my own host driver.
Why a bulk double buffering needs a special driver?
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: pcprogrammer on November 05, 2024, 04:36:37 pm
For the bulk double buffering I'm not sure if I tried it with my own host driver.
Why a bulk double buffering needs a special driver?

Not per se for the double buffering, but to obtain full speed. The CH340 driver only polls the device every millisecond to see if there is data to fetch. This leaves a lot of bandwidth in the channel not used. In the USB specifications it is allowed to use the free bandwidth if no other device on the channel needs it, but this has to be incorporated in the driver.

Another reason of why I switched to iso mode is that the buffer can be bigger. Full speed bulk transfer uses at max 64 byte buffers, which also means more overhead in transmissions.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 04:41:29 pm
Not per se for the double buffering, but to obtain full speed.
OK!
I've done some debugging:
The initial status of EP1 is 0x4131 = 0b0100 0001 0011 0001 as expected
after the first bulk read it changes to 0x0101 = 0b0000 0001 0000 0001
we see that:
   - STAT_TX  (bits[5:4]) = 00 disabled (expected 11)  !
   - DTOG_TX (bit6) = 0 NOT toggled by the hardware (expected 1) !!
   - DTOG_RX (bit14) = 0 toggled (by bitbanding) from 1 to 0 as expected.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 05:01:51 pm
@pcprogrammer:
If you've already tried double buffered bulk can you share your code please?
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: ataradov on November 05, 2024, 05:04:49 pm
Here's how I copy RAM to PMA:
I don't see anything obviously wrong with this code. Having USB sniffer might help. Even my RP2040 one should be good enough here, since the issue happens during enumeration.

Have you a working code please?

Here is how I clear it in my code:
Code: [Select]
if (USB_EPnR(ep) & USB_EP_DTOG_RX)
  USB_EPnR(ep) |= (USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EP_DTOG_RX);

But this code from endpoint clear feature request, so I don't think it was actually tested. But I expect this to be correct, I tried to get it right at the time of writing.

If you want to toggle, then you don't need the "if" part.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 05:14:17 pm
  USB_EPnR(ep) |= (USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EP_DTOG_RX);

A simple ORing with DTOG_RX mask?
It seems that bitbanding works for USB too. As you said it's a cool feature! Alas it's usful for single bits only I think. for multi bit fields like STAT_TX we have to do it à la old school.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: ataradov on November 05, 2024, 05:22:00 pm
Yes, a simple OR. OR will preserve all already set bits and CTR are written to1, since they are cleared by writing 0, so writing 1 is always safe and should not affect their value if they are set by the hardware in the meantime.

There is nothing special about START_xx field. There is absolutely no reason they are set by toggling. This is just bad design. But if bit-banding works, it should work for them too. Non-atomicity is not a problem since no matter what you do, you are transitioning from  disabled to valid state via NAK or STALL. And this is not a problem.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 05:32:34 pm
Having USB sniffer might help.
When I add a dummy byte at the end of the config desc, Wireshark complains from the format but it displays correctly the fields.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: Postal2 on November 05, 2024, 05:41:00 pm
.... Here is how I clear it in my code: ....
When I was looking for a description of the initialization of USB FS fields, the source code of the libraries for STM32F103 turned out to be the best. I especially liked the hid-device from STM32F103. Now I know who to thank for the excellent code of these libraries.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 05:43:51 pm
There is absolutely no reason they are set by toggling. This is just bad design.
If they designed it this way it's surely for a GOOD reason! The EP control register contains bits for both In and Out and the whole register is written at once.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: ataradov on November 05, 2024, 06:12:30 pm
ST has notoriously poorly designed register sets. There is no good reason for this. The reason this happens is that hardware people make the peripherals and by the time it gets to the software people it is too late to change anything. And then you get locked in into the poor design and carry it forward. And hardware people have completely different mindset of what is a good register design. Many things that are easy in the hardware end up being super ugly in the firmware.

Spending some time upfront designing stuff like this pays off in a long run, but nobody does it.
Title: Re: STM32F103 double buffered bulk IN endpoint.
Post by: DELTA67 on November 05, 2024, 06:27:21 pm
Yes, a simple OR.

WOOOOOOW, It works !!!

Code: [Select]
	if(EPn == 1){
if(USB->EPR[1] & EP_CTR_TX){
USB->EPR[1] = 1<<14 | EP_BULK | 1<<8 |  1; // clear CTR_TX and toggle DTOG_RX in the same time!
}
}
Now I get the two buffers alternatly as expected.
THANKS for all for your help.
If someone needs the full project PM me  and I'll attach it here.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 05, 2024, 07:32:19 pm
@DELTA67, if you had analyzed my CH340 code you would have seen that it is done in a similar way. I use specific registers for the endpoints instead of using array addressing, but the flags are handled in the same way. The comment also mentions the invariant values being used.

Code: [Select]
        //Signal we are ready to receive more data by preparing for toggling the needed RX status bits
        //Keep the other bits unaltered, by using the previous data or the invariant value
        USB->EP2R = ((USB->EP2R ^ USB_EP_RX_VALID) & (USB_EPREG_MASK | USB_EPRX_STAT)) | USB_EP_CTR_RX | USB_EP_CTR_TX;

This is not using the double buffering, but the principle is the same. Based on ataradov his way it seems it can be simplified and still work.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: DELTA67 on November 05, 2024, 07:51:30 pm
if you had analyzed my CH340 code you would have seen that it is done in a similar way.
Yes, your code is great, it has inspired me a lot,  very much thanks.
I'm waiting for your isochronous and bulk codes to studdy them. It seems that the host side for iso transfers is more complicated than that for bulk ones.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 09:29:12 am
Here is the project for the Linux iso host driver for the STM32F103 device I made.

It only supports reading data from the device, which is a continuous stream of samples. In the stuff directory there are scripts that show how the driver is used.

It is work from 5 years back and I have not used it since a long time, so forgot a lot about it.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 09:32:59 am
Here is the project for the STM32F103 device.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 09:48:35 am
I did not find the old projects with the bulk transfer mode. For what I recall of it, it was based on my CH340 driver. The double buffering setup most likely was the same as in the iso transfer mode project.

The whole setup was to use samples from a 16 bit 100kSa/s ADC to feed a FFT based spectrum analyzer and an oscilloscope. At the time I was not up to speed with Linux native GUI coding, so I used a database and webpages for displaying the signals on the screen. Never really finished the project.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: DELTA67 on November 06, 2024, 10:07:01 am
THANKS pcprogrammer for sharing this interresting project !
Hugs
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 10:15:29 am
I'm trying to figure out your problem with the size of the Config Descriptor, but fail to see the problem.

The size depends on the number of endpoints described in it, and it will be even when an even number of endpoints is described. The number of endpoints is given in the Interface Descriptor, and needs to match the number of Endpoint Descriptors that follow.

When there is a mismatch between these the host will not enumerate the device.

So when changing the Config Descriptor to add or remove an endpoint make sure to correct the number in the Interface Descriptor.

Code: [Select]
//USB Configuration Descriptor
const uint8_t ConfigDescriptor[] =
{
  0x09,   // bLength: Configuration Descriptor size
  0x02,   // bDescriptorType: Configuration
  0x27,   // wTotalLength:no of returned bytes
  0x00,
  0x01,   // bNumInterfaces: 1 interface
  0x01,   // bConfigurationValue: Configuration value
  0x00,   // iConfiguration: Index of string descriptor describing the configuration
  0x80,   // bmAttributes: self powered
  0x31,   // MaxPower 98 mA

  //Interface Descriptor
  0x09,   // bLength: Interface Descriptor size
  0x04,   // bDescriptorType: Interface
  // Interface descriptor type
  0x00,   // bInterfaceNumber: Number of Interface
  0x00,   // bAlternateSetting: Alternate setting
  0x03,   // bNumEndpoints: 3 endpoints used     !!!!!!! This needs to be changed when the number of endpoints changes !!!!!!!!
  0xFF,   // bInterfaceClass: Vendor Interface Class
  0x01,   // bInterfaceSubClass
  0x02,   // bInterfaceProtocol
  0x00,   // iInterface:

  //Endpoint 2 IN Descriptor
  0x07,   // bLength: Endpoint Descriptor size
  0x05,   // bDescriptorType: Endpoint
  0x82,   // bEndpointAddress: (IN2)
  0x02,   // bmAttributes: Bulk
  0x20,   // wMaxPacketSize:
  0x00,
  0x00,   // bInterval:

  //Endpoint 2 OUT Descriptor
  0x07,   // bLength: Endpoint Descriptor size
  0x05,   // bDescriptorType: Endpoint
  0x02,   // bEndpointAddress: (OUT2)
  0x02,   // bmAttributes: Bulk
  0x20,   // wMaxPacketSize:
  0x00,
  0x00,   // bInterval: ignore for Bulk transfer

  //Endpoint 1 IN Descriptor
  0x07,   // bLength: Endpoint Descriptor size
  0x05,   // bDescriptorType: Endpoint
  0x81,   // bEndpointAddress: (IN1)
  0x03,   // bmAttributes: Interrupt
  0x08,   // wMaxPacketSize:
  0x00,
  0x01    // bInterval
};
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: Postal2 on November 06, 2024, 10:41:21 am
Here is the project for the STM32F103 device.
Is it really possible to send a variable packet length to the host? I haven't done that for a long time, for FX2LP if I request more than the device will give - the Windows system crashes to a blue screen.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 11:18:24 am
Here is the project for the STM32F103 device.
Is it really possible to send a variable packet length to the host? I haven't done that for a long time, for FX2LP if I request more than the device will give - the Windows system crashes to a blue screen.

That project worked with the driver I wrote for Linux, so if there is variable length packages in there, which I don't recall, it is possible. To talk to the Linux driver I wrote other projects that get the data, perform checks and the FFT and write the result to a database. If wanted I can add those too.

Ah Windows, when does it not crash.  :-DD
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: Postal2 on November 06, 2024, 11:36:06 am
.... so if there is variable length packages in there, which I don't recall, it is possible.....
Well, I don't know. It seems to me that requesting a packet larger than sent is bad in any case. The bus is still overloaded with requests for some time. Although for FS this is probably not very relevant.

But I will still make equal packets. I solved variable length packets by pre-querying the length through another point, it looks stupid.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: DELTA67 on November 06, 2024, 12:03:55 pm
I'm trying to figure out your problem with the size of the Config Descriptor, but fail to see the problem.
Thanks for your effort to solve the problem.
Here's my config desc:
Code: [Select]
const uint8_t ConfigDescriptor[] = {
  0x09,   // bLength: Configuration Descriptor size
  0x02,   // bDescriptorType: Configuration
   // +14 for EP1 IN/OUT descriptors and +1 to keep the length ODD
  (9+9+7+7+1), // wTotalLength:no of returned bytes
  0x00,
  0x01,   // bNumInterfaces: 1 interface
  0x01,   // bConfigurationValue: Configuration value
  0x00,   // iConfiguration: Index of string descriptor describing the configuration
  0x80,   // bmAttributes: D7 =1 ==> bus powered
  50,   // MaxPower: 50x2 = 100mA 
  //Interface Descriptor
  0x09,   // bLength: Interface Descriptor size
  0x04,   // bDescriptorType: Interface descriptor type
  0x00,   // bInterfaceNumber: Number of Interface
  0x00,   // bAlternateSetting: Alternate setting
  0x02,   // bNumEndpoints: 2 EPs
  0xFF,   // bInterfaceClass: Vendor Interface Class
  0x00,   // bInterfaceSubClass
  0x00,   // bInterfaceProtocol
  0x00,   // iInterface:
  // EP1 OUT descriptor
  0x07,   // bLength: Endpoint Descriptor size
  0x05,   // bDescriptorType: Endpoint
  0x01,   // bEndpointAddress: (1OUT)
  0x02,   // bmAttributes: Bulk
  0x08,   // wMaxPacketSize: 8 bytes
  0x00,
  0x00,   // bInterval:
  //  EP1 IN descriptor
  0x07,   // bLength: Endpoint Descriptor size
  0x05,   // bDescriptorType: Endpoint
  0x81,   // bEndpointAddress: (1IN)
  0x02,   // bmAttributes: Bulk
  0x08,   // wMaxPacketSize: 8 bytes
  0x00,
  0x00,    // bInterval:
  // Add this byte to get an ODD length !!!!
  0x00
};

And here's how I send it:
Code: [Select]
uint16_t*	txbuf;
uint16_t l2tx; // bytes still need to be send.
//=================================================
void RAM2PMA(uint8_t EPn){
uint32_t i;
uint8_t count = l2tx <= 8 ? l2tx : 8;
uint32_t* dest = (PMA_BASE + BTable[EPn].TX_ADDR * 2);
BTable[EPn].TX_COUNT = count;
for (i = 0; i<(count+1)/2; i++) *dest++ = *txbuf++;
l2tx -= count;
//Signal ready to transmit
setValid(EPn, TX);
}

//=================================================
void sendData(uint8_t EPn, uint16_t *data, uint16_t length){
if(length > SETUPPACKET->wLength) l2tx = SETUPPACKET->wLength;
else l2tx = length;
txbuf = data;
RAM2PMA(EPn);
}

//=================================================================
void send_descriptor(){
switch(SETUPPACKET->wValueH){
case DEVICE_DESC_TYPE:
sendData(0, (uint16_t *)DeviceDescriptor, sizeof(DeviceDescriptor));
break;
case CFG_DESC_TYPE:
sendData(0, (uint16_t *)ConfigDescriptor, sizeof(ConfigDescriptor));
break;

...........................
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 12:35:45 pm
Ah yes, there is the total length that also needs to be set. As I wrote before, it has been way back that I worked on the USB stuff.

And your issue remains even when you adjust all the needed values?

In another project on another MCU I wrote a device driver for mass storage class and that has only two endpoints and thus an even length Config Descriptor. Works without problems, so it is a bit strange that it fails in your case.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: pcprogrammer on November 06, 2024, 12:49:27 pm
.... so if there is variable length packages in there, which I don't recall, it is possible.....
Well, I don't know. It seems to me that requesting a packet larger than sent is bad in any case. The bus is still overloaded with requests for some time. Although for FS this is probably not very relevant.

But I will still make equal packets. I solved variable length packets by pre-querying the length through another point, it looks stupid.

For as far as I know the host does not request a number of bytes when getting data from a device. The device is setup with a maximum length for the buffers in use and can setup packages up to that max buffer length. Take my CH340 emulation driver on the STM32F103, it tells the host the buffers in use are 32 bytes in size and when the process on the STM32F103 only wants to send a single byte to the host, it just does this. If the process wants to send 1000 bytes it will be chopped up by the USB handler in 32 byte chunks and the host will fetch the data until there is nothing more to fetch.

In my iso transfer based project the buffers are 232 bytes long and the process sends as many samples as fit in this 232 bytes, provided they are available. If there are less it will send less. If there are more it will have to lag behind and hope that the host catches up again. (I looked at the code to check this)

So I don't see what your problem with variable length packages is.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: DELTA67 on November 06, 2024, 12:50:26 pm
And your issue remains even when you adjust all the needed values?
YES !!
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: Postal2 on November 06, 2024, 01:50:01 pm
For as far as I know the host does not request a number of bytes when getting data from a device. ....
I know how the host works, but I'm not going to write my own driver for FX2LP to implement features I can do without. The driver needs to be sent the exact number of bytes to receive via deviceiocontrol.
Code: [Select]
bool myCyReadPipe()
{
//rcv via ep 86
//max size = 4096 (0x1000)
if ( hCyDevice == INVALID_HANDLE_VALUE ) return false;
//use endpoint 0x02 as OUT (from host to device)
//use endpoint 0x86 as IN (from device to host)
//bytesToSEND = myFtdiBBangRWbufCurPointer
//bytesToReceive = myFtdiCurFlushRcvBytes;//this use bit-bang via mpsse or real mpsse
//myFtdiBBangRWbuf[0] EARLY USED FOR R-W, BUT NOW myFtdiBBangRWbuf[1] FOR READ
ULONG length = sizeof(SINGLE_TRANSFER) + myFtdiCurFlushRcvBytes;
//ULONG lengthBuf = sizeof(SINGLE_TRANSFER) + myFtdiCurFlushRcvBytes + 4096;

//    PUCHAR buf = new UCHAR[lengthBuf];
    PUCHAR buf = myGlobalBuf2;

DWORD dwReturnBytes;

DWORD dwBytesReturned = 0;
DWORD dwBytesReturned2 = 0;

overlapped_R.hEvent = INVALID_HANDLE_VALUE;
overlapped_R.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    PSINGLE_TRANSFER pSingleTransfer = (PSINGLE_TRANSFER) buf;

UINT retryCounter = 0;
while(retryCounter++ < 2048)
{

    ZeroMemory (buf, length);


    pSingleTransfer->SetupPacket.bmReqType.Direction = DIR_DEVICE_TO_HOST;
    pSingleTransfer->SetupPacket.ulTimeOut = 25;//25 sec for transfer???
    pSingleTransfer->reserved = 0;
    pSingleTransfer->ucEndpointAddress = 0x86;
    pSingleTransfer->IsoPacketLength = 0;
    pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);
pSingleTransfer->BufferLength = myFtdiCurFlushRcvBytes;


DeviceIoControl(hCyDevice, IOCTL_ADAPT_SEND_NON_EP0_TRANSFER,
buf, length,
buf, length,
&dwReturnBytes, &overlapped_R);


//old timeout 500L, with 2000L correct timeout for i2c (?)
if(WaitForSingleObject(overlapped_R.hEvent, 2000L) == WAIT_OBJECT_0 )
{ GetOverlappedResult(hCyDevice, &overlapped_R, &dwBytesReturned2, TRUE);}
else
{
//ASSUME EVENT BROKEN, TRY LAST READ
GetOverlappedResult(hCyDevice, &overlapped_R, &dwBytesReturned2, TRUE);
// Copy last received to buf
if(0 != (dwBytesReturned2 - sizeof(SINGLE_TRANSFER))) memcpy(&myFtdiBBangRWbuf[1][dwBytesReturned], (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), (dwBytesReturned2 - sizeof(SINGLE_TRANSFER)));
dwBytesReturned += (dwBytesReturned2 - sizeof(SINGLE_TRANSFER));
myMesShow(_T("timeout pipe 86."));
// delete[] buf;
//CloseHandle(overlapped_R.hEvent);
//overlapped_R.hEvent = INVALID_HANDLE_VALUE;
// return false;
break;
}



// Copy received to buf
if(0 != (dwBytesReturned2 - sizeof(SINGLE_TRANSFER))) memcpy(&myFtdiBBangRWbuf[1][dwBytesReturned], (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), (dwBytesReturned2 - sizeof(SINGLE_TRANSFER)));


dwBytesReturned += (dwBytesReturned2 - sizeof(SINGLE_TRANSFER));
if(dwBytesReturned >= myFtdiCurFlushRcvBytes) break;
dwBytesReturned2 = sizeof(SINGLE_TRANSFER);//=0;
}





static UINT r_countMax = 0;
if(r_countMax < retryCounter)
{
r_countMax = retryCounter;

if(eMMC_showDebugInfo)
{
CString strTemp;
strTemp.Format( "r_count= %d", r_countMax);
myMesShow(strTemp);
}
}




CloseHandle(overlapped_R.hEvent);
overlapped_R.hEvent = INVALID_HANDLE_VALUE;

//if(dwReturnBytes >= length)// Copy received to buf
//{ if(0 != myFtdiCurFlushRcvBytes) memcpy(myFtdiBBangRWbuf[1], (PVOID)((PCHAR)pSingleTransfer + pSingleTransfer->BufferOffset), myFtdiCurFlushRcvBytes);
// delete[] buf;
// return true;}

if(dwBytesReturned >= myFtdiCurFlushRcvBytes) return true;



myMesShow(_T("err len pipe 86."));


nt_status_show(pSingleTransfer->NtStatus);
usbd_status_show(pSingleTransfer->UsbdStatus);
//delete[] buf;
return false;
}//end myCyReadPipe

... (I looked at the code to check this) ...
Code: [Select]
        //Tell the USB system how many bytes to send
        *cptr = (cnt * BYTES_PER_COUNT) + 2;
.... So I don't see what your problem with variable length packages is.
If you don't see a problem - it means there is no problem.
Title: Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
Post by: Postal2 on November 07, 2024, 10:29:46 am
Now I understand where the opinion about the FX2LP driver comes from.
... Yes, I've used the FX1 and FX2, but never with the Cypress drivers. They were indeed a piece of crap, and at the time (that was over 15 years ago), Cypress clearly stated that the drivers were just for testing purposes and not production-ready (so you pretty much had to either develop your own driver, or buy it - some companies sold Windows drivers at the time!) ...
The driver is great, has a signature for Windows 10x64, you just need to have a normal programming style.
Or use the option:
Quote
develop your own driver, or buy it