cancel
Showing results for 
Search instead for 
Did you mean: 

Your Input Matters: How Do You Use STM32Cube Examples?

Dear STM32 Community,

 

We believe that the example projects provided for the STM32Cube embedded software are a valuable resource when developing projects.

 

We would like to better understand how developers use these examples in their workflow and explore ways to improve them. Therefore, we have a few questions we would like to ask:

 

From where do you obtain the examples, and why?

  • Are you working with the examples through the STM32Cube MCU packages, the STM32CubeMX Example Selector, or through GitHub?
  • Is there a particular reason you prefer one channel over the others?

How do you use the examples in your work with STM32 embedded software?

  • Do you use the examples to learn how to use a driver or a feature, as reference code for implementation, and/or for debugging?

What is working well, and what can we do to improve the examples and/or your experience working with them?

 

You can either reply directly in this thread or feel free to send me a private message.

 

Best regards,
Emil

19 REPLIES 19

I'll agree.  Perhaps a different example code schema would be to write your code, then in a specific section do something like:

//*********************************************************************************
// Code here to write one character to the USART, assuming that the USART is already initialized
// example for HAL and CUBEMX using blocking send:
result = HAL_UART_Transmit(huart, dataptr, data_count, 20);
if (LF) result = HAL_UART_Transmit(huart, (uint8_t*)&terminate[0], sizeof(terminate), 20);
// ********************************************************************************

Using a usart send as an example.

Your BSP packages are so specific to a board as to limit them only to running a demo on your specific hardware.

You have experts in BSP packages, experts in LL packages, and experts in HAL packages.  Simple #ifdef statements can control which gets used, and each expert can contribute their own connection to the driver.

 

 

Hamady
Associate III

Hello,

As other mentioned BSP package can be a nightmare.

When you devlopp a custom PCB you can spend a lot of time debugging code !!!

Other when using DMA2D on STM32N6 after one week of debugging i had the not pleasant surpise to discover that the example had code put in the USER CODE section to make it work .

I think that examples should mention when code for driver other than cube MX is used !!!!!

Hello @Harvey White,

 

Sorry for my late replies, but to me it sounds more like an issue with how HAL is working with FreeRTOS rather than the examples. This type of feedback is also really appreciated.

For HAL and RTOS it is issue we are aware and are trying to solve in the future. Maybe you have seen the preview of HAL2 (https://community.st.com/t5/developer-news/get-a-preview-of-the-latest-stm32cube-hal-update-for-stm32u5-on/ba-p/821784) where the HAL is redesigned to work better with a RTOS

 

Just a FYI regarding AZURE, we have realized that this is not the solution we thought it would be and have therefore pivoted back to FreeRTOS (https://community.st.com/t5/developer-news/new-strategic-directions-for-stm32cube/ba-p/799537)

 

Best Regards,

Emil

Hello @Harvey White@chornbeck@Hamady  and @john37 

 

How would I fit with your way of work, if we changed the BSP code with code generated from STM32CubeMX and application code with a clear separation between the two, by having MX generated code in one set of files that the application code calls, in a structure like this?:

EmilDamkjaerPETERSEN_0-1758046828390.png

Best Regards,

Emil

@john37, for references could it be referring some of our own documentation?

We are putting in place new type of online doc, and could therefore make references like this one to our ADC (https://dev.st.com/stm32cube-docs/stm32u5-hal2/2.0.0-beta.1.1/docs/drivers/hal_drivers/adc/hal_adc_overview.html#hal-adc-overview) as an example. Also to the relevant API description e.g. ADC START (https://dev.st.com/stm32cube-docs/stm32u5-hal2/2.0.0-beta.1.1/docs/drivers/hal_drivers/adc/api/hal_adc_exported_functions.html#_CPPv413HAL_ADC_StartP16hal_adc_handle_t)

 

Best Regards,

Emil

No problem with the late replies.  

  1. HAL does not work with FreeRTOS.  In a HAL driver, there is a mechanism that seems to work to protect the driver from dual uses.  I've not seen that work in my code.  HAL drivers have no recognition of FreeRTOS at all.
  2. I see several layers of semaphores. (FreeRTOS or otherwise).  
    1. HAL level driver, that's your code.  You need to protect the driver from being called from multiple threads with the same hardware instance.  I solve that by having a unique set of calls for the low level driver depending on which hardware is specified.
    2. Chip level driver, that's my code and I can integrate that with FreeRTOS quite well.  That keeps the entire chip driver protected.
    3. System level driver, also my code.  That's above the transport layer and protects the subsystem
  3. If you're going to integrate this with an operating system, then rather than split out each operating system on a per driver basis (i.e. one #ifdef for FreeRTOS, one for Azure, etc)
    1. I'd suggest a section of code, accessible to all HAL level drivers, that define a macro for getting a semaphore.
    2. have a section where you do a global definition for an operating system
    3. In the attached code, you do something like #define GET_SEMAPHORE and for each operating system, call the code.
    4. In your code, you call the universal macro GET_SEMAPHORE.
    5. If you define no operating system, it can default to your code
    6. if you define _FREERTOS, your macro defaults to the FreeRTOS semaphore get.
    7. You can define _FREERTOS_STATIC to allow static allocation
    8. You do this for each RTOS you decide to support, allowing a USER_CODE section in each definition so the user can define his own #ifdef for the operating system of choice
    9. when you decide to add official code for another operating system, simply add the main section, which allows a simple user code change in this one file.
  4. I'd personally give the choice of BSP, HAL, or LL drivers, with the realization that BSP drivers are not a choice that seems to be universally applicable, since they are not expandable and applicable.
  5. I did look at the HAL2 drivers, and while I think you may have complicated them a bit much, I do like the idea.
  6. To solve the AZURE problem (of which I think there is one) The solution would be to step up the OS support for new processors, and release an AZURE version and a FreeRTOS version for a new processor at the same time.  A number of people are trying to make AZURE work, which from my experience, has very awkward uses of queues and does not work well with c++
  7. FreeRTOS works with C++, as long as you know what the workarounds are.  That's likely a head banging session between you and FreeRTOS, as needed.  I use C++ and do need the struture... (You try doing a graphics system in C, I prefer C++).

 

I'd be concerned that as long as I have to go through and rewrite all the low level calls, that I need to do this only one time and let the driver (or a global) figure out which driver to call.

From what I can see, the only use for a BSP package is to run pre packaged demos that do not (IMHO) contribute to learning much, if anything.  The problem is that you do not generate BSP code anywhere.  I have to dig the code out of the examples, and IIRC, the examples are not well documented, and are not written to play nice with other code.  The HAL2 drivers at least allow you to make a choice between the LL and the HAL level drivers.

Given that choice. I really don't care whether or not when I call a HAL2 driver if it uses LL drivers or higher level HAL2 drivers, as long as it works.  If you shifted to BSP drivers, I wouldn't notice as long as they were more or less compatible with the HAL drivers (in terms of function).

I tend to be far more interested in the "get it done" approach to drivers, as long as they do what I need to do.  I generally don't care what's under the hood.  

My software uses a lot of #ifdef to control operation. Want a serial port, change the #ifdef (uncomment it), and so on.  You may consider the same approach.  

What I'd like to see, given that you support more than one OS, is a definition that switches that OS in and out as needed.  

I do like the idea of a mode on a driver to use DMA or not, IRQ or not, blocking or not, and if an OS is defined, a queue or not.  These choices are not useful for all driver situations (SPI, I2C, Serial are all I use), but a good HAL2 driver should address these (and quite frankly, if you use the IOC file, then please put in the callbacks as needed).

 

I liked the idea so much that I decided to see if it would work.  I have a partial implementation using embOS and FreeRTOS.  Full testing of emBOS is going to require a lot of work, but the implementation should be more or less straight forward.  For how to do the actual substitutions, I'm using the instructions from Segger:  https://www.segger.com/products/rtos/embos/ 

File wise, OS_MACROS.h contains the main data, and HAL_I2C shows how to paste in the definitions of the OS handles, and the part in HAL_I2C.cpp shows how to insert the code.  It's still in progress, though.  The normal FreeRTOS views do show the proper creation of the semaphore.

For the macros:

/*******************************************************************************************************************
 *	MACRO SUBSTITUTIONS
 *	INCLUDE FILES
 *
 ******************************************************************************************************************/



// SEMAPHORES
//

// all FreeRTOS macros
#ifdef _FREERTOS

	// semaphore:
	// _WHICH is SemaphoreHandle_t, _DELAY not implemented since this is blocked
	// semaphore is created and given, so that the next _SEMAPHORE_GET will work automatically
	// this is a binary semaphore, non-counting

	#define _SEMAPHORE_CREATE(_WHICH) 	_WHICH = xSemaphoreCreateMutex(); xSemaphoreGive(_WHICH);
	#define _SEMAPHORE_GET (_WHICH, _DELAY) xSemaphoreTake(_WHICH, DELAY);
	#define _SEMAPHORE_RELEASE (_WHICH) xSemaphoreGive(_WHICH);

#endif

which is how the FreeRTOS would work.  Note that this and the embOS implementations make significant compromises because of the different way the two OS treat a semaphore.

#ifdef _EMBOS
	// semaphore:
	// _WHICH is OS_SEMAPHORE*, _DELAY in macro is ignored
	// _WHICH is a pointer to OS_MUTEX

	#define _FOREVER				0
	#define _SEMAPHORE_CREATE(_WHICH) 	 OS_SEMAPHORE_Create(_WHICH); OS_SEMAPHORE_GiveMax(_WHICH,1);			// uses macro for zero count
	#define _SEMAPHORE_GET (_WHICH, _DELAY) OS_SEMAPHORE_TakeBlocked(_WHICH);	// delay is ignored
	#define _SEMAPHORE_RELEASE (_WHICH) OS_SEMAPHORE_Give(_WHICH);

#endif

 and to illustrate the creation of the semaphore:

	_SEMAPHORE_CREATE(busy);


//#ifdef _FREERTOS_STATIC
//	busy = xSemaphoreCreateBinaryStatic( &static_map.I2C_STATIC[(uint8_t)which].BSemaphoreBuffer );
//#else
//	busy = xSemaphoreCreateBinary();
//#endif
//

and for the .hpp file, which is made from a template.

		// *********************************************** SEMAPHORE ******************************************************
#ifdef _FREERTOS
	SemaphoreHandle_t							busy;
#endif

#ifdef _EMBOS
	OS_SEMAPHORE								busy;
#endif

Design notes:  

Names of the macros are chosen to  (hopefully) conflict with no existing names.  Note that enabling _EMBOS and disabling _FREERTOS should take care of everything.

Some of the arguments are ignored, which might give flexibility from OS to OS.  See the notes in the OS_MACRO.h file for the reasoning

Looks as if it might work well, as long as the differences between OS can be ironed out.

 

Concept seems to work just fine.

However..........

embOS and FreeRTOS are apparently determined to be very different from each other, number of arguments, and what is returned.

Time for Plan B, 

Replace the macros by functional programming.

More to come.

 

skidadddytn
Associate II

Primarily, I usually like to get the examples from the latest MCU packages so I can also use that folder to "grep" through when I am looking for something.  Never tried the STM32CubeMX Example selector.   I may have accessed them through github a couple of times.  I like the idea of being able to see the rev history for them in github.

I usually run the examples first as-is to learn how the HAL calls work together, then I use it as a reference for writing what I need (which will differ).

I feel like the examples usually work, but If I could pick an area where I would like more examples it would definitely be "low power" (sleep, stop, etc, and multiple modes here).  This area seems to have the most variation when jumping from different stm32 mcus (lots of nuances and differences).