Author Topic: STM32F103 double buffered bulk IN endpoint. [SOLVED]  (Read 2184 times)

0 Members and 1 Guest are viewing this topic.

Offline Postal2

  • Frequent Contributor
  • **
  • Posts: 695
  • Country: ru
Re: STM32F103 double buffered bulk IN endpoint.
« Reply #25 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.
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint.
« Reply #26 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.
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11803
  • Country: us
    • Personal site
Re: STM32F103 double buffered bulk IN endpoint.
« Reply #27 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.
Alex
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint.
« Reply #28 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.
« Last Edit: November 05, 2024, 06:58:30 pm by DELTA67 »
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #29 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.

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #30 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.
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #31 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.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #32 on: November 06, 2024, 09:32:59 am »
Here is the project for the STM32F103 device.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #33 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.

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #34 on: November 06, 2024, 10:07:01 am »
THANKS pcprogrammer for sharing this interresting project !
Hugs
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #35 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
};

Offline Postal2

  • Frequent Contributor
  • **
  • Posts: 695
  • Country: ru
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #36 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.
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #37 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

Offline Postal2

  • Frequent Contributor
  • **
  • Posts: 695
  • Country: ru
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #38 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.
 

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #39 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;

...........................
« Last Edit: November 06, 2024, 12:29:23 pm by DELTA67 »
 

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #40 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.

Online pcprogrammer

  • Super Contributor
  • ***
  • Posts: 4526
  • Country: nl
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #41 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.

Offline DELTA67Topic starter

  • Regular Contributor
  • *
  • Posts: 104
  • Country: fr
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #42 on: November 06, 2024, 12:50:26 pm »
And your issue remains even when you adjust all the needed values?
YES !!
 

Offline Postal2

  • Frequent Contributor
  • **
  • Posts: 695
  • Country: ru
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #43 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.
« Last Edit: November 06, 2024, 11:56:05 pm by Postal2 »
 

Offline Postal2

  • Frequent Contributor
  • **
  • Posts: 695
  • Country: ru
Re: STM32F103 double buffered bulk IN endpoint. [SOLVED]
« Reply #44 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
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf