on
2023-05-22
08:10 AM
- edited on
2023-08-17
12:12 AM
by
Laurids_PETERSE
The following article is part 1/2. In part 2, we briefly discuss how you can easily export your STM32 project to different STM32 series using the “List Pinout Compatible MCUs” option in the STM32CubeMX. Furthermore, part 2 also includes troubleshooting with the STM32F4.
To view part 2, click here.
STM32 ioc files created using STM32CubeMX can streamline development and can abstract away all the tedious low-level configurations of the STM32 peripherals. However, the problem is that older STM32Cube firmware projects on the older boards lack this “ioc” configuration file. In this article, you get a walk through converting the old STM32 project, without the ioc file, to a more modern project containing the ioc file. In part 2 of the article, we briefly discuss how you can easily export your STM32 project to different STM32 series using the “List pinout compatible MCUs” option in the STM32CubeMX. If you get stuck at any point during the process, refer to the link section for the completed project [5].
Pick an example that has no ioc file. For this example, we pick the digital-to-analog converter (DAC) signal generation example on the STM32F4DISCOVERY. The good news is that you can easily generalize the process to any STM32 series and example projects.
The example code can be downloaded and accessed inside the STM32CubeF4 MCU firmware package:
STM32F4 cube package examples [1]
Alternatively, you can also easily access the example through STMicroelectronics’s GitHub page:
STM32F4 example signal generation GitHub page [2]
Before attempting to recreate the project, we should understand the expected output of the example project running on our MCU. According to the “readme.txt” of the “DAC_SignalsGeneration” example, the waveform will be generated on the PA4. Moving on, the user button will be used to select between the different waveforms (triangular or escalator). Also keep the DAC chapter in the STM32F407 reference manual RM0090 [6] handy as you walk through the original source code. This helps you understanding the configurations shown in the helper functions “DAC_Ch1_TriangleConfig” and “DAC_Ch1_EscalatorConfiging. It can also be helpful to reference any related application notes for the peripheral we are working with: For our example, we can reference the application note AN3126 [3]. To gain a good understanding of the project output, begin by running the original project without the ioc file and use your oscilloscope for measuring. Make the measurements at the pin PA4. Depending on whether the variable “ubSelectedWavesForm” is set to 1 or 0, you observe either a triangular wave generation (figure 1) or a custom wave (the escalator like waveform output in figure 2).
Figure 1 is easily generated using the dedicated HAL API “HAL_DACEx_TriangleWaveGenerate” (UM1725 [7]). Also, refer to the triangular wave generator section in the MCU reference manual or refer to the DAC application note. Figure 2 is generated using DAC_Ch1_EscalatorConfig. Regarding figure 2, we create a custom waveform using an array of numbers then transfer the data to the DAC using the DMA peripheral. For more details on how to generate a custom waveform, refer to the application examples in AN3126. Similar to the DAC_SignalsGeneration example, we use the timer 6 for triggering the DMA transfer and for triggering the DAC steps. The frequency of the signal is related to the frequency of the trigger source (timer 6 in our case).
Next, we use the “DAC_SignalsGeneration” main.c source file as a reference for creating our ioc project: STM32CubeF4/Projects/STM32F4-Discovery/Examples/DAC/DAC_SignalsGeneration/Src/main.c [4].
Create an empty STM32CubeMX project based on the STM32F4DISCOVERY like shown in figure 3:
Next, we transfer the DAC configurations shown in the helper function DAC_Ch1_EscalatorConfig to the STM32CubeMX. For example, referring to figure 4, line 195, the trigger source is timer 6. We transfer these settings to the STM32CubeMX interface as shown in figure 6.
Both escalator and triangle wave functions shown in figure 4 and 5 share some common DAC configurations. For our new project, based on the STM32CubeMX ioc configuration, we make some improvements to the code. Feel free to improve any of the code shown here, if you want. For example, we remove the old duplicate configuration code and use the “MX_DAC1_Init()” instead. You can also observe this in the attached project files.
In figure 5, pay attention to the content for the variables inside the “DAC_ChannelConfTypeDef” structure (“sConfig”). As another example, line 228 indicates that the output buffer must be enabled (as we do in figure 6). This gives you clues on the DAC settings that need to be configured in the STM32CubeMX interface.
Figure 7 shows the DMA configuration inside the “HAL_DAC_MspInit” located inside the “stm32f4xx_hal_msp.c” file.
We transfer the DMA configuration to our ioc file shown in figure 8. Line 94 in figure 7 also shows we must enable the interrupt. This is done for us automatically by the STM32CubeMX, as shown in figure 9.
For figure 10, we arrive at the configuration for the general-purpose hardware timer on the STM32. Lines 288-291 and line 295 from figure 10 is transferred to the timer configuration window shown in figure 11. Timer 6 interrupts are not enabled, as shown in figure 12.
Finally, we transfer the system clock configuration shown in figure 13 into the ioc clock tree shown in figure 14 and 15. In figure 14, we select the HSE crystal resonator as the fundamental clock source for our system (as shown on line 144 of figure 13).
Note: at this point, make sure to save your STM32CubeMX ioc project and generate the code before proceeding.
Before reproducing the output of the original project, do the following: Transfer some of the logic code from the old main.c to our new main.c in the project space with the ioc file.
Please note: you cannot simply copy and paste the main.c. If this is done, you only transfer the DAC related logic over into your new project - refer to the sample main.c inside the solution project [5] provided.
Do not copy the BSP routines into your new project. As seen in the main.c of the project solution, we made some minor changes. For example, we removed some of the duplicate DAC configuration code and instead used the generated "MX_DAC_Init()" call inside of the "DAC_Ch1_EscalatorConfig(void)" routine. As another example, observe the differences between this snippet of original source code for "DAC_Ch1_EscalatorConfig" and the modified version in our new project:
Original source code for one of the routines:
static void DAC_Ch1_EscalatorConfig(void)
{
/*##-1- Initialize the DAC peripheral ######################################*/
if(HAL_DAC_Init(&DacHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/*##-1- DAC channel1 Configuration #########################################*/
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if(HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL1) != HAL_OK)
{
/* Channel configuration Error */
Error_Handler();
}
/*##-2- Enable DAC Channel1 and associated DMA #############################*/
if(HAL_DAC_Start_DMA(&DacHandle, DACx_CHANNEL1, (uint32_t*)aEscalator8bit, 6, DAC_ALIGN_8B_R) != HAL_OK)
{
/* Start DMA Error */
Error_Handler();
}
}
Our modified routine inside our new project:
static void DAC_Ch1_EscalatorConfig(void)
{
MX_DAC1_Init();
/*##-2- Enable DAC Channel1 and associated DMA #############################*/
if(HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1, (uint32_t*)aEscalator8bit, 6, DAC_ALIGN_8B_R) != HAL_OK)
{
/* Start DMA Error */
Error_Handler();
}
}
For observing the result, you need at least a single oscilloscope channel attached to pin PA4. After compiling the code (see the attachment for the full project) and executing the code on the evaluation board, you should observe the following signal output shown in figure 16 and 17.
Click here to enter part 2 of the article, explaining this issue.