新增驱动文件
This commit is contained in:
commit
a6cb7e50f8
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "windows-gcc-x64",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"compilerPath": "C:/TDM-GCC-64/bin/gcc.exe",
|
||||
"cStandard": "${default}",
|
||||
"cppStandard": "${default}",
|
||||
"intelliSenseMode": "windows-gcc-x64",
|
||||
"compilerArgs": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "C/C++ Runner: Debug Session",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"cwd": "e:/work/stm32/driver/DAC",
|
||||
"program": "e:/work/stm32/driver/DAC/build/Debug/outDebug",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"C_Cpp_Runner.cCompilerPath": "gcc",
|
||||
"C_Cpp_Runner.cppCompilerPath": "g++",
|
||||
"C_Cpp_Runner.debuggerPath": "gdb",
|
||||
"C_Cpp_Runner.cStandard": "",
|
||||
"C_Cpp_Runner.cppStandard": "",
|
||||
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat",
|
||||
"C_Cpp_Runner.useMsvc": false,
|
||||
"C_Cpp_Runner.warnings": [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wpedantic",
|
||||
"-Wshadow",
|
||||
"-Wformat=2",
|
||||
"-Wcast-align",
|
||||
"-Wconversion",
|
||||
"-Wsign-conversion",
|
||||
"-Wnull-dereference"
|
||||
],
|
||||
"C_Cpp_Runner.msvcWarnings": [
|
||||
"/W4",
|
||||
"/permissive-",
|
||||
"/w14242",
|
||||
"/w14287",
|
||||
"/w14296",
|
||||
"/w14311",
|
||||
"/w14826",
|
||||
"/w44062",
|
||||
"/w44242",
|
||||
"/w14905",
|
||||
"/w14906",
|
||||
"/w14263",
|
||||
"/w44265",
|
||||
"/w14928"
|
||||
],
|
||||
"C_Cpp_Runner.enableWarnings": true,
|
||||
"C_Cpp_Runner.warningsAsError": false,
|
||||
"C_Cpp_Runner.compilerArgs": [],
|
||||
"C_Cpp_Runner.linkerArgs": [],
|
||||
"C_Cpp_Runner.includePaths": [],
|
||||
"C_Cpp_Runner.includeSearch": [
|
||||
"*",
|
||||
"**/*"
|
||||
],
|
||||
"C_Cpp_Runner.excludeSearch": [
|
||||
"**/build",
|
||||
"**/build/**",
|
||||
"**/.*",
|
||||
"**/.*/**",
|
||||
"**/.vscode",
|
||||
"**/.vscode/**"
|
||||
],
|
||||
"C_Cpp_Runner.useAddressSanitizer": false,
|
||||
"C_Cpp_Runner.useUndefinedSanitizer": false,
|
||||
"C_Cpp_Runner.useLeakSanitizer": false,
|
||||
"C_Cpp_Runner.showCompilationTime": false,
|
||||
"C_Cpp_Runner.useLinkTimeOptimization": false,
|
||||
"C_Cpp_Runner.msvcSecureNoWarnings": false
|
||||
}
|
|
@ -0,0 +1,455 @@
|
|||
#include "ad7124.h"
|
||||
/* Error codes */
|
||||
#define INVALID_VAL -1 /* Invalid argument */
|
||||
#define COMM_ERR -2 /* Communication error on receive */
|
||||
#define AD7124_TIMEOUT -3 /* A timeout has occured */
|
||||
|
||||
// 配置ad7124寄存器的值,根据实际项目需求配置
|
||||
static ad7124_st_reg_t ad7124_regs[AD7124_REG_NO] = {
|
||||
{AD7124_STATUS, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Status */
|
||||
{AD7124_ADC_CONTROL, 0x0280, AD7124_SIZE_2, AD7124_RW}, /* AD7124_ADC_Control */
|
||||
{AD7124_DATA, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Data */
|
||||
{AD7124_IOCON1, 0x000000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_IOCon1 */
|
||||
{AD7124_IOCON2, 0x0000, AD7124_SIZE_2, AD7124_RW}, /* AD7124_IOCon2 */
|
||||
{AD7124_ID, 0x02, AD7124_SIZE_1, AD7124_R}, /* AD7124_ID */
|
||||
{AD7124_ERROR, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Error */
|
||||
{AD7124_ERROR_EN, 0x000040, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Error_En */
|
||||
{AD7124_MCLK_COUNT, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Mclk_Count */
|
||||
{AD7124_CHANNEL_0, 0x0051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
|
||||
{AD7124_CHANNEL_1, 0x0071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
|
||||
{AD7124_CHANNEL_2, 0x0091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
|
||||
{AD7124_CHANNEL_3, 0x00B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
|
||||
{AD7124_CHANNEL_4, 0x00D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
|
||||
{AD7124_CHANNEL_5, 0x00F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
|
||||
{AD7124_CHANNEL_6, 0x0111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
|
||||
{AD7124_CHANNEL_7, 0x0131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
|
||||
{AD7124_CHANNEL_8, 0x0151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
|
||||
{AD7124_CHANNEL_9, 0x0171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
|
||||
{AD7124_CHANNEL_10, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_10 */
|
||||
{AD7124_CHANNEL_11, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_11 */
|
||||
{AD7124_CHANNEL_12, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_12 */
|
||||
{AD7124_CHANNEL_13, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_13 */
|
||||
{AD7124_CHANNEL_14, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_14 */
|
||||
{AD7124_CHANNEL_15, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_15 */
|
||||
{AD7124_CONFIG_0, 0x01E0, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_0 */
|
||||
{AD7124_CONFIG_1, 0x0040, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_1 */
|
||||
{AD7124_CONFIG_2, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_2 */
|
||||
{AD7124_CONFIG_3, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_3 */
|
||||
{AD7124_CONFIG_4, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_4 */
|
||||
{AD7124_CONFIG_5, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_5 */
|
||||
{AD7124_CONFIG_6, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_6 */
|
||||
{AD7124_CONFIG_7, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_7 */
|
||||
{AD7124_FILTER_0, 0x060020, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_0 */
|
||||
{AD7124_FILTER_1, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_1 */
|
||||
{AD7124_FILTER_2, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_2 */
|
||||
{AD7124_FILTER_3, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_3 */
|
||||
{AD7124_FILTER_4, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_4 */
|
||||
{AD7124_FILTER_5, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_5 */
|
||||
{AD7124_FILTER_6, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_6 */
|
||||
{AD7124_FILTER_7, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_7 */
|
||||
{AD7124_OFFSET_0, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_0 */
|
||||
{AD7124_OFFSET_1, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_1 */
|
||||
{AD7124_OFFSET_2, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_2 */
|
||||
{AD7124_OFFSET_3, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_3 */
|
||||
{AD7124_OFFSET_4, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_4 */
|
||||
{AD7124_OFFSET_5, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_5 */
|
||||
{AD7124_OFFSET_6, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_6 */
|
||||
{AD7124_OFFSET_7, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_7 */
|
||||
{AD7124_GAIN_0, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_0 */
|
||||
{AD7124_GAIN_1, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_1 */
|
||||
{AD7124_GAIN_2, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_2 */
|
||||
{AD7124_GAIN_3, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_3 */
|
||||
{AD7124_GAIN_4, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_4 */
|
||||
{AD7124_GAIN_5, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_5 */
|
||||
{AD7124_GAIN_6, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_6 */
|
||||
{AD7124_GAIN_7, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_7 */
|
||||
};
|
||||
|
||||
static ad7124_st_reg_t ad7124_channel_regs[AD7124_CHANNEL_EN_MAX] = {
|
||||
{AD7124_CHANNEL_0, 0x8051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
|
||||
{AD7124_CHANNEL_1, 0x8071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
|
||||
{AD7124_CHANNEL_2, 0x8091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
|
||||
{AD7124_CHANNEL_3, 0x80B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
|
||||
{AD7124_CHANNEL_4, 0x80D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
|
||||
{AD7124_CHANNEL_5, 0x80F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
|
||||
{AD7124_CHANNEL_6, 0x8111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
|
||||
{AD7124_CHANNEL_7, 0x8131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
|
||||
{AD7124_CHANNEL_8, 0x8151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
|
||||
{AD7124_CHANNEL_9, 0x8171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
|
||||
};
|
||||
|
||||
ad7124_analog_t ad7124_analog[AD7124_CHANNEL_EN_MAX] = {NULL}; // AD通道采样结构体数组,用于存放AD通道采样数据
|
||||
/**
|
||||
* @brief 无校验读取AD7124寄存器
|
||||
*
|
||||
* 读取AD7124的寄存器值,不进行校验。
|
||||
*
|
||||
* @param p_reg 指向要读取的寄存器结构的指针
|
||||
*
|
||||
* @return 读取成功返回0,失败返回负值
|
||||
*/
|
||||
int32_t ad7124_no_check_read_register(ad7124_st_reg_t *p_reg)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t i = 0;
|
||||
uint8_t add_status_length = 0;
|
||||
|
||||
/* Build the Command word */
|
||||
buffer[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_RD |
|
||||
AD7124_COMM_REG_RA(p_reg->addr);
|
||||
|
||||
/*
|
||||
* If this is an AD7124_DATA register read, and the DATA_STATUS bit is set
|
||||
* in ADC_CONTROL, need to read 4, not 3 bytes for DATA with STATUS
|
||||
*/
|
||||
if ((p_reg->addr == AD7124_DATA) &&
|
||||
(ad7124_regs[AD7124_ADC_CONTROL].value & AD7124_ADC_CTRL_REG_DATA_STATUS))
|
||||
{
|
||||
add_status_length = 1; // 此处是根据寄存器配置而决定,根据AD7124_ADC_CONTROL第10位决定
|
||||
}
|
||||
|
||||
/* Read data from the device */
|
||||
ret = ad7124_read_write_spi(buffer, p_reg->size + 1 + add_status_length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* if reading Data with 4 bytes, need to copy the status byte to the STATUS
|
||||
* register struct value member
|
||||
*/
|
||||
if (add_status_length)
|
||||
{
|
||||
ad7124_regs[AD7124_STATUS].value = buffer[p_reg->size + 1];
|
||||
}
|
||||
|
||||
/* Build the result */
|
||||
p_reg->value = 0;
|
||||
for (i = 1; i < p_reg->size + 1; i++)
|
||||
{
|
||||
p_reg->value <<= 8;
|
||||
p_reg->value += buffer[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向AD7124寄存器写入数据,不进行校验
|
||||
*
|
||||
* 将数据写入指定的AD7124寄存器,不进行数据校验。
|
||||
*
|
||||
* @param reg 指向要写入数据的寄存器地址和值的指针
|
||||
* @return 写入结果,成功返回0,失败返回负值
|
||||
*/
|
||||
int32_t ad7124_no_check_write_register(ad7124_st_reg_t *reg)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
int32_t reg_value = 0;
|
||||
uint8_t wr_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t i = 0;
|
||||
|
||||
/* Build the Command word */
|
||||
wr_buf[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_WR |
|
||||
AD7124_COMM_REG_RA(reg->addr);
|
||||
|
||||
/* Fill the write buffer */
|
||||
reg_value = reg->value;
|
||||
for (i = 0; i < reg->size; i++)
|
||||
{
|
||||
wr_buf[reg->size - i] = reg_value & 0xFF;
|
||||
reg_value >>= 8;
|
||||
}
|
||||
|
||||
/* Write data to the device */
|
||||
ret = ad7124_read_write_spi(wr_buf, reg->size + 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从AD7124寄存器读取数据
|
||||
*
|
||||
* 该函数用于从AD7124的指定寄存器中读取数据。
|
||||
*
|
||||
* @param p_reg 指向一个ad7124_st_reg_t类型的指针,其中包含了要读取的寄存器的地址。
|
||||
*
|
||||
* @return 返回读取到的数据,如果读取失败则返回负数。
|
||||
*
|
||||
* 在读取寄存器之前,会先检查ERROR寄存器的SPI_IGNORE_ERR位
|
||||
*/
|
||||
int32_t ad7124_read_register(ad7124_st_reg_t *p_reg)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if (p_reg->addr != AD7124_ERROR && (ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
|
||||
{
|
||||
ret = ad7124_wait_for_spi_ready(AD7124_RDY); // 读寄存器之前检查ERROR寄存器的SPI_IGNORE_ERR位
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = ad7124_no_check_read_register(p_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向AD7124寄存器写入数据
|
||||
*
|
||||
* 将数据写入AD7124的指定寄存器。如果错误寄存器中启用了忽略SPI错误的功能,则在写入前会等待SPI接口准备就绪。
|
||||
*
|
||||
* @param p_reg 指向要写入数据的寄存器结构体的指针
|
||||
*
|
||||
* @return 返回写入操作的结果。如果操作成功,则返回0;否则返回负数表示错误。
|
||||
*/
|
||||
int32_t ad7124_write_register(ad7124_st_reg_t *p_reg)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
if ((ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
|
||||
{
|
||||
ret = ad7124_wait_for_spi_ready(AD7124_RDY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = ad7124_no_check_write_register(p_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重置AD7124设备
|
||||
*
|
||||
* 该函数通过SPI接口向AD7124发送重置命令,并等待设备完成上电过程。
|
||||
*
|
||||
* @return 返回函数执行结果,成功返回0,失败返回错误码。
|
||||
*/
|
||||
int32_t ad7124_reset(void)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint8_t wr_buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 发送64个1,复位ad7124芯片
|
||||
|
||||
ret = ad7124_read_write_spi(wr_buf, 8);
|
||||
|
||||
/* Read POR bit to clear */
|
||||
ret = ad7124_wait_to_power_on(AD7124_RDY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待SPI接口准备就绪
|
||||
*
|
||||
* 等待AD7124的SPI接口准备就绪,直到超时。
|
||||
*
|
||||
* @param timeout 超时时间(单位:毫秒)
|
||||
* @return 成功返回0,超时返回AD7124_TIMEOUT
|
||||
*/
|
||||
int32_t ad7124_wait_for_spi_ready(uint32_t timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
int8_t ready = 0;
|
||||
|
||||
while (!ready && --timeout)
|
||||
{
|
||||
/* Read the value of the Error Register */
|
||||
ret = ad7124_read_register(&ad7124_regs[AD7124_ERROR]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check the SPI IGNORE Error bit in the Error Register */
|
||||
ready = (ad7124_regs[AD7124_ERROR].value &
|
||||
AD7124_ERR_REG_SPI_IGNORE_ERR) == 0;
|
||||
}
|
||||
|
||||
return timeout ? 0 : AD7124_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待AD7124电源开启
|
||||
*
|
||||
* 此函数将等待AD7124设备电源开启,直到超时或检测到电源开启标志。
|
||||
*
|
||||
* @param timeout 超时时间
|
||||
*
|
||||
* @return 返回0表示成功,返回AD7124_TIMEOUT表示超时
|
||||
*/
|
||||
int32_t ad7124_wait_to_power_on(uint32_t timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
int8_t powered_on = 0;
|
||||
|
||||
while (!powered_on && timeout--)
|
||||
{
|
||||
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check the POR_FLAG bit in the Status Register */
|
||||
powered_on = (ad7124_regs[AD7124_STATUS].value &
|
||||
AD7124_STATUS_REG_POR_FLAG) == 0;
|
||||
}
|
||||
|
||||
return (timeout || powered_on) ? 0 : AD7124_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待AD7124转换准备就绪
|
||||
*
|
||||
* 该函数等待AD7124完成转换并准备就绪。如果等待超时,则返回错误码。
|
||||
*
|
||||
* @param timeout 超时时间
|
||||
* @return 成功时返回0,超时时返回AD7124_TIMEOUT
|
||||
*/
|
||||
int32_t ad7124_wait_for_conv_ready(uint32_t timeout)
|
||||
{
|
||||
int32_t ret;
|
||||
int8_t ready = 0;
|
||||
|
||||
while (!ready && --timeout)
|
||||
{
|
||||
/* Read the value of the Status Register */
|
||||
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Check the RDY bit in the Status Register */
|
||||
ready = (ad7124_regs[AD7124_STATUS].value &
|
||||
AD7124_STATUS_REG_RDY) == 0;
|
||||
}
|
||||
|
||||
return timeout ? 0 : AD7124_TIMEOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从AD7124读取数据
|
||||
*
|
||||
* 从AD7124的数据寄存器中读取数据值。
|
||||
*
|
||||
* @return 读取到的数据值
|
||||
*/
|
||||
int32_t ad7124_read_data(void)
|
||||
{
|
||||
int32_t read_data;
|
||||
/* Read the value of the Status Register */
|
||||
ad7124_read_register(&ad7124_regs[AD7124_DATA]);
|
||||
/* Get the read result */
|
||||
read_data = ad7124_regs[AD7124_DATA].value;
|
||||
|
||||
return read_data;
|
||||
}
|
||||
/**
|
||||
* @brief 从AD7124获取模拟信号数据
|
||||
*
|
||||
* 该函数通过SPI接口从AD7124芯片获取模拟信号数据,并将数据保存到ad7124_analog中。
|
||||
*
|
||||
* @details
|
||||
* - 遍历所有模拟通道,对每个通道执行以下操作:
|
||||
* - 等待AD7124完成转换。
|
||||
* - 读取转换后的数据。
|
||||
* - 计算电压值(单极性计算公式)。
|
||||
* - 计算电流值(基于电压值和电阻值),有的通道没有电流值可以忽略。
|
||||
*
|
||||
* @note
|
||||
* - 转换完成后,通过公式计算电压和电流值,并将结果保存到全局数组ad7124_analog中。
|
||||
* - 电压计算公式:Code = (0xFFFFFF × AIN × Gain)/VREF,其中VREF为参考电压,GAIN为增益,AD_CODE为AD代码。
|
||||
* - 电流计算公式:电流 = 电压 / 电阻 * 1000,其中电阻值为AD7124_RES,单位转换为mA。
|
||||
*/
|
||||
// void ad7124_get_analog(void)
|
||||
// {
|
||||
// int32_t read_data;
|
||||
// uint8_t i;
|
||||
// uint8_t channel;
|
||||
// // for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
|
||||
// // {
|
||||
// // ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[i].value;
|
||||
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
|
||||
|
||||
// // ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
|
||||
// while (ad7124_wait_for_conv_ready(AD7124_RDY))
|
||||
// ; // 等待转换完成
|
||||
// channel = ad7124_regs[AD7124_STATUS].value;
|
||||
// ad7124_analog[channel].channel = channel;
|
||||
// read_data = ad7124_read_data();
|
||||
// ad7124_analog[channel].data = read_data;
|
||||
// ad7124_analog[channel].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式:Code = (0xFFFFFF × AIN × Gain)/VREF
|
||||
// ad7124_analog[channel].current = (float)(ad7124_analog[channel].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
|
||||
|
||||
// // ad7124_regs[AD7124_CHANNEL_0].value = 0;
|
||||
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
|
||||
// // }
|
||||
// }
|
||||
void ad7124_get_analog(uint8_t channel_nr)
|
||||
{
|
||||
int32_t read_data;
|
||||
// for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
|
||||
// {
|
||||
ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[channel_nr].value;
|
||||
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
|
||||
|
||||
while (ad7124_wait_for_conv_ready(AD7124_RDY))
|
||||
; // 等待转换完成
|
||||
ad7124_analog[channel_nr].channel = channel_nr;
|
||||
read_data = ad7124_read_data();
|
||||
ad7124_analog[channel_nr].data = read_data;
|
||||
ad7124_analog[channel_nr].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式:Code = (0xFFFFFF × AIN × Gain)/VREF
|
||||
ad7124_analog[channel_nr].current = (float)(ad7124_analog[channel_nr].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
|
||||
|
||||
ad7124_regs[AD7124_CHANNEL_0].value = 0;
|
||||
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
|
||||
// }
|
||||
}
|
||||
/**
|
||||
* @brief 配置AD7124设备
|
||||
*
|
||||
* 该函数负责初始化AD7124设备,初始化寄存器。
|
||||
*
|
||||
* @return 初始化结果,成功返回0,失败返回负数
|
||||
*/
|
||||
int32_t ad7124_setup(void)
|
||||
{
|
||||
int32_t ret;
|
||||
uint8_t reg_nr;
|
||||
// board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用,并且时序不一样,所以要先初始化SPI接口。
|
||||
/* Reset the device interface.*/
|
||||
ret = ad7124_reset();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
HAL_Delay(10);
|
||||
ad7124_read_register(&ad7124_regs[AD7124_ID]);
|
||||
/* Initialize registers AD7124_ADC_Control through AD7124_Filter_7. */
|
||||
for (reg_nr = AD7124_STATUS; reg_nr < AD7124_OFFSET_0; reg_nr++) // 对ad7124的可写寄存器进行配置,不包括只读寄存器
|
||||
{
|
||||
// ret = ad7124_read_register(&ad7124_regs[reg_nr]);
|
||||
if (ad7124_regs[reg_nr].rw == AD7124_RW)
|
||||
{
|
||||
ret = ad7124_write_register(&ad7124_regs[reg_nr]);
|
||||
ret = ad7124_read_register(&ad7124_regs[reg_nr]);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
HAL_GPIO_WritePin(AD7124_SYNC_GPIO_Port, AD7124_SYNC_Pin, GPIO_PIN_SET); // AD7124同步信号使能
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过SPI接口对AD7124进行读写操作
|
||||
*
|
||||
* 通过SPI接口对AD7124进行读写操作,。
|
||||
*
|
||||
* @param buff 指向待传输数据的指针
|
||||
* @param length 待传输数据的长度
|
||||
*
|
||||
* @return 传输结果,成功返回0,失败返回负数
|
||||
*/
|
||||
int32_t ad7124_read_write_spi(uint8_t *buff, uint8_t length)
|
||||
{
|
||||
int32_t ret;
|
||||
board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用,并且时序不一样,所以要先初始化SPI接口。
|
||||
board_spi_cs_on(AD7124);
|
||||
ret = spi_transmit_receive(&hspi1, buff, length);
|
||||
board_spi_cs_off(AD7124);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
#ifndef __AD7124_H
|
||||
#define __AD7124_H
|
||||
|
||||
/******************************************************************************/
|
||||
/***************************** Include Files **********************************/
|
||||
/******************************************************************************/
|
||||
#include "main.h"
|
||||
#include "user_spi.h"
|
||||
/******************************************************************************/
|
||||
/******************* Register map and register definitions ********************/
|
||||
/******************************************************************************/
|
||||
|
||||
/* Communication Register bits */
|
||||
#define AD7124_COMM_REG_WEN (0 << 7)
|
||||
#define AD7124_COMM_REG_WR (0 << 6)
|
||||
#define AD7124_COMM_REG_RD (1 << 6)
|
||||
#define AD7124_COMM_REG_RA(x) ((x) & 0x3F)
|
||||
|
||||
/* Status Register bits */
|
||||
#define AD7124_STATUS_REG_RDY (1 << 7)
|
||||
#define AD7124_STATUS_REG_ERROR_FLAG (1 << 6)
|
||||
#define AD7124_STATUS_REG_POR_FLAG (1 << 4)
|
||||
#define AD7124_STATUS_REG_CH_ACTIVE(x) ((x) & 0xF)
|
||||
|
||||
/* ADC_Control Register bits */
|
||||
#define AD7124_ADC_CTRL_REG_DOUT_RDY_DEL (1 << 12)
|
||||
#define AD7124_ADC_CTRL_REG_CONT_READ (1 << 11)
|
||||
#define AD7124_ADC_CTRL_REG_DATA_STATUS (1 << 10)
|
||||
#define AD7124_ADC_CTRL_REG_CS_EN (1 << 9)
|
||||
#define AD7124_ADC_CTRL_REG_REF_EN (1 << 8)
|
||||
#define AD7124_ADC_CTRL_REG_POWER_MODE(x) (((x) & 0x3) << 6)
|
||||
#define AD7124_ADC_CTRL_REG_MODE(x) (((x) & 0xF) << 2)
|
||||
#define AD7124_ADC_CTRL_REG_CLK_SEL(x) (((x) & 0x3) << 0)
|
||||
|
||||
/* IO_Control_1 Register bits */
|
||||
#define AD7124_IO_CTRL1_REG_GPIO_DAT2 (1 << 23)
|
||||
#define AD7124_IO_CTRL1_REG_GPIO_DAT1 (1 << 22)
|
||||
#define AD7124_IO_CTRL1_REG_GPIO_CTRL2 (1 << 19)
|
||||
#define AD7124_IO_CTRL1_REG_GPIO_CTRL1 (1 << 18)
|
||||
#define AD7124_IO_CTRL1_REG_PDSW (1 << 15)
|
||||
#define AD7124_IO_CTRL1_REG_IOUT1(x) (((x) & 0x7) << 11)
|
||||
#define AD7124_IO_CTRL1_REG_IOUT0(x) (((x) & 0x7) << 8)
|
||||
#define AD7124_IO_CTRL1_REG_IOUT_CH1(x) (((x) & 0xF) << 4)
|
||||
#define AD7124_IO_CTRL1_REG_IOUT_CH0(x) (((x) & 0xF) << 0)
|
||||
|
||||
/* IO_Control_1 AD7124-8 specific bits */
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT4 (1 << 23)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT3 (1 << 22)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT2 (1 << 21)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT1 (1 << 20)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL4 (1 << 19)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL3 (1 << 18)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL2 (1 << 17)
|
||||
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL1 (1 << 16)
|
||||
|
||||
/* IO_Control_2 Register bits */
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS7 (1 << 15)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS6 (1 << 14)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS5 (1 << 11)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS4 (1 << 10)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS3 (1 << 5)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS2 (1 << 4)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS1 (1 << 1)
|
||||
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS0 (1 << 0)
|
||||
|
||||
/* IO_Control_2 AD7124-8 specific bits */
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS15 (1 << 15)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS14 (1 << 14)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS13 (1 << 13)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS12 (1 << 12)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS11 (1 << 11)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS10 (1 << 10)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS9 (1 << 9)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS8 (1 << 8)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS7 (1 << 7)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS6 (1 << 6)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS5 (1 << 5)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS4 (1 << 4)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS3 (1 << 3)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS2 (1 << 2)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS1 (1 << 1)
|
||||
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS0 (1 << 0)
|
||||
|
||||
/* ID Register bits */
|
||||
#define AD7124_ID_REG_DEVICE_ID(x) (((x) & 0xF) << 4)
|
||||
#define AD7124_ID_REG_SILICON_REV(x) (((x) & 0xF) << 0)
|
||||
|
||||
/* Error Register bits */
|
||||
#define AD7124_ERR_REG_LDO_CAP_ERR (1 << 19)
|
||||
#define AD7124_ERR_REG_ADC_CAL_ERR (1 << 18)
|
||||
#define AD7124_ERR_REG_ADC_CONV_ERR (1 << 17)
|
||||
#define AD7124_ERR_REG_ADC_SAT_ERR (1 << 16)
|
||||
#define AD7124_ERR_REG_AINP_OV_ERR (1 << 15)
|
||||
#define AD7124_ERR_REG_AINP_UV_ERR (1 << 14)
|
||||
#define AD7124_ERR_REG_AINM_OV_ERR (1 << 13)
|
||||
#define AD7124_ERR_REG_AINM_UV_ERR (1 << 12)
|
||||
#define AD7124_ERR_REG_REF_DET_ERR (1 << 11)
|
||||
#define AD7124_ERR_REG_DLDO_PSM_ERR (1 << 9)
|
||||
#define AD7124_ERR_REG_ALDO_PSM_ERR (1 << 7)
|
||||
#define AD7124_ERR_REG_SPI_IGNORE_ERR (1 << 6)
|
||||
#define AD7124_ERR_REG_SPI_SLCK_CNT_ERR (1 << 5)
|
||||
#define AD7124_ERR_REG_SPI_READ_ERR (1 << 4)
|
||||
#define AD7124_ERR_REG_SPI_WRITE_ERR (1 << 3)
|
||||
#define AD7124_ERR_REG_SPI_CRC_ERR (1 << 2)
|
||||
#define AD7124_ERR_REG_MM_CRC_ERR (1 << 1)
|
||||
#define AD7124_ERR_REG_ROM_CRC_ERR (1 << 0)
|
||||
|
||||
/* Error_En Register bits */
|
||||
#define AD7124_ERREN_REG_MCLK_CNT_EN (1 << 22)
|
||||
#define AD7124_ERREN_REG_LDO_CAP_CHK_TEST_EN (1 << 21)
|
||||
#define AD7124_ERREN_REG_LDO_CAP_CHK(x) (((x) & 0x3) << 19)
|
||||
#define AD7124_ERREN_REG_ADC_CAL_ERR_EN (1 << 18)
|
||||
#define AD7124_ERREN_REG_ADC_CONV_ERR_EN (1 << 17)
|
||||
#define AD7124_ERREN_REG_ADC_SAT_ERR_EN (1 << 16)
|
||||
#define AD7124_ERREN_REG_AINP_OV_ERR_EN (1 << 15)
|
||||
#define AD7124_ERREN_REG_AINP_UV_ERR_EN (1 << 14)
|
||||
#define AD7124_ERREN_REG_AINM_OV_ERR_EN (1 << 13)
|
||||
#define AD7124_ERREN_REG_AINM_UV_ERR_EN (1 << 12)
|
||||
#define AD7124_ERREN_REG_REF_DET_ERR_EN (1 << 11)
|
||||
#define AD7124_ERREN_REG_DLDO_PSM_TRIP_TEST_EN (1 << 10)
|
||||
#define AD7124_ERREN_REG_DLDO_PSM_ERR_ERR (1 << 9)
|
||||
#define AD7124_ERREN_REG_ALDO_PSM_TRIP_TEST_EN (1 << 8)
|
||||
#define AD7124_ERREN_REG_ALDO_PSM_ERR_EN (1 << 7)
|
||||
#define AD7124_ERREN_REG_SPI_IGNORE_ERR_EN (1 << 6)
|
||||
#define AD7124_ERREN_REG_SPI_SCLK_CNT_ERR_EN (1 << 5)
|
||||
#define AD7124_ERREN_REG_SPI_READ_ERR_EN (1 << 4)
|
||||
#define AD7124_ERREN_REG_SPI_WRITE_ERR_EN (1 << 3)
|
||||
#define AD7124_ERREN_REG_SPI_CRC_ERR_EN (1 << 2)
|
||||
#define AD7124_ERREN_REG_MM_CRC_ERR_EN (1 << 1)
|
||||
#define AD7124_ERREN_REG_ROM_CRC_ERR_EN (1 << 0)
|
||||
|
||||
/* Channel Registers 0-15 bits */
|
||||
#define AD7124_CH_MAP_REG_CH_ENABLE (1 << 15)
|
||||
#define AD7124_CH_MAP_REG_SETUP(x) (((x) & 0x7) << 12)
|
||||
#define AD7124_CH_MAP_REG_AINP(x) (((x) & 0x1F) << 5)
|
||||
#define AD7124_CH_MAP_REG_AINM(x) (((x) & 0x1F) << 0)
|
||||
|
||||
/* Configuration Registers 0-7 bits */
|
||||
#define AD7124_CFG_REG_BIPOLAR (1 << 11)
|
||||
#define AD7124_CFG_REG_BURNOUT(x) (((x) & 0x3) << 9)
|
||||
#define AD7124_CFG_REG_REF_BUFP (1 << 8)
|
||||
#define AD7124_CFG_REG_REF_BUFM (1 << 7)
|
||||
#define AD7124_CFG_REG_AIN_BUFP (1 << 6)
|
||||
#define AD7124_CFG_REG_AINN_BUFM (1 << 5)
|
||||
#define AD7124_CFG_REG_REF_SEL(x) ((x) & 0x3) << 3
|
||||
#define AD7124_CFG_REG_PGA(x) (((x) & 0x7) << 0)
|
||||
|
||||
/* Filter Register 0-7 bits */
|
||||
#define AD7124_FILT_REG_FILTER(x) (((x) & 0x7) << 21)
|
||||
#define AD7124_FILT_REG_REJ60 (1 << 20)
|
||||
#define AD7124_FILT_REG_POST_FILTER(x) (((x) & 0x7) << 17)
|
||||
#define AD7124_FILT_REG_SINGLE_CYCLE (1 << 16)
|
||||
#define AD7124_FILT_REG_FS(x) (((x) & 0x7FF) << 0)
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** Types Declarations *******************************/
|
||||
/******************************************************************************/
|
||||
|
||||
/*! AD7124 registers list*/
|
||||
typedef enum
|
||||
{
|
||||
AD7124_STATUS = 0X00, // 只读的状态寄存器,读取芯片状态
|
||||
AD7124_ADC_CONTROL, // 控制寄存器,设置采样速率等
|
||||
AD7124_DATA, // 数据寄存器,读取采样数据
|
||||
AD7124_IOCON1, // 设置激励电流等参数,用作RTD测试时可用
|
||||
AD7124_IOCON2, // 使能偏置电压
|
||||
AD7124_ID, // ID寄存器,部分芯片的ID和手册上有所区别,可用此寄存器测试SPI通讯
|
||||
AD7124_ERROR, // 错误寄存器,读取错误信息,读写寄存器之前先读下该寄存器,检测芯片状态是否支持读写
|
||||
AD7124_ERROR_EN, // 通过使能该寄存器的相应位来使能或者禁用诊断功能
|
||||
AD7124_MCLK_COUNT, // 监控主时钟频率
|
||||
AD7124_CHANNEL_0, // 设置AD采样通道和所需要的配置,其中的Setup位决定了采用哪种Config、Filter、Offset、Gain寄存器的配置;共有八种配置
|
||||
AD7124_CHANNEL_1, // 通道寄存器的顺序并不是从AI0引脚读到最后一个引脚,而是通过自己的设置来决定顺序
|
||||
AD7124_CHANNEL_2,
|
||||
AD7124_CHANNEL_3,
|
||||
AD7124_CHANNEL_4,
|
||||
AD7124_CHANNEL_5,
|
||||
AD7124_CHANNEL_6,
|
||||
AD7124_CHANNEL_7,
|
||||
AD7124_CHANNEL_8,
|
||||
AD7124_CHANNEL_9,
|
||||
AD7124_CHANNEL_10,
|
||||
AD7124_CHANNEL_11,
|
||||
AD7124_CHANNEL_12,
|
||||
AD7124_CHANNEL_13,
|
||||
AD7124_CHANNEL_14,
|
||||
AD7124_CHANNEL_15,
|
||||
AD7124_CONFIG_0, // 配置极性,增益,基准选择等参数
|
||||
AD7124_CONFIG_1,
|
||||
AD7124_CONFIG_2,
|
||||
AD7124_CONFIG_3,
|
||||
AD7124_CONFIG_4,
|
||||
AD7124_CONFIG_5,
|
||||
AD7124_CONFIG_6,
|
||||
AD7124_CONFIG_7,
|
||||
AD7124_FILTER_0,
|
||||
AD7124_FILTER_1, // 配置滤波器
|
||||
AD7124_FILTER_2,
|
||||
AD7124_FILTER_3,
|
||||
AD7124_FILTER_4,
|
||||
AD7124_FILTER_5,
|
||||
AD7124_FILTER_6,
|
||||
AD7124_FILTER_7,
|
||||
AD7124_OFFSET_0,
|
||||
AD7124_OFFSET_1,
|
||||
AD7124_OFFSET_2,
|
||||
AD7124_OFFSET_3,
|
||||
AD7124_OFFSET_4,
|
||||
AD7124_OFFSET_5,
|
||||
AD7124_OFFSET_6,
|
||||
AD7124_OFFSET_7,
|
||||
AD7124_GAIN_0,
|
||||
AD7124_GAIN_1,
|
||||
AD7124_GAIN_2,
|
||||
AD7124_GAIN_3,
|
||||
AD7124_GAIN_4,
|
||||
AD7124_GAIN_5,
|
||||
AD7124_GAIN_6,
|
||||
AD7124_GAIN_7,
|
||||
AD7124_REG_NO
|
||||
} ad7124_registers_addr_e; // 寄存器地址
|
||||
typedef enum
|
||||
{
|
||||
|
||||
AD7124_SIZE_1 = 1,
|
||||
AD7124_SIZE_2 = 2,
|
||||
AD7124_SIZE_3 = 3,
|
||||
} ad7124_registers_size_e; // 寄存器字节大小
|
||||
typedef enum
|
||||
{
|
||||
AD7124_RW = 1,
|
||||
AD7124_R = 2,
|
||||
AD7124_W = 3,
|
||||
} ad7124_registers_rw_e; // 寄存器读写操作
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int addr; // 寄存器地址,ad7124_registers_e
|
||||
int value; // 寄存器值
|
||||
int size; // 寄存器字节大小
|
||||
int rw; // 寄存器可执行的操作,ad7124_registers_rw_e
|
||||
} ad7124_st_reg_t; // AD7124寄存器结构体
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STOP_NC_ADC = 0, // AD7124_CHANNEL_EN_2
|
||||
STOP_NO_ADC, // AD7124_CHANNEL_EN_3
|
||||
AI_IN1_ADC, // AD7124_CHANNEL_EN_4
|
||||
AI_IN2_ADC, // AD7124_CHANNEL_EN_5
|
||||
P1_DI2_ADC, // AD7124_CHANNEL_EN_6
|
||||
P1_DI1_ADC, // AD7124_CHANNEL_EN_7
|
||||
P1_AI_ADC, // AD7124_CHANNEL_EN_8
|
||||
P2_DI2_ADC, // AD7124_CHANNEL_EN_9
|
||||
P2_DI1_ADC, // AD7124_CHANNEL_EN_10
|
||||
P2_AI_ADC, // AD7124_CHANNEL_EN_11
|
||||
AD7124_CHANNEL_EN_MAX,
|
||||
} ad7124_channel_e; // 该项目所使用的通道
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t channel;
|
||||
int32_t data; // 采样数据
|
||||
float voltage; // 电压值
|
||||
float current; // 电流值
|
||||
} ad7124_analog_t; // 采样数据结构体
|
||||
|
||||
#define AD7124_CRC8_POLYNOMIAL_REPRESENTATION 0x07 /* x8 + x2 + x + 1 */
|
||||
#define AD7124_DISABLE_CRC 0 // 默认关闭校验
|
||||
#define AD7124_USE_CRC 1
|
||||
|
||||
#define AD7124_RDY 10000 // 等待时间
|
||||
|
||||
#define AD7124_RES 100 // 采样基准电阻
|
||||
#define VREF 2.5f // 基准电压
|
||||
#define GAIN 1 // 增益,该值和配置寄存器有关
|
||||
#define AD_CODE 0XFFFFFF // 24位ADC
|
||||
|
||||
/*! Reads the value of the specified register. */
|
||||
int32_t ad7124_read_register(ad7124_st_reg_t *p_reg); // 读寄存器
|
||||
|
||||
/*! Writes the value of the specified register. */
|
||||
int32_t ad7124_write_register(ad7124_st_reg_t *reg); // 写寄存器
|
||||
|
||||
/*! Reads the value of the specified register without a device state check. */
|
||||
int32_t ad7124_no_check_read_register(ad7124_st_reg_t *p_reg);
|
||||
|
||||
/*! Writes the value of the specified register without a device state check. */
|
||||
int32_t ad7124_no_check_write_register(ad7124_st_reg_t *reg);
|
||||
|
||||
/*! Resets the device. */
|
||||
int32_t ad7124_reset(void); // 复位ad7124芯片
|
||||
|
||||
/*! Waits until the device can accept read and write user actions. */
|
||||
int32_t ad7124_wait_for_spi_ready(uint32_t timeout); // 读取ad7124芯片状态,直到可以执行读写操作
|
||||
|
||||
/*! Waits until the device finishes the power-on reset operation. */
|
||||
int32_t ad7124_wait_to_power_on(uint32_t timeout);
|
||||
|
||||
/*! Waits until a new conversion result is available. */
|
||||
int32_t ad7124_wait_for_conv_ready(uint32_t timeout); // 等待转换完成
|
||||
|
||||
/*! Reads the conversion result from the device. */
|
||||
int32_t ad7124_read_data(void);
|
||||
void ad7124_get_analog(uint8_t channel_nr);
|
||||
/*! Initializes the AD7124. */
|
||||
int32_t ad7124_setup(void);
|
||||
|
||||
int32_t ad7124_read_write_spi(uint8_t *buff, uint8_t length);
|
||||
|
||||
#endif /* __AD7124_H__ */
|
|
@ -0,0 +1,154 @@
|
|||
#include "dac161p997.h"
|
||||
#include "delay.h"
|
||||
static dac161p997_t _handle;
|
||||
|
||||
static void _delay_us(uint32_t us)
|
||||
{
|
||||
delay_hardware_us(_handle.timer_us, us);
|
||||
}
|
||||
|
||||
static void dac161p997_output_0()
|
||||
{
|
||||
_handle.io->set(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_25);
|
||||
_handle.io->reset(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_75);
|
||||
}
|
||||
|
||||
static void dac161p997_output_1()
|
||||
{
|
||||
_handle.io->set(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_75);
|
||||
_handle.io->reset(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_25);
|
||||
}
|
||||
|
||||
static void dac161p997_output_d()
|
||||
{
|
||||
_handle.io->set(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_50);
|
||||
_handle.io->reset(*_handle.io);
|
||||
_delay_us(DUTY_CYCLE_50);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 输出DAC161符号
|
||||
*
|
||||
* 根据传入的符号类型,调用相应的DAC161输出函数。
|
||||
*
|
||||
* @param sym 符号类型,可以是ZERO_SYM、ONE_SYM或其他值。
|
||||
*/
|
||||
static void dac161p997_output_symbol(uint8_t sym)
|
||||
{
|
||||
switch (sym)
|
||||
{
|
||||
case ZERO_SYM:
|
||||
dac161p997_output_0();
|
||||
break;
|
||||
case ONE_SYM:
|
||||
dac161p997_output_1();
|
||||
break;
|
||||
default:
|
||||
dac161p997_output_d();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向DAC161写入寄存器
|
||||
*
|
||||
* 向DAC161写入一个16位的数据,并附加一个8位的标签。
|
||||
* 芯片会回复一个应答信号,此处忽略应答信号。可以通过设置寄存器关闭应答信号。
|
||||
* @param data 要写入的数据,16位。
|
||||
* @param tag 附加的标签,8位。tag = 0时,写DAC寄存器;tag = 1时,写配置寄存器。
|
||||
*/
|
||||
void dac161p997_swif_write_reg(uint16_t data, uint8_t tag)
|
||||
{
|
||||
uint8_t plow, phigh;
|
||||
uint16_t i, tmp;
|
||||
|
||||
/* compute parity low */
|
||||
tmp = data & 0x00ff; // get least significant byte
|
||||
for (plow = 0; tmp != 0; tmp >>= 1)
|
||||
{
|
||||
if (tmp & 0x1) // test if lsb is 1
|
||||
plow++; // count number of bits equal to 1
|
||||
}
|
||||
|
||||
if (plow & 0x1) // check if number of 1s is odd
|
||||
plow = 0; // set even parity
|
||||
else
|
||||
plow = 1; // else set odd parity
|
||||
|
||||
/* compute parity high */
|
||||
tmp = (data & 0xff00) >> 8; // get most significant byte
|
||||
for (phigh = 0; tmp != 0; tmp >>= 1)
|
||||
{
|
||||
if (tmp & 0x1) // test if lsb is 1
|
||||
phigh++; // count number of bits equal to 1
|
||||
}
|
||||
|
||||
if (phigh & 0x1) // check if number of 1s is odd
|
||||
phigh = 0; // set even parity
|
||||
else
|
||||
phigh = 1; // set odd parity
|
||||
|
||||
phigh = phigh ^ tag; // parity high is for high slice = tag + 1 byte
|
||||
|
||||
dac161p997_output_symbol(IDLE_SYM); // Frame start: send an idle symbol first
|
||||
dac161p997_output_symbol(tag);
|
||||
|
||||
tmp = data;
|
||||
for (i = 0; i < 16; i++) // send 16 data bits msb to lsb
|
||||
{
|
||||
if (tmp & 0x8000)
|
||||
{
|
||||
dac161p997_output_symbol(ONE_SYM); // send 1
|
||||
}
|
||||
else
|
||||
{
|
||||
dac161p997_output_symbol(ZERO_SYM); // send 0
|
||||
}
|
||||
|
||||
tmp = tmp << 1; // move next data bit to msb
|
||||
}
|
||||
|
||||
dac161p997_output_symbol(phigh); // send parity high bit
|
||||
dac161p997_output_symbol(plow); // send parity low bit
|
||||
|
||||
dac161p997_output_symbol(IDLE_SYM); // send idle
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置DAC161输出电流
|
||||
*
|
||||
* 通过向DAC161写入指定的电流值来设置其输出电流,输出电流持续时间100ms。
|
||||
*
|
||||
* @param current 要设置的电流值
|
||||
*/
|
||||
void dac161p997_output_current(float32 current)
|
||||
{
|
||||
uint16_t adc = (uint16_t)(current * DAC161P997_CURRENT_SLOPE);
|
||||
dac161p997_swif_write_reg(adc, DACCODE_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化DAC161设备
|
||||
*
|
||||
* 此函数用于初始化DAC161设备,进行必要的配置,以便设备正常工作。
|
||||
* 写寄存器之前要先解锁,具体配置寄存器根据需要配置的寄存器而定
|
||||
* 具体步骤包括:
|
||||
* 1. 解锁DAC161的配置寄存器
|
||||
* 2. 配置DAC161的错误下限寄存器
|
||||
* 3. 锁定DAC161的配置寄存器
|
||||
*/
|
||||
void dac161p997_init(TIM_TypeDef *timer_us)
|
||||
{
|
||||
DBG_ASSERT(timer_us != NULL __DBG_LINE);
|
||||
_handle.timer_us = timer_us;
|
||||
ENABLE_TIM_COUNT(_handle.timer_us);
|
||||
_handle.io = gpio_create(DAC161P997_IO_PORT, DAC161P997_IO_PIN);
|
||||
dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_UNLOCK, CONFIG_WRITE);
|
||||
dac161p997_swif_write_reg(DAC161P997_CONFIG2_REG, CONFIG_WRITE);
|
||||
dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_LOCK, CONFIG_WRITE);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef __DAC161P997_H__
|
||||
#define __DAC161P997_H__
|
||||
#include "main.h"
|
||||
#include "gpios.h"
|
||||
|
||||
#define DAC161P997_IO_PORT (DAC161P997_GPIO_Port)
|
||||
#define DAC161P997_IO_PIN (DAC161P997_Pin)
|
||||
|
||||
#define DAC161P997_CURRENT_SLOPE 2730.625f // adc = (current / 24) * 0xffff
|
||||
|
||||
// Symbol Periods
|
||||
#define DUTY_CYCLE_100 (1000U) // (CPU_CLK / BAUD_RATE)
|
||||
#define DUTY_CYCLE_75 (DUTY_CYCLE_100 * 0.75f)
|
||||
#define DUTY_CYCLE_50 (DUTY_CYCLE_100 * 0.50f)
|
||||
#define DUTY_CYCLE_25 (DUTY_CYCLE_100 * 0.25f)
|
||||
|
||||
/************************************************************
|
||||
* TI DAC161P997 REGISTER SET ADDRESSES
|
||||
************************************************************/
|
||||
#define DAC161P997_LCK_REG (0x0000)
|
||||
#define DAC161P997_CONFIG1_REG (0x0100)
|
||||
#define DAC161P997_CONFIG2_REG (0x0200)
|
||||
#define DAC161P997_CONFIG3_REG (0x0300)
|
||||
#define DAC161P997_ERR_LOW_REG (0x0400)
|
||||
#define DAC161P997_ERR_HIGH_REG (0x0500)
|
||||
|
||||
// TI DAC161P997 Register Bits
|
||||
#define DAC161P997_LCK_REG_LOCK (0x00AA) // any value other than 0x95
|
||||
#define DAC161P997_LCK_REG_UNLOCK (0x0095)
|
||||
#define DAC161P997_CONFIG1_REG_RST (0x0001)
|
||||
#define DAC161P997_CONFIG1_REG_NOP (0 * 0x08u)
|
||||
#define DAC161P997_CONFIG1_REG_SET_ERR (1 * 0x08u)
|
||||
#define DAC161P997_CONFIG1_REG_CLEAR_ERR (2 * 0x08u)
|
||||
#define DAC161P997_CONFIG1_REG_NOP3 (3 * 0x08u)
|
||||
#define DAC161P997_CONFIG2_REG_LOOP (0x0001)
|
||||
#define DAC161P997_CONFIG2_REG_CHANNEL (0x0002)
|
||||
#define DAC161P997_CONFIG2_REG_PARITY (0x0004)
|
||||
#define DAC161P997_CONFIG2_REG_FRAME (0x0008)
|
||||
#define DAC161P997_CONFIG2_REG_ACK_EN (0x0010)
|
||||
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_16 (0x000F)
|
||||
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_8 (0x0007)
|
||||
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_1 (0x0000)
|
||||
|
||||
// Tags
|
||||
#define DACCODE_WRITE (0x00)
|
||||
#define CONFIG_WRITE (0x01)
|
||||
|
||||
// Valid Symbols
|
||||
#define ZERO_SYM (0x00)
|
||||
#define ONE_SYM (0x01)
|
||||
#define IDLE_SYM (0x02)
|
||||
#define STATIC_LOW_SYM (0x03)
|
||||
|
||||
// DAC Codes for different currents
|
||||
#define DACCODE_0mA (0x0000)
|
||||
#define DACCODE_4mA (0x2AAA)
|
||||
#define DACCODE_8mA (0x5555)
|
||||
#define DACCODE_12mA (0x7FFF)
|
||||
#define DACCODE_16mA (0xAAAA)
|
||||
#define DACCODE_20mA (0xD555)
|
||||
#define DACCODE_24mA (0xFFFF)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DAC161P997_IDLE_SYM,
|
||||
|
||||
} dac161p997_e;
|
||||
typedef struct
|
||||
{
|
||||
TIM_TypeDef *timer_us;
|
||||
gpio_t *io;
|
||||
uint8_t count;
|
||||
} dac161p997_t;
|
||||
|
||||
void dac161p997_output_0(void);
|
||||
void dac161p997_output_1(void);
|
||||
void dac161p997_output_d(void);
|
||||
void dac161p997_output_symbol(uint8_t sym);
|
||||
void dac161p997_swif_write_reg(uint16_t data, uint8_t tag);
|
||||
|
||||
extern void dac161p997_output_current(float32 current);
|
||||
extern void dac161p997_init(TIM_TypeDef *timer_us);
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
#include "dac161s997.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief 向DAC161S997芯片写入寄存器值
|
||||
*
|
||||
* 该函数通过SPI接口向DAC161S997芯片写入指定的寄存器值。
|
||||
*
|
||||
* @param dac_num DAC芯片编号
|
||||
* @param reg 要写入的寄存器地址
|
||||
* @param data 要写入的数据,16位
|
||||
*/
|
||||
void dac161s997_write_reg(chip_type_e dac_num, uint8_t reg, uint16_t data)
|
||||
{
|
||||
uint8_t data_buffer[3] = {0, 0, 0};
|
||||
data_buffer[0] = reg;
|
||||
data_buffer[1] = data >> 8;
|
||||
data_buffer[2] = data;
|
||||
board_spi_init(dac_num); // 初始化SPI,因为ADC芯片也用SPI1,但是时序不同
|
||||
board_spi_cs_on(dac_num);
|
||||
spi_transmit_receive(&hspi1, data_buffer, 3);
|
||||
board_spi_cs_off(dac_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化DAC161S997 DAC设备
|
||||
*/
|
||||
void dac161s997_init(void)
|
||||
{
|
||||
dac161s997_write_reg(DAC161S997_1, DAC161S997_ERR_LOW_REG, 0xFFFF);
|
||||
dac161s997_write_reg(DAC161S997_1, DAC161S997_ERR_CONFIG_REG, 0x070E);
|
||||
|
||||
dac161s997_write_reg(DAC161S997_2, DAC161S997_ERR_LOW_REG, 0xFFFF);
|
||||
dac161s997_write_reg(DAC161S997_2, DAC161S997_ERR_CONFIG_REG, 0x070E);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DAC161S997芯片输出函数
|
||||
*
|
||||
* 此函数用于设置DAC161S997芯片的输出电流。
|
||||
*
|
||||
* @param dac_num DAC芯片类型
|
||||
* @param current 需要设置的电流值,单位:毫安
|
||||
*/
|
||||
void dac161s997_output(chip_type_e dac_num, float current)
|
||||
{
|
||||
uint32_t dac_code = (uint32_t)((current * 65535.0f) / 24.0f);
|
||||
uint8_t data_buffer[3] = {0, 0, 0};
|
||||
data_buffer[0] = DAC161S997_DACCODE_REG;
|
||||
data_buffer[1] = dac_code >> 8;
|
||||
data_buffer[2] = dac_code;
|
||||
board_spi_init(dac_num); // 初始化SPI,因为ADC芯片也用SPI1,但是时序不同
|
||||
board_spi_cs_on(dac_num);
|
||||
spi_transmit_receive(&hspi1, data_buffer, 3);
|
||||
board_spi_cs_off(dac_num);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __DAC161S997_H__
|
||||
#define __DAC161S997_H__
|
||||
|
||||
#include "main.h"
|
||||
#include "user_spi.h"
|
||||
/* Defines ********************************************************************/
|
||||
/**
|
||||
* @defgroup DAC161S997_REGS
|
||||
* @{
|
||||
*/
|
||||
#define DAC161S997_XFR_REG 0x01 /**< Command: transfer data into register (protected write mode) */
|
||||
#define DAC161S997_NOP_REG 0x02 /**< Command: does nothing except resetting the timeout timer */
|
||||
#define DAC161S997_PROTECT_REG_WR_REG 0x03 /**< 1 means protected write mode in effect */
|
||||
#define DAC161S997_DACCODE_REG 0x04 /**< 16 bit DAC code to be written */
|
||||
#define DAC161S997_ERR_CONFIG_REG 0x05 /**< Configuration of error states */
|
||||
#define DAC161S997_ERR_LOW_REG 0x06 /**< DAC code for the <4mA alarm level */
|
||||
#define DAC161S997_ERR_HIGH_REG 0x07 /**< DAC code for the >20mA alarm level */
|
||||
#define DAC161S997_RESET_REG 0x08 /**< Command: reset the chip */
|
||||
#define DAC161S997_STATUS_REG 0x09 /**< Status of the chip */
|
||||
|
||||
#define DAC161S997_SPI SPI1
|
||||
|
||||
void dac161s997_write_reg(uint8_t dac_num, uint8_t reg, uint16_t data);
|
||||
uint16_t dac161s997_read(uint8_t reg);
|
||||
extern void dac161s997_init(void);
|
||||
extern void dac161s997_output(uint8_t dac_num, float current);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,227 @@
|
|||
/**
|
||||
* @file eeprom_fm24.c
|
||||
* @author xxx
|
||||
* @date 2023-08-29 07:58:27
|
||||
* @brief 用于实现FM24 EEPROM相关的读写操作
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
#include "eeprom_fm24.h"
|
||||
#include "delay.h"
|
||||
|
||||
//========在此设定芯片地址=============
|
||||
|
||||
#define W_ADD_COM 0xa0 // 写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
|
||||
|
||||
#define R_ADD_COM 0xa1 // 读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
|
||||
|
||||
//=======在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
|
||||
|
||||
//=======在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
|
||||
|
||||
#define FM24_SPI SPI1
|
||||
|
||||
#define EEPROM_FM24_CS_PORT EE3_CS_GPIO_Port
|
||||
#define EEPROM_FM24_CS_PIN EE3_CS_Pin
|
||||
#define EEPROM_FM24_MOSI_PORT SPI_MOSI_GPIO_Port
|
||||
#define EEPROM_FM24_MOSI_PIN SPI_MOSI_Pin
|
||||
#define EEPROM_FM24_MISO_PORT SPI_MISO_GPIO_Port
|
||||
#define EEPROM_FM24_MISO_PIN SPI_MISO_Pin
|
||||
#define EEPROM_FM24_SCK_PORT SPI_CLK_GPIO_Port
|
||||
#define EEPROM_FM24_SCK_PIN SPI_CLK_Pin
|
||||
|
||||
static fm24_t _eeprom_fm24;
|
||||
|
||||
void eeprom_fm24_init(void)
|
||||
{
|
||||
spi_gpio_group_t gpios;
|
||||
spi_normal_config_t cfg;
|
||||
osel_memset((uint8_t *)&cfg, 0, sizeof(spi_normal_config_t));
|
||||
// 创建CS引脚
|
||||
gpios.cs = gpio_create(EEPROM_FM24_CS_PORT, EEPROM_FM24_CS_PIN);
|
||||
gpios.mosi = gpio_create(EEPROM_FM24_MOSI_PORT, EEPROM_FM24_MOSI_PIN);
|
||||
gpios.sck = gpio_create(EEPROM_FM24_SCK_PORT, EEPROM_FM24_SCK_PIN);
|
||||
gpios.miso = gpio_create(EEPROM_FM24_MISO_PORT, EEPROM_FM24_MISO_PIN);
|
||||
gpios.rst = gpio_create(NULL, 0);
|
||||
gpios.rdy = gpio_create(NULL, 0);
|
||||
|
||||
// 创建SPI对象
|
||||
eeprom_fm24_get()->spi = spi_create(SPI_TYPE_NORMAL, gpios, 0);
|
||||
DBG_ASSERT(eeprom_fm24_get() != NULL __DBG_LINE);
|
||||
cfg.cmd_rdsr = FM24_CMD_RDSR;
|
||||
cfg.cmd_wrsr = FM24_CMD_WRSR;
|
||||
cfg.cmd_wren = FM24_CMD_WREN;
|
||||
cfg.cmd_wrdi = FM24_CMD_WRDI;
|
||||
cfg.cmd_write = FM24_CMD_WRITE;
|
||||
cfg.cmd_read = FM24_CMD_READ;
|
||||
cfg.dummy_byte = FM24_DUMMY_BYTE;
|
||||
cfg.address_bytes = 2;
|
||||
cfg.page_size = FM24_PAGE_SIZE;
|
||||
cfg.total_size = FM24_SIZE;
|
||||
cfg.continuous_write = FALSE;
|
||||
osel_memcpy((uint8_t *)&eeprom_fm24_get()->spi->cfg, (uint8_t *)&cfg, sizeof(spi_normal_config_t));
|
||||
// 使能SPI
|
||||
eeprom_fm24_get()->spi->interface.hardware_enable(eeprom_fm24_get()->spi, FM24_SPI);
|
||||
// 这里需要复位下SPI,否则读出的数据不对
|
||||
eeprom_fm24_get()->spi->interface.u.normal.spi_reset(eeprom_fm24_get()->spi);
|
||||
|
||||
eeprom_fm24_write_protection_close();
|
||||
// eeprom_fm24_test();
|
||||
}
|
||||
|
||||
fm24_t *eeprom_fm24_get(void)
|
||||
{
|
||||
return &_eeprom_fm24;
|
||||
}
|
||||
|
||||
void eeprom_fm24_dinit(void)
|
||||
{
|
||||
LL_SPI_Disable(FM24_SPI);
|
||||
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.mosi->port, eeprom_fm24_get()->spi->gpios.mosi->pin);
|
||||
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.miso->port, eeprom_fm24_get()->spi->gpios.miso->pin);
|
||||
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.sck->port, eeprom_fm24_get()->spi->gpios.sck->pin);
|
||||
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.cs->port, eeprom_fm24_get()->spi->gpios.cs->pin);
|
||||
}
|
||||
|
||||
void eeprom_fm24_enable(void)
|
||||
{
|
||||
uint16_t count = 100;
|
||||
LL_SPI_Enable(FM24_SPI);
|
||||
// 判断SPI是否使能成功
|
||||
while (LL_SPI_IsEnabled(FM24_SPI) != 1)
|
||||
{
|
||||
if (count-- == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_fm24_disable(void)
|
||||
{
|
||||
uint16_t count = 100;
|
||||
LL_SPI_Disable(FM24_SPI);
|
||||
// 判断SPI是否关闭成功
|
||||
while (LL_SPI_IsEnabled(FM24_SPI) != 0)
|
||||
{
|
||||
if (count-- == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭EEPROM FM24的写保护
|
||||
*
|
||||
* 此函数用于关闭EEPROM FM24的写保护功能,允许对其进行写操作。
|
||||
*
|
||||
* 调用此函数前,应确保EEPROM FM24的SPI接口已正确初始化。
|
||||
*/
|
||||
void eeprom_fm24_write_protection_close(void)
|
||||
{
|
||||
DBG_ASSERT(eeprom_fm24_get()->spi != NULL __DBG_LINE);
|
||||
eeprom_fm24_enable();
|
||||
eeprom_fm24_get()->spi->interface.u.normal.spi_write_reg(eeprom_fm24_get()->spi, eeprom_fm24_get()->spi->cfg.cmd_wrsr, 0);
|
||||
eeprom_fm24_disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取EEPROM FM24的写保护状态
|
||||
*
|
||||
* 获取EEPROM FM24的写保护状态。
|
||||
*
|
||||
* @return BOOL 返回TRUE表示没有写保护,返回FALSE表示有写保护
|
||||
*/
|
||||
BOOL eeprom_fm24_write_protection_state(void)
|
||||
{
|
||||
DBG_ASSERT(eeprom_fm24_get()->spi != NULL __DBG_LINE);
|
||||
eeprom_fm24_enable();
|
||||
eeprom_fm24_get()->write_protection.data = eeprom_fm24_get()->spi->interface.u.normal.spi_read_reg(eeprom_fm24_get()->spi, eeprom_fm24_get()->spi->cfg.cmd_rdsr);
|
||||
eeprom_fm24_disable();
|
||||
|
||||
if (eeprom_fm24_get()->write_protection.bits.bp0 == 1 ||
|
||||
eeprom_fm24_get()->write_protection.bits.bp1 == 1 ||
|
||||
eeprom_fm24_get()->write_protection.bits.wpen == 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL eeprom_fm24_write(uint32_t write_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
if (length == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
// 开启和关闭SPI对读写实时性有影响
|
||||
eeprom_fm24_enable();
|
||||
ret = eeprom_fm24_get()->spi->interface.u.normal.spi_write(eeprom_fm24_get()->spi, write_addr, data, length);
|
||||
eeprom_fm24_disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL eeprom_fm24_read(uint32_t read_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
if (length == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
// 开启和关闭SPI对读写实时性有影响
|
||||
eeprom_fm24_enable();
|
||||
ret = eeprom_fm24_get()->spi->interface.u.normal.spi_read(eeprom_fm24_get()->spi, read_addr, data, length);
|
||||
eeprom_fm24_disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL eeprom_fm24_test(void)
|
||||
{
|
||||
const uint8_t buf_size = 5;
|
||||
uint16_t test_address = FM24_TEST_PAGE * FM24_PAGE_SIZE;
|
||||
uint8_t buf[buf_size];
|
||||
uint8_t rbuf[buf_size];
|
||||
osel_memset(buf, 0, buf_size);
|
||||
osel_memset(rbuf, 0, buf_size);
|
||||
buf[0] = 0xD5;
|
||||
buf[1] = 0xC8;
|
||||
buf[2] = 0x00;
|
||||
buf[3] = 0x01;
|
||||
buf[4] = 0x02;
|
||||
buf[buf_size - 1] = 0xfe;
|
||||
eeprom_fm24_write(test_address, buf, buf_size);
|
||||
__NOP();
|
||||
eeprom_fm24_read(test_address, rbuf, buf_size);
|
||||
if (osel_memcmp(buf, rbuf, buf_size) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取FM24 EEPROM的状态
|
||||
*
|
||||
* 获取FM24 EEPROM的当前状态。该函数始终返回TRUE,表示EEPROM正常工作。
|
||||
*
|
||||
* @return BOOL 始终返回TRUE
|
||||
*/
|
||||
BOOL eeprom_fm24_status_get(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* @file eeprom_fm24.h
|
||||
* @author xxx
|
||||
* @date 2023-08-30 14:05:55
|
||||
* @brief FM24系列EEPROM驱动 https://zhuanlan.zhihu.com/p/598934638
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __EEPROM_FM24_H__
|
||||
#define __EEPROM_FM24_H__
|
||||
#include "main.h"
|
||||
#include "spis.h"
|
||||
/**
|
||||
* High-endurance 100 trillion (1014) read/writes
|
||||
* 151-year data retention
|
||||
* NoDelay™ writes
|
||||
*/
|
||||
|
||||
#define e2prom 256 //
|
||||
|
||||
#if e2prom == 1
|
||||
#define FM24_PAGE_SIZE 16
|
||||
#define FM24_SIZE (128 * 8)
|
||||
#elif e2prom == 2
|
||||
#define FM24_PAGE_SIZE 16
|
||||
#define FM24_SIZE (256 * 8)
|
||||
#elif e2prom == 4
|
||||
#define FM24_PAGE_SIZE 32
|
||||
#define FM24_SIZE (512 * 8)
|
||||
#elif e2prom == 8
|
||||
#define FM24_PAGE_SIZE 64
|
||||
#define FM24_SIZE (1024 * 8)
|
||||
#elif e2prom == 16
|
||||
#define FM24_PAGE_SIZE 128
|
||||
#define FM24_SIZE (2048 * 8)
|
||||
#elif e2prom == 32
|
||||
#define FM24_PAGE_SIZE 128
|
||||
#define FM24_SIZE (4096 * 8)
|
||||
#elif e2prom == 64
|
||||
#define FM24_PAGE_SIZE 256
|
||||
#define FM24_SIZE (8192 * 8)
|
||||
#elif e2prom == 128
|
||||
#define FM24_PAGE_SIZE 256
|
||||
#define FM24_SIZE (16384)
|
||||
#elif e2prom == 256
|
||||
#define FM24_PAGE_SIZE 256
|
||||
#define FM24_SIZE (32768) // 32K 128页
|
||||
#define FM24_PAGE_NUM 128
|
||||
#elif e2prom == 512
|
||||
#define FM24_PAGE_SIZE 512
|
||||
#define FM24_SIZE (65536)
|
||||
#endif
|
||||
|
||||
#define FM24_CMD_RDSR 0x05 /*!< Read Status Register instruction */
|
||||
#define FM24_CMD_WRSR 0x01 /*!< Write Status Register instruction */
|
||||
|
||||
#define FM24_CMD_WREN 0x06 /*!< Write enable instruction */
|
||||
#define FM24_CMD_WRDI 0x04 /*!< Write disable instruction */
|
||||
|
||||
#define FM24_CMD_READ 0x03 /*!< Read from Memory instruction */
|
||||
#define FM24_CMD_WRITE 0x02 /*!< Write to Memory instruction */
|
||||
|
||||
#define FM24_DUMMY_BYTE 0x00 ///< 无用数据
|
||||
|
||||
#define FM24_TEST_PAGE 0 ///< 测试页地址
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t data;
|
||||
struct
|
||||
{
|
||||
uint8_t reserve1 : 1;
|
||||
uint8_t wel : 1; ///< Write enable latch
|
||||
uint8_t bp0 : 1; ///< Block protect 0
|
||||
uint8_t bp1 : 1; ///< Block protect 1
|
||||
uint8_t reserve2 : 3;
|
||||
uint8_t wpen : 1; ///< Write protect enable
|
||||
} bits;
|
||||
} fm24_write_protection_u;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
fm24_write_protection_u write_protection;
|
||||
spi_t *spi;
|
||||
} fm24_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes the FM24 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_fm24_init(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitializes the FM24 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_fm24_dinit(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the fm24_t handle of the FM24 EEPROM module.
|
||||
* @return The fm24_t handle of the FM24 EEPROM module.
|
||||
*/
|
||||
extern fm24_t *eeprom_fm24_get(void);
|
||||
|
||||
/**
|
||||
* @brief Enables the FM24 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_fm24_enable(void);
|
||||
|
||||
/**
|
||||
* @brief Disables the FM24 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_fm24_disable(void);
|
||||
|
||||
/**
|
||||
* @brief Reads data from the FM24 EEPROM module.
|
||||
* @param read_addr The starting address to read from.
|
||||
* @param data Pointer to the buffer to store the read data.
|
||||
* @param length The number of bytes to read.
|
||||
* @return TRUE if the read operation is successful, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL eeprom_fm24_read(uint32_t read_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Writes data to the FM24 EEPROM module.
|
||||
* @param write_addr The starting address to write to.
|
||||
* @param data Pointer to the data to be written.
|
||||
* @param length The number of bytes to write.
|
||||
* @return TRUE if the write operation is successful, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL eeprom_fm24_write(uint32_t write_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Closes the write protection of the FM24 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_fm24_write_protection_close(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the write protection state of the FM24 EEPROM module.
|
||||
* @return TRUE if the FM24 EEPROM module is not write-protected, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL eeprom_fm24_write_protection_state(void);
|
||||
|
||||
/**
|
||||
* @brief Performs a test on the FM24 EEPROM module.
|
||||
*/
|
||||
extern BOOL eeprom_fm24_test(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the status of the FM24 EEPROM module.
|
||||
* @return TRUE if the FM24 EEPROM module is ready, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL eeprom_fm24_status_get(void);
|
||||
|
||||
#endif // __EEPROM_FM24_H__
|
|
@ -0,0 +1,172 @@
|
|||
#include "eeprom_lc02b.h"
|
||||
#include "delay.h"
|
||||
#include "i2cs.h"
|
||||
|
||||
#define W_ADD_COM 0xa8 // 写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
|
||||
#define R_ADD_COM 0xa9 // 读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
|
||||
#define PAGE_SIZE 8U
|
||||
#define SIZE 256U
|
||||
|
||||
#define EEPROM_LC02B_SDA_PORT I2C1_SDA_GPIO_Port
|
||||
#define EEPROM_LC02B_SDA_PIN I2C1_SDA_Pin
|
||||
#define EEPROM_LC02B_SCL_PORT I2C1_SCL_GPIO_Port
|
||||
#define EEPROM_LC02B_SCL_PIN I2C1_SCL_Pin
|
||||
|
||||
static i2c_t *_eeprom_24lc028bt_i2c;
|
||||
static TIM_TypeDef *_timer_us;
|
||||
|
||||
static void _delay_us(uint32_t us)
|
||||
{
|
||||
if (_timer_us != NULL)
|
||||
{
|
||||
delay_hardware_us(_timer_us, us);
|
||||
}
|
||||
else
|
||||
{
|
||||
delay_us(us);
|
||||
}
|
||||
}
|
||||
|
||||
void eeprom_lc02b_test(void)
|
||||
{
|
||||
#define TEST_SIZE 15
|
||||
uint16_t test_address = SIZE - TEST_SIZE;
|
||||
uint8_t buf[TEST_SIZE];
|
||||
for (uint8_t i = 0; i < TEST_SIZE; i++)
|
||||
{
|
||||
buf[i] = i + 1;
|
||||
}
|
||||
|
||||
eeprom_lc02b_write(test_address, buf, TEST_SIZE);
|
||||
_delay_us(10000);
|
||||
osel_memset(buf, 0, ARRAY_LEN(buf));
|
||||
eeprom_lc02b_read(test_address, buf, TEST_SIZE);
|
||||
|
||||
__NOP();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取EEPROM LC02B的状态
|
||||
*
|
||||
* 此函数用于获取EEPROM LC02B的当前状态。
|
||||
*
|
||||
* @return 如果EEPROM LC02B处于正常状态,则返回TRUE;否则返回FALSE。
|
||||
* 注意:在本实现中,总是返回TRUE,因为这是一个简单的示例函数。
|
||||
*/
|
||||
BOOL eeprom_lc02b_status_get(void)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EEPROM LC02B初始化
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_lc02b_init(TIM_TypeDef *timer_us)
|
||||
{
|
||||
if (timer_us != NULL)
|
||||
{
|
||||
_timer_us = timer_us;
|
||||
ENABLE_TIM_COUNT(_timer_us);
|
||||
}
|
||||
|
||||
i2c_gpio_group_t gpios;
|
||||
gpios.scl = gpio_create(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN);
|
||||
gpios.sda = gpio_create(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN);
|
||||
|
||||
_eeprom_24lc028bt_i2c = i2c_create(gpios, 10);
|
||||
// eeprom_lc02b_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief EEPROM LC02B反初始化
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_lc02b_dinit(void)
|
||||
{
|
||||
GPIO_SET_ANALOG(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN);
|
||||
GPIO_SET_ANALOG(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN);
|
||||
}
|
||||
/**
|
||||
* @brief 写入数据
|
||||
* @param {uint32_t} write_addr
|
||||
* @param {uint8_t} *data
|
||||
* @param {uint16_t} length
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
// 发送开始信号
|
||||
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
|
||||
// 发送写入地址命令
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
|
||||
// 等待写入地址命令响应
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
// 发送要写入的地址
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
|
||||
// 循环写入数据
|
||||
|
||||
for (uint16_t i = 0; i < length; i++)
|
||||
{
|
||||
// 写入一个字节数据
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, *data++);
|
||||
// 等待响应
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
write_addr++;
|
||||
if (write_addr % PAGE_SIZE == 0)
|
||||
{
|
||||
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
|
||||
_delay_us(10000); // 延时10ms,等待写入完成
|
||||
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
}
|
||||
}
|
||||
// 写入完成,停止I2C总线
|
||||
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取数据
|
||||
* @param {uint32_t} read_addr
|
||||
* @param {uint8_t} *data
|
||||
* @param {uint16_t} length
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
// 发送开始信号
|
||||
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
|
||||
// 发送写入地址命令
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
|
||||
// 等待写入地址命令响应
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
|
||||
// 发送要读取的地址
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)read_addr);
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
|
||||
// 发送开始信号
|
||||
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
|
||||
// 发送读取地址命令
|
||||
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, R_ADD_COM);
|
||||
// 等待读取地址命令响应
|
||||
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
|
||||
// 循环读取数据
|
||||
for (uint16_t i = 0; i < length - 1; i++)
|
||||
{
|
||||
// 读取一个字节数据
|
||||
*data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, TRUE);
|
||||
}
|
||||
*data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, FALSE);
|
||||
// 停止I2C总线
|
||||
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @file eeprom_lc02b.h
|
||||
* @author xxx
|
||||
* @date 2023-12-27 14:44:02
|
||||
* @brief
|
||||
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
|
||||
*/
|
||||
#ifndef __EEPROM_LC02B_H
|
||||
#define __EEPROM_LC02B_H
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* is a 2 Kbit Electrically Erasable PROM. The LC02B EEPROM is organized as 256 x 8 bits. 256 bytes
|
||||
* Data Retention >200 Years
|
||||
* More than 1 Million Erase/Write Cycles
|
||||
* Page Write Time 3 ms, typical
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initializes the LC02B EEPROM module.
|
||||
*/
|
||||
void eeprom_lc02b_init(TIM_TypeDef *timer_us);
|
||||
|
||||
/**
|
||||
* @brief Deinitializes the LC02B EEPROM module.
|
||||
*/
|
||||
void eeprom_lc02b_dinit(void);
|
||||
|
||||
/**
|
||||
* @brief Writes data to the LC02B EEPROM module.
|
||||
*
|
||||
* @param write_addr The starting address to write the data.
|
||||
* @param data The pointer to the data to be written.
|
||||
* @param length The length of the data to be written.
|
||||
*/
|
||||
void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Reads data from the LC02B EEPROM module.
|
||||
*
|
||||
* @param read_addr The starting address to read the data.
|
||||
* @param data The pointer to store the read data.
|
||||
* @param length The length of the data to be read.
|
||||
*/
|
||||
void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Performs a test on the LC02B EEPROM module.
|
||||
*/
|
||||
void eeprom_lc02b_test(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the LC02B EEPROM status.
|
||||
*
|
||||
* This function is used to get the current status of the LC02B EEPROM.
|
||||
*
|
||||
* @return TRUE if the LC02B EEPROM is in normal status, FALSE otherwise.
|
||||
*/
|
||||
BOOL eeprom_lc02b_status_get(void);
|
||||
#endif ///< !__EEPROM_LC02B_H
|
|
@ -0,0 +1,330 @@
|
|||
/**
|
||||
* @file eeprom_m95.c
|
||||
* @author xxx
|
||||
* @date 2023-08-30 08:58:43
|
||||
* @brief 用于实现M95 EEPROM相关的读写操作
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "eeprom_m95.h"
|
||||
#include "spis.h"
|
||||
#include "delay.h"
|
||||
#include "storage.h"
|
||||
|
||||
#define M95_SPI SPI1
|
||||
|
||||
#define EEPROM_M95_1_CS_PORT EE1_CS_GPIO_Port
|
||||
#define EEPROM_M95_1_CS_PIN EE1_CS_Pin
|
||||
#define EEPROM_M95_2_CS_PORT EE2_CS_GPIO_Port
|
||||
#define EEPROM_M95_2_CS_PIN EE2_CS_Pin
|
||||
|
||||
// 下面宏定义为2个EEPROM_M95的引脚定义
|
||||
#define EEPROM_M95_MOSI_PORT SPI_MOSI_GPIO_Port
|
||||
#define EEPROM_M95_MOSI_PIN SPI_MOSI_Pin
|
||||
#define EEPROM_M95_MISO_PORT SPI_MISO_GPIO_Port
|
||||
#define EEPROM_M95_MISO_PIN SPI_MISO_Pin
|
||||
#define EEPROM_M95_SCK_PORT SPI_CLK_GPIO_Port
|
||||
#define EEPROM_M95_SCK_PIN SPI_CLK_Pin
|
||||
|
||||
#define M95_TEST_PAGE (M95_PAGE_SIZE_256 - 1) ///< 测试页地址
|
||||
|
||||
m95_number_t eeprom_m95s[M95_MAX];
|
||||
|
||||
/**
|
||||
* @brief 初始化EEPROM_M95eeprom_m95s
|
||||
* @param {m95_number_e} num
|
||||
* @return {*}
|
||||
* @note 初始化函数对板卡上不同的芯片定义了块大小
|
||||
*/
|
||||
void eeprom_m95_init(m95_number_e num)
|
||||
{
|
||||
DBG_ASSERT(num < M95_MAX __DBG_LINE);
|
||||
spi_gpio_group_t gpios;
|
||||
spi_t *eeprom_m95_spi;
|
||||
spi_normal_config_t cfg;
|
||||
osel_memset((uint8_t *)&cfg, 0, sizeof(spi_normal_config_t));
|
||||
cfg.cmd_rdsr = M95_CMD_RDSR;
|
||||
cfg.cmd_wrsr = M95_CMD_WRSR;
|
||||
cfg.cmd_wren = M95_CMD_WREN;
|
||||
cfg.cmd_wrdi = M95_CMD_WRDI;
|
||||
cfg.cmd_write = M95_CMD_WRITE;
|
||||
cfg.cmd_read = M95_CMD_READ;
|
||||
cfg.dummy_byte = M95_DUMMY_BYTE;
|
||||
cfg.continuous_write = FALSE;
|
||||
// 128 byte
|
||||
if (num == M95_1)
|
||||
{
|
||||
// 创建CS引脚
|
||||
gpios.cs = gpio_create(EEPROM_M95_1_CS_PORT, EEPROM_M95_1_CS_PIN);
|
||||
|
||||
cfg.address_bytes = 3;
|
||||
cfg.page_size = M95_PAGE_SIZE_256;
|
||||
cfg.total_size = _M95M02_;
|
||||
}
|
||||
// 256 byte
|
||||
else if (num == M95_2)
|
||||
{
|
||||
// 创建CS引脚
|
||||
gpios.cs = gpio_create(EEPROM_M95_2_CS_PORT, EEPROM_M95_2_CS_PIN);
|
||||
|
||||
cfg.address_bytes = 3;
|
||||
cfg.page_size = M95_PAGE_SIZE_256;
|
||||
cfg.total_size = _M95M02_;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_ASSERT(FALSE __DBG_LINE);
|
||||
}
|
||||
|
||||
gpios.mosi = gpio_create(EEPROM_M95_MOSI_PORT, EEPROM_M95_MOSI_PIN);
|
||||
gpios.sck = gpio_create(EEPROM_M95_SCK_PORT, EEPROM_M95_SCK_PIN);
|
||||
gpios.miso = gpio_create(EEPROM_M95_MISO_PORT, EEPROM_M95_MISO_PIN);
|
||||
gpios.rst = gpio_create(NULL, 0);
|
||||
gpios.rdy = gpio_create(NULL, 0);
|
||||
|
||||
// 创建SPI对象
|
||||
eeprom_m95_spi = spi_create(SPI_TYPE_NORMAL, gpios, 10);
|
||||
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
|
||||
osel_memcpy((uint8_t *)&eeprom_m95_spi->cfg, (uint8_t *)&cfg, sizeof(spi_normal_config_t));
|
||||
// 使能SPI
|
||||
eeprom_m95_spi->interface.hardware_enable(eeprom_m95_spi, M95_SPI);
|
||||
eeprom_m95s[num].num = num;
|
||||
eeprom_m95s[num].spi = eeprom_m95_spi;
|
||||
// 这里需要设置,否则读出的数据不对
|
||||
eeprom_m95_spi->interface.u.normal.spi_reset(eeprom_m95_spi);
|
||||
eeprom_m95_write_protection_close(num); // 关闭写保护
|
||||
|
||||
// eeprom_m95_test(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 反初始化EEPROM_M95
|
||||
* @param {m95_number_e} num
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_m95_dinit(m95_number_e num)
|
||||
{
|
||||
LL_SPI_Disable(M95_SPI);
|
||||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.mosi->port, eeprom_m95s[num].spi->gpios.mosi->pin);
|
||||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.miso->port, eeprom_m95s[num].spi->gpios.miso->pin);
|
||||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.sck->port, eeprom_m95s[num].spi->gpios.sck->pin);
|
||||
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.cs->port, eeprom_m95s[num].spi->gpios.cs->pin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief M95 EEPROM使能
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_m95_enable(void)
|
||||
{
|
||||
uint16_t count = 100;
|
||||
LL_SPI_Enable(M95_SPI);
|
||||
// 判断SPI是否使能成功
|
||||
while (LL_SPI_IsEnabled(M95_SPI) != 1)
|
||||
{
|
||||
if (count-- == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief M95 EEPROM失能
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void eeprom_m95_disable(void)
|
||||
{
|
||||
uint16_t count = 100;
|
||||
LL_SPI_Disable(M95_SPI);
|
||||
// 判断SPI是否关闭成功
|
||||
while (LL_SPI_IsEnabled(M95_SPI) != 0)
|
||||
{
|
||||
if (count-- == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭EEPROM M95写保护
|
||||
*
|
||||
* 关闭指定M95 EEPROM的写保护功能。
|
||||
*
|
||||
* @param num 指定M95 EEPROM的编号
|
||||
*/
|
||||
void eeprom_m95_write_protection_close(m95_number_e num)
|
||||
{
|
||||
spi_t *handle = eeprom_m95s[num].spi;
|
||||
DBG_ASSERT(handle != NULL __DBG_LINE);
|
||||
eeprom_m95_enable();
|
||||
handle->interface.u.normal.spi_write_reg(handle, handle->cfg.cmd_wrsr, 0);
|
||||
eeprom_m95_disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取M95 EEPROM写保护状态(软件)
|
||||
*
|
||||
* 根据传入的M95编号获取其写保护状态。
|
||||
*
|
||||
* @param num M95编号
|
||||
* @return 如果M95 EEPROM处于写保护状态,则返回FALSE;否则返回TRUE。
|
||||
*/
|
||||
BOOL eeprom_m95_write_protection_state(m95_number_e num)
|
||||
{
|
||||
spi_t *handle = eeprom_m95s[num].spi;
|
||||
DBG_ASSERT(handle != NULL __DBG_LINE);
|
||||
eeprom_m95_enable();
|
||||
eeprom_m95s[num].write_protection.data = handle->interface.u.normal.spi_read_reg(handle, handle->cfg.cmd_rdsr);
|
||||
eeprom_m95_disable();
|
||||
|
||||
if (eeprom_m95s[num].write_protection.bits.bp0 == 1 ||
|
||||
eeprom_m95s[num].write_protection.bits.bp1 == 1 ||
|
||||
eeprom_m95s[num].write_protection.bits.srwd == 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取M95 EEPROM内存数据
|
||||
* @param num EEPROM模块编号(0或1)
|
||||
* @param read_addr 要读取的地址
|
||||
* @param data 存储读取数据的缓冲区
|
||||
* @param length 要读取的数据长度
|
||||
* @return {*}
|
||||
*/
|
||||
BOOL eeprom_m95_read(m95_number_e num, uint32_t read_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
if (length == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi; // 获取EEPROM模块的SPI配置
|
||||
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
|
||||
// 开启和关闭SPI对读写实时性有影响
|
||||
eeprom_m95_enable();
|
||||
ret = eeprom_m95_spi->interface.u.normal.spi_read(eeprom_m95_spi, read_addr, data, length);
|
||||
eeprom_m95_disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向M95 EEPROM内存写入数据
|
||||
* @param num EEPROM模块编号(0或1)
|
||||
* @param write_addr 要写入的地址
|
||||
* @param data 包含要写入数据的缓冲区
|
||||
* @param length 要写入的数据长度
|
||||
* @return {*}
|
||||
*/
|
||||
BOOL eeprom_m95_write(m95_number_e num, uint32_t write_addr, uint8_t *data, uint16_t length)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
if (length == 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi;
|
||||
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
|
||||
// 开启和关闭SPI对读写实时性有影响
|
||||
eeprom_m95_enable();
|
||||
ret = eeprom_m95_spi->interface.u.normal.spi_write(eeprom_m95_spi, write_addr, data, length);
|
||||
eeprom_m95_disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL eeprom_m95_1_read(uint32_t addr, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
return eeprom_m95_read(M95_1, addr, buf, size);
|
||||
}
|
||||
|
||||
BOOL eeprom_m95_1_write(uint32_t addr, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
return eeprom_m95_write(M95_1, addr, (uint8_t *)buf, size);
|
||||
}
|
||||
|
||||
BOOL eeprom_m95_2_read(uint32_t addr, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
return eeprom_m95_read(M95_2, addr, buf, size);
|
||||
}
|
||||
|
||||
BOOL eeprom_m95_2_write(uint32_t addr, uint8_t *buf, uint16_t size)
|
||||
{
|
||||
return eeprom_m95_write(M95_2, addr, (uint8_t *)buf, size);
|
||||
}
|
||||
/**
|
||||
* @brief 用于M95 EEPROM测试
|
||||
* @param {m95_number_e} num
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
BOOL eeprom_m95_test(m95_number_e num)
|
||||
{
|
||||
const uint8_t buf_size = 5;
|
||||
storage_t *st = storage_init(M95_TEST_PAGE * M95_PAGE_SIZE_256, M95_PAGE_SIZE_256);
|
||||
DBG_ASSERT(st != NULL __DBG_LINE);
|
||||
|
||||
if (num == M95_1)
|
||||
{
|
||||
st->ops.read = eeprom_m95_1_read;
|
||||
st->ops.write = eeprom_m95_1_write;
|
||||
}
|
||||
else
|
||||
{
|
||||
st->ops.read = eeprom_m95_2_read;
|
||||
st->ops.write = eeprom_m95_2_write;
|
||||
}
|
||||
uint8_t buf[buf_size];
|
||||
uint8_t rbuf[buf_size];
|
||||
storage_add_node(st, 0, buf_size);
|
||||
osel_memset(buf, 0, buf_size);
|
||||
buf[0] = 0xD5;
|
||||
buf[1] = 0xC8;
|
||||
buf[2] = num;
|
||||
buf[3] = 0xaa;
|
||||
buf[4] = 0xbb;
|
||||
storage_write(st, 0, buf);
|
||||
__NOP();
|
||||
storage_read(st, 0, rbuf);
|
||||
storage_destroy(st);
|
||||
if (osel_memcmp(buf, rbuf, buf_size) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取EEPROM M95状态
|
||||
*
|
||||
* 获取EEPROM M95设备的工作状态。
|
||||
*
|
||||
* @param num EEPROM M95设备编号
|
||||
*
|
||||
* @return 如果EEPROM M95设备正常工作,返回TRUE;否则返回FALSE
|
||||
*/
|
||||
BOOL eeprom_m95_status_get(m95_number_e num)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/**
|
||||
* @file eeprom_m95.h
|
||||
* @author xxx
|
||||
* @date 2023-08-30 14:05:55
|
||||
* @brief 头文件 eeprom_m95.h
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __EEPROM_M95_H
|
||||
#define __EEPROM_M95_H
|
||||
#include "main.h"
|
||||
#include "spis.h"
|
||||
|
||||
/**
|
||||
* Byte Write within 10 ms
|
||||
* More than 4 million Write cycles
|
||||
* More than 200-year data retention
|
||||
*/
|
||||
|
||||
#define _M95010_ 128
|
||||
#define _M95020_ 256
|
||||
#define _M95040_ 512
|
||||
|
||||
#define _M95080_ 1024
|
||||
#define _M95160_ 2048
|
||||
#define _M95320_ 4096
|
||||
#define _M95640_ 8192
|
||||
|
||||
#define _M95128_ 16384
|
||||
#define _M95256_ 32768
|
||||
|
||||
#define _M95512_ 65536 ///< 65K
|
||||
#define _M95M02_ 262144 ///< 256K 262144/256 = 1024
|
||||
|
||||
#define M95_CMD_RDSR 0x05 /*!< Read Status Register instruction */
|
||||
#define M95_CMD_WRSR 0x01 /*!< Write Status Register instruction */
|
||||
|
||||
#define M95_CMD_WREN 0x06 /*!< Write enable instruction */
|
||||
#define M95_CMD_WRDI 0x04 /*!< Write disable instruction */
|
||||
|
||||
#define M95_CMD_READ 0x03 /*!< Read from Memory instruction */
|
||||
#define M95_CMD_WRITE 0x02 /*!< Write to Memory instruction */
|
||||
|
||||
///< Instruction available only for the M95_2-D device.
|
||||
#define M95_CMD_RDID 0x83 /*!< Read identification page*/
|
||||
#define M95_CMD_WRID 0x82 /*!< Write identification page*/
|
||||
#define M95_CMD_RDLS 0x83 /*!< Reads the Identification page lock status*/
|
||||
#define M95_CMD_LID 0x82 /*!< Locks the Identification page in read-only mode*/
|
||||
|
||||
#define M95_DUMMY_BYTE 0xA5 ///< 虚拟字节
|
||||
|
||||
///< 定义存储器大小(Bytes)
|
||||
typedef enum
|
||||
{
|
||||
M95_PAGE_SIZE_16 = 16, ///< _M95010_ 、_M95020_ 、_M95040_
|
||||
M95_PAGE_SIZE_32 = 32, ///< _M95080_ 、_M95160_、_M95320_、_M95640_
|
||||
M95_PAGE_SIZE_64 = 64, ///< _M95128_、_M95256_
|
||||
M95_PAGE_SIZE_128 = 128, ///< _M95512_
|
||||
M95_PAGE_SIZE_256 = 256, ///< _M95M02_
|
||||
} m95_page_size_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
M95_1,
|
||||
M95_2,
|
||||
M95_MAX,
|
||||
} m95_number_e; ///< 板卡上2块m95芯片定义
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t data;
|
||||
struct
|
||||
{
|
||||
uint8_t wip : 1; ///< Write in progress
|
||||
uint8_t wel : 1; ///< Write enable latch
|
||||
uint8_t bp0 : 1; ///< Block protect 0
|
||||
uint8_t bp1 : 1; ///< Block protect 1
|
||||
uint8_t reserve : 3;
|
||||
uint8_t srwd : 1; ///< Status register write protect
|
||||
} bits;
|
||||
} m95_write_protection_u;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
m95_number_e num;
|
||||
m95_write_protection_u write_protection;
|
||||
spi_t *spi;
|
||||
} m95_number_t;
|
||||
|
||||
extern m95_number_t eeprom_m95s[M95_MAX]; ///< m95芯片数组
|
||||
|
||||
/**
|
||||
* @brief Initializes the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern void eeprom_m95_init(m95_number_e num);
|
||||
|
||||
/**
|
||||
* @brief Deinitializes the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern void eeprom_m95_dinit(m95_number_e num);
|
||||
|
||||
/**
|
||||
* @brief Enables the M95 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_m95_enable(void);
|
||||
|
||||
/**
|
||||
* @brief Disables the M95 EEPROM module.
|
||||
*/
|
||||
extern void eeprom_m95_disable(void);
|
||||
|
||||
/**
|
||||
* @brief Closes the write protection of the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern void eeprom_m95_write_protection_close(m95_number_e num);
|
||||
|
||||
/**
|
||||
* @brief write protection state of the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern BOOL eeprom_m95_write_protection_state(m95_number_e num);
|
||||
|
||||
/**
|
||||
* @brief Reads data from the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
* @param read_addr The address to read from.
|
||||
* @param data The buffer to store the read data.
|
||||
* @param length The number of bytes to read.
|
||||
*/
|
||||
extern BOOL eeprom_m95_read(m95_number_e num, uint32_t read_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Writes data to the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
* @param write_addr The address to write to.
|
||||
* @param data The data to write.
|
||||
* @param length The number of bytes to write.
|
||||
*/
|
||||
extern BOOL eeprom_m95_write(m95_number_e num, uint32_t write_addr, uint8_t *data, uint16_t length);
|
||||
|
||||
/**
|
||||
* @brief Performs a test on the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern BOOL eeprom_m95_test(m95_number_e num);
|
||||
|
||||
/**
|
||||
* @brief Gets the status of the M95 EEPROM module.
|
||||
*
|
||||
* @param num The M95 EEPROM number.
|
||||
*/
|
||||
extern BOOL eeprom_m95_status_get(m95_number_e num);
|
||||
|
||||
extern BOOL eeprom_m95_1_read(uint32_t addr, uint8_t *buf, uint16_t size);
|
||||
extern BOOL eeprom_m95_1_write(uint32_t addr, uint8_t *buf, uint16_t size);
|
||||
extern BOOL eeprom_m95_2_read(uint32_t addr, uint8_t *buf, uint16_t size);
|
||||
extern BOOL eeprom_m95_2_write(uint32_t addr, uint8_t *buf, uint16_t size);
|
||||
#endif ///< __EEPROM_M95_H
|
|
@ -0,0 +1,68 @@
|
|||
#include "gp8302.h"
|
||||
|
||||
#define I2C_GP8302_1_SCL_PORT I2C2_SCL_GPIO_Port
|
||||
#define I2C_GP8302_1_SCL_PIN I2C2_SCL_Pin
|
||||
#define I2C_GP8302_1_SDA_PORT I2C2_SDA_GPIO_Port
|
||||
#define I2C_GP8302_1_PIN I2C2_SDA_Pin
|
||||
#define I2C_GP8302_1_DETECTION_PORT ALARM1_GPIO_Port
|
||||
#define I2C_GP8302_1_DETECTION_PIN ALARM1_Pin
|
||||
|
||||
#define I2C_GP8302_2_SCL_PORT I2C3_SCL_GPIO_Port
|
||||
#define I2C_GP8302_2_SCL_PIN I2C3_SCL_Pin
|
||||
#define I2C_GP8302_2_SDA_PORT I2C3_SDA_GPIO_Port
|
||||
#define I2C_GP8302_2_PIN I2C3_SDA_Pin
|
||||
#define I2C_GP8302_2_DETECTION_PORT ALARM2_GPIO_Port
|
||||
#define I2C_GP8302_2_DETECTION_PIN ALARM2_Pin
|
||||
|
||||
static gp8302_t gp8302[GP8302_MAX];
|
||||
|
||||
void gp8302_init(void)
|
||||
{
|
||||
i2c_gpio_group_t gpios;
|
||||
gpios.scl = gpio_create(I2C_GP8302_1_SCL_PORT, I2C_GP8302_1_SCL_PIN);
|
||||
gpios.sda = gpio_create(I2C_GP8302_1_SDA_PORT, I2C_GP8302_1_PIN);
|
||||
gp8302[GP8302_1].i2c = i2c_create(gpios, 0);
|
||||
|
||||
gpios.scl = gpio_create(I2C_GP8302_2_SCL_PORT, I2C_GP8302_2_SCL_PIN);
|
||||
gpios.sda = gpio_create(I2C_GP8302_2_SDA_PORT, I2C_GP8302_2_PIN);
|
||||
gp8302[GP8302_2].i2c = i2c_create(gpios, 0);
|
||||
}
|
||||
|
||||
BOOL gp8302_detection(void)
|
||||
{
|
||||
BOOL res = FALSE;
|
||||
if (GPIO_READ(I2C_GP8302_1_DETECTION_PORT, I2C_GP8302_1_DETECTION_PIN) == 0)
|
||||
{
|
||||
res = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GPIO_READ(I2C_GP8302_2_DETECTION_PORT, I2C_GP8302_2_DETECTION_PIN) == 0)
|
||||
{
|
||||
res = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void gp8302_output(gp8302_number_e no, uint16_t pressure)
|
||||
{
|
||||
uint16_t hi = ((pressure >> 8) << 4) + ((uint8_t)pressure >> 4);
|
||||
uint8_t lo = ((uint8_t)pressure) << 4;
|
||||
pressure = (hi << 8) + lo;
|
||||
i2c_t *p = gp8302[no].i2c;
|
||||
p->interface.start(p);
|
||||
p->interface.write_byte(p, 0xb0);
|
||||
p->interface.wait_ack(p);
|
||||
p->interface.write_byte(p, 2);
|
||||
p->interface.wait_ack(p);
|
||||
p->interface.write_word(p, pressure);
|
||||
p->interface.wait_ack(p);
|
||||
p->interface.stop(p);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef __GP8302_H__
|
||||
#define __GP8302_H__
|
||||
#include "main.h"
|
||||
#include "i2cs.h"
|
||||
#include "lib.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GP8302_1,
|
||||
GP8302_2,
|
||||
GP8302_MAX,
|
||||
} gp8302_number_e;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
i2c_t *i2c;
|
||||
} gp8302_t;
|
||||
|
||||
void gp8302_init(void);
|
||||
BOOL gp8302_detection(void);
|
||||
void gp8302_output(gp8302_number_e no, uint16_t pressure);
|
||||
#endif
|
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* @file ntc_3950.c
|
||||
* @author xxx
|
||||
* @date 2023-08-30 08:58:43
|
||||
* @brief 用于实现NTC的应用功能
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "ntc_3950.h"
|
||||
#define CPU_VREF 2.5
|
||||
#define NTC_VREF 2.5
|
||||
#define TABLE_SIZE 185
|
||||
#define NTC_SERIES_RESISTOR 200000 ///< 200K
|
||||
#define TEMP_MIN -55
|
||||
#define TEMP_MAX 129
|
||||
|
||||
const uint32_t _table[TABLE_SIZE] = {
|
||||
8989000, 8242680, 7592960, 7021380, 6513750, // -55,-54,-53,-52,-51
|
||||
6059060, 5648680, 5275800, 4935020, 4621990, 4333220, 4065840, 3817520, 3586310, 3370600, // -50,-49,-48,-47,-46,-45,-44,-43,-42,-41
|
||||
3169000, 2980330, 2803600, 2637910, 2482470, 2336580, 2199620, 2071020, 1950230, 1836790, // -40,-39,-38,-37,-36,-35,-34,-33,-32,-31
|
||||
1730230, 1630150, 1536140, 1447840, 1364900, 1287000, 1213820, 1145090, 1080530, 1019890, // -30,-29,-28,-27,-26,-25,-24,-23,-22,-21
|
||||
962912, 909379, 859074, 811797, 767359, 725581, 686296, 649348, 614590, 581883, // -20,-19,-18,-17,-16,-15,-14,-13,-12,-11
|
||||
551100, 522117, 494824, 469113, 444886, 422050, 400518, 380209, 361048, 342963, // -10,-9,-8,-7,-6,-5,-4,-3,-2,-1
|
||||
326560, 309764, 294529, 280131, 266520, 253647, 241470, 229946, 219036, 208706, // 0,1, 2, 3,4,5,6,7,8,9
|
||||
198920, 189647, 180857, 172523, 164618, 157118, 150000, 143243, 136827, 130731, // 10,11 ,12, 13,14,15,16,17,18,19
|
||||
124940, 119435, 114202, 109225, 104491, 100000, 95699, 91617, 87731, 84028, // 20,21, 22, 23,24,25,26,27,28,29
|
||||
80501, 77140, 73936, 70881, 67968, 65188, 62537, 60006, 57590, 55283, // 30,31, 32, 33,34,35,36,37,38,39
|
||||
53080, 50976, 48965, 47044, 45207, 43451, 41771, 40165, 38628, 37157, // 40,41, 42, 43,34,35,36,37,38,39
|
||||
35750, 34402, 33112, 31876, 30692, 29558, 28471, 27429, 26430, 25472, // 50,51, 52, 53,54,55,56,57,58,59
|
||||
24554, 23672, 22827, 22016, 21237, 20489, 19771, 19082, 18420, 17784, // 60,61, 62, 63,64,65,66,67,68,69
|
||||
17172, 16585, 16020, 15477, 14955, 14453, 13970, 13505, 13058, 12628, // 70,71, 72, 73,74,75,76,77,78,79
|
||||
12213, 11815, 11431, 11061, 10705, 10362, 10031, 9712, 9405, 9110, // 80,81, 82, 83,84,85,86,87,88,89
|
||||
8824, 8549, 8284, 8028, 7782, 7544, 7314, 7093, 6879, 6673, // 90,91, 92, 93,94,95,96,97,98,99
|
||||
6474, 6281, 6096, 5916, 5743, 5576, 5415, 5259, 5108, 4963, // 101,102, 103,104,105,106,107,108,109
|
||||
4822, 4687, 4555, 4428, 4306, 4187, 4073, 3962, 3855, 3751, // 111,112, 113,114,115,116,117,118,119
|
||||
3651, 3555, 3461, 3371, 3283, 3199, 3100, 3099, 2899, 2799, // 121,122, 123,124,125,126,127,128,129
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 温度查表
|
||||
* @param {uint32_t} *list
|
||||
* @param {uint32_t} rt
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
static uint8_t ntc_lookup(const uint32_t *list, uint32_t rt)
|
||||
{
|
||||
uint8_t middle = 0;
|
||||
uint8_t indexL = 0;
|
||||
uint8_t indexR = TABLE_SIZE - 1;
|
||||
if (rt >= *(list + 0))
|
||||
return 0;
|
||||
if (rt <= *(list + TABLE_SIZE - 1))
|
||||
return TABLE_SIZE - 1;
|
||||
|
||||
while ((indexR - indexL) > 1)
|
||||
{
|
||||
middle = (indexL + indexR) >> 1;
|
||||
if (rt == *(list + middle))
|
||||
return middle;
|
||||
else if (rt > *(list + middle))
|
||||
indexR = middle;
|
||||
else if (rt < *(list + middle))
|
||||
indexL = middle;
|
||||
}
|
||||
return indexL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取温度值,单位为0.1摄氏度
|
||||
* @param {uint16_t} adc采集值
|
||||
* @return {float32_u} 温度值
|
||||
* @note
|
||||
*/
|
||||
float32_u ntc_get_temp(uint16_t adc)
|
||||
{
|
||||
|
||||
uint8_t index = 0;
|
||||
int16_t data = 0;
|
||||
int16_t t = 0;
|
||||
int16_t result = 0;
|
||||
uint32_t rt = 0;
|
||||
const int16_t base = TEMP_MIN * 10;
|
||||
float32_u res;
|
||||
res.f = TEMP_MIN;
|
||||
|
||||
/**
|
||||
* ad = (4095*rt)/(rt+10000)
|
||||
*
|
||||
* rt = (ad*NTC_SERIES_RESISTOR*CPU_VREF)/(NTC_VREF*4095-CPU_VREF*ad)
|
||||
*/
|
||||
rt = (adc * NTC_SERIES_RESISTOR * CPU_VREF) / (NTC_VREF * 4095 - CPU_VREF * adc);
|
||||
index = ntc_lookup(_table, rt);
|
||||
if (rt >= _table[0])
|
||||
return res;
|
||||
if (rt <= *(_table + TABLE_SIZE - 1))
|
||||
{
|
||||
result = (TABLE_SIZE - 1) * 10 + base;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = _table[index] - _table[index + 1];
|
||||
t = 10 * (_table[index] - rt) / data;
|
||||
result = base + index * 10 + t;
|
||||
}
|
||||
res.f = result / 10.0;
|
||||
return res;
|
||||
}
|
||||
|
||||
// 判断传感器是否故障
|
||||
BOOL ntc_is_fault_temp(float32 temp)
|
||||
{
|
||||
if (temp < TEMP_MIN || temp > TEMP_MAX)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* @file ntc_3950.h
|
||||
* @author xxx
|
||||
* @date 2023-08-30 14:05:55
|
||||
* @brief 头文件 ntc_3950.h
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __NTC_B3950_H__
|
||||
#define __NTC_B3950_H__
|
||||
#include "main.h"
|
||||
|
||||
extern float32_u ntc_get_temp(uint16_t adc); ///< 获取温度值
|
||||
extern BOOL ntc_is_fault_temp(float32 temp); ///< 判断传感器是否故障
|
||||
#endif ///< __NTC_B3950_H__
|
|
@ -0,0 +1,203 @@
|
|||
#include "pt100.h"
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t address; // 从机地址
|
||||
uint8_t code; // 功能码
|
||||
uint16_t reg_address; // 寄存器地址
|
||||
uint16_t reg_num; // 寄存器数量
|
||||
uint16_t crc;
|
||||
} pt100_data_t;
|
||||
#pragma pack()
|
||||
|
||||
extern uart_t *uarts[UART_NUM_MAX];
|
||||
static pt100_t handle;
|
||||
float32 pt100_tempture[PT100_DATA_CHANNEL_NUM];
|
||||
/* CRC low byte table */
|
||||
static const unsigned char auchCRCLo[] =
|
||||
{
|
||||
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
|
||||
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
|
||||
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
|
||||
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
|
||||
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
|
||||
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
||||
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
|
||||
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
|
||||
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
|
||||
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
|
||||
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
|
||||
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
||||
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
|
||||
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
|
||||
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
|
||||
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
|
||||
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
|
||||
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
||||
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
|
||||
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
|
||||
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
|
||||
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
|
||||
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
|
||||
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
|
||||
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
|
||||
0x43, 0x83, 0x41, 0x81, 0x80, 0x40};
|
||||
|
||||
/* CRC high byte table */
|
||||
static const unsigned char auchCRCHi[] =
|
||||
{
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
|
||||
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
|
||||
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
|
||||
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
|
||||
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
|
||||
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
||||
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};
|
||||
|
||||
/* Public functions ----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Calculate Modbus CRC16
|
||||
* @param puchMsg: Data to calculate CRC
|
||||
* @param usMsgLen: Data length
|
||||
* @param puchCRCHi: High byte of CRC value
|
||||
* @param puchCRCLo: Low byte of CRC value
|
||||
* @note Send the low byte first
|
||||
* @retval None
|
||||
*/
|
||||
void GetModbusCRC16(unsigned char *puchMsg, unsigned short usMsgLen,
|
||||
unsigned char *puchCRCLo, unsigned char *puchCRCHi)
|
||||
{
|
||||
unsigned char uchCRCLo = 0xFF;
|
||||
unsigned char uchCRCHi = 0xFF;
|
||||
unsigned short uIndex = 0;
|
||||
|
||||
while (usMsgLen--)
|
||||
{
|
||||
uIndex = (unsigned char)(uchCRCHi ^ *puchMsg++);
|
||||
uchCRCHi = (unsigned char)(uchCRCLo ^ auchCRCHi[uIndex]);
|
||||
uchCRCLo = (unsigned char)(auchCRCLo[uIndex]);
|
||||
}
|
||||
|
||||
*puchCRCLo = uchCRCHi;
|
||||
*puchCRCHi = uchCRCLo;
|
||||
}
|
||||
|
||||
static void pt100_rx_cb(uint8_t uart_index, uint8_t *data, uint16_t len)
|
||||
{
|
||||
uart_t *h = handle.huart;
|
||||
if (h != NULL)
|
||||
{
|
||||
if (h->uart_index == uart_index)
|
||||
{
|
||||
if ((h->rx_sta & 0x8000) == 0) // 接收未完成
|
||||
{
|
||||
handle.ctx_recv_buf[h->rx_sta & 0X3FFF] = h->rxbuf[0];
|
||||
h->rx_sta++;
|
||||
if (h->rx_sta > (PT100_MODBUS_RECV_LENGTH - 1))
|
||||
h->rx_sta = 0; // 接收数据错误,重新开始接收
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pt100_uart_init(void)
|
||||
{
|
||||
if (uarts[PT100_RS485_PORT] == NULL)
|
||||
{
|
||||
uarts[PT100_RS485_PORT] = uart_create(USART4, FALSE, 1, pt100_rx_cb, FALSE, 0, NULL);
|
||||
uarts[PT100_RS485_PORT]->uart_index = PT100_RS485_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
void pt100_init(send_data_cb_t cb)
|
||||
{
|
||||
handle.send_data_cb = cb;
|
||||
pt100_uart_init();
|
||||
handle.huart = uarts[PT100_RS485_PORT];
|
||||
DBG_ASSERT(handle.huart != NULL __DBG_LINE);
|
||||
GPIO_RESET(RS485_EN2_GPIO_Port, RS485_EN2_Pin);
|
||||
uart_recv_en(handle.huart);
|
||||
handle.idel_flag = false;
|
||||
osel_memset((uint8_t *)pt100_tempture, 0, sizeof(float32) * PT100_DATA_CHANNEL_NUM);
|
||||
}
|
||||
|
||||
void pt100_process(void)
|
||||
{
|
||||
uart_t *h = handle.huart;
|
||||
DBG_ASSERT(h != NULL __DBG_LINE);
|
||||
pt100_data_t data;
|
||||
data.address = 0x01;
|
||||
data.code = 0x04;
|
||||
|
||||
data.reg_address = 0x0000;
|
||||
data.reg_address = S2B_UINT16(data.reg_address);
|
||||
|
||||
data.reg_num = PT100_DATA_CHANNEL_NUM;
|
||||
data.reg_num = S2B_UINT16(data.reg_num);
|
||||
GetModbusCRC16((uint8_t *)&data, sizeof(pt100_data_t) - 2, (uint8_t *)&data.crc, (uint8_t *)&data.crc + 1);
|
||||
|
||||
h->rx_sta = 0;
|
||||
handle.send_data_cb((uart_num_e)h->uart_index, (uint8_t *)&data, sizeof(pt100_data_t));
|
||||
}
|
||||
|
||||
void pt100_data_deal(void)
|
||||
{
|
||||
uart_t *h = handle.huart;
|
||||
uint8_t *p = handle.ctx_recv_buf;
|
||||
uint8_t offset = 0;
|
||||
uint16_t crc = 0, crc1 = 0;
|
||||
uint16_t length = h->rx_sta;
|
||||
uint16_t pt100_data[PT100_DATA_CHANNEL_NUM];
|
||||
uint8_t pt100_data_length = 0;
|
||||
if (h->rx_sta == 0)
|
||||
{
|
||||
return; // 未收到数据切换到下一个设备
|
||||
}
|
||||
h->rx_sta |= 0x8000; // 暂停串口接收数据,20ms预留了充足的接收时间
|
||||
|
||||
if (p[offset] == 0x01 && p[++offset] == 0x04 && length > 4)
|
||||
{
|
||||
offset++;
|
||||
// CRC校验
|
||||
GetModbusCRC16(p, length - 2, (uint8_t *)&crc, (uint8_t *)&crc + 1);
|
||||
osel_memcpy((uint8_t *)&crc1, p + length - 2, 2);
|
||||
if (crc == crc1)
|
||||
{
|
||||
pt100_data_length = p[offset];
|
||||
offset++; // 偏移过长度
|
||||
osel_memcpy((uint8_t *)pt100_data, p + offset, pt100_data_length);
|
||||
for (uint8_t i = 0; i < PT100_DATA_CHANNEL_NUM; i++)
|
||||
{
|
||||
pt100_data[i] = B2S_UINT16(pt100_data[i]);
|
||||
if (pt100_data[i] != 0xffff)
|
||||
{
|
||||
pt100_tempture[i] = (float32)pt100_data[i] / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
pt100_tempture[i] = 129;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __PT100_H__
|
||||
#define __PT100_H__
|
||||
#include "board.h"
|
||||
#include "agile_modbus.h"
|
||||
#define PT100_RS485_PORT UART_NUM_3
|
||||
|
||||
#define PT100_SLAVER_ADDR 1U // 从机地址
|
||||
#define PT100_DATA_CHANNEL_NUM 3U // 通道数
|
||||
#define PT100_MODBUS_RECV_LENGTH 30U // 接收缓冲区大小
|
||||
#define PT100_MODBUS_SEND_LENGTH 30U // modbus最大数据长度
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL idel_flag; // 通过这个标识位来判断是否需要初始化modbus
|
||||
uart_t *huart;
|
||||
float32_t temperature; // 温度
|
||||
|
||||
agile_modbus_rtu_t ctx_rtu;
|
||||
uint8_t ctx_send_buf[PT100_MODBUS_SEND_LENGTH];
|
||||
uint8_t ctx_recv_buf[PT100_MODBUS_RECV_LENGTH]; // 公用一个接收缓冲区
|
||||
send_data_cb_t send_data_cb; // 发送数据回调函数,外部传入
|
||||
} pt100_t;
|
||||
|
||||
extern float32 pt100_tempture[PT100_DATA_CHANNEL_NUM];
|
||||
void pt100_init(send_data_cb_t cb);
|
||||
void pt100_process(void);
|
||||
void pt100_data_deal(void);
|
||||
#endif // __PT100_H__
|
|
@ -0,0 +1,560 @@
|
|||
/**
|
||||
* @file rtc_rx8010.c
|
||||
* @author xxx
|
||||
* @date 2023-08-30 08:58:43
|
||||
* @brief 用于实现RTC芯片RX8010的应用功能
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "rtc_rx8010.h"
|
||||
#include "i2cs.h"
|
||||
#include "delay.h"
|
||||
|
||||
#define RTC_RX8010_SDA_PORT RTC_SDA_GPIO_Port
|
||||
#define RTC_RX8010_SDA_PIN RTC_SDA_Pin
|
||||
#define RTC_RX8010_SCL_PORT RTC_SCL_GPIO_Port
|
||||
#define RTC_RX8010_SCL_PIN RTC_SCL_Pin
|
||||
|
||||
static i2c_t *rtc;
|
||||
static TIM_TypeDef *_timer_us;
|
||||
|
||||
static void _delay_us(uint32_t us)
|
||||
{
|
||||
if (_timer_us != NULL)
|
||||
{
|
||||
delay_hardware_us(_timer_us, us);
|
||||
}
|
||||
else
|
||||
{
|
||||
delay_us(us);
|
||||
}
|
||||
}
|
||||
|
||||
/* sec, min, hour, week, day, month, year */
|
||||
// static uint8_t calendar[7] = {0, 0, 0, 1, 29, 2, 98};
|
||||
|
||||
/**
|
||||
* @brief 从RTC芯片的指定地址读取一个字节数据
|
||||
* @param {uint8_t} *read_buf
|
||||
* @param {uint8_t} addr
|
||||
* @return {*}
|
||||
*/
|
||||
static BOOL rtc_read_byte(uint8_t *read_buf, uint8_t addr)
|
||||
{
|
||||
uint8_t *p = read_buf;
|
||||
|
||||
/* 发送起始信号 */
|
||||
rtc->interface.start(rtc);
|
||||
|
||||
/* 发送从机地址 + 读写方向 */
|
||||
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 发送读地址 */
|
||||
rtc->interface.write_byte(rtc, addr);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 重新发送起始信号。前面的代码的目的向RTC传送地址,下面开始读取数据 */
|
||||
rtc->interface.start(rtc);
|
||||
|
||||
/* 发送从机地址 + 读写方向 */
|
||||
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
/* 读取数据 */
|
||||
*p = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
|
||||
|
||||
/* 命令执行成功,发送I2C总线停止信号 */
|
||||
rtc->interface.stop(rtc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从RTC芯片的指定地址读取若干数据
|
||||
* @param {uint8_t} *read_buf
|
||||
* @param {uint8_t} addr
|
||||
* @param {int} size
|
||||
* @return {*}
|
||||
*/
|
||||
static BOOL rtc_read_bytes(uint8_t *read_buf, uint8_t addr, int size)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* 发送起始信号 */
|
||||
rtc->interface.start(rtc);
|
||||
|
||||
/* 发送从机地址 + 读写方向 */
|
||||
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 发送读地址 */
|
||||
rtc->interface.write_byte(rtc, addr);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 重新发送起始信号。前面的代码的目的向RTC传送地址,下面开始读取数据 */
|
||||
rtc->interface.start(rtc);
|
||||
|
||||
/* 发送从机地址 + 读写方向 */
|
||||
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 循环读取数据,RTC芯片地址自动自增 */
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
/* 每读完1个字节后,需要发送Ack, 最后一个字节需要发Nack */
|
||||
if (i != (size - 1))
|
||||
{
|
||||
read_buf[i] = rtc->interface.read_byte(rtc, TRUE); /* 读1个字节 */
|
||||
}
|
||||
else
|
||||
{
|
||||
read_buf[i] = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 命令执行成功,发送I2C总线停止信号 */
|
||||
rtc->interface.stop(rtc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向RTC芯片的指定地址写入一个数据
|
||||
* @param {uint8_t} data
|
||||
* @param {uint8_t} addr
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
static BOOL rtc_write_byte(uint8_t data, uint8_t addr)
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
/* 尝试与RTC芯片建立I2C通讯 */
|
||||
for (retry = 0; retry < 100; retry++)
|
||||
{
|
||||
rtc->interface.start(rtc); /* 发送起始信号 */
|
||||
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
|
||||
if (rtc->interface.wait_ack(rtc) == TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retry == 100)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 发送起始写地址 */
|
||||
rtc->interface.write_byte(rtc, addr);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 写入数据 */
|
||||
rtc->interface.write_byte(rtc, data);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 命令执行成功,发送I2C总线停止信号 */
|
||||
rtc->interface.stop(rtc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向RTC芯片的指定地址写入若干数据
|
||||
* @param {uint8_t} *write_buf
|
||||
* @param {uint8_t} addr
|
||||
* @param {int} size
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
static BOOL rtc_write_bytes(uint8_t *write_buf, uint8_t addr, int size)
|
||||
{
|
||||
int i = 0;
|
||||
int retry = 0;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
/* 尝试与RTC芯片建立I2C通讯 */
|
||||
for (retry = 0; retry < 100; retry++)
|
||||
{
|
||||
rtc->interface.start(rtc); /* 发送起始信号 */
|
||||
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
|
||||
if (rtc->interface.wait_ack(rtc) == TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retry == 100)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 发送起始写地址 */
|
||||
rtc->interface.write_byte(rtc, addr);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 循环写入数据,RTC芯片地址自动自增 */
|
||||
rtc->interface.write_byte(rtc, write_buf[i]);
|
||||
if (rtc->interface.wait_ack(rtc) != TRUE)
|
||||
{
|
||||
rtc->interface.stop(rtc);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 命令执行成功,发送I2C总线停止信号 */
|
||||
rtc->interface.stop(rtc);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 假读RTC芯片,任意读地址,不判断RTC响应
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
static void rtc_dummy_read(void)
|
||||
{
|
||||
rtc->interface.start(rtc);
|
||||
rtc->interface.write_byte(rtc, RTC_WR_ADDR);
|
||||
rtc->interface.write_byte(rtc, 0x20);
|
||||
|
||||
rtc->interface.start(rtc);
|
||||
rtc->interface.write_byte(rtc, RTC_RD_ADDR);
|
||||
rtc->interface.read_byte(rtc, FALSE);
|
||||
|
||||
rtc->interface.stop(rtc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 用于检查VLF,寄存器地址:0x1e bit[1]
|
||||
* @return {uint8_t} 0 = VLF位为0,1 = VLF位为1
|
||||
* @note
|
||||
*/
|
||||
static uint8_t rtc_check_vlf(void)
|
||||
{
|
||||
uint8_t flag_register = 1;
|
||||
uint8_t vlf = 0;
|
||||
|
||||
rtc_read_byte(&flag_register, RTC_FLAG_ADDR);
|
||||
|
||||
vlf = (flag_register & 0x02);
|
||||
if (vlf == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等待VLF位清除,寄存器地址:0x1e bit[1]
|
||||
* @return {uint8_t} 0 = 清零成功,1 = 清零失败,2 = 无需清零
|
||||
*/
|
||||
static uint8_t rtc_wait_vlf_clear(void)
|
||||
{
|
||||
uint8_t ret = 1;
|
||||
uint8_t i = 0;
|
||||
uint8_t vlf;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
vlf = rtc_check_vlf();
|
||||
|
||||
if (vlf == 0)
|
||||
{
|
||||
ret = ((i > 0) ? 0 : 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 清除VLF */
|
||||
rtc_write_byte(0, RTC_FLAG_ADDR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 复位
|
||||
* @return {BOOL} FALSE = 复位成功,TRUE = 复位失败
|
||||
*/
|
||||
static BOOL rtc_soft_reset(void)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
ret = rtc_write_byte(0x00, 0x1f);
|
||||
ret = rtc_write_byte(0x80, 0x1f);
|
||||
ret = rtc_write_byte(0xd3, 0x60);
|
||||
ret = rtc_write_byte(0x03, 0x66);
|
||||
ret = rtc_write_byte(0x02, 0x6b);
|
||||
ret = rtc_write_byte(0x01, 0x6b);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
_delay_us(2000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 时钟寄存器初始化函数
|
||||
* @return {BOOL} TRUE = 初始化成功,FALSE = 初始化失败
|
||||
*/
|
||||
static BOOL rtc_clock_reginit(void)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
|
||||
/* set reserve register */
|
||||
ret = rtc_write_byte(RTC_REG17_DATA, RTC_REG17_ADDR);
|
||||
ret = rtc_write_byte(RTC_REG30_DATA, RTC_REG30_ADDR);
|
||||
ret = rtc_write_byte(RTC_REG31_DATA, RTC_REG31_ADDR);
|
||||
ret = rtc_write_byte(RTC_IRQ_DATA, RTC_IRQ_ADDR);
|
||||
/* write 0x04 to reg_0x1d */
|
||||
ret = rtc_write_byte(0x04, 0x1d);
|
||||
/* write 0x00 to reg_0x1e */
|
||||
ret = rtc_write_byte(0x00, 0x1e);
|
||||
/* stop clock */
|
||||
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
|
||||
/* set the present time */
|
||||
// ret = rtc_write_bytes(calendar, RTC_CLOCK_ADDR, sizeof(calendar));
|
||||
/* start clock */
|
||||
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RTC芯片初始化
|
||||
* @return {BOOL} TRUE = 成功,FALSE = 失败
|
||||
* @note
|
||||
*/
|
||||
BOOL rtc_init(TIM_TypeDef *timer_us)
|
||||
{
|
||||
if (timer_us != NULL)
|
||||
{
|
||||
_timer_us = timer_us;
|
||||
ENABLE_TIM_COUNT(_timer_us);
|
||||
}
|
||||
|
||||
i2c_gpio_group_t gpios;
|
||||
int ret = 1;
|
||||
gpios.scl = gpio_create(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
|
||||
gpios.sda = gpio_create(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
|
||||
|
||||
rtc = i2c_create(gpios, 10);
|
||||
|
||||
rtc_dummy_read();
|
||||
/* wait for VLF bit clear */
|
||||
ret = rtc_wait_vlf_clear();
|
||||
if (ret == 0)
|
||||
{
|
||||
/* software reset */
|
||||
ret = rtc_soft_reset();
|
||||
if (ret == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (ret == 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* register initialize */
|
||||
|
||||
return rtc_clock_reginit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RTC芯片反初始化
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
BOOL rtc_dinit(void)
|
||||
{
|
||||
GPIO_SET_ANALOG(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
|
||||
GPIO_SET_ANALOG(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从RTC芯片读取时间
|
||||
* @param {uint8_t} *read_buf - 接收缓存指针,用于接收读取到的数据
|
||||
* @return {BOOL} TRUE = 成功,FALSE = 失败
|
||||
* @note
|
||||
*/
|
||||
BOOL rtc_get_clock_time(uint8_t *read_buf)
|
||||
{
|
||||
return rtc_read_bytes(read_buf, RTC_CLOCK_ADDR, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向RTC芯片写入时间
|
||||
* @param {rtc_date} *data - 发送缓存指针,用于存储要发送的数据
|
||||
* @return {BOOL} TRUE = 成功,FALSE = 失败
|
||||
* @note
|
||||
*/
|
||||
BOOL rtc_set_clock_time(rtc_date *data)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
uint8_t tmp[7];
|
||||
tmp[0] = data->second;
|
||||
tmp[1] = data->minute;
|
||||
tmp[2] = data->hour;
|
||||
tmp[3] = data->weekday;
|
||||
tmp[4] = data->day;
|
||||
tmp[5] = data->month;
|
||||
tmp[6] = data->year;
|
||||
|
||||
tmp[3] = (rtc_week_e)tmp[3]; // 改成星期几
|
||||
|
||||
/* stop clock */
|
||||
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
|
||||
/* set the present time */
|
||||
ret = rtc_write_bytes(tmp, RTC_CLOCK_ADDR, sizeof(tmp));
|
||||
/* start clock */
|
||||
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实时时钟(RTC)的时间戳
|
||||
*
|
||||
* 该函数从RTC设备中获取当前的日期和时间,并将其转换为自1970年1月1日以来的秒数(时间戳)。
|
||||
* 如果无法从RTC设备中获取时间,则返回0。
|
||||
*
|
||||
* @return 返回从1970年1月1日以来的秒数(时间戳),如果无法获取时间则返回0。
|
||||
*/
|
||||
uint32_t rtc_timestamp(void)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
uint8_t tmp[7];
|
||||
rtc_date_t date;
|
||||
rtc_time_t time;
|
||||
ret = rtc_get_clock_time(tmp);
|
||||
if (ret == FALSE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
date.year = hex_format_dec(tmp[6]);
|
||||
date.month = hex_format_dec(tmp[5]);
|
||||
date.day = hex_format_dec(tmp[4]);
|
||||
time.hour = hex_format_dec(tmp[2]);
|
||||
time.minute = hex_format_dec(tmp[1]);
|
||||
time.second = hex_format_dec(tmp[0]);
|
||||
return time2stamp(&date, &time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将星期转为星期码
|
||||
* @param {uint8_t} *weekday 星期几
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void rtc_weekday_convert(uint8_t *weekday)
|
||||
{
|
||||
switch (*weekday)
|
||||
{
|
||||
case 1:
|
||||
*weekday = MON;
|
||||
break;
|
||||
case 2:
|
||||
*weekday = TUE;
|
||||
break;
|
||||
case 3:
|
||||
*weekday = WED;
|
||||
break;
|
||||
case 4:
|
||||
*weekday = THUR;
|
||||
break;
|
||||
case 5:
|
||||
*weekday = FRI;
|
||||
break;
|
||||
case 6:
|
||||
*weekday = SAT;
|
||||
break;
|
||||
case 7:
|
||||
*weekday = SUN;
|
||||
break;
|
||||
default:
|
||||
*weekday = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将星期码转为星期
|
||||
* @param {uint8_t} *weekday 星期码
|
||||
* @return {*}
|
||||
* @note
|
||||
*/
|
||||
void rtc_weekday_rconvert(uint8_t *weekday)
|
||||
{
|
||||
switch (*weekday)
|
||||
{
|
||||
case MON:
|
||||
*weekday = 1;
|
||||
break;
|
||||
case TUE:
|
||||
*weekday = 2;
|
||||
break;
|
||||
case WED:
|
||||
*weekday = 3;
|
||||
break;
|
||||
case THUR:
|
||||
*weekday = 4;
|
||||
break;
|
||||
case FRI:
|
||||
*weekday = 5;
|
||||
break;
|
||||
case SAT:
|
||||
*weekday = 6;
|
||||
break;
|
||||
case SUN:
|
||||
*weekday = 7;
|
||||
break;
|
||||
default:
|
||||
*weekday = 0;
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* @file rtc_rx8010.h
|
||||
* @author xxx
|
||||
* @date 2023-08-30 14:05:55
|
||||
* @brief 头文件 rtc_rx8010.h
|
||||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __RTC_RX8010_H__
|
||||
#define __RTC_RX8010_H__
|
||||
#include "main.h"
|
||||
|
||||
#define RTC_DEVICE_ADDR 0x32
|
||||
|
||||
#define RTC_WR_ADDR ((RTC_DEVICE_ADDR << 1) | 0)
|
||||
#define RTC_RD_ADDR ((RTC_DEVICE_ADDR << 1) | 1)
|
||||
|
||||
#define RTC_FLAG_ADDR 0x1e
|
||||
#define RTC_CLOCK_ADDR 0x10
|
||||
#define RTC_CONTROL_ADDR 0x1f
|
||||
|
||||
#define RTC_REG17_ADDR 0x17
|
||||
#define RTC_REG17_DATA 0xd8
|
||||
|
||||
#define RTC_REG30_ADDR 0x30
|
||||
#define RTC_REG30_DATA 0x00
|
||||
|
||||
#define RTC_REG31_ADDR 0x31
|
||||
#define RTC_REG31_DATA 0x08
|
||||
|
||||
#define RTC_IRQ_ADDR 0x32
|
||||
#define RTC_IRQ_DATA 0x00
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SUN = BIT0,
|
||||
MON = BIT1,
|
||||
TUE = BIT2,
|
||||
WED = BIT3,
|
||||
THUR = BIT4,
|
||||
FRI = BIT5,
|
||||
SAT = BIT6
|
||||
} rtc_week_e; ///< 星期码
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t year; ///< 7 bit - 1 63
|
||||
uint8_t month; ///< 4 bit
|
||||
uint8_t day; ///< 5 bit
|
||||
uint8_t weekday; ///< rtc_week_e
|
||||
uint8_t hour; ///< 5 bit
|
||||
uint8_t minute; ///< 6 bit
|
||||
uint8_t second; ///< 6 bit
|
||||
} rtc_date;
|
||||
|
||||
/**
|
||||
* @brief Initializes the RTC module.
|
||||
* @return TRUE if the initialization is successful, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL rtc_init(TIM_TypeDef *timer_us);
|
||||
|
||||
/**
|
||||
* @brief Deinitializes the RTC module.
|
||||
* @return TRUE if the deinitialization is successful, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL rtc_dinit(void);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current clock time from the RTC module.
|
||||
* @param read_buf Pointer to the buffer to store the clock time.
|
||||
* @return TRUE if the clock time is successfully retrieved, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL rtc_get_clock_time(uint8_t *read_buf);
|
||||
|
||||
/**
|
||||
* @brief Sets the clock time in the RTC module.
|
||||
* @param data Pointer to the RTC date structure containing the new clock time.
|
||||
* @return TRUE if the clock time is successfully set, FALSE otherwise.
|
||||
*/
|
||||
extern BOOL rtc_set_clock_time(rtc_date *data);
|
||||
|
||||
/**
|
||||
* @brief Retrieves the current alarm time from the RTC module.
|
||||
* @param read_buf Pointer to the buffer to store the alarm time.
|
||||
* @return TRUE if the alarm time is successfully retrieved, FALSE otherwise.
|
||||
*/
|
||||
extern uint32_t rtc_timestamp(void);
|
||||
/**
|
||||
* @brief Converts the weekday value to a human-readable format.
|
||||
* @param weekday Pointer to the weekday value to be converted.
|
||||
*/
|
||||
extern void rtc_weekday_convert(uint8_t *weekday);
|
||||
|
||||
/**
|
||||
* @brief Converts the weekday value from a human-readable format to the RTC format.
|
||||
* @param weekday Pointer to the weekday value to be converted.
|
||||
*/
|
||||
extern void rtc_weekday_rconvert(uint8_t *weekday);
|
||||
#endif ///< !__RTC_RX8010_H__
|
|
@ -0,0 +1,181 @@
|
|||
#include "sht40.h"
|
||||
#include "i2cs.h"
|
||||
#include "delay.h"
|
||||
#define SHT40_SDA_PORT I2C1_SDA_GPIO_Port
|
||||
#define SHT40_SDA_PIN I2C1_SDA_Pin
|
||||
#define SHT40_SCL_PORT I2C1_SCL_GPIO_Port
|
||||
#define SHT40_SCL_PIN I2C1_SCL_Pin
|
||||
|
||||
#define SHT40_I2C_ADDRESS 0x44
|
||||
#define SHT40_MEASURE_CMD 0xFD // 2*8-bit T-data:8-bit CRC:2*8-bit RH-data: 8-bit CRC
|
||||
|
||||
static i2c_t *_sht40_i2c;
|
||||
static TIM_TypeDef *_timer_us;
|
||||
static uint8_t crc8(uint8_t *data, uint8_t len);
|
||||
|
||||
static void _delay_us(uint32_t us)
|
||||
{
|
||||
if (_timer_us != NULL)
|
||||
{
|
||||
delay_hardware_us(_timer_us, us);
|
||||
}
|
||||
else
|
||||
{
|
||||
delay_us(us);
|
||||
}
|
||||
}
|
||||
|
||||
void sht40_test(void)
|
||||
{
|
||||
float32 temperature = 0;
|
||||
float32 humidity = 0;
|
||||
sht40_read(&temperature, &humidity);
|
||||
|
||||
__NOP();
|
||||
}
|
||||
/**
|
||||
* @brief 初始化 SHT40 传感器
|
||||
*
|
||||
* 该函数用于初始化 SHT40 传感器,包括创建 I2C 通讯所需的 GPIO 引脚和 I2C 通讯对象。
|
||||
*
|
||||
* 初始化完成后,sht40_i2c 变量将用于后续的 SHT40 传感器通信。
|
||||
*/
|
||||
void sht40_init(TIM_TypeDef *timer_us)
|
||||
{
|
||||
DBG_ASSERT(timer_us != NULL __DBG_LINE);
|
||||
if (timer_us != NULL)
|
||||
{
|
||||
_timer_us = timer_us;
|
||||
ENABLE_TIM_COUNT(_timer_us);
|
||||
}
|
||||
|
||||
i2c_gpio_group_t gpios;
|
||||
gpios.scl = gpio_create(SHT40_SCL_PORT, SHT40_SCL_PIN);
|
||||
gpios.sda = gpio_create(SHT40_SDA_PORT, SHT40_SDA_PIN);
|
||||
|
||||
_sht40_i2c = i2c_create(gpios, 10);
|
||||
DBG_ASSERT(_sht40_i2c != NULL __DBG_LINE);
|
||||
|
||||
// sht40_test(); // 测试 SHT40
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化 SHT40 传感器
|
||||
*
|
||||
* 此函数用于初始化 SHT40 温湿度传感器,以便进行后续的温度和湿度测量。
|
||||
*
|
||||
* 注意:该函数没有返回值,也不接受任何参数。
|
||||
*/
|
||||
void sht40_dinit(void)
|
||||
{
|
||||
GPIO_SET_ANALOG(SHT40_SDA_PORT, SHT40_SDA_PIN);
|
||||
GPIO_SET_ANALOG(SHT40_SCL_PORT, SHT40_SCL_PIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取温湿度传感器数据
|
||||
*
|
||||
* 从温湿度传感器读取温度和湿度数据,并将读取到的数据存储在传入的浮点数指针指向的位置。
|
||||
*
|
||||
* @param temperature 用于存储读取到的温度值的浮点数指针
|
||||
* @param humidity 用于存储读取到的湿度值的浮点数指针
|
||||
*/
|
||||
BOOL sht40_read(float32 *temperature, float32 *humidity)
|
||||
{
|
||||
uint8_t data[6];
|
||||
|
||||
osel_memset(data, 0, ARRAY_LEN(data));
|
||||
// 发送开始信号
|
||||
_sht40_i2c->interface.start(_sht40_i2c);
|
||||
// 发送写入地址命令
|
||||
_sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_I2C_ADDRESS << 1);
|
||||
// 等待写入地址命令响应
|
||||
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
// 发送测量命令
|
||||
_sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_MEASURE_CMD);
|
||||
// 等待测量命令响应
|
||||
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
// 停止I2C总线
|
||||
_sht40_i2c->interface.stop(_sht40_i2c);
|
||||
|
||||
_delay_us(10000); // 根据 SHT40 数据手册,等待至少 10ms
|
||||
|
||||
// 发送开始信号
|
||||
_sht40_i2c->interface.start(_sht40_i2c);
|
||||
// 发送写入地址命令
|
||||
_sht40_i2c->interface.write_byte(_sht40_i2c, (SHT40_I2C_ADDRESS << 1) | 1);
|
||||
// 等待写入地址命令响应
|
||||
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < ARRAY_LEN(data); i++)
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// 停止I2C总线
|
||||
_sht40_i2c->interface.stop(_sht40_i2c);
|
||||
|
||||
*temperature = 0;
|
||||
*humidity = 0;
|
||||
if (crc8(&data[0], 2) != data[2] || crc8(&data[3], 2) != data[5])
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*temperature = (float32)((uint16_t)data[0] << 8 | data[1]) * 175 / 65535 - 45;
|
||||
*humidity = (float32)((uint16_t)data[3] << 8 | data[4]) * 125 / 65535 - 6;
|
||||
if (*humidity > 100)
|
||||
{
|
||||
*humidity = 100;
|
||||
}
|
||||
if (*humidity < 0)
|
||||
{
|
||||
*humidity = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief crc8校验函数,多项式为 x^8 + x^5 + x^4 + 1
|
||||
* @param data 要校验的数据
|
||||
* @param len 要校验的数据的字节数
|
||||
* @retval 校验结果
|
||||
* @note 该校验适合SHT3温湿度传感器的数据校验
|
||||
*/
|
||||
static uint8_t crc8(uint8_t *data, uint8_t len)
|
||||
{
|
||||
const uint8_t polynomial = 0x31;
|
||||
uint8_t crc = 0xFF;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
crc ^= *data++;
|
||||
|
||||
for (j = 0; j < 8; ++j)
|
||||
{
|
||||
crc = (crc & 0x80) ? (crc << 1) ^ polynomial : (crc << 1);
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __SHT40_H
|
||||
#define __SHT40_H
|
||||
#include "main.h"
|
||||
|
||||
void sht40_init(TIM_TypeDef *timer_us); ///< 初始化 SHT40 传感器
|
||||
void sht40_dinit(void); ///< 反初始化 SHT40 传感器
|
||||
BOOL sht40_read(float32 *temperature, float32 *humidity); ///< 读取温湿度传感器数据
|
||||
|
||||
#endif ///< !__SHT40_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
#ifndef __SSD1306_OLED_H
|
||||
#define __SSD1306_OLED_H
|
||||
|
||||
#include "main.h"
|
||||
|
||||
// OLED引脚定义
|
||||
#define SSD1306_SDA_PORT OLED_SDA_GPIO_Port
|
||||
#define SSD1306_SDA_PIN OLED_SDA_Pin
|
||||
#define SSD1306_SCK_PORT OLDE_SCK_GPIO_Port
|
||||
#define SSD1306_SCK_PIN OLDE_SCK_Pin
|
||||
|
||||
// I2C地址
|
||||
#define SSD1306_I2C_ADDRESS 0x78
|
||||
// OLED显示参数
|
||||
#define SSD1306_WIDTH 128
|
||||
#define SSD1306_HEIGHT 64
|
||||
// OLED颜色
|
||||
#define SSD1306_WHITE 1
|
||||
#define SSD1306_BLACK 0
|
||||
|
||||
// OLED命令定义
|
||||
#define SSD1306_CMD_DISPLAY_OFF 0xAE
|
||||
#define SSD1306_CMD_DISPLAY_ON 0xAF
|
||||
#define SSD1306_CMD_SET_CONTRAST 0x81
|
||||
#define SSD1306_CMD_DISPLAY_ALL_ON_RESUME 0xA4
|
||||
#define SSD1306_CMD_DISPLAY_ALL_ON 0xA5
|
||||
#define SSD1306_CMD_NORMAL_DISPLAY 0xA6
|
||||
#define SSD1306_CMD_INVERT_DISPLAY 0xA7
|
||||
#define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3
|
||||
#define SSD1306_CMD_SET_COM_PINS 0xDA
|
||||
#define SSD1306_CMD_SET_VCOM_DETECT 0xDB
|
||||
#define SSD1306_CMD_SET_DISPLAY_CLOCK_DIV 0xD5
|
||||
#define SSD1306_CMD_SET_PRECHARGE 0xD9
|
||||
#define SSD1306_CMD_SET_MULTIPLEX 0xA8
|
||||
#define SSD1306_CMD_SET_LOW_COLUMN 0x00
|
||||
#define SSD1306_CMD_SET_HIGH_COLUMN 0x10
|
||||
#define SSD1306_CMD_SET_START_LINE 0x40
|
||||
#define SSD1306_CMD_MEMORY_MODE 0x20
|
||||
#define SSD1306_CMD_COLUMN_ADDR 0x21
|
||||
#define SSD1306_CMD_PAGE_ADDR 0x22
|
||||
#define SSD1306_CMD_COM_SCAN_INC 0xC0
|
||||
#define SSD1306_CMD_COM_SCAN_DEC 0xC8
|
||||
#define SSD1306_CMD_SEG_REMAP 0xA0
|
||||
#define SSD1306_CMD_CHARGE_PUMP 0x8D
|
||||
#define SSD1306_CMD_SET_DC_DC_ENABLE 0x14
|
||||
|
||||
#define SDA_OUT() \
|
||||
{ \
|
||||
GPIO_SET_OUTPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
|
||||
}
|
||||
|
||||
#define SDA_IN() \
|
||||
{ \
|
||||
GPIO_SET_INPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
|
||||
}
|
||||
|
||||
// 函数声明
|
||||
void ssd1306_init(void);
|
||||
void ssd1306_logo(void);
|
||||
void ssd1306_display_on(void);
|
||||
void ssd1306_display_off(void);
|
||||
void ssd1306_update_screen(void);
|
||||
|
||||
void ssd1306_fill(uint8_t color);
|
||||
void ssd1306_clear(void);
|
||||
void ssd1306_clear_buffer(void);
|
||||
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t *bmp);
|
||||
void ssd1306_f6x8_string(uint8_t x, uint8_t y, const uint8_t *ch);
|
||||
void ssd1306_f6x8_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num);
|
||||
void ssd1306_f6x8_string_number(uint8_t x, uint8_t y, const uint8_t *ch, uint8_t unit, float32 num);
|
||||
void ssd1306_f8x16_string(uint8_t x, uint8_t y, const uint8_t *ch);
|
||||
void ssd1306_f8x16_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num);
|
||||
|
||||
void ssd1306_draw_text_center(uint8_t y, const char *text);
|
||||
void ssd1306_draw_progress_bar(uint8_t progress);
|
||||
void ssd1306_fill_rect_angle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
void ssd1306_draw_rect_angle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
void ssd1306_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color);
|
||||
void ssd1306_draw_pixel(uint8_t x, uint8_t y, uint8_t color);
|
||||
#endif // __SSD1306_OLED_H
|
|
@ -0,0 +1,129 @@
|
|||
#include "tca9555.h"
|
||||
#include "i2cs.h"
|
||||
#define I2C_MASTER_SCL_PORT I2C1_SCL_GPIO_Port
|
||||
#define I2C_MASTER_SCL_PIN I2C1_SCL_Pin
|
||||
#define I2C_MASTER_SDA_PORT I2C1_SDA_GPIO_Port
|
||||
#define I2C_MASTER_SDA_PIN I2C1_SDA_Pin
|
||||
static i2c_t *tca9555_i2c;
|
||||
|
||||
void tca9555_init(void)
|
||||
{
|
||||
i2c_gpio_group_t gpios;
|
||||
gpios.scl = gpio_create(I2C_MASTER_SCL_PORT, I2C_MASTER_SCL_PIN);
|
||||
gpios.sda = gpio_create(I2C_MASTER_SDA_PORT, I2C_MASTER_SDA_PIN);
|
||||
|
||||
tca9555_i2c = i2c_create(gpios, 0);
|
||||
|
||||
tca9555_register reg;
|
||||
osel_memset((uint8_t *)®, 0, sizeof(tca9555_register));
|
||||
tca9555_write_config(®);
|
||||
|
||||
osel_memset((uint8_t *)®, 0, sizeof(tca9555_register));
|
||||
reg.port.p0.asint = 0;
|
||||
reg.port.p1.asint = 0;
|
||||
tca9555_write_output(®);
|
||||
}
|
||||
|
||||
void tca9555_configure_input(tca9555_register *reg, uint8_t port, uint8_t pin)
|
||||
{
|
||||
if (port == 0)
|
||||
{
|
||||
reg->port.p0.asint |= (1 << pin); // 设置对应的引脚为输入
|
||||
}
|
||||
else if (port == 1)
|
||||
{
|
||||
reg->port.p1.asint |= (1 << pin); // 设置对应的引脚为输入
|
||||
}
|
||||
tca9555_write_config(reg);
|
||||
}
|
||||
|
||||
uint8_t tca9555_read_single_register(tca9555_reg_t address)
|
||||
{
|
||||
uint8_t reg_data = 0; // 定义一个8位无符号字符型变量reg_data,用于存储读取到的寄存器值
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, address);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, READ_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
reg_data = tca9555_i2c->interface.read_byte(tca9555_i2c, FALSE);
|
||||
tca9555_i2c->interface.stop(tca9555_i2c);
|
||||
return reg_data;
|
||||
}
|
||||
|
||||
void tca9555_write_single_register(tca9555_reg_t address, uint8_t reg_val)
|
||||
{
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, address);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_val);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.stop(tca9555_i2c);
|
||||
}
|
||||
|
||||
void tca9555_read_struct(tca9555_register *reg, tca9555_reg_t reg_num)
|
||||
{
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, READ_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
|
||||
reg->port.p0.asint = tca9555_i2c->interface.read_byte(tca9555_i2c, TRUE);
|
||||
reg->port.p1.asint = tca9555_i2c->interface.read_byte(tca9555_i2c, FALSE);
|
||||
|
||||
tca9555_i2c->interface.stop(tca9555_i2c);
|
||||
}
|
||||
void tca9555_write_struct(tca9555_register *reg, tca9555_reg_t reg_num)
|
||||
{
|
||||
uint8_t reg_data[2];
|
||||
osel_memcpy(reg_data, (uint8_t *)reg, sizeof(tca9555_register));
|
||||
tca9555_i2c->interface.start(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_num);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_data[0]);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_data[1]);
|
||||
tca9555_i2c->interface.wait_ack(tca9555_i2c);
|
||||
tca9555_i2c->interface.stop(tca9555_i2c);
|
||||
}
|
||||
|
||||
void tca9555_write_output(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_OUTPUT_REG0);
|
||||
}
|
||||
void tca9555_write_polarity(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_POLARITY_REG0);
|
||||
}
|
||||
void tca9555_write_config(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_CONFIG_REG0);
|
||||
}
|
||||
|
||||
void tca9555_read_input(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_INPUT_REG0);
|
||||
}
|
||||
void tca9555_read_output(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_OUTPUT_REG0);
|
||||
}
|
||||
void tca9555_read_polarity(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_POLARITY_REG0);
|
||||
}
|
||||
void tca9555_read_config(tca9555_register *reg)
|
||||
{
|
||||
tca9555_write_struct(reg, TCA9555_CONFIG_REG0);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef __TCA9555_H__
|
||||
#define __TCA9555_H__
|
||||
#include "main.h"
|
||||
#include "lib.h"
|
||||
|
||||
#define TCA9555_ADDRESS 0x20 /*!< I2C Address */
|
||||
|
||||
/************************** I2C Registers *************************************/
|
||||
typedef enum
|
||||
{
|
||||
TCA9555_INPUT_REG0 = 0x00, /*!< 输入状态寄存器 */
|
||||
TCA9555_INPUT_REG1 = 0x01, /*!< 输入状态寄存器 */
|
||||
TCA9555_OUTPUT_REG0 = 0x02, /*!< 输出寄存器以更改输出状态的位。设置为1时,设置为高电平 */
|
||||
TCA9555_OUTPUT_REG1 = 0x03, /*!< 输出寄存器以更改输出状态的位。设置为1时,设置为高电平 */
|
||||
TCA9555_POLARITY_REG0 = 0x04, /*!< 极性反转寄存器。位'1'在寄存器0x00上反转输入极性 */
|
||||
TCA9555_POLARITY_REG1 = 0x05, /*!< 极性反转寄存器。位'1'在寄存器0x00上反转输入极性 */
|
||||
TCA9555_CONFIG_REG0 = 0x06, /*!< 配置寄存器。位'1'设置为输入,位'0'设置为输出 */
|
||||
TCA9555_CONFIG_REG1 = 0x07 /*!< 配置寄存器。位'1'设置为输入,位'0'设置为输出 */
|
||||
} tca9555_reg_t;
|
||||
|
||||
#define CONFIG_INPUT_VAL 0xFF
|
||||
#define CONFIG_OUTPUT_VAL 0x00
|
||||
|
||||
#define WRITE_ADDRESS ((TCA9555_ADDRESS << 1) | 0) /*!< I2C主设备写入 */
|
||||
#define READ_ADDRESS ((TCA9555_ADDRESS << 1) | 1) /*!< I2C主设备读取 */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C主设备检查从设备ACK */
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C主设备不检查从设备ACK */
|
||||
#define ACK_VAL 0x0 /*!< I2C从设备ACK值 */
|
||||
#define NACK_VAL 0x1 /*!< I2C从设备NACK值 */
|
||||
|
||||
struct tca9555_sbit
|
||||
{
|
||||
uint8_t b0 : 1;
|
||||
uint8_t b1 : 1;
|
||||
uint8_t b2 : 1;
|
||||
uint8_t b3 : 1;
|
||||
uint8_t b4 : 1;
|
||||
uint8_t b5 : 1;
|
||||
uint8_t b6 : 1;
|
||||
uint8_t b7 : 1;
|
||||
};
|
||||
|
||||
union tca9555_uinputport
|
||||
{
|
||||
uint8_t asint; /*!< port data as unsigned integer */
|
||||
struct tca9555_sbit bit; /*!< port data as separate bits */
|
||||
};
|
||||
|
||||
struct tca9555_sregister
|
||||
{
|
||||
union tca9555_uinputport p0;
|
||||
union tca9555_uinputport p1;
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint16_t asint; /*!< register data as unsigned integer */
|
||||
struct tca9555_sregister port; /*!< register data as separate ports */
|
||||
} tca9555_register;
|
||||
|
||||
void tca9555_init(void); // 初始化i2c总线
|
||||
void tca9555_configure_input(tca9555_register *reg, uint8_t port, uint8_t pin); // 配置输入
|
||||
uint8_t tca9555_read_single_register(tca9555_reg_t address); // 读取单个寄存器
|
||||
void tca9555_write_single_register(tca9555_reg_t address, uint8_t reg_val); // 写入单个寄存器
|
||||
|
||||
void tca9555_read_struct(tca9555_register *reg, tca9555_reg_t reg_num); // 读取结构体
|
||||
void tca9555_write_struct(tca9555_register *reg, tca9555_reg_t reg_num); // 写入结构体
|
||||
|
||||
void tca9555_write_output(tca9555_register *reg);
|
||||
void tca9555_write_polarity(tca9555_register *reg);
|
||||
void tca9555_write_config(tca9555_register *reg);
|
||||
|
||||
void tca9555_read_input(tca9555_register *reg);
|
||||
void tca9555_read_output(tca9555_register *reg);
|
||||
void tca9555_read_polarity(tca9555_register *reg);
|
||||
void tca9555_read_config(tca9555_register *reg);
|
||||
|
||||
#endif // __TCA9555_H__
|
|
@ -0,0 +1,368 @@
|
|||
#include "tmc2240.h"
|
||||
|
||||
tmc2240_t _tmc2240[TMC2240_MAX];
|
||||
|
||||
static void tmc2240_write(tmc2240_index_e index, uint8_t *data)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
|
||||
|
||||
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
|
||||
for (uint16_t i = 0; i < 5; i++)
|
||||
{
|
||||
tmc->spi->interface.u.normal.spi_send(tmc->spi, data[i]);
|
||||
}
|
||||
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
|
||||
}
|
||||
|
||||
static void tmc2240_read(tmc2240_index_e index, uint8_t *wdata, uint8_t *rdata)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
|
||||
|
||||
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
|
||||
for (uint16_t i = 0; i < 5; i++)
|
||||
{
|
||||
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
|
||||
}
|
||||
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
|
||||
|
||||
__NOP();
|
||||
__NOP();
|
||||
__NOP();
|
||||
|
||||
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
|
||||
for (uint16_t i = 0; i < 5; i++)
|
||||
{
|
||||
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
|
||||
}
|
||||
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
|
||||
}
|
||||
|
||||
static void tmc2240_reg_write(tmc2240_index_e index, uint8_t reg, uint32_t data)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
|
||||
|
||||
uint8_t wdata[5] = {0};
|
||||
wdata[0] = TMC2240_HIGHT_BIT | reg;
|
||||
wdata[1] = (data >> 24) & 0xFF;
|
||||
wdata[2] = (data >> 16) & 0xFF;
|
||||
wdata[3] = (data >> 8) & 0xFF;
|
||||
wdata[4] = data & 0xFF;
|
||||
tmc2240_write(index, wdata);
|
||||
}
|
||||
|
||||
static uint32_t tmc2240_reg_read(tmc2240_index_e index, uint8_t reg)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
|
||||
|
||||
uint8_t wdata[5] = {0};
|
||||
uint8_t rdata[5] = {0};
|
||||
wdata[0] = reg;
|
||||
tmc2240_read(index, wdata, rdata);
|
||||
return (rdata[1] << 24) | (rdata[2] << 16) | (rdata[3] << 8) | rdata[4];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 配置TMC2240步进电机驱动器
|
||||
*
|
||||
* 该函数用于配置TMC2240步进电机驱动器的各种参数,包括步进电机的工作模式、加减速曲线等。
|
||||
*
|
||||
* @param index TMC2240步进电机驱动器的索引,用于指定要配置的驱动器。
|
||||
*/
|
||||
static void tmc2240_config_write(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
tmc->config.gconf.data = 0x00000000;
|
||||
|
||||
tmc->config.chopconf.data = 0x00410153;
|
||||
tmc->config.chopconf.bits.mres = TMC2240_MRES_8;
|
||||
|
||||
tmc->config.drvconf.data = 0x00000021;
|
||||
tmc->config.global_scaler.data = 0x00000000;
|
||||
|
||||
tmc->config.ihold_irun.bits.ihold = 31;
|
||||
tmc->config.ihold_irun.bits.irun = 31;
|
||||
tmc->config.ihold_irun.bits.iholddelay = 0;
|
||||
tmc->config.ihold_irun.bits.irundelay = 0;
|
||||
|
||||
tmc->config.pwmconf.data = 0xC44C261E;
|
||||
tmc->config.gstat.data = 0x00000007;
|
||||
tmc2240_reg_write(index, TMC2240_GCONF, tmc->config.gconf.data);
|
||||
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
|
||||
tmc2240_reg_write(index, TMC2240_DRV_CONF, tmc->config.drvconf.data);
|
||||
tmc2240_reg_write(index, TMC2240_GLOBAL_SCALER, tmc->config.global_scaler.data);
|
||||
tmc2240_reg_write(index, TMC2240_IHOLD_IRUN, tmc->config.ihold_irun.data);
|
||||
tmc2240_reg_write(index, TMC2240_PWMCONF, tmc->config.pwmconf.data);
|
||||
tmc2240_reg_write(index, TMC2240_GSTAT, tmc->config.gstat.data);
|
||||
}
|
||||
|
||||
static void _tmc2240_motor_update(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
switch (tmc->config.chopconf.bits.mres)
|
||||
{
|
||||
case TMC2240_MRES_256:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 256;
|
||||
break;
|
||||
case TMC2240_MRES_128:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 128;
|
||||
break;
|
||||
case TMC2240_MRES_64:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 64;
|
||||
break;
|
||||
case TMC2240_MRES_32:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 32;
|
||||
break;
|
||||
case TMC2240_MRES_16:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 16;
|
||||
break;
|
||||
case TMC2240_MRES_8:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 8;
|
||||
break;
|
||||
case TMC2240_MRES_4:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 4;
|
||||
break;
|
||||
case TMC2240_MRES_2:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 2;
|
||||
break;
|
||||
case TMC2240_MRES_1:
|
||||
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tmc->motor.circle_pulse = 360 / tmc->motor.step_angle;
|
||||
}
|
||||
|
||||
static void _tmc2240_enable(tmc2240_index_e index, BOOL enable)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
BOOL state = tmc->en->read(*tmc->en) == 0 ? TRUE : FALSE;
|
||||
|
||||
if (state == enable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable == TRUE)
|
||||
{
|
||||
PWM_START(tmc->timer, tmc->time_ch);
|
||||
tmc->en->reset(*tmc->en);
|
||||
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
PWM_STOP(tmc->timer, tmc->time_ch);
|
||||
tmc->en->set(*tmc->en);
|
||||
chopconf_u chopconf;
|
||||
osel_memset((uint8_t *)&chopconf, 0, sizeof(chopconf_u));
|
||||
chopconf.bits.mres = TMC2240_MRES_1;
|
||||
tmc2240_reg_write(index, TMC2240_CHOPCONF, chopconf.data);
|
||||
}
|
||||
}
|
||||
|
||||
static void _tmc2240_direction(tmc2240_index_e index, tmc2240_direction_e dir)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
if (dir == TMC2240_FORWARD)
|
||||
{
|
||||
tmc->dir->reset(*tmc->dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmc->dir->set(*tmc->dir);
|
||||
}
|
||||
}
|
||||
|
||||
void tmc2240_init(tmc2240_index_e index, SPI_TypeDef *SPIx, TIM_TypeDef *timer, uint32_t time_ch, spi_gpio_group_t *gpios)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
osel_memset((uint8_t *)tmc, 0, sizeof(tmc2240_t));
|
||||
|
||||
tmc->timer = timer;
|
||||
tmc->time_ch = time_ch;
|
||||
tmc->spi = spi_create(SPI_TYPE_NORMAL, *gpios, 0);
|
||||
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
|
||||
tmc->spi->interface.hardware_enable(tmc->spi, SPIx);
|
||||
{
|
||||
tmc->default_tm.sysclk = SystemCoreClock / 1000;
|
||||
tmc->default_tm.psc = PWM_GET_PSC(tmc->timer);
|
||||
tmc->default_tm.arr = PWM_GET_ARR(tmc->timer);
|
||||
tmc->default_tm.freq = PWM_GET_FREQ(tmc->timer);
|
||||
}
|
||||
tmc->params.percent = TMC2240_PWM_DUTY_DEFAULT;
|
||||
tmc->params.arr = 0;
|
||||
tmc->params.freq = 0;
|
||||
tmc->params.enable = FALSE;
|
||||
tmc->params.direction = TMC2240_FORWARD;
|
||||
tmc2240_config_write(index);
|
||||
_tmc2240_motor_update(index);
|
||||
}
|
||||
|
||||
tmc2240_t *tmc2240_get(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
return &_tmc2240[index];
|
||||
}
|
||||
|
||||
void tmc2240_percent(tmc2240_index_e index, float32 percent)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
PWM_SET_DUTY(tmc->timer, tmc->time_ch, ABS(percent));
|
||||
}
|
||||
|
||||
void tmc2240_config_read(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
tmc->read_config.gconf.data = tmc2240_reg_read(index, TMC2240_GCONF);
|
||||
tmc->read_config.chopconf.data = tmc2240_reg_read(index, TMC2240_CHOPCONF);
|
||||
tmc->read_config.drvconf.data = tmc2240_reg_read(index, TMC2240_DRV_CONF);
|
||||
tmc->read_config.global_scaler.data = tmc2240_reg_read(index, TMC2240_GLOBAL_SCALER);
|
||||
tmc->read_config.ihold_irun.data = tmc2240_reg_read(index, TMC2240_IHOLD_IRUN);
|
||||
tmc->read_config.pwmconf.data = tmc2240_reg_read(index, TMC2240_PWMCONF);
|
||||
tmc->read_config.gstat.data = tmc2240_reg_read(index, TMC2240_GSTAT);
|
||||
tmc->data.tmc2240_adc_temp = tmc2240_reg_read(index, TMC2240_ADC_TEMP);
|
||||
tmc->data.tmc2240_temperature = (float32)(tmc->data.tmc2240_adc_temp - 2038) / 7.7;
|
||||
}
|
||||
|
||||
void tmc2240_test(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
_tmc2240_enable(index, tmc->params.enable);
|
||||
|
||||
if (tmc->params.enable == TRUE)
|
||||
{
|
||||
_tmc2240_direction(index, tmc->params.direction);
|
||||
|
||||
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
|
||||
{
|
||||
if (tmc->params.arr == 0)
|
||||
{
|
||||
tmc->params.arr = tmc->default_tm.arr;
|
||||
}
|
||||
PWM_SET_ARR(tmc->timer, tmc->params.arr);
|
||||
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
|
||||
}
|
||||
|
||||
tmc2240_percent(index, tmc->params.percent);
|
||||
|
||||
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
|
||||
{
|
||||
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
|
||||
_tmc2240_motor_update(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tmc2240_motor_set_angle(tmc2240_index_e index, int32_t angle)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
if (angle == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tmc->params.enable = FALSE;
|
||||
_tmc2240_enable(index, tmc->params.enable);
|
||||
tmc->motor.pulse_count = 0;
|
||||
|
||||
if (angle > 0)
|
||||
{
|
||||
tmc->params.direction = TMC2240_FORWARD;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmc->params.direction = TMC2240_BACKWARD;
|
||||
}
|
||||
|
||||
tmc->motor.pulse_count = ABS(angle) / tmc->motor.step_angle;
|
||||
tmc->motor.step_angle_count = 0;
|
||||
|
||||
tmc->params.enable = TRUE;
|
||||
|
||||
_tmc2240_direction(index, tmc->params.direction);
|
||||
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
|
||||
{
|
||||
if (tmc->params.arr == 0)
|
||||
{
|
||||
tmc->params.arr = tmc->default_tm.arr;
|
||||
}
|
||||
PWM_SET_ARR(tmc->timer, tmc->params.arr);
|
||||
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
|
||||
}
|
||||
|
||||
tmc2240_percent(index, tmc->params.percent);
|
||||
|
||||
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
|
||||
{
|
||||
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
|
||||
_tmc2240_motor_update(index);
|
||||
}
|
||||
_tmc2240_enable(index, tmc->params.enable);
|
||||
}
|
||||
|
||||
void tmc2240_motor_update(tmc2240_index_e index)
|
||||
{
|
||||
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
|
||||
tmc2240_t *tmc = &_tmc2240[index];
|
||||
DBG_ASSERT(tmc != NULL __DBG_LINE);
|
||||
|
||||
if (tmc->motor.pulse_count > 0)
|
||||
{
|
||||
tmc->motor.pulse_count--; // 脉冲数
|
||||
tmc->motor.step_angle_count++; // 步距个数
|
||||
if (tmc->params.direction == TMC2240_FORWARD)
|
||||
{
|
||||
tmc->motor.add_pulse_count++; /* 绝对位置++ */
|
||||
}
|
||||
else
|
||||
{
|
||||
tmc->motor.add_pulse_count--; /* 绝对位置-- */
|
||||
}
|
||||
}
|
||||
|
||||
/* 当脉冲数等于0的时候 代表需要发送的脉冲个数已完成,停止输出 */
|
||||
|
||||
if (tmc->motor.pulse_count <= 0)
|
||||
{
|
||||
tmc->params.enable = FALSE;
|
||||
_tmc2240_enable(index, tmc->params.enable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
/**
|
||||
* @file tmc2240.h
|
||||
* @author xushenghao
|
||||
* @brief TMC2240驱动头文件
|
||||
* @version 0.1
|
||||
* @note
|
||||
* 1. 芯片VM需要供电,否则SPI无法正常通信
|
||||
* 2. 42步进电机每步1.8度,1圈200步。1/8细分,1步=0.225度,电机转一周需要1600个脉冲
|
||||
*/
|
||||
|
||||
#ifndef __TMC2240_H
|
||||
#define __TMC2240_H
|
||||
#include "main.h"
|
||||
#include "spis.h"
|
||||
|
||||
#define MOTOR_42_STEP_ANGLE 1.8f // 42步进电机每步1.8度
|
||||
#define TMC2240_PWM_DUTY_DEFAULT 50 // PWM默认占空比
|
||||
|
||||
/*
|
||||
0x00 = 0x00002108 ;; writing GCONF @ address 0=0x00 with 0x00002108=8456=0.0
|
||||
0x03 = 0x00000000 ;; writing SLAVECONF @ address 1=0x03 with 0x00000000=0=0.0
|
||||
0x04 = 0x4001682C ;; writing IOIN @ address 2=0x04 with 0x4001682C=1073834028=0.0
|
||||
0x0A = 0x00000021 ;; writing DRV_CONF @ address 3=0x0A with 0x00000021=33=0.0
|
||||
0x0B = 0x00000000 ;; writing GLOBAL_SCALER @ address 4=0x0B with 0x00000000=0=0.0
|
||||
0x10 = 0x00001208 ;; writing IHOLD_IRUN @ address 5=0x10 with 0x00001208=4616=0.0
|
||||
0x11 = 0x00000000 ;; writing TPOWERDOWN @ address 6=0x11 with 0x00000000=0=0.0
|
||||
0x13 = 0x00000000 ;; writing TPWMTHRS @ address 7=0x13 with 0x00000000=0=0.0
|
||||
0x14 = 0x000003BE ;; writing TCOOLTHRS @ address 8=0x14 with 0x000003BE=958=0.0
|
||||
0x15 = 0x00000000 ;; writing THIGH @ address 9=0x15 with 0x00000000=0=0.0
|
||||
0x2D = 0x00000000 ;; writing DIRECT_MODE @ address 10=0x2D with 0x00000000=0=0.0
|
||||
0x38 = 0x00000000 ;; writing ENCMODE @ address 11=0x38 with 0x00000000=0=0.0
|
||||
0x39 = 0x00000000 ;; writing X_ENC @ address 12=0x39 with 0x00000000=0=0.0
|
||||
0x3A = 0x00010000 ;; writing ENC_CONST @ address 13=0x3A with 0x00010000=65536=0.0
|
||||
0x52 = 0x0B920F25 ;; writing OTW_OV_VTH @ address 14=0x52 with 0x0B920F25=194121509=0.0
|
||||
0x60 = 0xAAAAB554 ;; writing MSLUT[0] @ address 15=0x60 with 0xAAAAB554=0=0.0
|
||||
0x61 = 0x4A9554AA ;; writing MSLUT[1] @ address 16=0x61 with 0x4A9554AA=1251300522=0.0
|
||||
0x62 = 0x24492929 ;; writing MSLUT[2] @ address 17=0x62 with 0x24492929=608774441=0.0
|
||||
0x63 = 0x10104222 ;; writing MSLUT[3] @ address 18=0x63 with 0x10104222=269500962=0.0
|
||||
0x64 = 0xFBFFFFFF ;; writing MSLUT[4] @ address 19=0x64 with 0xFBFFFFFF=0=0.0
|
||||
0x65 = 0xB5BB777D ;; writing MSLUT[5] @ address 20=0x65 with 0xB5BB777D=0=0.0
|
||||
0x66 = 0x49295556 ;; writing MSLUT[6] @ address 21=0x66 with 0x49295556=1227445590=0.0
|
||||
0x67 = 0x00404222 ;; writing MSLUT[7] @ address 22=0x67 with 0x00404222=4211234=0.0
|
||||
0x68 = 0xFFFF8056 ;; writing MSLUTSEL @ address 23=0x68 with 0xFFFF8056=0=0.0
|
||||
0x69 = 0x00F70000 ;; writing MSLUTSTART @ address 24=0x69 with 0x00F70000=16187392=0.0
|
||||
0x6C = 0x00410153 ;; writing CHOPCONF @ address 25=0x6C with 0x00410153=4260179=0.0
|
||||
0x6D = 0x00040000 ;; writing COOLCONF @ address 26=0x6D with 0x00040000=262144=0.0
|
||||
0x70 = 0xC44C001E ;; writing PWMCONF @ address 27=0x70 with 0xC44C001E=0=0.0
|
||||
0x74 = 0x00000000 ;; writing SG4_THRS @ address 28=0x74 with 0x00000000=0=0.0
|
||||
*/
|
||||
|
||||
#define TMC2240_GCONF 0x00
|
||||
#define TMC2240_GSTAT 0x01
|
||||
#define TMC2240_IFCNT 0x02
|
||||
#define TMC2240_SLAVECONF 0x03
|
||||
#define TMC2240_IOIN 0x04
|
||||
#define TMC2240_DRV_CONF 0x0A
|
||||
#define TMC2240_GLOBAL_SCALER 0x0B
|
||||
|
||||
#define TMC2240_IHOLD_IRUN 0x10
|
||||
#define TMC2240_TPOWERDOWN 0x11
|
||||
#define TMC2240_TSTEP 0x12
|
||||
#define TMC2240_TPWMTHRS 0x13
|
||||
#define TMC2240_TCOOLTHRS 0x14
|
||||
#define TMC2240_THIGH 0x15
|
||||
|
||||
#define TMC2240_DIRECT_MODE 0x2D
|
||||
|
||||
#define TMC2240_ENCMODE 0x38
|
||||
#define TMC2240_XENC 0x39
|
||||
#define TMC2240_ENC_CONST 0x3A
|
||||
#define TMC2240_ENC_STATUS 0x3B
|
||||
#define TMC2240_ENC_LATCH 0x3C
|
||||
|
||||
#define TMC2240_ADC_VSUPPLY_AIN 0x50
|
||||
#define TMC2240_ADC_TEMP 0x51
|
||||
#define TMC2240_OTW_OV_VTH 0x52
|
||||
|
||||
#define TMC2240_MSLUT0 0x60
|
||||
#define TMC2240_MSLUT1 0x61
|
||||
#define TMC2240_MSLUT2 0x62
|
||||
#define TMC2240_MSLUT3 0x63
|
||||
#define TMC2240_MSLUT4 0x64
|
||||
#define TMC2240_MSLUT5 0x65
|
||||
#define TMC2240_MSLUT6 0x66
|
||||
#define TMC2240_MSLUT7 0x67
|
||||
#define TMC2240_MSLUTSEL 0x68
|
||||
#define TMC2240_MSLUTSTART 0x69
|
||||
#define TMC2240_MSCNT 0x6A
|
||||
#define TMC2240_MSCURACT 0x6B
|
||||
#define TMC2240_CHOPCONF 0x6C
|
||||
#define TMC2240_COOLCONF 0x6D
|
||||
#define TMC2240_DCCTRL 0x6E
|
||||
#define TMC2240_DRVSTATUS 0x6F
|
||||
|
||||
#define TMC2240_PWMCONF 0x70
|
||||
#define TMC2240_PWMSCALE 0x71
|
||||
#define TMC2240_PWM_AUTO 0x72
|
||||
#define TMC2240_SG4_THRS 0x74
|
||||
#define TMC2240_SG4_RESULT 0x75
|
||||
#define TMC2240_SG4_IND 0x76
|
||||
|
||||
#define TMC2240_HIGHT_BIT 0x80
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMC2240_1,
|
||||
TMC2240_MAX,
|
||||
} tmc2240_index_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMC2240_FORWARD, // 正转
|
||||
TMC2240_BACKWARD, // 反转
|
||||
} tmc2240_direction_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TMC2240_MRES_256,
|
||||
TMC2240_MRES_128,
|
||||
TMC2240_MRES_64,
|
||||
TMC2240_MRES_32,
|
||||
TMC2240_MRES_16,
|
||||
TMC2240_MRES_8,
|
||||
TMC2240_MRES_4,
|
||||
TMC2240_MRES_2,
|
||||
TMC2240_MRES_1, // FULL STEP
|
||||
} tmc2240_mres_e;
|
||||
|
||||
// 0x00 GCONF
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
|
||||
uint32_t reserved1 : 1;
|
||||
/**
|
||||
* 停止之前的步骤执行超时检测。
|
||||
* 0x0:正常时间:2^20个时钟
|
||||
* 0x1:短时间:2^18个时钟
|
||||
*/
|
||||
uint32_t fast_standstill : 1;
|
||||
/**
|
||||
* 启用StealthChop2模式。
|
||||
* 0x0:无StealthChop2
|
||||
* 0x1:StealthChop2电压PWM模式使能(取决于速度阈值)。从关闭状态切换
|
||||
在静止状态下和在lHOLD = 时为开状态 仅限额定电流。
|
||||
*/
|
||||
uint32_t en_pwm_mode : 1;
|
||||
/**
|
||||
* 启用StealthChop2的步进输入筛选
|
||||
* 0x0:无StealthChop2
|
||||
* 0x1:StealthChop2电压PWM模式使能
|
||||
(取决于速度阈值)。从关闭状态切换
|
||||
在静止状态下和在lHOLD=时为开状态
|
||||
仅限额定电流。
|
||||
*/
|
||||
uint32_t multistep_filt : 1;
|
||||
/**
|
||||
* 更改电机方向/方向标志
|
||||
* 0x0:默认电机方向
|
||||
* 0x1:电机方向相反
|
||||
*/
|
||||
uint32_t shaft : 1;
|
||||
uint32_t diag0_error : 1;
|
||||
uint32_t diag0_otpw : 1;
|
||||
uint32_t diag0_stall : 1;
|
||||
uint32_t diag1_stall : 1;
|
||||
uint32_t diag1_index : 1;
|
||||
uint32_t diag1_onstate : 1;
|
||||
uint32_t reserved2 : 1;
|
||||
uint32_t diag0_pushpull : 1;
|
||||
uint32_t diag1_pushpull : 1;
|
||||
uint32_t small_hysteresis : 1;
|
||||
/**
|
||||
* 电机硬停止功能启用。
|
||||
* 0x0:正常运行
|
||||
* 0x1:紧急停止:ENCA停止定序器
|
||||
当绑得很高时(不执行任何步骤
|
||||
定序器、电机进入停顿状态)。
|
||||
*/
|
||||
uint32_t stop_enable : 1;
|
||||
/**
|
||||
* 通过以下方式启用直接motpr相电流控制
|
||||
* 0x0:正常运行
|
||||
* 0x1:电机线圈电流和极性直接
|
||||
通过串口编程:寄存器
|
||||
直接模式(0x2D)指定带符号线圈A
|
||||
电流(位8..0)和线圈B电流(位24..16)。在……里面
|
||||
在此模式下,电流按lHOLD设置进行定标。
|
||||
基于速度的StealthChop2电流调节
|
||||
在此模式下不可用。自动的
|
||||
StealthChop2电流调节仅适用于
|
||||
步进电机速度低。
|
||||
*/
|
||||
uint32_t direct_mode : 1;
|
||||
} bits;
|
||||
} gconf_u;
|
||||
|
||||
// 0x01 GSTAT
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t reset : 1;
|
||||
uint32_t drv_err : 1;
|
||||
uint32_t uv_cp : 1;
|
||||
uint32_t register_reset : 1;
|
||||
uint32_t vm_uvlo : 1;
|
||||
} bits;
|
||||
} gstat_u;
|
||||
|
||||
// 0x0A DRVCONF
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t current_range : 2; // 0-1
|
||||
uint32_t reserved1 : 2; // 2-3
|
||||
uint32_t slope_control : 2; // 4-5
|
||||
} bits;
|
||||
} drvconf_u;
|
||||
|
||||
// 0x0B GLOBAL_SCALER
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t global_scale : 8; // 0-7
|
||||
} bits;
|
||||
} global_scaler_u;
|
||||
|
||||
// 0x10 IHOLD_IRUN
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t ihold : 5; // 0-4
|
||||
uint32_t reserved1 : 3; // 5-7
|
||||
uint32_t irun : 5; // 8-12
|
||||
uint32_t reserved2 : 3; // 13-15
|
||||
uint32_t iholddelay : 4; // 16-19
|
||||
uint32_t reserved3 : 4; // 20-23
|
||||
uint32_t irundelay : 4; // 24-27
|
||||
} bits;
|
||||
} ihold_irun_u;
|
||||
|
||||
// 0x6C CHOPCONF
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
uint32_t toff : 4; // 0-3
|
||||
uint32_t hstrt : 3; // 4-6
|
||||
uint32_t hend : 4; // 7-10
|
||||
uint32_t fd3 : 1; // 11
|
||||
uint32_t disfdcc : 1; // 12
|
||||
uint32_t reserved1 : 1;
|
||||
uint32_t chm : 1; // 14
|
||||
uint32_t tbl : 2; // 15-16
|
||||
uint32_t reserved2 : 1;
|
||||
uint32_t vhighfs : 1; // 18
|
||||
uint32_t vhighchm : 1; // 19
|
||||
uint32_t tpfd : 4; // 20-23
|
||||
uint32_t mres : 4; // 24-27
|
||||
uint32_t intpol : 1; // 28
|
||||
uint32_t dedge : 1; // 29
|
||||
uint32_t diss2g : 1; // 30
|
||||
uint32_t diss2vs : 1; // 31
|
||||
} bits;
|
||||
} chopconf_u;
|
||||
|
||||
// 0x70 PWMCONF
|
||||
typedef union
|
||||
{
|
||||
uint32_t data;
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* 用户定义的 PWM 幅度偏移(0-255)与静止状态下的全电机电流(CS_ACTUAL=31)相关。 (重置默认值=30) 使用 PWM_OFS 作为自动缩放的初始值,
|
||||
* 以加快自动调谐过程。为此,请将 PWM_OFS 设置为确定的、特定于应用的值,并将 pwm_autoscale 设置为 0。之后,将 pwm_autoscale 设置为 1。
|
||||
* 完成后启用 StealthChop2。 PWM_OFS = 0 将禁用将电机电流缩放到低于电机特定的较低测量阈值。此设置应仅在某些条件下使用,
|
||||
* 例如当电源电压可以上下变化两倍或更多时。它可以防止电机超出调节范围,但也会防止电流降到调节限制以下。 PWM_OFS > 0 允许自动缩放到低 PWM 占空比,
|
||||
* 甚至低于较低的调节阈值。这允许基于实际(保持)电流比例(寄存器 IHOLD_IRUN)的低(静止)电流设置。
|
||||
*/
|
||||
uint32_t pwm_ofs : 8;
|
||||
/**
|
||||
* PWM 幅度的速度依赖梯度: PWM_GRAD x 256 / TSTEP 此值加到 PWM_OFS 以补偿速度依赖的电机反电动势。 使用 PWM_GRAD 作为自动缩放的初始值,
|
||||
* 以加快自动调谐过程。为此,请将 PWM_GRAD 设置为确定的、特定于应用的值,并将 pwm_autoscale 设置为 0。之后,将 pwm_autoscale 设置为 1。
|
||||
* 完成后启用 StealthChop2。 提示: 初始调谐后,可以从 PWM_GRAD_AUTO 中读取所需的初始值。
|
||||
*/
|
||||
uint32_t pwm_grad : 8;
|
||||
uint32_t pwm_freq : 2;
|
||||
uint32_t pwm_autoscale : 1;
|
||||
uint32_t pwm_autograd : 1;
|
||||
} bits;
|
||||
} pwmconf_u;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gconf_u gconf; // 0x00 GCONF
|
||||
gstat_u gstat; // 0x01 GSTAT
|
||||
drvconf_u drvconf; // 0x0A DRVCONF
|
||||
global_scaler_u global_scaler; // 0x0B GLOBAL_SCALER
|
||||
ihold_irun_u ihold_irun; // 0x10 IHOLD_IRUN
|
||||
chopconf_u chopconf; // 0x6C CHOPCONF
|
||||
pwmconf_u pwmconf; // 0x70 PWMCONF
|
||||
} tmc2240_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gpio_t *en; ///< EN_PIN
|
||||
gpio_t *dir; ///< DIR_PIN
|
||||
TIM_TypeDef *timer;
|
||||
uint32_t time_ch;
|
||||
spi_t *spi;
|
||||
|
||||
tmc2240_config_t config;
|
||||
tmc2240_config_t read_config;
|
||||
|
||||
uint32_t step;
|
||||
__IO uint32_t step_count;
|
||||
|
||||
// PRIVATE
|
||||
struct
|
||||
{
|
||||
uint32_t sysclk; // 系统时钟
|
||||
uint32_t psc; // 预分频系数
|
||||
uint16_t arr; // 自动重装值 auto reload value
|
||||
uint32_t freq; // 频率
|
||||
} default_tm;
|
||||
struct
|
||||
{
|
||||
BOOL enable; // 使能
|
||||
tmc2240_direction_e direction; // 方向
|
||||
float32 percent; // 占空比
|
||||
uint16_t arr; // 自动重装值(改变速度)
|
||||
uint32_t freq; // 频率
|
||||
} params;
|
||||
|
||||
struct
|
||||
{
|
||||
float32 step_angle; // 步进角度
|
||||
uint16_t circle_pulse; // 一圈脉冲数
|
||||
|
||||
__IO int32_t add_pulse_count; /* 脉冲个数累计 */
|
||||
__IO uint32_t pulse_count; /* 脉冲个数记录 */
|
||||
__IO uint32_t step_angle_count; /* 步距个数 */
|
||||
} motor;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t tmc2240_adc_temp; // 温度ADC值
|
||||
float32 tmc2240_temperature; // 温度
|
||||
} data;
|
||||
|
||||
} tmc2240_t;
|
||||
|
||||
void tmc2240_init(tmc2240_index_e index, SPI_TypeDef *SPIx, TIM_TypeDef *timer, uint32_t time_ch, spi_gpio_group_t *gpios);
|
||||
tmc2240_t *tmc2240_get(tmc2240_index_e index);
|
||||
|
||||
void tmc2240_motor_set_angle(tmc2240_index_e index, int32_t angle);
|
||||
void tmc2240_motor_update(tmc2240_index_e index);
|
||||
|
||||
void tmc2240_test(tmc2240_index_e index);
|
||||
void tmc2240_config_read(tmc2240_index_e index);
|
||||
#endif // __TMC2240_H
|
Loading…
Reference in New Issue