OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5580|回复: 4

TIM+DMA驱动SPI读取ADS8861读数出错

[复制链接]

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2022-3-30
在线时间
21 小时
发表于 2022-7-25 10:52:20 | 显示全部楼层 |阅读模式
10金钱
本帖最后由 BigKid 于 2022-7-25 13:57 编辑

最近项目调试需要用到ADS8861以1M采样率采集数据,芯片时序采用三线制:

目前的实现思路是DIN引脚一直拉高,用TIM1配置PWM波,控制CONVST引脚翻转,同时tim1_up触发一个DMA事件,向SPI1—DR寄存器写数据,再用SPI1—RX对应的DMA通道接收数据。
通过示波器观察CONVST时序正常,符合1us周期,DOUT时序为短暂低电平后开始传输数据。
现在的问题在于DMA接收SPI1时貌似会错位,并不是每次DOUT开始传输后才读数据,而是连续采集该引脚电平,输出数据,代码如下,请问如何才能控制DOUT的读取时序?

main.c:


SPI.c:

DMA.c:

timer.c:





最佳答案

查看完整内容[请看2#楼]

已解决,问题在于DMA和SPI顺序,否则SPI会先走一个时钟
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2022-3-30
在线时间
21 小时
 楼主| 发表于 2022-7-25 10:52:21 | 显示全部楼层
已解决,问题在于DMA和SPI顺序,否则SPI会先走一个时钟
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2022-7-27 22:33:43 | 显示全部楼层
帮顶
回复

使用道具 举报

2

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2021-10-25
在线时间
5 小时
发表于 2022-8-1 16:15:42 | 显示全部楼层
楼主上代码看看,也许能解决
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2022-3-30
在线时间
21 小时
 楼主| 发表于 2022-8-2 15:10:23 | 显示全部楼层
406178052y 发表于 2022-8-1 16:15
楼主上代码看看,也许能解决

        uint16_t adc[1024] = {0};
        u16 spi_buf[1024]={0};
        u8 com_flag=0;
       
        u16 tim_buf[1024]={0};
       
        u16 spi_tx_buf=0x00;
       
        u8 spi_tx[1024*2]={0};
int main(void)
{  

        double volt = 0;
        u16 cnt=0;
       

        u16 i=0;
       
    HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
       
       
        MX_DMA_Init();
        MX_SPI1_Init();
        MX_GPIO_Init();
        ads8861_Init();
       
       
        LED_Init();                     //初始化LED
    TIM3_PWM_Init(500-1,90-1);      //90M/90=1M的计数频率,自动重装载为500,那么PWM频率为1M/500=2kHZ
       
        MX_TIM1_Init(60-1,3-1);//使用APB2时钟,180M  180/3=60 60/60=1M
       
        //ADS8861_test();
        HAL_DMA_Start_IT(&hdma_tim1_up, (uint32_t )&spi_tx_buf,(uint32_t )&hspi1.Instance->DR, 1);
        HAL_SPI_Receive_DMA(&hspi1, (uint8_t *)&spi_buf, 1024);//接收速度与PWM无关,一直在读       












#include "spi.h"

SPI_HandleTypeDef hspi1;

void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;//SPI_MODE_MASTER
  hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY ;//只接收模式SPI_DIRECTION_2LINES_RXONLY
  hspi1.Init.DataSize = SPI_DATASIZE_16BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
       
        HAL_SPI_Init(&hspi1);
//  if (HAL_SPI_Init(&hspi1) != HAL_OK)
//  {
//    Error_Handler();
//  }

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
    __HAL_RCC_SPI1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration   
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL   GPIO_PULLUP
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
          
          
        hdma_spi1_rx.Instance = DMA2_Stream0;
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;//DMA_NORMAL;//     DMA_CIRCULAR
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_spi1_rx);

    __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi1_rx);
       
        //__HAL_SPI_ENABLE(spiHandle);//使能时钟
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
  if(hspi->Instance==SPI1)
  {

    __HAL_RCC_SPI1_CLK_DISABLE();


    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6);

    HAL_DMA_DeInit(hspi->hdmarx);

  }

}





















#include "timer.h"
#include "led.h"
//////////////////////////////////////////////////////////////////////////////////         
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//定时器驱动代码          
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/6
//版本:V1.1
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved                                                                          
//////////////////////////////////////////////////////////////////////////////////        
//修改说明
//V1.1 20160106
//新增TIM3_PWM_Init函数,用于PWM输出
//////////////////////////////////////////////////////////////////////////////////          

TIM_HandleTypeDef TIM3_Handler;         //定时器3PWM句柄
TIM_OC_InitTypeDef TIM3_CH4Handler;            //定时器3通道4句柄

void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim);

//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u32 psc)
{
    TIM3_Handler.Instance=TIM3;            //定时器3
    TIM3_Handler.Init.Prescaler=psc;       //定时器分频
    TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM3_Handler.Init.Period=arr;          //自动重装载值
    TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM
   
    TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM3_CH4Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低
    HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
       
    HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}


//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef GPIO_Initure;
        __HAL_RCC_TIM3_CLK_ENABLE();                        //使能定时器3
    __HAL_RCC_GPIOB_CLK_ENABLE();                        //开启GPIOB时钟
       
    GPIO_Initure.Pin=GPIO_PIN_1;                   //PB1
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用推挽输出
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
        GPIO_Initure.Alternate= GPIO_AF2_TIM3;        //PB1复用为TIM3_CH4
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
}


//设置TIM通道4的占空比
//compare:比较值
void TIM_SetTIM3ARR4(u32 ARR_Change)
{
        TIM3->ARR=ARR_Change;
}


//void TIM_SetTIM3Compare(TIM_HandleTypeDef *htim,u32 compare)
//{
//        htim->Instance->CCR4=compare;
//}

void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)
{
  if (NewState != DISABLE)
  {
    TIMx->CR1 |= TIM_CR1_ARPE;
  }
  else
  {
    TIMx->CR1 &= (uint16_t)~((uint16_t)TIM_CR1_ARPE);
  }
}




void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload)
{
  uint16_t tmpccmr1 = 0;

  tmpccmr1 = TIMx->CCMR1;
  tmpccmr1 &= (uint16_t)~((uint16_t)TIM_CCMR1_OC1PE);
  tmpccmr1 |= TIM_OCPreload;
  TIMx->CCMR1 = tmpccmr1;
}





TIM_HandleTypeDef htim1;

void MX_TIM1_Init(u16 arr,u32 psc)
{

  /* USER CODE BEGIN TIM1_Init 0 */

  /* USER CODE END TIM1_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  /* USER CODE BEGIN TIM1_Init 1 */

  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = psc;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = arr;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;

  HAL_TIM_Base_Init(&htim1);
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);

  HAL_TIM_PWM_Init(&htim1);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 24;//占空比  600ns高电平,400ns低电平,arr=60
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;//TIM_OCNPOLARITY_HIGH
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig);

  HAL_TIM_MspPostInit(&htim1);

}



void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspInit 0 */

  /* USER CODE END TIM1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_TIM1_CLK_ENABLE();

    /* TIM1 DMA Init */
    /* TIM1_UP Init */
    hdma_tim1_up.Instance = DMA2_Stream5;
    hdma_tim1_up.Init.Channel = DMA_CHANNEL_6;
    hdma_tim1_up.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tim1_up.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tim1_up.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tim1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim1_up.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_tim1_up.Init.Mode = DMA_CIRCULAR;
    hdma_tim1_up.Init.Priority = DMA_PRIORITY_LOW;
    hdma_tim1_up.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_tim1_up);

    __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_up);

  /* USER CODE BEGIN TIM1_MspInit 1 */

  /* USER CODE END TIM1_MspInit 1 */
  }

}

/**
* @brief TIM_Base MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param htim_base: TIM_Base handle pointer
* @retval None
*/
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* htim_base)
{
  if(htim_base->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspDeInit 0 */

  /* USER CODE END TIM1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM1_CLK_DISABLE();

    /* TIM1 DMA DeInit */
    HAL_DMA_DeInit(htim_base->hdma[TIM_DMA_ID_UPDATE]);
  /* USER CODE BEGIN TIM1_MspDeInit 1 */

  /* USER CODE END TIM1_MspDeInit 1 */
  }

}


void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(htim->Instance==TIM1)
  {
  /* USER CODE BEGIN TIM1_MspPostInit 0 */

  /* USER CODE END TIM1_MspPostInit 0 */

    __HAL_RCC_GPIOE_CLK_ENABLE();
    /**TIM1 GPIO Configuration
    PE9     ------> TIM1_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM1_MspPostInit 1 */

  /* USER CODE END TIM1_MspPostInit 1 */
        HAL_TIM_PWM_Start(htim,TIM_CHANNEL_1);//开启PWM通道4
  }

}


















#include "dma.h"
#include "ads8861.h"

DMA_HandleTypeDef hdma_tim1_up;

DMA_HandleTypeDef hdma_spi1_rx;

void MX_DMA_Init(void)
{


  __HAL_RCC_DMA2_CLK_ENABLE();


  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);

  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
       


}

void DMA2_Stream0_IRQHandler(void)
{

  HAL_DMA_IRQHandler(&hdma_spi1_rx);

}

void DMA2_Stream5_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream5_IRQn 0 */

  /* USER CODE END DMA2_Stream5_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_tim1_up);
  /* USER CODE BEGIN DMA2_Stream5_IRQn 1 */

  /* USER CODE END DMA2_Stream5_IRQn 1 */
}


extern uint16_t adc[1024];
extern u8 spi_buf[1024];
extern u8 com_flag;
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
//        u16 i=0;
//        for (i = 0; i < 1024; i++)
//                {
////                        adc = spi_buf[i*2];
////                        adc = adc[i*2] << 8;
////                        adc |=  spi_buf[i*2+1];
//                }
        com_flag=1;
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-26 04:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表