Accessing USB buffer memory in STM32F10x

The USB device peripheral in STM32F10x seems not very well integrated in the chip like other parts. The USB related registers are even not defined in the header file stm32f10x.h , to programme with the USB, you have to define these registers by yourself.

Of course, you can use the factory provided peripheral library, and further more you can use the USB device stack which comes with the STM32CubeMX. But I like to do things in the way that writing and reading the registers directly. To me understanding other people’s code is even harder than writing my own.

The job was done on a STM32F107, which has a dedicated 512 bytes buffer memory for the USB port. But this memory is not like the normal memory that you can access it with a simple read or write. In the reference manual, there’s few words about it, user is only told the memory is “structured as 256 words by 16 bits”, “all packet memory locations are accessed by the APB using 32-bit aligned addresses”, and “the actual memory location address must be multiplied by two”. It’s very vague and the information is scattered in different places in the manual.

It cost me quite a while to figure out how to access the USB buffer memory. Let’s get to the conclusion first:

  • Don’t use byte-width access, use 16bit, even if you just want to write 1 byte.
  • The address in the buffer should be doubled
  • When write a sequence of data, increase the buffer address double as the outside RAM.

If the address you are accessing is 8 in the USB buffer, or in another word you are accessing the 8th byte in the buffer, you have to write or read at BUFFER_BASE_ADDRESS+16.

In the USB device enumeration process, the micro-controller may need to send any amount of data from 1 byte to hundreds. But even if you just need to write 1 byte to the buffer, you need to use 16-bit access to write a 16bit word.

Here is my code to copy data to the USB buffer. DestAddr is the buffer address

    uint16_t *SourceAddr, *DestAddr;

    for (i=0; i<(BytesToMove+1)/2; i++)   // copy data to buffer
        *DestAddr = *SourceAddr++;
        DestAddr += 2;