|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2016-4-1 17:47:38
|
显示全部楼层
5.3 需要另外做的工作
初始化后,调用如下两个函数,重点说说如下两个函数。
HAL_TIM_DMABurst_WriteStart(&htim2, TIM_DMABASE_ARR, TIM_DMA_UPDATE,
(uint32_t*)aSRC_Buffer, TIM_DMABURSTLENGTH_3TRANSFERS);
//函数1,用来配置要传送的目标外设寄存器起始地址,这里配置为:TIM_DMABASE_ARR,即从自动重加载寄存器开始写,产生DMA请求的事件配置为:TIM_DMA_UPDATE 即定时器更新事件产生DMA请求,接下来是要传送的源数据起始地址,设置成要发送的数据数组的首地址,然后是DMA连续传输的数据长度,配置为TIM_DMABURSTLENGTH_3TRANSFERS,即连续传输三组寄存器的值,可以理解为一次定时器一次DMA请求,DMA进行三次数据传输,分别写给了TIM_DMABASE_ARR起的三组寄存器。
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //使能比较匹配输出通道,使能定时器
看看第一个函数的原型及内部调用函数:
/**
* @brief Configure the DMA Burst to transfer Data from the memory to the TIM peripheral
* @param htim: TIM handle
* @param BurstBaseAddress: TIM Base address from when the DMA will starts the Data write
* This parameters can be on of the following values:
* @arg TIM_DMABASE_CR1
* @arg TIM_DMABASE_CR2
* @arg TIM_DMABASE_SMCR
* @arg TIM_DMABASE_DIER
* @arg TIM_DMABASE_SR
* @arg TIM_DMABASE_EGR
* @arg TIM_DMABASE_CCMR1
* @arg TIM_DMABASE_CCMR2
* @arg TIM_DMABASE_CCER
* @arg TIM_DMABASE_CNT
* @arg TIM_DMABASE_PSC
* @arg TIM_DMABASE_ARR
* @arg TIM_DMABASE_RCR
* @arg TIM_DMABASE_CCR1
* @arg TIM_DMABASE_CCR2
* @arg TIM_DMABASE_CCR3
* @arg TIM_DMABASE_CCR4
* @arg TIM_DMABASE_BDTR
* @arg TIM_DMABASE_DCR
* @param BurstRequestSrc: TIM DMA Request sources
* This parameters can be on of the following values:
* @arg TIM_DMA_UPDATE: TIM update Interrupt source
* @arg TIM_DMA_CC1: TIM Capture Compare 1 DMA source
* @arg TIM_DMA_CC2: TIM Capture Compare 2 DMA source
* @arg TIM_DMA_CC3: TIM Capture Compare 3 DMA source
* @arg TIM_DMA_CC4: TIM Capture Compare 4 DMA source
* @arg TIM_DMA_COM: TIM Commutation DMA source
* @arg TIM_DMA_TRIGGER: TIM Trigger DMA source
* @param BurstBuffer: The Buffer address.
* @param BurstLength: DMA Burst length. This parameter can be one value
* between: TIM_DMABurstLength_1Transfer and TIM_DMABurstLength_18Transfers.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc,
uint32_t* BurstBuffer, uint32_t BurstLength)//,uint16_t Bursttimes
{
/* Check the parameters */
assert_param(IS_TIM_DMABURST_INSTANCE(htim->Instance));
assert_param(IS_TIM_DMA_BASE(BurstBaseAddress));
assert_param(IS_TIM_DMA_SOURCE(BurstRequestSrc));
assert_param(IS_TIM_DMA_LENGTH(BurstLength));
if((htim->State == HAL_TIM_STATE_BUSY))
{
return HAL_BUSY;
}
else if((htim->State == HAL_TIM_STATE_READY))
{
if((BurstBuffer == 0 ) && (BurstLength > 0))
{
return HAL_ERROR;
}
else
{
htim->State = HAL_TIM_STATE_BUSY;
}
}
switch(BurstRequestSrc)
{
case TIM_DMA_UPDATE:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = TIM_DMAPeriodElapsedCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */ //用来设置传输的源地址、目标地址、DMA传送次数及中断
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);//Bursttimes
}
break;
case TIM_DMA_CC1:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC2:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC2]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC2]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC2], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC3:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC3]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC3], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC4:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC4]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC4]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC4], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_COM:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferCpltCallback = TIMEx_DMACommutationCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_COMMUTATION], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_TRIGGER:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_TRIGGER]->XferCpltCallback = TIM_DMATriggerCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_TRIGGER]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_TRIGGER], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
default:
break;
}
/* configure the DMA Burst Mode */
htim->Instance->DCR = BurstBaseAddress | BurstLength;//这里设置的是DBL和DBA
/* Enable the TIM DMA Request */
__HAL_TIM_ENABLE_DMA(htim, BurstRequestSrc);
htim->State = HAL_TIM_STATE_READY;
/* Return function status */
return HAL_OK;
}
此函数中,只有第一个case语句及函数最后几句对我们有用。先看一个case语句中的调用函数
/**
* @brief Start the DMA Transfer with interrupt enabled.
* @param hdma: pointer to a DMA_HandleTypeDef structure that contains
* the configuration information for the specified DMA Channel.
* @param SrcAddress: The source memory Buffer address
* @param DstAddress: The destination memory Buffer address
* @param DataLength: The length of data to be transferred from source to destination
* @retval HAL status
*/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
/* Process locked */
__HAL_LOCK(hdma);
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
/* Check the parameters */
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
/* Disable the peripheral */
__HAL_DMA_DISABLE(hdma);
/* Configure the source, destination address and the data length */
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);//设置源地址、目标地址、DMA传输次数
/* Enable the transfer complete interrupt */
/* Enable the Half transfer complete interrupt */
/* Enable the transfer Error interrupt */
__HAL_DMA_ENABLE_IT(hdma, DMA_IT_TC);// | DMA_IT_HT | DMA_IT_TE 只开DMA传输完成中断,不开半传输中断及错误中断
/* Enable the Peripheral */
__HAL_DMA_ENABLE(hdma);
return HAL_OK;
}
其中函数:
/* Configure the source, destination address and the data length */
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);//设置源地址、目标地址、DMA传输次数,这里有两个比较难以理解的寄存器,TIMx_DMAR和TIMx_DCR,不要去看TIM2的寄存器,去看TIM1的对应寄存器,应为后者讲的更详细些,数据手册如下:
可以这么理解,DMAR中存放的是要传送至的起始寄存器到截止寄存器的地址,其由DCR中的内容决定,DCR中,DBL设置的是TIM一次DMA请求,DMA将传送的数据长度/次数,DBA设置的是TIM一次DMA请求,DMA将传送数据到的起始寄存器。
再来看DMA的数量寄存器:
这个寄存器设置的是DMA传送的次数,传送的字节数跟设置的传输类型有关BYTE/WORD/HALFWORD,没传送一次,该寄存器减一,减到零则产生DMA传输完成中断。
看一下这个函数,有一个问题:
HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc,
uint32_t* BurstBuffer, uint32_t BurstLength)//,uint16_t Bursttimes
看函数内容里这个BurstLength,赋给了TIM寄存器DCR的DBL,又赋给了DMA寄存器DMA_CNDTRx,这样的话每传输完一次TIM的DMA请求,进一次DMA传输完成中断,显然不满足我们的要求,我们用此方式就是为了产生一定数量的脉冲后才进一次中断,否则就直接用TIM溢出中断计数方式了。将此函数改造如下:
HAL_StatusTypeDef HAL_TIM_DMABurst_WriteStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc,
uint32_t* BurstBuffer, uint32_t BurstLength,uint16_t Bursttimes)//
{
/* Check the parameters */
assert_param(IS_TIM_DMABURST_INSTANCE(htim->Instance));
assert_param(IS_TIM_DMA_BASE(BurstBaseAddress));
assert_param(IS_TIM_DMA_SOURCE(BurstRequestSrc));
assert_param(IS_TIM_DMA_LENGTH(BurstLength));
if((htim->State == HAL_TIM_STATE_BUSY))
{
return HAL_BUSY;
}
else if((htim->State == HAL_TIM_STATE_READY))
{
if((BurstBuffer == 0 ) && (BurstLength > 0))
{
return HAL_ERROR;
}
else
{
htim->State = HAL_TIM_STATE_BUSY;
}
}
switch(BurstRequestSrc)
{
case TIM_DMA_UPDATE:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_UPDATE]->XferCpltCallback = TIM_DMAPeriodElapsedCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_UPDATE]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */ //((BurstLength) >> 8) + 1
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_UPDATE], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, Bursttimes);//
}
break;
case TIM_DMA_CC1:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC2:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC2]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC2]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC2], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC3:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC3]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC3]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC3], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_CC4:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_CC4]->XferCpltCallback = TIM_DMADelayPulseCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_CC4]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC4], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_COM:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferCpltCallback = TIMEx_DMACommutationCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_COMMUTATION]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_COMMUTATION], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
case TIM_DMA_TRIGGER:
{
/* Set the DMA Period elapsed callback */
htim->hdma[TIM_DMA_ID_TRIGGER]->XferCpltCallback = TIM_DMATriggerCplt;
/* Set the DMA error callback */
htim->hdma[TIM_DMA_ID_TRIGGER]->XferErrorCallback = TIM_DMAError ;
/* Enable the DMA channel */
HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_TRIGGER], (uint32_t)BurstBuffer, (uint32_t)&htim->Instance->DMAR, ((BurstLength) >> 8) + 1);
}
break;
default:
break;
}
/* configure the DMA Burst Mode */
htim->Instance->DCR = BurstBaseAddress | BurstLength;
/* Enable the TIM DMA Request */
__HAL_TIM_ENABLE_DMA(htim, BurstRequestSrc);
htim->State = HAL_TIM_STATE_READY;
/* Return function status */
return HAL_OK;
}
如此,就可以完成Bursttimes次DMA传输进一次DMA传输完成中断,产生的脉冲数为:Bursttimes/BurstLength。
在main里添加:
uint32_t aSRC_Buffer[15] = {1199, 0,600,
1199, 0,600,
1199, 0,600,
1199, 0,600,
1199, 0,600,
};
HAL_TIM_DMABurst_WriteStart(&htim2, TIM_DMABASE_ARR, TIM_DMA_UPDATE,
(uint32_t*)aSRC_Buffer, TIM_DMABURSTLENGTH_3TRANSFERS,15);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
在DMA传输完成中断里添加:
HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);//停止脉冲输出及TIM2
编译,下载,观测:
有成果了吧..........
本着求真、务实、讲科学的态度,还要进行验证测试
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|