//------------------------------------------------------------------------------
// 模块名称：步进电机芯片DRV8880驱动模块
// 文件名称：bsp_drv8880
// 版本名称：V1.0
// 文件说明：控制步进电机芯片DRV8880
// 日期时间：2018年8月17日16点23分
// 文件作者：Jackie Chan
// 修改记录：
//    版本号  日期        作者  说明
//    V1.0    2018.08.17  J.C   正式发布
//
// 公司名称：多场低温科技有限公司
//
//------------------------------------------------------------------------------

#include "bsp.h"

// DRV888控制引脚对应的RCC时钟
#define RCC_ALL_MOTO (RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | \
                      RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOG)

// DRV8880控制引脚
#define GPIO_PORT_STEP GPIOC // 脉冲输入，内部下拉，上升沿触发
#define GPIO_PIN_STEP GPIO_Pin_7

#define GPIO_PORT_DIR GPIOE // 转动方向，内部下拉
#define GPIO_PIN_DIR GPIO_Pin_10

#define GPIO_PORT_ENABLE GPIOE // 器件使能，内部下拉
#define GPIO_PIN_ENABLE GPIO_Pin_11

#define GPIO_PORT_SLEEP GPIOB // 低电平进入睡眠模式，内部下拉
#define GPIO_PIN_SLEEP GPIO_Pin_11

#define GPIO_PORT_ATE GPIOE // 高电平进入自动整定模式，内部下拉
#define GPIO_PIN_ATE GPIO_Pin_15

#define GPIO_PORT_TRQ1 GPIOG // 力矩设置，内部下拉
#define GPIO_PIN_TRQ1 GPIO_Pin_1

#define GPIO_PORT_TRQ0 GPIOG // 力矩设置，内部下拉
#define GPIO_PIN_TRQ0 GPIO_Pin_0

#define GPIO_PORT_M1 GPIOE // 细分，三态输入引脚
#define GPIO_PIN_M1 GPIO_Pin_8

#define GPIO_PORT_M0 GPIOE // 细分，三态输入引脚
#define GPIO_PIN_M0 GPIO_Pin_7

#define GPIO_PORT_DECAY1 GPIOE // 衰减模式设置，自动整定时被忽略
#define GPIO_PIN_DECAY1 GPIO_Pin_13

#define GPIO_PORT_DECAY0 GPIOE // 衰减模式设置，自动整定时被忽略
#define GPIO_PIN_DECAY0 GPIO_Pin_12

#define GPIO_PORT_TOFF GPIOB // Off time设置，三态输入
#define GPIO_PIN_TOFF GPIO_Pin_10

#define GPIO_PORT_FAULT GPIOE // 失效报警输出，开漏输出
#define GPIO_PIN_FAULT GPIO_Pin_14

// 细分相关宏定义
#define M1_ENABLE (GPIO_PORT_M1->BSRR = GPIO_PIN_M1)
#define M0_ENABLE (GPIO_PORT_M0->BSRR = GPIO_PIN_M0)
#define M1_DISABLE (GPIO_PORT_M1->BRR = GPIO_PIN_M1)
#define M0_DISABLE (GPIO_PORT_M0->BRR = GPIO_PIN_M0)
#define M0_SET_AS_INPUT()            \
  {                                  \
    GPIO_PORT_M0->CRL &= 0X0FFFFFFF; \
    GPIO_PORT_M0->CRL |= 0X40000000; \
  }
#define M0_SET_AS_OUTPUT()           \
  {                                  \
    GPIO_PORT_M0->CRL &= 0X0FFFFFFF; \
    GPIO_PORT_M0->CRL |= 0X30000000; \
  }

// DRV8880使能相关宏定义
#define DRV8880_ENABLE (GPIO_PORT_ENABLE->BSRR = GPIO_PIN_ENABLE)
#define DRV8880_DISABLE (GPIO_PORT_ENABLE->BRR = GPIO_PIN_ENABLE)

// DRV8880方向控制引脚
#define DRV8880_CW (GPIO_PORT_DIR->BRR = GPIO_PIN_DIR)   // 样品杆从上往下看，顺时针旋转（+）
#define DRV8880_CCW (GPIO_PORT_DIR->BSRR = GPIO_PIN_DIR) // 样品杆从上往下看，逆时针旋转（-）

extern DIGITIAL_TUBE_T g_tTube;

// 供外部调用的函数声明
void bsp_Init_Drv8880_Hard(void);
void bsp_drv8880_enable_config(FunctionalState en);
void bsp_drv8880_microstep_config(MICRO_STEPPING_E step);
void bsp_drv8880_config_dir(DIR_E dir);
// void bsp_drv8880_vref_config(uint16_t vol); // vol:0~3300,代表0~3.3V
static void bsp_dev8880_vref_init_hard(uint16_t vol); // vol:0~3300,代表0~3.3V

void bsp_drv8880_microstep_config(MICRO_STEPPING_E step)
{
  switch (step)
  {
  case STEP_FULL: // M1M0: 00
    M0_SET_AS_OUTPUT();
    M1_DISABLE;
    M0_DISABLE;
    break;
  case STEP_1_2_NC: // M1M0: 01
    M0_SET_AS_OUTPUT();
    M1_DISABLE;
    M0_ENABLE;
    break;
  case STEP_1_2: // M1M0: 10
    M0_SET_AS_OUTPUT();
    M1_ENABLE;
    M0_DISABLE;
    break;
  case STEP_1_4: // M1M0: 11
    M0_SET_AS_OUTPUT();
    M1_ENABLE;
    M0_ENABLE;
    break;
  case STEP_1_8: // M1M0: 0Z
    M0_SET_AS_INPUT();
    M1_DISABLE;
    break;
  case STEP_1_16: // M1M0: 1Z
    M0_SET_AS_INPUT();
    M1_ENABLE;
    break;
  default:
    break;
  }
}
void bsp_drv8880_config_dir(DIR_E dir)
{
  switch (dir)
  {
  case DIR_CW:
    DRV8880_CW;
    g_tTube.dir = DIR_CW;
    break;
  case DIR_CCW:
    DRV8880_CCW;
    g_tTube.dir = DIR_CCW;
    break;
  default:
    break;
  }
}
void bsp_drv8880_enable_config(FunctionalState en)
{
  if (en == DISABLE)
  {
    DRV8880_DISABLE;
  }
  else
  {
    DRV8880_ENABLE;
  }
}

// vol:0~3300,代表0~3.3V
static void bsp_dev8880_vref_init_hard(uint16_t vol)
{
  float temp = vol;

  GPIO_InitTypeDef GPIO_InitStructure;
  DAC_InitTypeDef DAC_InitType;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能PORTA通道时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);   // 使能DAC通道时钟

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;     // 端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  GPIO_SetBits(GPIOA, GPIO_Pin_4); // PA.4 输出高

  DAC_InitType.DAC_Trigger = DAC_Trigger_None;                         // 不使用触发功能 TEN1=0
  DAC_InitType.DAC_WaveGeneration = DAC_WaveGeneration_None;           // 不使用波形发生
  DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0; // 屏蔽、幅值设置
  DAC_InitType.DAC_OutputBuffer = DAC_OutputBuffer_Disable;            // DAC1输出缓存关闭 BOFF1=1
  DAC_Init(DAC_Channel_1, &DAC_InitType);                              // 初始化DAC通道1

  DAC_Cmd(DAC_Channel_1, ENABLE); // 使能DAC1

  DAC_SetChannel1Data(DAC_Align_12b_R, 0); // 12位右对齐数据格式设置DAC值

  temp /= 1000;
  temp = temp * 4096 / 3.3;
  DAC_SetChannel1Data(DAC_Align_12b_R, temp); // 12位右对齐数据格式设置DAC值
}

void bsp_Init_Drv8880_Hard(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_ALL_MOTO, ENABLE);

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  // 配置自动整定引脚为高电平，设置为自动整定模式
  GPIO_PORT_ATE->BSRR = GPIO_PIN_ATE;
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_ATE;
  GPIO_Init(GPIO_PORT_ATE, &GPIO_InitStructure);

  // 配置脉冲输入引脚，设置为默认低电平
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_STEP;
  GPIO_Init(GPIO_PORT_STEP, &GPIO_InitStructure);

  // 配置方向引脚，设置默认为低电平
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_DIR;
  GPIO_Init(GPIO_PORT_DIR, &GPIO_InitStructure);

  // 配置使能引脚，设置默认为低电平，不使能
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_ENABLE;
  GPIO_Init(GPIO_PORT_ENABLE, &GPIO_InitStructure);

  // 配置睡眠引脚，设置默认为低电平，处于睡眠状态
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_SLEEP;
  GPIO_Init(GPIO_PORT_SLEEP, &GPIO_InitStructure);

  // 配置细分引脚，设置默认为低电平，不细分
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_M1;
  GPIO_Init(GPIO_PORT_M1, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_M0;
  GPIO_Init(GPIO_PORT_M0, &GPIO_InitStructure);

  // 配置力矩引脚，设置默认为低电平，100%力矩
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_TRQ1;
  GPIO_Init(GPIO_PORT_TRQ1, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_TRQ0;
  GPIO_Init(GPIO_PORT_TRQ0, &GPIO_InitStructure);

  // 设置衰减模式，设置默认为低电平，为slow decay模式
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_DECAY1;
  GPIO_Init(GPIO_PORT_DECAY1, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_DECAY0;
  GPIO_Init(GPIO_PORT_DECAY0, &GPIO_InitStructure);

  // 设置fixed-off-time，设置默认为低电平，为20us
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_TOFF;
  GPIO_Init(GPIO_PORT_TOFF, &GPIO_InitStructure);

  // 设置报警输出引脚，设置为输入浮空模式
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN_FAULT;
  GPIO_Init(GPIO_PORT_FAULT, &GPIO_InitStructure);

  // 设置细分
  bsp_drv8880_microstep_config(STEP_1_16);

  // 方向设置
  bsp_drv8880_config_dir(DIR_CCW);

  // DA输出，步进电机电流设置 0.495V

  // 设置DA输出的电压为0.495V
  bsp_dev8880_vref_init_hard(1500);

  // 退出睡眠模式
  GPIO_PORT_SLEEP->BSRR = GPIO_PIN_SLEEP;

  // 暂时不使能，等待零点所搜命令
  // bsp_drv8880_enable_config(DISABLE);
  bsp_drv8880_enable_config(ENABLE);
}

//-------------------------------- End of file ---------------------------------
