STM32F103C8T6, use HAL library to simulate IIC reading MT6701 magnetic encoder

Foreword:

The MT6701 magnetic encoder has a variety of reading methods, but the SSI and IIC reading methods are generally used more often. The blogger here uses the IIC driving method. The configuration of software and hardware is as follows, with source code attached, hoping to help more people.

This article recommends two blogs:

STM32 HAL library driver MT6701 magnetic encoder_mt6701 program-CSDN Blog

MT6701 magnetic encoder user guide, 14Bit single-turn absolute value, I2C stm32 HAL library reading angle, compatible with AS5600_Mark_md’s blog-CSDN blog

The first article provides the use of the IIC that comes with the HAL library to read data (the blogger failed, which may be related to the hardware settings, and other IICs in the blogger’s project also use handwritten IICs, so I did not study it further)

The second article explains the MT6701 chip in detail, and the code is also very clear (but the blogger still hasn’t started running… I don’t know why)

A blogger who has been engaged in embedded development for less than a year after graduation is considered a newbie. If there are any deficiencies in the code or blog, you are welcome to correct me. If you encounter problems with the code, you can leave me a message. The blogger will try his best to help everyone. I wish you all a happy CV~~

1. Hardware description

The finished chip purchased by the blogger online, see the picture below for details

2. Things to know before CV

MT6701 has two adjustable addresses. The default is 0000110 (0x06). The address can be changed to 1000110 (0x46). The .h file in the code has macro definitions for the two addresses, but the code to modify the addresses has not been written. Later, Will update the post.

3. CubeMX configuration

Set clock source

Set up the programmer

set clock

Set up USART

Set GPIO

4. Please check the attached code

1. MT6701.h

#ifndef __MT6701_H
#define __MT6701_H

#include "main.h"
#include "Delay.h"

/*=========================Address information====================== ====*/
#define Low_Address 0X0c //00001100 default low address
#define High_Address 0X8c //10001100 can adjust the high address
#define ReadAddress1 0X03 //Data high register address
#define ReadAddress2 0X04 //Data low register address

double MT6701_RecvData(GPIO_TypeDef *sda_GPIO, uint16_t sda_Pin, GPIO_TypeDef *scl_GPIO, uint16_t scl_Pin, uint8_t Number);
/*-----------------Support functions required inside the function------------------*/
void MT6701_Start(void); //Start signal
void MT6701_Stop(void); //End signal
void GPIO_Write(void); //Set SDA to output mode
void GPIO_Read(void); //Set SDA to input mode
void MT6701_SendACK(int ack); //Send ACK signal
int MT6701_RecvACK(void); //Read ACK signal
uint8_t MT6701_RecvByte(void); //Read one byte of data
void MT6701_SendByte(uint8_t dat); //Write one byte of data


#endif

2. MT6701.C

#include "MT6701.h"

/*======================Global variable section======================*/
GPIO_InitTypeDef GPIO_InitStruct; //Modify the structure used for GPIO
\t
/*------------Record the two-wire pin information passed by the initialization function----------*/
GPIO_TypeDef *SDA_GPIO = NULL; //sda bus data
uint16_t SDA_Pin; //sda pin data
GPIO_TypeDef *SCL_GPIO = NULL; //scl bus data
uint16_t SCL_Pin; //scl pin data
uint8_t Address = Low_Address; //BH1750 address data, default is low level

/*======================Read MT6701 encoder data==================== */
/*\tparameter list:\t\t\t\t\t\t\t            \t\t\t\t\t*/
/* GPIO_TypeDef *sda_GPIO is SDA bus information */
/* uint16_t sda_Pin is SDA pin information */
/* GPIO_TypeDef *scl_GPIO is SCL bus information */
/* uint16_t scl_Pin is SCL pin information */
/* uint8_t Number is the address information, 0 is the low address, 1 is the high address*/
/*================================================ ==============*/
double MT6701_RecvData(GPIO_TypeDef *sda_GPIO, uint16_t sda_Pin, GPIO_TypeDef *scl_GPIO, uint16_t scl_Pin, uint8_t Number)
{
uint8_t RecvData = 0;
uint32_t MT6701_Data = 0;
/*---------------Save data into global variables for easy transplantation----------------*/
SDA_GPIO = sda_GPIO;
SDA_Pin = sda_Pin;
SCL_GPIO = scl_GPIO;
SCL_Pin = scl_Pin;
if(Number == 1)
Address = High_Address;
else if(Number == 0)
Address = Low_Address;
/*------------------------Start reading data-------------------- ----*/
/*-----------------------Reading data for the first time------------------ ----*/
MT6701_Start(); //Start signal
MT6701_SendByte(Address); //Send address and write instructions
MT6701_SendByte(ReadAddress1); //Send instruction to read 0x03 register
MT6701_Start(); //Send the second start signal to start reading
MT6701_SendByte(Address | 1); //Send address and read command
RecvData = MT6701_RecvByte(); //Read the data in register 0x03
MT6701_Stop(); //Stop signal
MT6701_Data = RecvData; //Assign data
/*-----------------------Read data for the second time------------------ ----*/
MT6701_Start(); //Start signal
MT6701_SendByte(Address); //Send address and write instructions
MT6701_SendByte(ReadAddress2); //Send instruction to read 0x04 register
MT6701_Start(); //Send the second start signal to start reading
MT6701_SendByte(Address | 1); //Send address and read command
RecvData = MT6701_RecvByte(); //Read the data of register 0x04
MT6701_Stop(); //Stop signal
MT6701_Data = (MT6701_Data << 8) + RecvData;
MT6701_Data >>= 2; //Get the high 14 bits of data
return (MT6701_Data*360.0)/16384.0;
}

/*========================Function function: start signal==================== ===*/
/*When the start signal is SCL high, SDA is pulled down from high to at least 250nm, and SCL is pulled low */
/*================================================ ===============*/
void MT6701_Start()
{
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET); //Pull up the data line
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET); //Pull up the clock line
//In the initial stage of the HAL library, set the two GPIOs to output mode high level, and set them again for safety;
My_Delay_us(10);
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET); //Generate falling edge
    My_Delay_us(10);
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET); //Pull down the clock line
My_Delay_us(10);
}


/*=======================Function function: Stop signal==================== ==*/
/*The stop signal is the action of pulling SDA from low to high for at least 250nm when SCL is high */
/*================================================ ==============*/
void MT6701_Stop()
{
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET); //Pull the data line low
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET); //Pull up the clock line
    My_Delay_us(10);
    HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET); //Generate rising edge
    My_Delay_us(10);
}

/*==========================Send response signal==================== ======*/
/* Parameter list: ack (0:ACK 1:NAK) */
/*================================================ ==============*/
void MT6701_SendACK(int ack)
{
GPIO_Write();
    if(ack == 1) //Write response signal
HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET);
else if(ack == 0)
HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET);
else
return;
\t\t\t
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET);
    My_Delay_us(10);
    HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET);
    My_Delay_us(10);
}

/*========================Receive response signal======================== ==*/
/* This has no effect, it will still run without ACK~~ */
/*================================================ ==========*/
int MT6701_RecvACK()
{
int ACK = 0;
GPIO_Read();
  HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET); //Pull up the clock line
  My_Delay_us(10);
if(HAL_GPIO_ReadPin(SDA_GPIO, SDA_Pin) == 1 ) //Read response signal
        ACK = 1;
    else
        ACK = 0;
  HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET); //Pull down the clock line
  My_Delay_us(10);
GPIO_Write();
    return ACK;
}

/*==================Send one byte of data to the iic bus==================*/
/* Parameter list: dat--the data you want to send */
/*================================================ ===========*/
void MT6701_SendByte(uint8_t dat)
{
    uint8_t i;
    for (i=0; i<8; i + + ) //8-bit counter
    {
if(0X80&dat)
HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_SET);
else
HAL_GPIO_WritePin(SDA_GPIO, SDA_Pin,GPIO_PIN_RESET);
dat <<= 1;
HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET); //Pull up the clock line
My_Delay_us(10);
HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET); //Pull down the clock line
My_Delay_us(10);
    }
    MT6701_RecvACK();
}

/*====================Read a byte address from the iic bus================*/
/* The return value is one byte of data read */
/*================================================ ===========*/
uint8_t MT6701_RecvByte()
{
    uint8_t i;
    uint8_t dat = 0;
uint8_t bit;
\t
GPIO_Read();

    for (i=0; i<8; i + + ) //8-bit counter
    {
        dat <<= 1;
        HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_SET); //Pull up the clock line
        My_Delay_us(10);
if( SET == HAL_GPIO_ReadPin(SDA_GPIO, SDA_Pin) )
             bit = 0X01;
       else
             bit = 0x00;
        dat |= bit; //Read data
        HAL_GPIO_WritePin(SCL_GPIO, SCL_Pin,GPIO_PIN_RESET); //Pull down the clock line
        My_Delay_us(10);
    }
MT6701_SendACK(1); //There is GPIO_Write(); inside the function;
    return dat;
}
/*======================Set SDA to output mode====================== */
void GPIO_Write(void)
{
  GPIO_InitStruct.Pin = SDA_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(SDA_GPIO, & amp;GPIO_InitStruct);
}

/*====================== Set SDA to input mode ==================== */
void GPIO_Read(void)
{
GPIO_InitStruct.Pin = SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(SDA_GPIO, & amp;GPIO_InitStruct);
}

3. Delay.h

#ifndef __DELAY_H
#define __DELAY_H

#include "main.h"

void My_Delay_us_init(uint8_t SYSCLK);
void My_Delay_us(uint32_t nus);
void My_Delay_ms(uint32_t nms);

#endif

4. Delay.c

#include "Delay.h"

uint32_t fac_us;
/*==================Delay calibration function====================*/
/* The parameter uint8_t SYSCLK is the system clock */
/*================================================ ==*/
void My_Delay_us_init(uint8_t SYSCLK)
{
     fac_us=SYSCLK;
}

/*==================Nanosecond level Delay==================*/
void My_Delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t told,tnow,tcnt=0;
    uint32_t reload=SysTick->LOAD;
    ticks=nus*fac_us;
    told=SysTick->VAL;
    while(1)
    {
        tnow=SysTick->VAL;
        if(tnow!=told)
        {
            if(tnow<told)tcnt + =told-tnow;
            else tcnt + =reload-tnow + told;
            told=tnow;
            if(tcnt>=ticks)break;
        }
    };
}

/*==================Millisecond level Delay==================*/
void My_Delay_ms(uint32_t nms)
{
while(nms--)
{
My_Delay_us(1000);
}
}

5. Main.c

/* USER CODE BEGIN Header */
/**
  *************************************************** ****************************
  * @file: main.c
  * @brief: Main program body
  *************************************************** ****************************
  *@attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  *************************************************** ****************************
  */
/* USER CODE END Header */
/* Includes ----------------------------------------------- ------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes -------------------------------------------------- ----------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "MT6701.h"
#include "Delay.h"
/* USER CODE END Includes */

/* Private typedef ----------------------------------------------- -------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define -------------------------------------------------- ---------------*/
/* USER CODE BEGIN PD */
/*==================Define serial port transceiver function array size================*/
#define USART1_Rx_Data_Number 1
#define USART1_Tx_Data_Number 1

uint8_t USART1_Tx_Data[USART1_Tx_Data_Number];
uint8_t USART1_Rx_Data [USART1_Rx_Data_Number];
/* USER CODE END PD */

/* Private macro ----------------------------------------------- ---------------*/
/* USER CODE BEGIN PM */
/*======================Print output redirection====================== */
/*-----------------Please cooperate with #include"stdio.h"------------------*/
int fputc(int ch, FILE *f)
{
 uint8_t temp[1] = {ch};
 HAL_UART_Transmit( & amp;huart1, temp, 1, 2);
 return ch;
}
/*-----------------Don't forget to open the USE MicroLIB library-----------------*/
/*====================usart1 receiving interrupt function==================*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
HAL_UART_Transmit( & amp;huart1, USART1_Rx_Data, USART1_Rx_Data_Number, 10);
}
HAL_UART_Receive_IT ( & amp;huart1, USART1_Rx_Data , USART1_Rx_Data_Number);//Restart receive interrupt
}
/* USER CODE END PM */

/* Private variables -------------------------------------------------- -----------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes --------------------------------------------- --*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/*Private user code------------------------------------------------ ----------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
double MT6701_Data = 0.0; //Used to receive magnetic encoder
  /* USER CODE END 1 */

  /* MCU Configuration------------------------------------------------- ----------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
My_Delay_us_init(72); //Delay function initialization
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
MT6701_Data = MT6701_RecvData(My_I2C_SDA_GPIO_Port, My_I2C_SDA_Pin, My_I2C_SCL_GPIO_Port, My_I2C_SCL_Pin, 0);
printf("%.2f\
", MT6701_Data);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(500);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig( & amp;RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig( & amp;RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT
/**
  * @brief Reports the name of the source file and the source line number
  * where the assert_param error has occurred.
  * @param file: pointer to the source file name
  * @param line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\
", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */