2.6k views
in System Integration by
I will be implementing the SPI and UART periherals of the STM32F746. Should I put all of the code in the device driver. I'll be using STM32CubeMX to generate the code and paste it into a file. Is there a more elegant way instead of copying and pasting code. What are others using to manage the code and for project management? Thanks in advance.

1 Answer

0 votes
by

Hi there,

 

regarding to your question about where to place SPI and UART code; Actually the UART and SPI code doesn’t is a part of the Embedded Wizard GUI framework, so we do not recommend it to place it into the device driver part. This part is dedicated for user code which directly sends or fetches data from and to the GUI. For example, within the Build Environment for STM32F746 you can see that the UART API is configured in ‘ew_bsp_serial.c/.h’ which is appart of the target specific (BSP) code.

Regarding to your question about STM32CubeMX; At the moment we do not officially support STM32CubeMX. Anyway a few months ago I had prepared a STM32CubeMX project for the use with Embedded Wizard, you can download that project here

Within the folder “CubeMX_with_EmbeddedWizard” you can find the .ioc file for CubeMX and a TrueSTUDIO project. The STMCubeMX project configures the minimum hardware requirements, that are necessary for Embedded Wizard. Within CubeMX you can press the “Generate Code” and this will update/regenerate the source code, except the user defined parts. Within the “USER CODE BEGIN/END” parts is the code added, which Embedded Wizard needs. With this STM32CubeMX project you can add other software parts as ever you want.

When you press “Generate Code” probably a will warning appear, just press “Yes”, FreeRTOS will work anyway.

This project isn't an official release from our side, thus it looks slightly different as one of our Build Environments.

The STM32CubeMX project was tested with:

*STM32F746-Discovery

*Embedded Wizard 9.30 Free Version (with Watermark and Libraries)

*STM32CubeMX 5.5.0

*Atollic TrueSTUDIO 9.3.0

*STM32Cube_FW_F7_V1.15.0 (within CubeMX)

 

Hopefully this will help you to start your own project.

 

Tim

 

 

by
Tim,

I don't see the batch file to build the project and upload it to the STM32F746 Discovery? Can I build the project without FreeRTOS?
by
So now I see, when I press the debug button in Truestudio, the firmware is uploaded to the discovery board then. I have not tried this yet.

When I build the project, I am getting the following error,

Description    Resource    Path    Location    Type
fatal error: stm32746g_discovery_sdram.h: No such file or directory    main.c    /CubeMX_with_EmbeddedWizard/Src    line 62    C/C++ Problem

Will it still work if I comment out this include file? Can't get it to build.
by

Hi there,

 

I am pretty sure that the project will not work if you uncomment that file.

Could you please verify whether your file structure looks like this:

 

I assume that something went wrong during the import of your TrueSTUDIO project.

 

Best regards,

 

Tim

by
Tim,

I'll check that now.

I did get my project to build with Truestudio. I was reading some earlier post and saw Manfreds post stating that since Embedded Wizard 9.0.0 there is a truestudio project included with the build environment. I resorted to the readme file to build my project.
by
The file structure looks exactly like the above screen shot. Where should I place the project? Should I have it in the STM32F746 Discovery build environment?
by
I get the following error when I try to build the Helloworld app!

11:08:39 **** Incremental Build of configuration Debug for project CubeMX_with_EmbeddedWizard ****
Info: Internal Builder is used for build
arm-atollic-eabi-gcc -c -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -std=gnu11 -DUSE_HAL_DRIVER -DSTM32F746xx -DUSE_STM32746G_DISCO=1 -DEW_FRAME_BUFFER_COLOR_FORMAT=EW_FRAME_BUFFER_COLOR_FORMAT_RGB565 -DEW_SURFACE_ROTATION=0 -DEW_USE_FREE_RTOS=1 -DEW_USE_EXTERNAL_FLASH=1 -I../Inc -I../Drivers/STM32F7xx_HAL_Driver/Inc -I../Drivers/STM32F7xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32F7xx/Include -I../Drivers/CMSIS/Include -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\Application\Source -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\Application\GeneratedCode -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\TargetSpecific -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\TargetSpecific\Drivers -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\PlatformPackage\RTE -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\PlatformPackage\RGB565 -IC:\STM32F746-Discovery\Application\Project\TrueSTUDIO\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS (2)\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\ThirdParty\STM32Cube_FW_F7\Drivers\BSP\STM32746G-Discovery -I../Middlewares/Third_Party/FreeRTOS/Source/include -I../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS -I../Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang -I../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM7/r0p1 -Os -ffunction-sections -fdata-sections -g -fstack-usage -Wall -specs=nano.specs -o Drivers\STM32F7xx_HAL_Driver\Src\stm32f7xx_hal_i2c_ex.o ..\Drivers\STM32F7xx_HAL_Driver\Src\stm32f7xx_hal_i2c_ex.c
arm-atollic-eabi-gcc: error: ..\Drivers\STM32F7xx_HAL_Driver\Src\stm32f7xx_hal_i2c_ex.c: No such file or directory
arm-atollic-eabi-gcc: fatal error: no input files
compilation terminated.

11:08:39 Build Finished (took 188ms)

 

Yet I do see this file in the file structure tree! I am guessing the issue is because of where I put the CubeMX_with_EmbeddedWizard projected.
by

Hi again,

 

So, I guess this topic needs some more explanation.

The zipped file ‘CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS.rar’ isn’t a part of our Build Environment. It represents an unofficial stand-alone package especially configured for the use with STM32CubeMX. So please do not mix this package and our Build Environment.

 

1.  Please create a workspace folder at any location that you want. For example ‘C:\Users\Tim Zierer\Desktop\Workspace’

2. Unpack the file ‘CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS.rar’ in to this folder.

3. Open the recently created folder as workspace with TrueSTUDIO.

4. Press then ‘File->Import’

4. Navigate to ‘General->Existing Projects into Workspace’ and press ‘Next’.

5. Press ‘Browse’ and select the recently unpacked folder within your workspace folder. Finally press ‘Ok’.

 

Now you will have a fully configured TrueSTUDIO project that was automatically made with STM32CubeMX. This project already contains Embedded Wizard 9.30 for the STM32F746 discovery board with already precompiled UI code. You can build and flash the binary as usual. Additionally you can build all UI example that are located in ‘Workspace\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard\EmbeddedWizard\Examples’ with your Embedded Wizard 9.30 Free version. How this works, you can read in our Getting started article for STM32F7456G discovery.

As next comes the STM32CubeMX part. Therefore please open ‘CubeMX_with_EmbeddedWizard.ioc’ project file with your STM32CubeMX software.

6. Press ‘File->Load Project’.

6. Navigate to ‘…\Workspace\CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS\CubeMX_with_EmbeddedWizard’ and open the .ioc file.

Now you can use STM32CubeMX as ever you want, for example you can add additional hardware and software  components.

When you press ‘Generate Code’ STM32CubeMX will regenerate the code which is used by the TrueSTUDIO project that you have opened. Simply accept the warning about FreeRTOS, the project will work anyways.

 

This process will update and add the new software parts without changing the parts that are necessary for Embedded Wizard. The difference between our normal Build Environment to this package is that all hardware and essential software components were configured with STM32CubeMX.

Hopefully that will clear your issue in using that package, let it know me wheatear it works.

Best regards

Tim

by
Well Tim,

I was able to get the paper cutter example to build and run on the f746 discovery. But when I tried to build my project, I got 28 errors. And I made sure that I set the output directory in the profile correctly. So I don't know why it won't build. I might add that this project is not inside the stand alone environment. Getting late so I will look at it tomorrow. Thanks for your help.
by
Hi there,

could please specify in which software do you get the errors and how the errors looks like?

 

STM32CubeMX?

TrueSTUDIO?

Embedded Wizard?

 

Best regards,

Tim
by
Tim,

My project is now building. I am getting a blank screen but I suspect it is because I had to modify ew_bsp_inout.c to add code to set up 3 GPIO pins to read a 3 button key pad and I had to add code to the ewmain.c file to scan the key pad and I haven't added these files to the standalone CubeMX_5_5_0_with_EmbeddedWizard_9_30_for_TrueSTUDIO_9_3_0_FreeRTOS build environment.

I found out that I had to close the TrueSTUDIO app before generating code in Embedded Wizard for it to build properly.

I even tried adding a GPIO output pin with STM32CubeMX. I could build the TrueSTUDIO app without any errors.

I am excited to add this modified files to the app to see how it does. This will be great as I needed one enviroment to do everything. Especially adding perihirals with STM32CubeMX.
by

When I build and upload my app with TrueSTUDIO, the screen is blank. When I set a breakpoint at the line CHECK_HANDLE( Viewport ); in Ewinit.c, and step through the app, I can never step past this line! Any ideas? 

 

This app works fine when I build it with StartGccBuildEnvironment.bat with make, and then make install, the firmware works fine on the board.

int EwInit( void )
{
  /* initalize system clocks */
  EwBspClockInit();

  /* set RTC, if current RTC time is before the minimum time */
  if ( EwBspClockGetTime() < RTC_MINIMUM_TIME )
    EwBspClockSetTime( RTC_DEFAULT_TIME );

  /* initialize display */
  EwPrint( "Initialize Display...                        " );
  EwBspDisplayInit( &DisplayInfo );
  EwPrint( "[OK]\n" );

  /* initialize touchscreen */
  EwPrint( "Initialize Touch Driver...                   " );
  EwBspTouchInit( DisplayInfo.DisplayWidth, DisplayInfo.DisplayHeight );
  EwPrint( "[OK]\n" );

  /* initialize heap manager */
  EwPrint( "Initialize Memory Manager...                 " );
  EwInitHeap( 0 );
  EwAddHeapMemoryPool( (void*)MEMORY_POOL_ADDR, MEMORY_POOL_SIZE );

  #if EXTRA_POOL_SIZE > 0
    EwAddHeapMemoryPool( (void*)EXTRA_POOL_ADDR, EXTRA_POOL_SIZE );
  #endif

  EwPrint( "[OK]\n" );

  /* initialize the Graphics Engine and Runtime Environment */
  EwPrint( "Initialize Graphics Engine...                " );
  CHECK_HANDLE( EwInitGraphicsEngine( 0 ));

  /* create the applications root object ... */
  EwPrint( "Create Embedded Wizard Root Object...        " );
  RootObject = (CoreRoot)EwNewObjectIndirect( EwApplicationClass, 0 );
  CHECK_HANDLE( RootObject );

  EwLockObject( RootObject );
  CoreRoot__Initialize( RootObject, EwScreenSize );

  /* create Embedded Wizard viewport object to provide uniform access to the framebuffer */
  EwPrint( "Create Embedded Wizard Viewport...           " );
  Viewport = EwInitViewport( EwScreenSize, EwNewRect( 0, 0, DisplayInfo.BufferWidth, DisplayInfo.BufferHeight ),
    0, 255, DisplayInfo.FrameBuffer, DisplayInfo.DoubleBuffer, 0, 0 );
  CHECK_HANDLE( Viewport );

  /* initialize your device driver(s) that provide data for your GUI */
  DeviceDriver_Initialize();

  return 1;
}

by
Tim,

Finally got it to build my project! I forgot to change the frame buffer height and width in the ewconfig.h file! Thanks for your patience!

Do I have to use FreeRTOS with this build environment? It is causing issues with reading my keypad.
by
When I built my app from the command line, I was not using the RTOS. And I was polling my keypad in the Ewmain process function. But when I build the app from Truestudio the RTOS is used. The program hung up when I used the keypad. So I tried using external interrupts for the keypad. Now when I press the third key 7 times, it causes a Hardfault. Something about attempting to use an unaligned access. I even tried using a different GPIO pin to no avail. Funny thing is I can press the first button to my hearts content without issue. I don't have experience using an RTOS and would just as soon not to use one. So I was wondering if I can turn it off using the Truestudio/STM32CubeMX environment. I really like using this combo because of the ease of setting up periherals and the debugging features.
by
I tried doing what you suggested in the "Trying to disable FreeRTOS" thread. I built and uploaded my project after doing this, but the screen was messed up. So I was thinking that I probably have to disable it in STM32CubeMX as well. Is this correct?
by
Hi there,

you do not have to use FreeRTOS. If you want to remove the OS, please take a look into our Build Environment to see which code parts have to be excluded for running the project without FreeRTOS. The STM32CubeMX stand-alone package is configured with FreeRTOS and up to now it&rsquo;s not foreseen to configure the project for bare metal too. Therefore please modify your project manually instead using EW_USE_FREE_RTOS like in our normal Build Environment. Please take into account that this project isn&rsquo;t an official Build Environment, therefore the automatically enabling/disabling of the FreeRTOS is not configured.

In general it is possible to configure the STM32CubeMX project without FreeRTOS as well. Then you should be able to use the CubeMX/TrueSTUDIO combination as you want.
 

Best regards,

Tim
by
Hi,

That is what I figured about the CubeMX build environment. Is it possible to poll 3 buttons and send keyboard events with the FreeRTOS? Cause when I put the code to poll the buttons, it works for a while and then the program hangs up. I was able to do this in the normal build environment without the RTOS, so I am guessing that it can't be done using the RTOS.
by
Hi,

in general it is possible to use Embedded Wizard with FreeRTOS in the same way as bare metal, even with the STM32CubeMX stand-alone project.

What exactly cause your problem with the button/GPIO is hard to estimate, without having your project.

Did you make sure that the data access to variables isn't simultaneously from two tasks?

When you are using FreeRTOS it is important to avoid simultaneously data access by using OS concepts like semaphores.

Best regards,

Tim
by
Hello,

I watched a tutorial video on semaphores. I Have a much better understanding on the topic. So I created another task to read the button inputs. I also created a semaphore. Im using a binary semaphore in both the button read task and the main GUI task. Made the button read task a lower priority than the main gui task. After building and flashing the board and observing the terminal, I do not see any output. So it looks like it never initializes. I'll continue with this tomorrow.
by
Got it working. Thanks TIm.
by

The above post was about getting a seperate thread and a semaphore working. I keep getting the same results for my project. The buttons work for awhile but then it stops responding, maybe after 8 or 9 button presses. If I pause debugging, I can see that this is where it is hanging;

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;

	__asm volatile
	(
		"	mov %0, %1												\n"	\
		"	cpsid i													\n" \
		"	msr basepri, %0											\n" \
		"	isb														\n" \
		"	dsb														\n" \
		"	cpsie i													\n" \
		:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
	);
}

/*-----------------------------------------------------------*/

Here are my interrupt handlers for the three buttons;

/**
  * @brief This function handles EXTI line2 interrupt.
  * pin 2 of GPIOI
  * button 2
  */
void EXTI2_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI2_IRQn 0 */
	btn2 = 1;
	EwPrint("Button2 interrupt\n");
  /* USER CODE END EXTI2_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
  /* USER CODE BEGIN EXTI2_IRQn 1 */

  /* USER CODE END EXTI2_IRQn 1 */
}

/**
  * @brief This function handles EXTI line[9:5] interrupts.
  * pins 7 and 6 of GPIOG
  * buttons 1 and 3
  */
void EXTI9_5_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI9_5_IRQn 0 */
    uint32_t pending = EXTI->PR;
    if(pending & (1 << 6))
    	btn3 = 1;
    if(pending & (1 << 7))
    	btn1 = 1;
  /* USER CODE END EXTI9_5_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
  /* USER CODE BEGIN EXTI9_5_IRQn 1 */

  /* USER CODE END EXTI9_5_IRQn 1 */
}

Here is code that fetches button variables located in the stm32f7xx_it.c file. 

/* USER CODE BEGIN 1 */
int Getbtn1(void)
{
	return btn1;
}

void Setbtn1(int btn)
{
	btn1 = btn;
}

int Getbtn2(void)
{
	return btn2;
}

void Setbtn2(int btn)
{
	btn2 = btn;
}

int Getbtn3(void)
{
	return btn3;
}

void Setbtn3(int btn)
{
	btn3 = btn;
}
/* USER CODE END 1 */

And finally code to check the buttons and to invoke a keyboard event. This is in the ewmain.c file. 

	if (Getbtn1() == 1) {
		EwPrint("Button 1 pressed\n");
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 1);
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 0);
		Setbtn1(0);
	}

	if (Getbtn2() == 1) {
		EwPrint("Button 2 pressed\n");
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 1);
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 0);
		Setbtn2(0);
	}

	if (Getbtn3() == 1) {
		EwPrint("Button 3 pressed\n");
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 1);
		events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 0);
		Setbtn3(0);
	}

I have tried using interrupts to read the buttons. I have used a seperate thread to read the buttons. I have scanned the button input directly from ewmain.c. They all work for a time, but then it hangs. 

Any help will be greatly appreciated. 

by
Hi there,

unfortunately your issue sounds more like a problem with the ST HAL software itself. We are also just using the ST code parts as is, even the initialisation of the GPIO.

Therefore I kindly would forward you to ST's user forum and to the CubeF examples which are really detailed about GPIO etc.

Best regards,

Tim
by

Tim,

Can you take a look at my code. Should I place the code to invoke a keyboard event in EwProcess function in ewmain? Keep in mind when I just scanned the key pad inputs in ewmain, it worked. But I was building the project without FreeRTOS. The issue I am having is the keypad will work for a period of time, and then the external interrupts stop. It hangs. When I comment out the code to envoke a keyboard event, the interrupts work just fine. 

Here is my code;

External interrupt code

/******************************************************************************/
/* STM32F7xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f7xx.s).                    */
/******************************************************************************/

/**
 * @brief This function handles EXTI line[9:5] interrupts.
 */
void EXTI9_5_IRQHandler(void) {
    /* USER CODE BEGIN EXTI9_5_IRQn 0 */
    uint32_t pending = EXTI->PR;
    BaseType_t checkIfYieldRequired;
    if (pending & (1 << 9)) {
            EwPrint("Button2 Interrupt occured\n");
            checkIfYieldRequired = xTaskResumeFromISR(Btn2TaskHandle);
            portYIELD_FROM_ISR(checkIfYieldRequired);
    }
    if (pending & (1 << 6)) {
            EwPrint("Button3 Interrupt occured\n");
            checkIfYieldRequired = xTaskResumeFromISR(Btn3TaskHandle);
            portYIELD_FROM_ISR(checkIfYieldRequired);
    }
    if (pending & (1 << 7)) {
            EwPrint("Button1 Interrupt occured\n");
            checkIfYieldRequired = xTaskResumeFromISR(Btn1TaskHandle);
            portYIELD_FROM_ISR(checkIfYieldRequired);
    }
    /* USER CODE END EXTI9_5_IRQn 0 */

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
    /* USER CODE BEGIN EXTI9_5_IRQn 1 */

    /* USER CODE END EXTI9_5_IRQn 1 */
}
 

Task code for each button in main.c. The button task are created with an osPriorityIdle priority. 

/* USER CODE BEGIN Header_StartBtn1Task */
/**
* @brief Function implementing the Btn1Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn1Task */
void StartBtn1Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn1Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem01Handle);
      EwPrint("btn1 task\n");
  }
 }

  /* USER CODE END StartBtn1Task */

/* USER CODE BEGIN Header_StartBtn2Task */
/**
* @brief Function implementing the Btn2Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn2Task */
void StartBtn2Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn2Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem02Handle);
      EwPrint("btn2 task\n");
  }
  /* USER CODE END StartBtn2Task */
}

/* USER CODE BEGIN Header_StartBtn3Task */
/**
* @brief Function implementing the Btn3Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn3Task */
void StartBtn3Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn3Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem03Handle);
      EwPrint("btn3 task\n");
  }
  /* USER CODE END StartBtn3Task */
}
 

 

Code to recieve button task semaphores in ewmain.c. 

  /* this section takes a semaphore from each external button interrupt task in the main.c file
   *
   ********************************************************************************************/
  if(xSemaphoreTake(BinarySem01Handle, 20)){
      EwPrint("button 1 pressed\n");
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 1);
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 0);
  }

  if(xSemaphoreTake(BinarySem02Handle, 20)){
      EwPrint("button 2 pressed\n");
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 1);
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 0);
  }

  if(xSemaphoreTake(BinarySem03Handle, 20)){
      EwPrint("button 3 pressed\n");
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 1);
//      events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 0);
  }

  /*
   *
   ********************************************************************************************/
 

by
I am betting it is because I am not doing any software debouncing. So I will implement this later today.
by
Hi ezed,

in general it looks good, but I have seen one thing.

It is important to know that you never call Embedded Wizard functions in the scope of two separate task. These functions are not thread safe, which means you have to avoid multiple calls from separate tasks.

Let it know me whether you implementation works now.

Best regards,

Tim
by

Hi Tim,

I take it that you mean calling the EwPrint from the button task. I took them out . I'm sad to say that it is still hanging up. It works for a little while and then hangs up.

Frustrating to say the least.

Interrupt code:

/**
 * @brief This function handles EXTI line[9:5] interrupts.
 */
void EXTI9_5_IRQHandler(void) {
    /* USER CODE BEGIN EXTI9_5_IRQn 0 */
    uint32_t pending = EXTI->PR;
    GPIO_PinState pinState;
    long taskwoken = 0;
    BaseType_t *xHigherPriorityTaskWoken;

    if (pending & (1 << 7)) {
        pinState = HAL_GPIO_ReadPin( GPIOG, GPIO_PIN_7);
        if (pinState == 1) {
            printf("Button1 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem01Handle, &taskwoken);
            if (taskwoken)
                portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);
        }
    }
    if (pending & (1 << 9)) {
        pinState = HAL_GPIO_ReadPin( GPIOF, GPIO_PIN_9);
        if (pinState == 1) {
            printf("Button2 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem02Handle, &taskwoken);
            if (taskwoken)
                portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);
        }
    }

    if (pending & (1 << 6)) {
        pinState = HAL_GPIO_ReadPin( GPIOG, GPIO_PIN_6);
        if (pinState == 1) {
            printf("Button3 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem03Handle, &taskwoken);
            if (taskwoken)
                portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);
        }
    }
    /* USER CODE END EXTI9_5_IRQn 0 */

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
    /* USER CODE BEGIN EXTI9_5_IRQn 1 */

    /* USER CODE END EXTI9_5_IRQn 1 */
}

Button task code:

/* USER CODE BEGIN Header_StartBtn1Task */
/**
* @brief Function implementing the Btn1Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn1Task */
void StartBtn1Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn1Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem01Handle);
      printf("btn1 task\n");
  }
 }

  /* USER CODE END StartBtn1Task */

/* USER CODE BEGIN Header_StartBtn2Task */
/**
* @brief Function implementing the Btn2Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn2Task */
void StartBtn2Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn2Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem02Handle);
      printf("btn2 task\n");
  }
  /* USER CODE END StartBtn2Task */
}

/* USER CODE BEGIN Header_StartBtn3Task */
/**
* @brief Function implementing the Btn3Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartBtn3Task */
void StartBtn3Task(void const * argument)
{
  /* USER CODE BEGIN StartBtn3Task */
  /* Infinite loop */
  for(;;)
  {
      vTaskSuspend(NULL);
      xSemaphoreGive(BinarySem03Handle);
      printf("btn3 task\n");
  }
  /* USER CODE END StartBtn3Task */
}
 

 

Ewmain code:

    /* this section takes a semaphore from each external button interrupt task in the main.c file
     *
     ********************************************************************************************/
    if(xSemaphoreTake(BinarySem01Handle, 0))
        btn1 = 1;
    else
        btn1 = 0;
    if (xSemaphoreTake(BinarySem02Handle, 0))
        btn2 = 1;
    else
        btn2 = 0;
    if (xSemaphoreTake(BinarySem03Handle, 0))
        btn3 = 1;
    else
        btn3 = 0;

    if(btn1 == 1){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 0);
    }
    if(btn2 == 1){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 0);
    }
    if(btn3 == 1){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 0);
    }
    /*
     *
     ********************************************************************************************/
 

 

by
This approach doesn't seem to be working. Can I just read the button inputs from ewmain process loop to keep everything in the main gui thread?

 

But first I am going declare and create three global queue's. And use xQueueSend in the button task and xQueueRecieve in ewmain. We'll see. I'll let you know.
by

My latest code. I even tried using QueueSend and QueueRecieve to send the button state value to ewmain. It still hangs up after a number of button presses. 

 

Interrupt code:

 

void EXTI9_5_IRQHandler(void) {
    /* USER CODE BEGIN EXTI9_5_IRQn 0 */
    uint32_t pending = EXTI->PR;
    GPIO_PinState pinState;
    //short xHigherPriorityTaskWoken = pdFALSE;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if (pending & (1 << 7)) {
        pinState = HAL_GPIO_ReadPin( GPIOG, GPIO_PIN_7);
        if (pinState == 1) {
            xHigherPriorityTaskWoken = pdFALSE;
            //EwPrint("Button1 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem01Handle, &xHigherPriorityTaskWoken);
            portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);
        }
    }
    if (pending & (1 << 9)) {
        pinState = HAL_GPIO_ReadPin( GPIOF, GPIO_PIN_9);
        if (pinState == 1) {
            xHigherPriorityTaskWoken = xTaskResumeFromISR(Btn2TaskHandle);
            //EwPrint("Button2 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem02Handle, &xHigherPriorityTaskWoken);
            portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);


        }
    }
    if (pending & (1 << 6)) {
        pinState = HAL_GPIO_ReadPin( GPIOG, GPIO_PIN_6);
        if (pinState == 1) {
            xHigherPriorityTaskWoken = xTaskResumeFromISR(Btn3TaskHandle);
            //EwPrint("Button3 Interrupt occured\n");
            xSemaphoreGiveFromISR(BinarySem03Handle, &xHigherPriorityTaskWoken);
            portYIELD_FROM_ISR(&xHigherPriorityTaskWoken);

        }
    }
    /* USER CODE END EXTI9_5_IRQn 0 */

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
    /* USER CODE BEGIN EXTI9_5_IRQn 1 */

    /* USER CODE END EXTI9_5_IRQn 1 */
}
 

Button task code:

 

/**
 * @brief Function implementing the Btn1Task thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartBtn1Task */
void StartBtn1Task(void const * argument) {
    const TickType_t xBlockTime = pdMS_TO_TICKS(200);
    /* USER CODE BEGIN StartBtn1Task */
    /* Infinite loop */
    int32_t btn1;
    for (;;) {
        if(xSemaphoreTake(BinarySem01Handle, LONG_TIME) == pdTRUE)
        {
            btn1 = 1;
            //EwPrint("Button 1 task\n");
            xQueueSend(button1Queue, &btn1, xBlockTime);
        }
    }
}

/* USER CODE END StartBtn1Task */

/* USER CODE BEGIN Header_StartBtn2Task */
/**
 * @brief Function implementing the Btn2Task thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartBtn2Task */
void StartBtn2Task(void const * argument) {
    //QueueHandle_t Btn2Queue;
    int32_t btn2;
    const TickType_t xBlockTime = pdMS_TO_TICKS(200);
    /* USER CODE BEGIN StartBtn2Task */
    /* Infinite loop */
    for (;;) {
        if(xSemaphoreTake(BinarySem02Handle, LONG_TIME))
        {
            btn2 = 1;
            //EwPrint("Button 1 task\n");
            xQueueSend(button2Queue, &btn2, xBlockTime);
        }
    }

    /* USER CODE END StartBtn2Task */
}

/* USER CODE BEGIN Header_StartBtn3Task */
/**
 * @brief Function implementing the Btn3Task thread.
 * @param argument: Not used
 * @retval None
 */
/* USER CODE END Header_StartBtn3Task */
void StartBtn3Task(void const * argument) {
    //QueueHandle_t Btn3Queue;
    int32_t btn3;

    const TickType_t xBlockTime = pdMS_TO_TICKS(200);
    /* USER CODE BEGIN StartBtn3Task */
    /* Infinite loop */
    for (;;) {
        if(xSemaphoreTake(BinarySem03Handle, LONG_TIME))
        {
            btn3 = 1;
            //EwPrint("Button 1 task\n");
            xQueueSend(button3Queue, &btn3, xBlockTime);
        }
    }
    /* USER CODE END StartBtn3Task */
}
 

EwProcess code:

 

    /* this section takes a semaphore from each external button interrupt task in the main.c file
     *
     *
     ********************************************************************************************/
    xQueueReceive(button1Queue, &button_1, xBlockTime);
    if (button_1 == 1) {
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0,    1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0,    0);
        button_1 = 0;
    }
    xQueueReceive(button2Queue, &button_2, xBlockTime);
    if (button_2 == 1) {
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 0);
        button_2 = 0;
    }
    xQueueReceive(button3Queue, &button_3, xBlockTime);
    if (button_3 == 1) {
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 0);
        button_3 = 0;
    }
    /*
     *
     ********************************************************************************************/
 

All three of my button task are created with a priority of osPriorityIdle.

by
Hello,

maybe you can make it very simple: Just use a volatile variable (named as "KeyCode") to make the communication between your button interrupt routine and the main loop.

Once the button is pressed, you can set the corresponding KeyCode. The main loop is more or less unchanged - just read the KeyCode and forward it to the GUI application. Then the KeyCode is cleared.

Does this work without any troubles?

Best regards,

Manfred.
by

Manfred,

I tried this. I added a volatile int KeyCode in the ewmain.h file. It works great for a number of button presses but eventually hangs up the program just as before. This is driving me crazy! I am using the CubeMX_with_EmbeddedWizard build environment. 

 

Here is my interrupt code:

void EXTI9_5_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI9_5_IRQn 0 */
    if (__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_7)) {
        KeyCode = 1; // button 1 pressed
    }
    if (__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_9)) {
        KeyCode = 2; // button 2 pressed
    }
    if (__HAL_GPIO_EXTI_GET_FLAG(GPIO_PIN_6)) {
        KeyCode = 3; // button 3 pressed
    }

  /* USER CODE END EXTI9_5_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_9);
  /* USER CODE BEGIN EXTI9_5_IRQn 1 */

  /* USER CODE END EXTI9_5_IRQn 1 */
}
 

 

EwProcess code:

  if(KeyCode == 1){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeEnd, 0, 0);
        KeyCode = 0;
  }
  if(KeyCode == 2){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodeDown, 0, 0);
        KeyCode = 0;
  }
  if(KeyCode == 3){
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 1);
        events |= CoreRoot__DriveKeyboardHitting(RootObject, CoreKeyCodePageDown, 0, 0);
        KeyCode = 0;
  }
 

 

Would it be possible to send you the EmbeddedWizard project and the TrueStudio project? I have tried so many things but I keep getting this issue. This app worked fine when I was building it with the batch file in the STM32F746-Discovery build environment with FreeRTOS disabled! I was polling the buttons in the EwProcess loop. Yes, I did try polling with the CubeMX and TrueStudio build environment with the same results, it hanging up.

by
O.k., when the application runs fine in case of compiling it with GCC, then it seems to be not an issue with the GUI application or your code.

Can you check the stack settings and ensure that there is no stack corruption?

Best regards,

Manfred.
by

The main GUI thread is set to 1280.

  /* Create the thread(s) */
  /* definition and creation of EwThreadHandle */
  osThreadDef(EwThreadHandle, GuiThread, osPriorityNormal, 0, 1280);

 

Looking at the call graph in stack analyser I do not see any function that requires over 736 bytes of stack. I do see one fuction that is recursive that has aa question mark near it. This is the ADC_IRQHandler. What is this used for? I am not using a touch screen. Maybe this is the culprit!

by
Does it run stable when you remove the ADC_IRQ handler? There is no need for that from GUI point of view.
by
I haven't tried that yet as I wanted to make sure that it wasn't needed. I will try it out later and let you know. Last night I built the same app using the console/batch file STM32F746 Discovery build environment but without FreeRTOS. It runs fine.
by

The ADC_IRQHandle was just part of the interrupt vector table in the startup file. The interrupt was not enabled. i wanted to determine if it was FreeRTOS that was causing the hangup issue, so I built the same app with the console/batch file STM32F746 Discovery build environment without FreeRTOS and it worked fine. So it seems my program will not work with FreeRTOS which means I can not use CubeMX and TrueStudio.

 

Also, when I run it in the debugger, when the program locks up after so many button presses, I pause the debugger to see where it is hanging. It is always here:

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;

    __asm volatile
    (
        "    mov %0, %1                                                \n"    \
        "    cpsid i                                                    \n" \
        "    msr basepri, %0                                            \n" \
        "    isb                                                        \n" \
        "    dsb                                                        \n" \
        "    cpsie i                                                    \n" \
        :"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
    );
}
 

 

Any ideas. I am new to FreeRTOS. 

by

I have given up on trying to get my app to work properly with CubeMX and TrueStudio. I'm convinced that the app is just not going to work with FreeRTOS. 

So on another note...

I recieved an email today from ST saying that TrueSTUDIO development was discontinued and that STM32CubeIDE is the recommended ST developed IDE for STM32 development. So I am trying out STM32CubeIDE. I tried building my project with this IDE. I followed Tim's post on how to import a TrueStudio project into the STM32CubeIDE. Eveything went smooth. I built my project with no errors, and flashed it to the STM32F746 Discovery board, but I am not seeing the the horizontal value bars, the bitmaps, or text on the screen. It's like the GUI library is missing. Any ideas. I'm sure it's something simple. 

Picture of the screen built with STM32CubeIDE:

Picture of screen built with Command line:

 

by
Are there any messages on the console window? I assume there are error messages helping us to find the reason...
by
Yes,

This is the console output:

---------------------------------------------
Initialize Display...                        [OK]
Initialize Touch Driver...                   EwBspTouchInit: Initialization of FT5336 failed
[OK]
Initialize Memory Manager...                 [OK]
Initialize Graphics Engine...                [OK]
Create Embedded Wizard Root Object...        EMWI ERROR: code: 321
For details please visit https://doc.embedded-wizard.de/errors
[OK]
Create Embedded Wizard Viewport...           [OK]
---------------------------------------------
Target system                                STM32F746-Discovery
Color format                                 RGB888
MemoryPool address                           0xC003D860
MemoryPool size                              7884608 bytes
Framebuffer address                          0xC0000000
Doublebuffer address                         0xC07C27A0
Framebuffer size                             350 x 240
EwScreeenSize                                350 x 240
Graphics accelerator                         DMA2D
Vector graphics support                      enabled
Warp function support                        enabled
Index8 bitmap resource format                enabled
RGB565 bitmap resource format                enabled
Bidirectional text support                   enabled
Operating system                             none
External flash device                        QSPI Flash
Linker section for bitmap pixel data         .SectionEwResource
Linker section for font pixel data           .SectionEwResource
Toolchain                                    GCC
C-Compiler version                           7.3.1
Build date and time                          Mar 17 2020, 22:58:33
Runtime Environment (RTE) version            9.30
Graphics Engine (GFX) version                9.30
Max surface cache size                       4194304 bytes
Glyph cache size                             256 x 256
Max issue tasks                              100
Surface rotation                             0
---------------------------------------------
EMWI ERROR: code: 321
For details please visit https://doc.embedded-wizard.de/errors
EMWI ERROR: code: 321
For details please visit https://doc.embedded-wizard.de/errors
EMWI ERROR: code: 321
For details please visit https://doc.embedded-wizard.de/errors
EMWI ERROR: code: 321
For details please visit https://doc.embedded-wizard.de/errors
System halted! [HardFault_Handler]

 

My app works when I build it from the command line. One thing I notice is that there is two different GCC compiler versions. The command line one uses a newer version of the GCC compiler. 8.3.1 compared to 7.3.1.

Console output from command line build:

nitialize Display...                        [OK]
Initialize Touch Driver...                   Initialize Memory Manager...                 [OK]
Initialize Graphics Engine...                [OK]
Create Embedded Wizard Root Object...        [OK]
Create Embedded Wizard Viewport...           [OK]
---------------------------------------------
Target system                                STM32F746-Discovery
Color format                                 RGB888
MemoryPool address                           0xC003D860
MemoryPool size                              7884608 bytes
Framebuffer address                          0xC0000000
Doublebuffer address                         0xC07C27A0
Framebuffer size                             350 x 240
EwScreeenSize                                350 x 240
Graphics accelerator                         DMA2D
Vector graphics support                      enabled
Warp function support                        enabled
Index8 bitmap resource format                enabled
RGB565 bitmap resource format                enabled
Bidirectional text support                   enabled
Operating system                             none
External flash device                        QSPI Flash
Linker section for bitmap pixel data         .SectionEwResource
Linker section for font pixel data           .SectionEwResource
Toolchain                                    GCC
C-Compiler version                           8.3.1
Build date and time                          Mar 18 2020, 19:03:43
Runtime Environment (RTE) version            9.30
Graphics Engine (GFX) version                9.30
Max surface cache size                       8388608 bytes
Glyph cache size                             256 x 256
Max issue tasks                              100
Surface rotation                             0
---------------------------------------------
by
This error indicates that the resources cannot be loaded... There must be something going wrong with flashing the application. So far I did not try the STM32CubeIDE.

Can you try to flash the entire application (created with STM32CubeIDE) by using ST-LINK utility (same as in case of GCC/make). Maybe the QSPI flash is not programmed correctly.

Btw: Why does the intializtation of the touch driver not work?

Best regards,

Manfred.
by
Thanks for the reply. I will try this.

FYI, the same thing happens when I build it with TrueSTUDIO.

 

I commented out the touch screen lines as we are not using a touch screen.
by
When I use the st-link utility to program the board, I get the following:

09:51:30 : No elf loader found for this operation.
by
I fixed it, I had to add an external loader to the st-link utility. Now I have to figure out why I can't do it from TrueSTUDIO.
by
Does the application run correctly after flashing it via ST-LINK utility?
by
Oops, I didn't have the right loader set in TrueSTUDIO! It's working.

Question: Should I continue to use TrueSTUDIO, or should I switch to STM32CubeIDE?

Thanks for helping me find this issue. It was driving me crazy!
by
Yes it does! Thanks very much for the help.
by
Tim,

Where is the file, ew_bsp_serial.c/.h? I don't see these files in the build environment!
by
Meanwhile these files are renamed to ew_bsp_console.c/.h - but same (similar) content.

Best regards,

Manfred.
by
Thanks,

What about using the USB OTG full speed communications on the STM32F746G Discovery board? Is this part of the framework?
by
Hi,

Embedded Wizard is a GUI solution and does not provide an USB stack... Please have a look to the examples and documents provided by ST.

Best regards,

Manfred.

Ask Embedded Wizard

Welcome to the question and answer site for Embedded Wizard users and UI developers.

Ask your question and receive answers from the Embedded Wizard support team or from other members of the community!

Embedded Wizard Website | Privacy Policy | Imprint

...