|
佬们,最近我需要使用ADS8698进行采样,这款18bitADC的特点是每次采样都需要SPI的tx连续发送34bit(16bit控制位+18bit任意值),才能接收rx返回的18bit数据(全程HAL库)。当然,我们很容易想到:
HAL_SPI_TransmitReceive(&hspi3, (uint8_t*)g_spiTxBuf3, (uint8_t*)g_spiRxBuf3, g_spiLen_tx3, 1000)
将控制命令分割成8bit(SPI_DATASIZE_8BIT),传5次,凑40bit进行发送即可。然而参考硬汉哥的例程,若要利用TIM12的TRGO触发DMAMUX进行DMA传输,问题来了:
1. 首先考虑硬件NSS还是软件NSS。实测后发现软件NSS无法自动拉低拉高CS脚,所以要么尝试自己控制CS,要么使用硬件NSS。
2. 使用硬件NSS,发现8bit传输的情况下每次传完8bit后CS都会自动拉低拉高一次,而SPI3最大传输位数是32,满足不了ADC时序,控制命令没传完CS就又拉高了。
3. 使用软件NSS,尝试在HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)函数中控制CS引脚,想法是SPI传输完成后先拉高CS,再读取数据,再拉低CS,开启下一次传输。结果CS的波形对不上MISO和MOSI的波形,有十分明显的延迟。
DAC8563的DMA例程中,传24bit只需将DataSize设置为24,后面再补8bit即可,但我这个超32位了,想请教一下如何控制CS,和SPI的FifoThreshold有关系吗?或者说这种情况就用不了DMA?附上配置:
/************************************** DMA配置 ******************************************/
void ADS8698_SelectMode_DMA(uint16_t mode, uint32_t _ulFreq)
{
g_spiLen_tx3 = 0;
g_spiLen_rx3 = 0;
g_spiTxBuf3[g_spiLen_tx3++] = (uint8_t)(mode >> 8);
g_spiTxBuf3[g_spiLen_tx3++] = (uint8_t)(mode & 0xFF);
g_spiTxBuf3[g_spiLen_tx3++] = 0x00;
g_spiTxBuf3[g_spiLen_tx3++] = 0x00;
g_spiTxBuf3[g_spiLen_tx3++] = 0x00;
if (g_spiLen_tx3 > SPI_BUFFER_SIZE)
{
Error_Handler(__FILE__, __LINE__);
}
spi3_reinit_flag = 1;
/* 复位SPI配置 */
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_MASTER;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 0x0;
hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_16DATA;
hspi3.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi3.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_01CYCLE;
hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_02CYCLE;
hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_DeInit(&hspi3) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* DMA配置 */
DMA2_CLK_ENABLE();
hdma_spi3_tx.Instance = SPI3_TX_DMA_STREAM;
hdma_spi3_tx.Init.Request = DMA_REQUEST_SPI3_TX;
hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi3_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi3_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi3_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_spi3_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_spi3_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi3_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_DeInit(&hdma_spi3_tx) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(&hspi3, hdmatx, hdma_spi3_tx);
/* 同步触发配置 */
sDmamux_SyncParams.SyncSignalID = HAL_DMAMUX1_SYNC_TIM12_TRGO;
sDmamux_SyncParams.SyncPolarity = HAL_DMAMUX_SYNC_RISING;
sDmamux_SyncParams.SyncEnable = ENABLE;
sDmamux_SyncParams.EventEnable = ENABLE;
sDmamux_SyncParams.RequestNumber = 1;
if (HAL_DMAEx_ConfigMuxSync(&hdma_spi3_tx, &sDmamux_SyncParams) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
TIM12_Config(_ulFreq);
hdma_spi3_rx.Instance = SPI3_RX_DMA_STREAM;
hdma_spi3_rx.Init.Request = DMA_REQUEST_SPI3_RX;
hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi3_rx.Init.Mode = DMA_CIRCULAR;
hdma_spi3_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_spi3_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_spi3_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi3_rx.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_DeInit(&hdma_spi3_rx) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
__HAL_LINKDMA(&hspi3, hdmarx, hdma_spi3_rx);
/* 开SPI DMA中断 */
HAL_NVIC_SetPriority(SPI3_DMA_TX_IRQn, 1, 0);
HAL_NVIC_DisableIRQ(SPI3_DMA_TX_IRQn);
HAL_NVIC_SetPriority(SPI3_DMA_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPI3_DMA_RX_IRQn);
HAL_NVIC_SetPriority(SPI3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPI3_IRQn);
//CS2_0();
/* 启动DMA */
if (HAL_SPI_TransmitReceive_DMA(&hspi3, (uint8_t*)g_spiTxBuf3, (uint8_t*)g_spiRxBuf3, g_spiLen_tx3) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
/************************************** SPI配置 ******************************************/
if (i == 3)
{
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_MASTER;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.BaudRatePrescaler = _BaudRatePrescaler;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 0x0;
hspi3.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi3.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi3.Init.FifoThreshold = SPI_FIFO_THRESHOLD_16DATA;
hspi3.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi3.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi3.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_01CYCLE;
hspi3.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_02CYCLE;
hspi3.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi3.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
hspi3.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_DeInit(&hspi3) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
if (_hspi->Instance == SPI3)
{
//SPI3_NSS_CLK_ENABLE();
//SPI3_SCK_CLK_ENABLE();
//SPI3_MISO_CLK_ENABLE();
//SPI3_MOSI_CLK_ENABLE();
SPI3_CLK_ENABLE();
/* SPI3 NSS */
GPIO_InitStruct.Pin = SPI3_NSS_PIN;
if (spi3_reinit_flag)
{
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
}
else
{
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
}
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = SPI3_NSS_AF;
HAL_GPIO_Init(SPI3_NSS_GPIO, &GPIO_InitStruct);
/* SPI3 SCK */
GPIO_InitStruct.Pin = SPI3_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = SPI3_SCK_AF;
HAL_GPIO_Init(SPI3_SCK_GPIO, &GPIO_InitStruct);
/* SPI3 MISO */
GPIO_InitStruct.Pin = SPI3_MISO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = SPI3_MISO_AF;
HAL_GPIO_Init(SPI3_MISO_GPIO, &GPIO_InitStruct);
/* SPI3 MOSI */
GPIO_InitStruct.Pin = SPI3_MOSI_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = SPI3_MOSI_AF;
HAL_GPIO_Init(SPI3_MOSI_GPIO, &GPIO_InitStruct);
}
/************************************** 这个就是硬汉哥的例程了 ******************************************/
void TIM12_Config(uint32_t _ulFreq)
{
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;
__HAL_RCC_TIM12_CLK_ENABLE();
/*-----------------------------------------------------------------------
System Clock source = PLL (HSI)
SYSCLK(Hz) = 400000000 (CPU Clock)
HCLK(Hz) = 200000000 (AXI and AHBs Clock)
AHB Prescaler = 2
D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz; 不含这个总线下的LPTIM1
因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
APB4上面的TIMxCLK没有分频,所以就是100MHz;
APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17
APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
----------------------------------------------------------------------- */
uiTIMxCLK = SystemCoreClock / 2;
if (_ulFreq < 100)
{
usPrescaler = 10000 - 1; /* 分频比 = 10000 */
usPeriod = (uiTIMxCLK / 10000) / _ulFreq - 1; /* 自动重装的值 */
}
else if (_ulFreq < 3000)
{
usPrescaler = 100 - 1; /* 分频比 = 100 */
usPeriod = (uiTIMxCLK / 100) / _ulFreq - 1; /* 自动重装的值 */
}
else /* 大于4K的频率,无需分频 */
{
usPrescaler = 0; /* 分频比 = 1 */
usPeriod = uiTIMxCLK / _ulFreq - 1; /* 自动重装的值 */
}
/* TIM12配置 */
htim12.Instance = TIM12;
htim12.Init.Prescaler = usPrescaler;
htim12.Init.CounterMode = TIM_COUNTERMODE_UP;
htim12.Init.Period = usPeriod;
htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim12.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_DeInit(&htim12) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
if (HAL_TIM_Base_Init(&htim12) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = usPeriod / 2;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim12, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 启动OC1 */
if (HAL_TIM_OC_Start(&htim12, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* TIM12的TRGO用于触发DMAMUX的请求发生器 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim12, &sMasterConfig) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
|
|