2021-11-11 11:01 PM
Hi,
I have spent three days trying to put some real-time FIR filters into ITCM to speed things up.
I have been able to allocate the functions, copy the code from flash to ITCM in the start-up file, but when I run the system the ITCM memory gets changed for no apparent reason. If I single step through the parts where the ITCM memory changes, it doesn't change.
The functions work the first time through, but as the code is corrupted processor registers aren't initialized properly so I get hard faults.
The only working example I can find is one ported to Keil uVision which uses scatter files, much easier than that abominable gcc linker script.
I would post the results of my efforts, but that will take another day and I'm fed up with it.
I would just love to see a working example developed under STM32CubeIDE.
My functions are simple, self contained no input parameters. It shouldn't be hard. It isn't with uVision.
Can anyone help?
Best regards
Rob
Solved! Go to Solution.
2021-11-13 02:17 AM
Rob,
Which STM32?
If hospi->Instance is zero, it means it hasn't been properly initialized previously. So walk back in your code (and Cube now forms part of your code), find out how hopsi is defined and how is it initialized and find out why is hospi->Instance zero.
I don't know about RTOS, I don't use it.
JW
2021-11-12 01:24 AM
Which STM32?
You can try to place a data breakpoint (watchpoint) to some of the areas you are suspecting to change, that would reveal the culprit which overwrites it.
JW
2021-11-12 07:12 AM
If it works once, sounds like you got it working, you just need to figure out where and why the rogue memory write is happening and fix it.
Some other leads here:
2021-11-12 05:30 PM
Hi Jan
Thanks for your prompt response.
I took your advice and set up a couple of trace points at memory addresses 0x8 and 0x4.
Instead of running the functions in ITCM I left them in flash and put a pattern of 0x40 words in the ITCM starting at zero. (0xFAFAFBFB)
I then ran without break points and found that there were writes being made to the ITCM ram.
The first write was made by the ospi deinit:
The second by freeRTOS vTaskSwitchContext function:
Looking at the disassembly first of these the, ospi de init we get:
You can see that the next instruction:
0801749a: str r2, [r3, #8]
will set the ITCM ram addr. to 0xFAFAFBF9
Which it does:
This looks a lot like a naughty stack problem. What do you think?
Th problem with this line of thinking is that the operating system scheduler isn't running when the ospi initialisation is running as this is executed at startup. So stack usage shouldn't be very high.
I will have a look at what the stack is doing.
Any futher thoughts?
Best regards
Rob
2021-11-13 02:17 AM
Rob,
Which STM32?
If hospi->Instance is zero, it means it hasn't been properly initialized previously. So walk back in your code (and Cube now forms part of your code), find out how hopsi is defined and how is it initialized and find out why is hospi->Instance zero.
I don't know about RTOS, I don't use it.
JW
2021-11-13 03:56 PM
Hi
I found the answer to the overwriting problem. The two areas which were overwriting the ITCM ram were the Octo Spi Initialization function for the discovery board STM32H7B3I-DK and the uxListRemove of FreeRTOS.
The first of these was:
static void MX_OCTOSPI1_Init(void)
{
/* USER CODE END OCTOSPI1_Init 1 */
/* OCTOSPI1 parameter configuration*/
hospi1.Instance = OCTOSPI1;
hospi1.Init.FifoThreshold = 1;
hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;
...
hospi1.Init.MaxTran = 0;
hospi1.Init.Refresh = 0;
if (HAL_OSPI_Init(&hospi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN OCTOSPI1_Init 2 */
BSP_OSPI_NOR_Init_t Flash;
Flash.InterfaceMode = BSP_OSPI_NOR_OPI_MODE;
Flash.TransferRate = BSP_OSPI_NOR_DTR_TRANSFER;
hospi_nor->Instance = hospi1.Instance; /* rjg mod */
BSP_OSPI_NOR_DeInit(0);
int32_t RetVal = BSP_OSPI_NOR_Init(0, &Flash);
if(RetVal != BSP_ERROR_NONE)
{
Error_Handler();
}
RetVal = BSP_OSPI_NOR_EnableMemoryMappedMode(0);
if(RetVal != BSP_ERROR_NONE)
{
Error_Handler();
}
/* USER CODE END OCTOSPI1_Init 2 */
}
The programmer creates a new handle for the ospi driver called hospi_nor, but doesn't initialize it to the hardware instance of the actual peripherals memory locations. The sequence is:
BSP_OSPI_NOR_DeInit(uint32_t Instance) below calls
if (HAL_OSPI_DeInit(&hospi_nor[Instance]) != HAL_OK). Line 34.
/**
* @brief De-Initializes the OSPI interface.
* @param Instance OSPI Instance
* @retval BSP status
*/
int32_t BSP_OSPI_NOR_DeInit(uint32_t Instance)
{
int32_t ret = BSP_ERROR_NONE;
/* Check if the instance is supported */
if(Instance >= OSPI_NOR_INSTANCES_NUMBER)
{
ret = BSP_ERROR_WRONG_PARAM;
}
else
{
/* Disable Memory mapped mode */
if(Ospi_Nor_Ctx[Instance].IsInitialized == OSPI_ACCESS_MMP)
{
if(BSP_OSPI_NOR_DisableMemoryMappedMode(Instance) != BSP_ERROR_NONE)
{
ret = BSP_ERROR_COMPONENT_FAILURE;
}
}
if(ret == BSP_ERROR_NONE)
{
/* Set default Ospi_Nor_Ctx values */
Ospi_Nor_Ctx[Instance].IsInitialized = OSPI_ACCESS_NONE;
Ospi_Nor_Ctx[Instance].InterfaceMode = BSP_OSPI_NOR_SPI_MODE;
Ospi_Nor_Ctx[Instance].TransferRate = BSP_OSPI_NOR_STR_TRANSFER;
#if (USE_HAL_OSPI_REGISTER_CALLBACKS == 0)
OSPI_NOR_MspDeInit(&hospi_nor[Instance]);
#endif /* (USE_HAL_OSPI_REGISTER_CALLBACKS == 0) */
/* Call the DeInit function to reset the driver */
if (HAL_OSPI_DeInit(&hospi_nor[Instance]) != HAL_OK)
{
ret = BSP_ERROR_PERIPH_FAILURE;
}
}
}
/* Return BSP status */
return ret;
}
if (HAL_OSPI_DeInit(&hospi_nor[Instance]) != HAL_OK) this calls macro
CLEAR_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK); Line 17 below.
HAL_StatusTypeDef HAL_OSPI_DeInit(OSPI_HandleTypeDef *hospi)
{
HAL_StatusTypeDef status = HAL_OK;
/* Check the OSPI handle allocation */
if (hospi == NULL)
{
status = HAL_ERROR;
/* No error code can be set set as the handler is null */
}
else
{
/* Disable OctoSPI */
__HAL_OSPI_DISABLE(hospi);
/* Disable free running clock if needed : must be done after OSPI disable */
CLEAR_BIT(hospi->Instance->DCR1, OCTOSPI_DCR1_FRCK);
as hospi_nor isn't initialized the clear bit macro accesses the ITCM address at offset #4.
I don't know what the programmer was trying to achieve and I didn't want to break working? code so I added the line:
hospi_nor->Instance = hospi1.Instance; /* rjg mod */
This sets the hospi_nor.Instance to the correct peripheral address.
The second area overwriting was the uxListRemove function of the FreeRTOS lists module.
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in. Obtain the list from the list
item. */
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
...
}
Lines 7 and 8 were the lead in the saddlebags here. The cause was twofold first I had executed a task suspend before starting the scheduler and secondly i used taskSuspend on a sw timer rather than timerStop. This causes the uxTaskRemove function to behave badly and corrupt the ITCM.
Fixing my two errors stopped the problem, but I could see the same thing happening again. To prevent writing to the ITCM ram program area I invoked the MPU after copying the code from flash to ram. I set the MPU for this ram to read only so if I inadvertently try to write to it I will get a memory fault which is a lot safer than if the program soldiers on with bad code in the ITCM.
It was all worth it as my critical functions with compiler optimization on only take 190 us compared to 500 us before.
Just to help others my startup code and linker script are attached.
and my function calls are:
__attribute__((section(".Tim2itcm"))) void PositionFilter_step(void)
{
...
}
__attribute__((section(".Tim2itcm"))) void impulseCurveFit_step(void)
{
...
}
etc.
Anyway guys thanks for your help.
Best regards
Rob
2021-11-17 08:01 PM
Hi Jan,
Trouble is it's not my code, its a driver written by ST for the Tiny Shark Octi SPI and like a lot of this code it hasn't been tested all that well. I will have to rewrite it and simplify it at some stage, but I don't have the time right now, so I've set the handles instance to the hw instance.