2023-05-04 05:34 AM - edited 2023-11-20 06:28 AM
Hello,
I am about to improve the execution speed of an existing code base on a NUCLEO-H743ZI2 board.
So far, I have the following memory setup:
Instruction Memory:
Data Memory:
My program with the above setup works fine.
Now I want to check whether enabling the D-Cache can actually further improve execution speed. My intention is, to use this Cache solely for a faster reading/processing of the DMA-Buffers in AXI_SRAM. Their reading happens upon a DMA half- or full-complete interrupt and the D-Cache is always invalidated before accessing any DMA-Buffer data. SRAM1 stays non-cacheable.
This is my new setup:
Instruction Memory:
Data Memory:
MPU:
Here I am facing a weird problem.
When I download the program to the nucleo, it often does not start and instead goes to the error handler. However, when I press the reset button a couple of times, it suddenly starts and runs perfectly fine.
Has anybody faced a similar problem? Can somebody help me debugging?
Solved! Go to Solution.
2023-05-05 02:38 AM
I think I found the problem now! The reason for the Error Handler lies in this section of Code that is called by MX_USB_OTG_FS_PCD_Init().
/**
* @brief Reset the USB Core (needed after USB clock settings change)
* @param USBx Selected device
* @retval HAL status
*/
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
uint32_t count = 0U;
/* Wait for AHB master IDLE state. */
do
{
if (++count > 200000U)
{
return HAL_TIMEOUT; /* This timeout causes Error_Handler() when building in release mode */
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
/* Core Soft Reset */
count = 0U;
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
do
{
if (++count > 200000U)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
return HAL_OK;
}
Apparently the counter value increases much faster when building in release mode (-ofast) and when D/I-Caches + D/I-TCMs are used in addition.
Increasing the counter threshold from 200'000 to 400'000'000 fixed the problem.
Now everything works perfectly fine :)
Is there somewhere a bug report portal where I can report this?
2023-05-04 05:55 AM
Hello,
First try to disable the access to non valid memory regions using MPU:
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* Disable the MPU */
HAL_MPU_Disable();
/* Configure the MPU as Strongly ordered for not defined regions */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x00;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enable the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
and add your MPU regions after.
2023-05-04 07:56 AM
Thank you for your answer. Unfortunately, the problem remains.
This is my MPU config now:
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.SubRegionDisable = 0x0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.BaseAddress = 0x30000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_128KB;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
I have removed anything from main now, such that just an LED is going to blink:
int main(void)
{
/* USER CODE BEGIN 1 */
SCB_CleanInvalidateDCache();
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* 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();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ETH_Init();
MX_USART3_UART_Init();
MX_USB_OTG_FS_PCD_Init();
MX_SPI1_Init();
MX_SPI3_Init();
MX_SPI4_Init();
MX_I2C1_Init();
MX_I2C2_Init();
MX_I2C4_Init();
MX_SPI2_Init();
MX_SPI5_Init();
MX_UART4_Init();
MX_UART5_Init();
MX_UART7_Init();
MX_USART2_UART_Init();
MX_USART6_UART_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_ADC3_Init();
MX_DAC1_Init();
MX_TIM1_Init();
MX_TIM6_Init();
MX_TIM15_Init();
MX_TIM7_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
cnt++;
if (cnt > 60000000) {
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
cnt = 0;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
It seems, that I cannot reproduce the problem when building in debug mode.
In release mode (-ofast) the problem remains. Most of the time, I end up in the error handler but sometimes it works.
2023-05-05 02:38 AM
I think I found the problem now! The reason for the Error Handler lies in this section of Code that is called by MX_USB_OTG_FS_PCD_Init().
/**
* @brief Reset the USB Core (needed after USB clock settings change)
* @param USBx Selected device
* @retval HAL status
*/
static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
uint32_t count = 0U;
/* Wait for AHB master IDLE state. */
do
{
if (++count > 200000U)
{
return HAL_TIMEOUT; /* This timeout causes Error_Handler() when building in release mode */
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
/* Core Soft Reset */
count = 0U;
USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;
do
{
if (++count > 200000U)
{
return HAL_TIMEOUT;
}
} while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
return HAL_OK;
}
Apparently the counter value increases much faster when building in release mode (-ofast) and when D/I-Caches + D/I-TCMs are used in addition.
Increasing the counter threshold from 200'000 to 400'000'000 fixed the problem.
Now everything works perfectly fine :)
Is there somewhere a bug report portal where I can report this?
2023-05-05 03:34 AM
Hello,
Is it possible to declare the counter as volatile __IO uint32_t count and tell us if it does fix the issue?
2023-05-05 04:28 AM
Yes changing the variable from uint32_t to volatile __IO uint32_t and leaving the counter threshold at 200'000 works too.
2023-05-05 05:54 AM
To avoid changing the ST library, maybe better is to make a small change in the user code.
Instead of the (lame) counter, check for timeout in ms, which is independent of clock rate and cache (need to test and find the max. required time).
HAL_StatusTypeDef st;
for (unsigned n=10; n > 0; n--) {
st = USB_CoreInit(....);
if (st == OK) break;
HAL_Delay(1);
}
if (st != HAL_OK) {
// fail
}