STM32 USB libraries - Page 1
Forum section: electronics / general

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 02:34:52 pm
content: So I now realise that my C language understanding sucks when trying to read or even follow a tutorial.Whats this ugly thing called? This unnamed ( or named at the end of the block) typedef struct wich holds functions?

author: andersm
author_rank: Super Contributor
timestamp: January 17, 2020, 02:55:39 pm
content: Code:uint8_t *(*GetDeviceDescriptor)(...)is a pointer to a function that returns a pointer to uint8_t. The tag is optional in a structure declaration. That is basically one implementation of classes and virtual functions in C.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 03:06:37 pm
content: Say that again in universally googleable terms? I wanna know reasons, use cases and technique.Yeah I was talking about theseCode:typedefstruct{uint8_t *(*GetDeviceDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetLangIDStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetManufacturerStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetProductStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetSerialStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetConfigurationStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);uint8_t *(*GetInterfaceStrDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);#if(USBD_LPM_ENABLED == 1)uint8_t *(*GetBOSDescriptor )( USBD_SpeedTypeDef speed , uint16_t *length);#endif}USBD_DescriptorsTypeDef

author: ogden
author_rank: Super Contributor
timestamp: January 17, 2020, 03:19:48 pm
content: Quote from: lawrence11 on January 17, 2020, 03:06:37 pmThis is array of pointers to a functions that returns a pointer to uint8_t.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 03:31:25 pm
content: What do you mean an array? Technically there is not an array.There is a multitude of pointers to a functions that returns a pointer to uint8_t, on each line, yes.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 03:41:26 pm
content: like this?

author: ogden
author_rank: Super Contributor
timestamp: January 17, 2020, 03:42:00 pm
content: Right. Bunch of function pointers in the structure

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 03:48:32 pm
content: and there would be no difference in the code if I moved USBD_DescriptorsTypeDef right next to typedef structinstead oftypedef struct{}USBD_DescriptorsTypeDefcorrect? I dont like this style, it should follow a convention.

author: andersm
author_rank: Super Contributor
timestamp: January 17, 2020, 05:55:42 pm
content: Quote from: lawrence11 on January 17, 2020, 03:48:32 pmYes there would, because that is the name of the type alias that is being defined. Moving it would generate a syntax error. You can add a tag to the struct if you insist, there's an example in the first picture.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 17, 2020, 06:08:39 pm
content: No ides what you just said, whats the role of the name underneaht the unnamed typedef structUSBD_DescriptorsTypeDef

author: Kilrah
author_rank: Unknown
timestamp: January 17, 2020, 06:27:24 pm
content: When you doCode:struct blah{};you then declare a variable asCode:struct blah myVar;But if you wrap that with a typedef you can then omit thestructin the declaration, so withCode:typedef struct blah{}blah;you can instead declare your variable withCode:blah myVar;Which is shorter and people prefer.But when you typedef there is no need to give the struct a name anymore, so people omit it since it's pointless to have it twice, so it becomesCode:typedef struct{}blah;

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 23, 2020, 11:24:54 pm
content: So I notice this uncomfortable feeling of not knowing WTF is going on when I single step through ALL the config, trying to make sense of all this BS stepping to setup the registers. Since most of this stuff I soon wont care about exept their 1 or 2 functions, but the USB I need to study a bit, yet when it gets to this peripheral, it sets it up in a Handler, and I cant see the relationship going between setup page and SFR's, wich I like to do.How do people know where to check for Handlers. Now theres a handler but its lost somewhere...I wanna see where this Interrupt is enabled for the USB clock in the first place, I know that as soon as the CLK bit is set it trips, but thats because its enabled.I wanna practice and watch over the INTERRUPT ENABLE registers for such and such peripherals, is there there a "tree like" diagram for all the possible interrupt names and their peripherals for each family??BTW, I dont see why people complain about this IDE its quite fast and stable with hardware reset and setup with "connect on reset". using ST-link V3

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 01:17:48 am
content: http://blog.atollic.com/what-you-need-to-know-about-debugging-interrupts-and-exceptions-on-cortex-m-devicesSo I wanna know to to trace exeption event but lol, I dont see where he teaches me this??

author: Kilrah
author_rank: Unknown
timestamp: January 24, 2020, 04:45:04 am
content: As mentioned it's about gatheringstatsabout interrupts in a running application, where halting isn't possible because it would cause everything to break.

author: ogden
author_rank: Super Contributor
timestamp: January 24, 2020, 05:25:54 am
content: Memory read/write breakpoints are very useful when you debug HAL/driver code. Knowing your MCU and debugger helps as well. Take some time to learn more about ARM, debugger and probe. When you know what is available - it is much more easier to find right approach. Info just aboutbreakpoint features. It's IAR, but other debuggers in general do not differ much.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 11:59:43 am
content: Yeah I know about breakpoints, its just the blue dots on the left that can be all deleted in a view and you get 5 maximum.I would put one in the exeption handler but I dont where it is.

author: ogden
author_rank: Super Contributor
timestamp: January 24, 2020, 12:05:50 pm
content: Quote from: lawrence11 on January 24, 2020, 11:59:43 amThose are not memory breakpoints. Before you jump into conclusion that you know everything about breakpoints - make sure that you are not mistaken

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 12:20:37 pm
content: I thought these were breakpoints? As it says breakpoints in the tab.So they are just software? Not written into memory of the cortex, I see.So they are more like watchpoints.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 12:29:10 pm
content: I see now, you can change them.

author: ogden
author_rank: Super Contributor
timestamp: January 24, 2020, 12:40:54 pm
content: There are code breakpoints and then there are memory access breakpoint. Those you show are all related to code. Maybe read IAR article I linked to see that breakpoints differ?

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 01:29:12 pm
content: And what do you think I am trying to do?Heres a register I wanna watch, theres 4 things I can do in terms of debugging..1: Watch by breakpoints by installing blue dots in the text editor manually, then tediously setting them as Hardware since there seems to be no quick Hardware breakoints, these cannot be set on address directly as I would just *USB peripheral address. in a field of some sort, there is no field for direct address.2: Expressions, these seem to give the right value but only after the exeption is fully done and nothing seems stopped by Hardware breakpoint and I cant see nothing still, thus I have no sense of comprehension.3: Live expressions, same as #2, seems useless.4: The useless stuff on the bottom with having to do with ITM ports, these only log and dont stop, same problem.So now I wonder if this capability is not found by a special code in the edit watch expression window to make this a hardware breakpoint on address write?

author: kamtar
author_rank: Regular Contributor
timestamp: January 24, 2020, 01:50:07 pm
content: this is what you want

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 02:15:48 pm
content: WOW I was looking for that thing, well hidden.But it seems its type cannot be specified to hardware, and shows nothing. Hardware breakpoints seem to only be possible on blue dots that you specify.No idea how to step on an unknown exeption handlers still...All the SFR fields instantly appear on a Step over.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 24, 2020, 02:34:13 pm
content: https://community.nxp.com/thread/389027Well it seems like in my case I cant configure it to stop on a write or read.Perhaps I am in this category?Watchpointscan be configured to halt on a Read(or Load), Write (or Store), or both. Since watchpoints 'watch' accesses to memory, they are suitable for tracking accesses to global or static variables, and any data accesses to memory including those to memory mapped peripherals.Note: Due to the way watchpoints are implemented, any monitored access will be performed by the CPU before a halts occurs (unlike instruction breakpoints - which halt the CPU before the underlying instruction executes). When a watchpoint is hit you will seesome 'skid' beyond the instruction that performed the watched data access. If the instruction after the data access changes program flow (e.g. a branch or function return), then the IDE may not show the instruction or statement that caused the CPU to halt.

author: ogden
author_rank: Super Contributor
timestamp: January 24, 2020, 03:30:18 pm
content: Quote from: lawrence11 on January 24, 2020, 02:34:13 pmWhy don't you just try?

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 25, 2020, 07:39:53 am
content: Can anybody share insight onto how people usually debug IRQ's from complicated libraries that elude them?Cant seem to follow along 100% of the way, am trying hard to setup a Hardware breakpoint somewhere, but where?

author: blacksheeplogic
author_rank: Frequent Contributor
timestamp: January 25, 2020, 08:27:52 am
content: Quote from: lawrence11 on January 25, 2020, 07:39:53 amI usually instrument the code path. I find it is often quicker than stepping in a debugger and it also has minimal run-time impact.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 25, 2020, 03:21:46 pm
content: I would like to do that, I will insert a printF in it, once I can find where to put it.Well my needs right now are educationnal, I managed to make the device class work and move a mouse. But I also wanna learn how to use big libraries, explore them to see how the registers are setup, btw I hate big libraries.I thought a Hardware breakpoint had superpowers and can never be skipped by an interrupt routine and the reason I didnt find the "culprit" yet is because I havent put the Hardware bp in the right function yet.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 25, 2020, 04:19:34 pm
content: Also, the ogden was partly right.3 or 4 of these registers react and stop on the line once commanded by a C/C++ Watchpoint.Wich is a useful trick.But most of them are only discovered as "murdered", it seems as if this is a "priority game" and that the Debuggers priority is unable to stop this IRQ (the silent invisible register setter), or w/e name it should have.Now I guess blacksheeplogic is right, when you debug these high priority IRQ's ( Or should I say low in cortex-M terms), instrumentation by SWO should be the standard debug tactic, wich incurs being in control and knowing where to put it.Sadly I remain in the dark as to the mysteries of these ST Libraries, I'm the little cuckold of these libraries, and I dont like this.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 25, 2020, 06:18:28 pm
content: So I guess I should just treat it as such? A black box and send report?Forget about all this, stick to the descriptors as in the videos.

author: ogden
author_rank: Super Contributor
timestamp: January 25, 2020, 06:58:16 pm
content: Quote from: lawrence11 on January 25, 2020, 03:21:46 pm"In the function" is code breakpoint, notdata or IOmemory access breakpoint.

author: lawrence11
author_rank: Frequent Contributor
timestamp: January 25, 2020, 08:02:41 pm
content: I havent put the Hardware bp "On the right function" then, right on the line name. A blue dot with Hardware type?Anyways, Address watchpoint, or SFR watchpoint, w/e you wanna call it, is late on the ball on certain address while others work OK.Its a Watchpoint that can stop the execution on the right line, when the conditions are right, yes, quit useful, but not in this case.Super man come, superman steals the bank, I blink and see nothing.Why is that?See my theory above.Maybe I'm stupid I dunno, I dont know how to do this "data or IO memory access breakpoint." that catches this culprit. I use STM32CUBEIDE remember.

author: LostTime77
author_rank: Contributor
timestamp: March 03, 2020, 04:23:28 am
content: Ah the infamous Synopsys USB IP. I have developed many a bare metal USB driver for my previous company for the STM32 controllers. The STM32 have several forms of IP used for the USB controllers in the chips. The main two are the synopsys IP, which I can tell just by looking at those registers and a device only IP. The device only IP is much easier to work with compared to the synopsys IP, which supports OTG. Fun fact - many people from the raspberry pi side have still not figured out that the IP for the USB module inside the pi is identical to the STM32 Synopsys IP (they use the same IP). Register sets are identical.Anyhow, let me be frank and say you will not get very far in trying to hit breakpoints and having useful information be produced from the USB registers. The reason is that the synopsys IP works a lot in the background without being knowledgeable of what you are trying to do in the debugger. For example, you could set a breakpoint for an interrupt after a packet is sent and expect certain bit patterns inside the USB registers in that interrupt only to find those bits are not in the state you expect - the hardware has already done a lot of hand wiping before you can catch it.For debugging the USB hardware, the easiest solution is to do it at higher level in the drivers - not looking at individual bits in the registers but instead looking at overall transactions. Even trying to write debugging code to save the states of registers before your debugger breakpoints hit is not very reliable due to the previous paragraph. Part of the why this happens is because of the two complicated clock domains and clock crossings between the CPU and USB hardware. My advice would be to scour the documentation closely and understand what it is doing at a high level and how the register bits play a role in that. From this you can understand better what is happening and or design your own code / tests to make the hardware work. Another fun fact - I have cross referenced some documentation with the EFM32 USB peripheral a lot, because it contains the EXACT same synopsys USB IP as well.The way the hardware works is a little convoluted; however, also being an FPGA / hardware developer myself, I can understand the design decisions. Once you figure it out and compare to what they 'could' have done you will find its not the worst way of doing things.The Synopsys OTG IP can be found on any STM32 that has the OTG functionality and the device only USB IP can be found in some STM32 chips with lessened functionality (STM32L5, some STM32L4, some of the old STM32F series). The device only IP is 'much' easier to work with even if it requires a bit more hand holding in software, but doesn't require you to sacrifice an arm and a leg to understand exactly what its doing compared to the synopsys IP.

author: andersm
author_rank: Super Contributor
timestamp: March 03, 2020, 06:57:58 am
content: Quote from: LostTime77 on March 03, 2020, 04:23:28 amAccording to Synopsys engineers on the Linux-USB mailing list, there are in fact several versions of the same DWC2 controller, with slightly different capabilities. There's also a number of knobs the silicon vendor can use to tune the controller to their specific application.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 03, 2020, 02:04:12 pm
content: Code:uint16_t buffer_k;extern USBD_HandleTypeDef hUsbDeviceHS;int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USB_DEVICE_Init();MX_SPI1_Init();MX_SPI2_Init();MX_SPI3_Init();MX_TIM2_Init();/* USER CODE BEGIN 2 */buffer_k=0b0000000000000001;//reportIDbuffer_k=0x0400;//modifierbuffer_k=0;//OEMbuffer_k=0;//keycode dataLL_SPI_Enable(SPI2);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_Delay(100);USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)buffer_k, sizeof(buffer_k));}/* USER CODE END WHILE *//* USER CODE BEGIN 3 *//* USER CODE END 3 */}Why doesnt this code write A ?? it does when I go by the example.

author: LostTime77
author_rank: Contributor
timestamp: March 03, 2020, 04:11:25 pm
content: Quote from: andersm on March 03, 2020, 06:57:58 amThe overall operation is the same. The things that I have seen that are silicon options are the number of endpoints, DMA capability, amount of RAM, etc.. How you program transfers in the firmware does (should) not change - its a matter of which endpoint you are using and if its DMA based. Case and point - STM32L4 does not have DMA and has less RAM (IIRC) than a STM32H7 which has DMA and more RAM.For example, the way the controller handles the receive FIFO in terms of the information words that the controller puts there should not change (packet complete, setup packet received, NAK received, etc.). This is really the bulk of the understanding of how the controller works and causes the most confusion. If there is a different way to load and start packet transfers between controllers, it doesn't matter so much; understanding the overall hardware flow is the toughest nut to crack.Compare this with the device only IP that essentially you hand hold on 'every' packet transfer inside the firmware. Theres a 'lot' less unknowns about what is going on.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 03, 2020, 04:26:41 pm
content: Nah sorry, theres something that messes up the descriptor and now it has the same icon but is a mousesorry guys.I upgraded cubemx and it did a stealth change somewhere and I was only checking the control panel and it looked the same, but it was not the same.weird shit, I sware I didnt touch cubemx.back to square 1, from like 10 days ago.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 03, 2020, 06:18:55 pm
content: Code:while (1)#include "usbd_hid.h"#include "usbd_customhid.h"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/SPI_HandleTypeDef hspi2;/* USER CODE BEGIN PV */uint16_t bufferk;int *ptr; // so whats the magic here that I gotta do to start at bufferk+2extern USBD_HandleTypeDef hUsbDeviceHS;/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);static void MX_GPIO_Init(void);static void MX_SPI2_Init(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USB_DEVICE_Init();MX_SPI2_Init();/* USER CODE BEGIN 2 */bufferk=0;bufferk=0;bufferk=1;//reportIDbufferk=0x0400;//modifierbufferk=0;//OEMbufferk=0;//keycode data/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)bufferk, 8); //gives warning, dont type AHAL_Delay(100);USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)bufferk, 8); //gives warning, dont type AHAL_Delay(100);USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)bufferk, 8); //gives warning, dont type A/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */}}Now whats the best way to pass an offset array?If I make it like this, it writes A, gives no warninguint16_t bufferk;bufferk=1;//reportIDbufferk=0x0400;//modifierbufferk=0;//OEMbufferk=0;//keycode dataUSBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)bufferk,8 );

author: rounin
author_rank: Regular Contributor
timestamp: March 03, 2020, 07:30:03 pm
content: Quote from: lawrence11 on January 25, 2020, 07:39:53 amFor ISRs that can tolerate some small delay I have a logging framework that uses an object pool for string buffers. It is safe to try_allocate strings from the ISR and seems to be fast enough. This lets you log up to however many strings are in the object pool with minimal overhead.I actually used this while writing my USB driver for the STM32H7. I had a lot of logs queue inside the interrupt (logging silicon IP state & bus traffic), still was able to enumerate and service USB HS. Another thread (FreeRTOS) sends the logs out the UART when there isn't anything else to do.So to generalize for another lib, I have added code to the vendor libs to log stuff. Sometimes just dropping the IP state in a queue.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 03, 2020, 07:54:16 pm
content: Bah, All that stuff is old.I dont really care anymore, peoplse seem to hack things together by molding the black box to their needs.My question now, how to write A as asked above.I can already write A, but I wanna practice my C.

author: LostTime77
author_rank: Contributor
timestamp: March 03, 2020, 09:14:35 pm
content: Sorry.. I will be honest.. I have not been reading every nook and kranny on this thread. What was the actual question?Are you asking why something like this:USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)bufferk,; //gives warning, dont type AIs giving you a warning? You asked how do you "write an offset array"? I am not sure what that means, but I think you are asking how do you pass a pointer to the array from a given offset. I have not looked at the USBD_HID_SendReport function, but I presume the second parameter is asking for a byte pointer and then parameter 3 is the number of bytes to transfer from the actual data.What you are doing in the above function call is taking the value of the data at array entry 3 (0 based) and passing that to the function. The type of the value stored in the array is a uint16_t (2 byte data), not a pointer that the function expects. (You can cast a value to a pointer if the value was an actual physical address here, but I don't think that's your intended operation)I think you want to to pass the data to the function starting at array entry 3. Therefore, the second parameter should be (uint8_t*)&bufferk. The third parameter should be 8 or less since there are only 8 bytes of data starting at array entry 3 (your array is 6 entries big).ALSO! It looks like you are trying to manipulate multi byte data values in a buffer that is transferred byte wise on the USB bus. Keep in mind that in USB the endianness does matter. If you wanted the code to be portable, the usual way is to declare a byte buffer and have a function to be called to encode each multi byte data value into that buffer with the correct endianness. This buffer is then encoded properly as per whatever your USB class is to be sent as raw bytes to the driver. For low level testing and fast stuff, I don't think there is an issue with what you have done, but keep in mind that the uint16_t data values going into your buffer may not be in the correct endianness that the HID class expects. (Talking general terms here... take note.. HID might already be little endian.. would have to look it up)

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 03, 2020, 09:51:51 pm
content: awesome bro thx it works, writing A.&buffer& = the address of.Since an array is already a pointer it can be already written & if I want to.

author: Kilrah
author_rank: Unknown
timestamp: March 03, 2020, 10:11:41 pm
content: Why are you making an array of uint16_t instead of uint8_t like in the example?These things work on bytes so you're only making your life harder and risking to cause you all sorts of trouble.