【STM32】HAL库教程-SPI通信

使用工具和依赖

  • 芯片:STM32C011F6U6、MA782(芯片手册
  • 代码初始化软件:STM32CUBEMX
  • IDE:MDK-ARM Keil5
  • 依赖:stm32c0xx hal库

SPI通信实验

根据MA782芯片手册,实现MCU芯片读/写MA782内部寄存器,并进行SPI通信的功能。

  • ma782_driver.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Define to prevent recursive inclusion */
#ifndef __MA782_DRIVER_H
#define __MA782_DRIVER_H
/* =================================================================================
File name: __MA782_DRIVER_H
Author: AdventurerDXC
===================================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/

#include "main.h"

// MA782寄存器地址
#define MA782_REG_ZERO_HIGH 0x0000 // 零位高字节
#define MA782_REG_ZERO_LOW 0x0100 // 零位低字节
#define MA782_REG_BIAS_TRIM 0x0200 // 偏置电流调整
#define MA782_REG_ENABLE_TRIM_X 0x0300 // 启用X轴偏置调整
#define MA782_REG_ENABLE_TRIM_Y 0x0300 // 启用Y轴偏置调整
#define MA782_REG_CYCLE_TIME_LOW 0x0400 // 周期时间低字节
#define MA782_REG_CYCLE_TIME_HIGH 0x0500 // 周期时间高字节
#define MA782_REG_MAGNET_LOW_THRESH 0x0600 // 磁场强度低阈值
#define MA782_REG_MAGNET_HIGH_THRESH 0x0600 // 磁场强度高阈值
#define MA782_REG_MAGNET_ENABLE 0x0700 // 磁场强度检测使能
#define MA782_REG_ND_MODE 0x0700 // ND引脚模式
#define MA782_REG_ND_HYSTERESIS 0x0700 // ND引脚迟滞
#define MA782_REG_ROTATION_DIRECTION 0x0900 // 旋转方向
#define MA782_REG_REFERENCE_ANGLE 0x0A00 // 参考角度 ASC mode
#define MA782_REG_ASC_ENABLE 0x0B00 // 自动采样使能 ASC mode
#define MA782_REG_ASC_REGISTER 0x0B00 // 自动采样寄存器
#define MA782_REG_FILTER_WINDOW 0x0E00 // 滤波窗口大小
#define MA782_REG_ERROR_FLAGS 0x1A00 // 错误标志
#define MA782_REG_MAGNET_FLAGS 0x1B00 // 磁场标志

// MA782寄存器位定义
#define MA782_ENABLE_TRIM_X (1 << 7) // 启用X轴偏置调整
#define MA782_ENABLE_TRIM_Y (1 << 6) // 启用Y轴偏置调整
#define MA782_ND_MODE_LOGIC_LEVEL (1 << 7) // ND引脚逻辑电平模式
#define MA782_ND_HYSTERESIS_MASK 0x3F // ND引脚迟滞掩码
#define MA782_MAGNET_ENABLE (1 << 7) // 磁场强度检测使能
#define MA782_ASC_ENABLE (1 << 7) // 自动采样使能
#define MA782_ASC_REGISTER_ENABLE (1 << 7) // 自动采样寄存器使能

// MA782命令宏定义
#define MA782_CMD_READ_ANGLE 0x0000 // 读取角度
#define MA782_CMD_CLEAR_ERROR_FLAGS 0x2000 // 清除错误标志
#define MA782_CMD_READ_REGISTER 0x4000 // 读取寄存器
#define MA782_CMD_WRITE_REGISTER 0x8000 // 写入寄存器
#define MA782_CMD_RESTORE_ALL_NVM 0xA000 // 从NVM恢复所有寄存器
#define MA782_CMD_STORE_ALL_NVM 0xC000 // 存储所有寄存器到NVM
#define MA782_CMD_STORE_SINGLE_NVM 0xE000 // 存储单个寄存器到NV

// 齿轮传动比
#define gear_ratio 7/4

typedef struct MA782_Driver_ MA782_Driver;

struct MA782_Driver_{
uint8_t dev_id; // 磁编码器id

SPI_HandleTypeDef *hspi;
GPIO_TypeDef *cs_port;
uint16_t cs_pin;

HAL_StatusTypeDef status; // 状态

uint16_t rx_buf[2]; // 接收数据 2x16bits
uint16_t tx_buf[2]; // 发送数据 2x16bits

q15_t origin; // 零点

q15_t* data; // 角度数据
};

typedef enum {
true=1, false=0
}bool;

MA782_Driver* new_MA782_Driver(uint8_t dev_id, SPI_HandleTypeDef *hspi,
GPIO_TypeDef *cs_port, uint16_t cs_pin);

void delete_MA782_Driver(MA782_Driver* hdev);

HAL_StatusTypeDef MA782_Driver_Init(MA782_Driver *hdev, q15_t* data);

HAL_StatusTypeDef MA782_Driver_SetCommand(MA782_Driver *hdev,
uint16_t pTxData, uint16_t* pRxData); // 与MCU进行SPI通信

HAL_StatusTypeDef MA782_Driver_ReadAngle(MA782_Driver *hdev); // 读角度

bool MA782_Driver_CheckMagField(MA782_Driver *hdev); // 检查磁编码器位置的磁场在阈值范围内

HAL_StatusTypeDef MA782_Driver_SetOrigin(MA782_Driver *hdev, q15_t origin); // 设置磁编码器零点

HAL_StatusTypeDef MA782_Driver_SetRotDirection(MA782_Driver *hdev, bool dir); // 设置磁编码器旋转正向

float32_t MA782_Driver_Q15_to_angle(MA782_Driver *hdev); // 角度q15_t->float

#ifdef __cplusplus
}
#endif

#endif

  • ma782_driver.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* =================================================================================
File name: __MA782_Driver_DRIVER_C
Author: AdventurerDXC
===================================================================================*/
#include "ma782_driver.h"

MA782_Driver* new_MA782_Driver(uint8_t dev_id, SPI_HandleTypeDef *hspi,
GPIO_TypeDef *cs_port, uint16_t cs_pin)
{
MA782_Driver* hdev = NULL;
hdev = (MA782_Driver*)malloc(sizeof(MA782_Driver));
if (hdev == NULL)
{
//printf("WARN: MA782_Driver_Driver[%d] initialization failed.\r\n", dev_id);
return NULL;
}
//printf("\t");

hdev->dev_id = dev_id;

hdev->hspi = hspi;
hdev->cs_port = cs_port;
hdev->cs_pin = cs_pin;

return hdev;
}

void delete_MA782_Driver(MA782_Driver* hdev)
{
free(hdev->hspi);
free(hdev->cs_port);
free(hdev->data);
free(hdev);
}

HAL_StatusTypeDef MA782_Driver_Init(MA782_Driver *hdev, q15_t* data)
{
if(hdev->data != NULL)
free(hdev->data);

if(data == NULL)
hdev->data = (q15_t*)malloc(sizeof(q15_t));
else
hdev->data = data;

HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_SET);
return HAL_OK;
}

HAL_StatusTypeDef MA782_Driver_SetCommand(MA782_Driver *hdev,
uint16_t pTxData, uint16_t* pRxData)
{
hdev->status = HAL_OK;
HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_RESET);

hdev->tx_buf[0] = pTxData;
hdev->tx_buf[1] = 0;

hdev->status = HAL_SPI_TransmitReceive(hdev->hspi, (uint8_t*)hdev->tx_buf, (uint8_t*)hdev->rx_buf, 2, HAL_MAX_DELAY);

if((hdev->rx_buf[0] & 0xF0) != (hdev->rx_buf[1] & 0xF0))
hdev->status = HAL_ERROR;
else
*pRxData = hdev->rx_buf[1] & 0x0F;

HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_SET);

return hdev->status;
}

HAL_StatusTypeDef MA782_Driver_ReadAngle(MA782_Driver *hdev)
{
HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_RESET);

hdev->tx_buf[0] = 0;
hdev->tx_buf[1] = 0;

hdev->status = HAL_SPI_TransmitReceive(hdev->hspi, (uint8_t*)hdev->tx_buf, (uint8_t*)hdev->rx_buf, 1, HAL_MAX_DELAY);
if (hdev->status == HAL_OK)
*hdev->data = (q15_t)(hdev->rx_buf[0] << 1) - hdev->origin;

HAL_GPIO_WritePin(hdev->cs_port, hdev->cs_pin, GPIO_PIN_SET);

return hdev->status;
}

bool MA782_Driver_CheckMagField(MA782_Driver *hdev)
{
uint16_t cmd = MA782_CMD_READ_REGISTER | MA782_REG_MAGNET_FLAGS;
uint8_t* rxdata;
MA782_Driver_SetCommand(hdev, cmd, (uint16_t*)rxdata);

if(*rxdata & 0xC0) return false;
else return true;
}

HAL_StatusTypeDef MA782_Driver_SetOrigin(MA782_Driver *hdev, q15_t origin)
{
hdev->origin = origin;
uint16_t cmd = MA782_CMD_WRITE_REGISTER | MA782_REG_ZERO_HIGH | (hdev->origin >> 8);
uint8_t* rxdata;
hdev->status = MA782_Driver_SetCommand(hdev, cmd, (uint16_t*)rxdata);
if(*rxdata != (hdev->origin >> 8)) hdev->status = HAL_ERROR;

cmd = MA782_CMD_WRITE_REGISTER | MA782_REG_ZERO_LOW | (hdev->origin & 0x00FF);
hdev->status = MA782_Driver_SetCommand(hdev, cmd, (uint16_t*)rxdata);
if(*rxdata != (hdev->origin & 0x00FF)) hdev->status = HAL_ERROR;

return hdev->status;
}

HAL_StatusTypeDef MA782_Driver_SetRotDirection(MA782_Driver *hdev, bool dir)
{
uint16_t cmd = MA782_CMD_WRITE_REGISTER | MA782_REG_ROTATION_DIRECTION | (dir << 7);
uint8_t* rxdata;
hdev->status = MA782_Driver_SetCommand(hdev, cmd, (uint16_t*)rxdata);
if(*rxdata != (dir << 7)) hdev->status = HAL_ERROR;

return hdev->status;
}

float32_t MA782_Driver_Q15_to_angle(MA782_Driver *hdev)
{
return ((*hdev->data) >> 15)*360*gear_ratio;
}