Electronics > Microcontrollers

STM32F103 double buffered bulk IN endpoint. [SOLVED]

(1/9) > >>

DELTA67:
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!!/
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: ---  0x07,   // bLength
  0x05,   // bDescriptorType: Endpoint
  0x81,   // bEndpointAddress: (1IN)
  0x02,   // bmAttributes: Bulk
  0x08,   // wMaxPacketSize: 8 bytes
  0x00,
  0x00,    // bInterval:

--- End code ---

2- EP1 initialization:

--- Code: --- ...............
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

--- End code ---
3- EP1 transfer complete interrupt handler:
to toggle the DTOG_RX bit I declared a pointer to it in the bitband region:

--- Code: ---#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);

--- End code ---

and the handler:

--- Code: --- 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
}
}

--- End code ---

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.

ataradov:
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.

pcprogrammer:

--- Quote from: DELTA67 on November 04, 2024, 08:10:23 pm ---and the handler:

--- Code: ---  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
    }
  }

--- End code ---

--- End quote ---

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


--- Code: ---  *bb_DTOGRX ^= 1;  //toggle DTOG_RX  by bitbanding

--- End code ---

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.

ataradov:
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.

DELTA67:
Thanks ataradov and pcprogrammer.

--- Quote from: 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.

--- End quote ---
Here's how I copy RAM to PMA:

--- Code: ---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);
}

--- End code ---


--- Quote from: ataradov on November 04, 2024, 10:16:15 pm ---Just toggle it manually.

--- End quote ---

I tried it this way but it did'nt work:

--- Code: ---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
}

--- End code ---
Have you a working code please?


--- Quote from: pcprogrammer on November 05, 2024, 06:38:25 am --- there is a button in the editor to list code, which works better than using the quote button.

--- End quote ---

DONE!

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod