cancel
Showing results for 
Search instead for 
Did you mean: 

M4 Coprocessor (of MP15xx) DMA SPI4 example stays in "busy" state after first transmission

EOF
Associate II

Hello,

I'd like to setup a DMA transfer to feed a SPI Display with 8192 bytes per DMA cycle. To offload the MP1 I want to do this with the help of the M4 coprocessor. For my tests I am using the CubeIDE and a custom board. As a basis for learning I tried the example "SPI_FullDuplex_ComDMA_Master". The example (FW_MP1_V1.6.0) itself waits for a keypress and then starts exactly one DMA transfer, I can see the clock pulses on the scope.

Since I need a peridoc refresh of the display, I tried as an experiment to wrap a simple loop together with a delay around the DMA-Send section but for some reason the DMA does not repeat, it gets stuck in a

hspi->State = HAL_SPI_STATE_BUSY_TX_RX

state and the error handler is called.

 

 

while(1)
{
  if(HAL_SPI_TransmitReceive_DMA(&hspi4, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_Delay(50);
}

 

Why is the "DMA-in-a-loop" not working?

I can increase the time to HAL_Delay(1000) but that makes no difference. Any idea?

4 REPLIES 4
STea
ST Employee

Hello @EOF ,

Before starting a new communication transfer, you must wait the callback call to get the transfer complete confirmation or an error detection.
for this you need to trigger a flag and test on it before starting a new transfer in the callback of transfer complete. Here is an example:
 
 
enum {
  TRANSFER_WAIT,
  TRANSFER_COMPLETE,
  TRANSFER_ERROR
};
__IO uint32_t wTransferState = TRANSFER_WAIT;
while(1)
{
if(HAL_SPI_TransmitReceive_DMA(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE) != HAL_OK)
  {
    /* Transfer error in transmission process */
    Error_Handler();
  }
  while (wTransferState == TRANSFER_WAIT)
  {
  }
}

//callback 
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
  /* Turn LED1 on: Transfer in transmission process is complete */
  BSP_LED_On(LED1);
  /* Turn LED2 on: Transfer in reception process is complete */
  BSP_LED_On(LED2);
  wTransferState = TRANSFER_COMPLETE;
}

BR

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
EOF
Associate II

Hello S Tea.

Yes, I know about the concept of the "HAL_SPI_TxRxCpltCallback", actually it is part of the SPI example. But it should also work without using the callback. The transfer takes around 2ms of time and the delay of 50ms is far enough time for the previous DMA to be finished before another one fires. Still you are right, this is the way it should be done.

But actually after a reboot of Linux and then a download "through Linux core" without any breakpoints it is working with the code I posted for an infinit time. But after changing code, add / remove breakpoints suddenly things become worse and as a result the example is not working anymore. Code changes do not help, as well as removing all breakpoints, repeating downloads...

What I can say "for sure" is, that in the "bad" situation the SysTick, though it is counting up in the processor register (STCVR), does not trigger the "void SysTick_Handler(void)" anymore. So all functions that rely on the HAL ticker will fail, I guess. There seems not to be any kind of remedy for this apart from issuing a "reboot" command in the Linux shell. After the reboot (not power off) the system runs again well until I start again making changes.

Actually I doubt my environment. Could be something with my Linux image for openAMP. A typical output is:

INIT: Id "STM1" respawning too fast: disabled for 5 minutes
INIT: Id "STM2" respawning too fast: disabled for 5 minutes
[ 46.008109] remoteproc remoteproc0: powering up m4
[ 46.017179] remoteproc remoteproc0: Booting fw image SPI_FullDuplex_ComDMA_Master_CM4.elf, size 2344144
[ 46.025168] remoteproc remoteproc0: header-less resource table
[ 46.031117] remoteproc remoteproc0: no resource table found for this firmware
[ 46.038286] remoteproc remoteproc0: header-less resource table
[ 46.043892] remoteproc remoteproc0: remote processor m4 is now up

Thank you S Tea for your effort, if you have any ideas (or a minimal working openAMP Linux image), please tell me (I read about users who report also problems with the "SysTick") but I understand that it is hard for you to help me in my somewhat complex environment.

STea
ST Employee

Hello @EOF ,

Clearly I can't get all your changes and configuration with your Linux image but if it is impacting your systick we can bypass this by choosing another Timebase to be used for the HAL like Tim2 for example.

take a look to see how this can be done in UM1718 Example of configuration using TIM2 as HAL timebase source.

if it is the case and the problem is related to Systick this can be your way around it.

BR 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
EOF
Associate II

Hello S Tea,

I did some more investigations. Let's say I have a working situation and I set a breakpoint on the codeline

HAL_SPI_TransmitReceive_DMA(...)

the debugger stops accordingly. If I continue debugging by pressing F8-key, I can see the DMA clock burst on the scope with each F8 key press so everything is fine...

But if I press F6 instead of F8 (F6: "jump over"), I see one last DMA clock burst and with the next F8 and then F6 (on the DMA codeline again) the DMA is busy and so it runs into the error handler. Probably the F6 key starts the DMA transfer but the debugger at once "stops" the code execution / M4 core, so maybe the "end-of-transfer" can not be properly detected somewhere in the M4 guts.

But the more delicate thing is: After restarting the debug session again, still the DMA machine claims to be busy (as wirtten in my last post above) and that's why no more DMA transfers will appear on the scope any longer, regardless of the efforts. This is a static situation and can only be changed with a Linux reboot (perhaps the MP1 issues a (hard-) reset on the M4). Start / stop via linux (like: "echo start >/sys/class/remoteproc/remoteprocX/state") also does not help.

There is a (strange?) workaround that lets the M4 recover back to a "proper" state: In the program, before issuing any DMA transfer, send just anything (like one byte) via the SPI manually. This seems to initialise something.

  uint8_t ui8Byte = 0;
  HAL_SPI_Transmit(&hspi4, &ui8Byte, 1, 1);   // <---- this does the trick!

  while(1)
  {
    if (HAL_SPI_TransmitReceive_DMA(&hspi4, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE) != HAL_OK)
    {
      Error_Handler();
    }
    HAL_Delay(50);
  }

So in a normal environment (i.e. no debugger connected) all this should be of no concern, it happens only with the combination breakpoint / F6 key. So for me now the whole thing is not really understood, but of "now concern" anymore. I am aware now of this behaviour and can deal with it.

(by the way, actually I was wrong in the post above: I am NOT sure about SysTick working or not in case of DMA not longer working).