STM32
直播中

王艳

7年用户 1276经验值
私信 关注
[问答]

STM32F439的HASH模块DMA传输计算问题求解

项目中需要使用439的的HASH模块计算文件的MD5值,使用的DMA方式,为了提高CPU效率,让其他任务在DMA传输数据、硬件计算MD5期间可以得到运行,DMA的数据来自FMC外扩的SDRAM。

现在的问题是,经过多次调试发现,启动DMA传输后 CPU貌似没运行代码,而是等DMA传输和计算都完成了之后才运行后面的代码,我使用时间戳功能测量了函数
HAL_HASH_MD5_Start_DMA 的运行时间,得到的时间就是DMA传入数据和MD5计算的时间,也就是说,这个函数里面启动了DMA传输后 程序就停了,等整个MD5都计算完了才从这个函数中出来,很是费解,我看了下总线矩阵,也没冲突的地方啊,为什么会出现这个情况...有人知道吗?

下面的是HAL的程序,我在里面加入了测量时间功能,86-89行是我指出的有问题的地方

  • HAL_StatusTypeDef HASH_Start_DMA(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size, uint32_t Algorithm)
  • {
  •   uint32_t inputaddr;
  •   uint32_t inputSize;
  •   HAL_StatusTypeDef status ;
  •   HAL_HASH_StateTypeDef State_tmp = hhash->State;

  • #if defined (HASH_CR_MDMAT)
  •   /* Make sure the input buffer size (in bytes) is a multiple of 4 when MDMAT bit is set
  •      (case of multi-buffer HASH processing) */
  •   assert_param(IS_HASH_DMA_MULTIBUFFER_SIZE(Size));
  • #endif /* MDMA defined*/
  •    /* If State is ready or suspended, start or resume polling-based HASH processing */
  • if((State_tmp == HAL_HASH_STATE_READY) || (State_tmp == HAL_HASH_STATE_SUSPENDED))
  •   {
  •     /* Check input parameters */
  •     if ( (pInBuffer == NULL ) || (Size == 0U) ||
  •     /* Check phase coherency. Phase must be
  •        either READY (fresh start)
  •        or PROCESS (multi-buffer HASH management) */
  •        ((hhash->Phase != HAL_HASH_PHASE_READY)    (!(IS_HASH_PROCESSING(hhash)))))
  •     {
  •       hhash->State = HAL_HASH_STATE_READY;
  •       return  HAL_ERROR;
  •     }


  •     /* Process Locked */
  •     __HAL_LOCK(hhash);

  •     /* If not a resumption case */
  •     if (hhash->State == HAL_HASH_STATE_READY)
  •     {
  •       /* Change the HASH state */
  •       hhash->State = HAL_HASH_STATE_BUSY;

  •       /* Check if initialization phase has already been performed.
  •          If Phase is already set to HAL_HASH_PHASE_PROCESS, this means the
  •          API is processing a new input data message in case of multi-buffer HASH
  •          computation. */
  •       if(hhash->Phase == HAL_HASH_PHASE_READY)
  •       {
  •         /* Select the HASH algorithm, clear HMAC mode and long key selection bit, reset the HASH processor core */
  •         MODIFY_REG(HASH->CR, HASH_CR_LKEY|HASH_CR_ALGO|HASH_CR_MODE|HASH_CR_INIT, Algorithm | HASH_CR_INIT);

  •         /* Set the phase */
  •         hhash->Phase = HAL_HASH_PHASE_PROCESS;
  •       }

  •       /* Configure the Number of valid bits in last word of the message */
  •       __HAL_HASH_SET_NBVALIDBITS(Size);

  •       inputaddr = (uint32_t)pInBuffer;     /* DMA transfer start address   */
  •       inputSize = Size;                    /* DMA transfer size (in bytes) */

  •       /* In case of suspension request, save the starting parameters */
  •       hhash->pHashInBuffPtr =  pInBuffer;  /* DMA transfer start address   */
  •       hhash->HashInCount = Size;           /* DMA transfer size (in bytes) */

  •     }
  •     /* If resumption case */
  •     else
  •     {
  •       /* Change the HASH state */
  •       hhash->State = HAL_HASH_STATE_BUSY;

  •       /* Resumption case, inputaddr and inputSize are not set to the API input parameters
  •          but to those saved beforehand by HAL_HASH_DMAFeed_ProcessSuspend() when the
  •          processing was suspended */
  •       inputaddr = (uint32_t)hhash->pHashInBuffPtr;  /* DMA transfer start address   */
  •       inputSize = hhash->HashInCount;               /* DMA transfer size (in bytes) */

  •     }

  •     /* Set the HASH DMA transfert complete callback */
  •     hhash->hdmain->XferCpltCallback = HASH_DMAXferCplt;
  •     /* Set the DMA error callback */
  •     hhash->hdmain->XferErrorCallback = HASH_DMAError;

  •     /* Store number of words already pushed to manage proper DMA processing suspension */
  •     hhash->NbWordsAlreadyPushed = HASH_NBW_PUSHED();

  •     /* Enable the DMA In DMA Stream */
  •     status = HAL_DMA_Start_IT(hhash->hdmain, inputaddr, (uint32_t) HASH->DIN, (((inputSize %4U)!=0U) ? ((inputSize+(4U-(inputSize %4U)))/4U):(inputSize/4U)));

  • sts = OS_TS_GET(); //获取时间戳;
  •     /* Enable DMA requests */
  •     SET_BIT(HASH->CR, HASH_CR_DMAE); //就是这一句,执行完这一句按理说程序应该继续往下执行,但是实际上经过时间戳的测量,执行完这句耗费了约 4ms,这个时间正好是DMA传输数据+MD5的计算时间。
  • ets = OS_TS_GET() - sts; //计算耗费的时间

  •     /* Process Unlock */
  •     __HAL_UNLOCK(hhash);

  •     /* Return function status */
  •     if (status != HAL_OK)
  •     {
  •       /* Update HASH state machine to error */
  •       hhash->State = HAL_HASH_STATE_ERROR;
  •     }
  •     else
  •     {
  •       /* Change HASH state */
  •       hhash->State = HAL_HASH_STATE_READY;
  •     }

  •     return status;
  •   }
  •   else
  •   {
  •     return HAL_BUSY;
  •   }
  • }


回帖(2)

江松洁

2024-4-19 09:36:37
建议你用IO翻转来代替OS_TS_GET()测量时间。
举报

张波

2024-4-19 15:51:54
从描述来看,你的目标是使用STM32F439的HASH模块计算文件的MD5值,同时通过DMA传输数据以提高CPU效率。你的问题是启动DMA传输后,CPU似乎不会执行其他代码,直到DMA传输和MD5计算都完成。

要解决这个问题,首先需要确认一些事项。

1. 确保DMA传输配置正确:确保DMA正确地配置为从FMC外扩的SDRAM传输数据到HASH模块。检查DMA传输参数,包括源和目的地址、传输长度等,并确保它们与SDRAM和HASH模块的正确地址匹配。

2. 确保DMA接收中断使能:检查DMA接收中断的使能状态。如果没有使能中断,则DMA传输完成后不会触发中断,CPU也不会执行相关的中断处理程序。如果需要,在DMA配置中使能中断,并编写相应的中断处理程序。

3. 确保MD5计算没有阻塞CPU:某些情况下,MD5计算可能会阻塞CPU,而不仅仅是DMA传输。确保你使用的MD5计算库或代码不会导致这种情况。可以使用时间戳来测量MD5计算的时间,确保它不会超过可接受的范围。

4. 确保其他任务获得运行机会:使用RTOS或其他任务管理器来确保其他任务获得足够的运行时间。在DMA和MD5计算期间,确保其他任务可以得到适当的CPU资源,可以使用任务优先级或抢占式调度来实现。

关于总线矩阵和总线优先级的问题,STM32F439芯片是基于ARM Cortex-M4内核,具有高度配置灵活性和优先级控制。你可以使用总线矩阵配置寄存器来设置不同总线之间的优先级,确保DMA和其他外设之间的公平共享。可以参考芯片手册以了解更多关于总线矩阵的详细信息。

另外,可以尝试使用读取SR寄存器的方式来确认CPU是否被阻塞。SR寄存器包含HASH模块的状态信息,通过检查SR寄存器的标志位,可以确定是否在MD5计算期间阻塞了CPU。

最后,如果问题仍然存在,建议检查你的代码实现,确保没有其他地方阻塞了CPU。可能还需要查看HAL库的源代码,以确保函数`HAL_HASH_MD5_Start_DMA`的实现没有阻塞CPU的操作。如果需要的话,可以参考库代码的实现并进行相应的修改。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分