/* ============================================================================= * ist8310.c - C 板板载磁力计 IST8310 —— 硬件 I2C3 版 * 总线: I2C3(PA8=SCL, PC9=SDA, CubeMX 已配置 100kHz 标准模式), * 替代 legacy 的软件模拟 I2C 与早期移植版的 bsp_i2c_soft * 初始化: 必须先把 RSTN(PG6) 拉高再检测——CubeMX 默认输出低电平会把芯片 * 按在复位态,WHO_AM_I(0x10) 永远读不到(绿灯慢闪的根因); * 之后配置 CNTL1(连续 200Hz)/CNTL2(DRDY 下降沿)/AVGCNTL(4 次平均) * 数据: ist8310_poll() 每 5ms 阻塞读一次 6 字节(约 0.7ms@100kHz), * 由 IMU_Task 调用;DRDY(EXTI3) 不再使用(数据仅做健康监测与 * 9 轴扩展预留,无需中断实时性) * 报警: 检测失败/连续读失败 -> 绿灯慢闪(见 monitor_task) * ========================================================================== */ #include "ist8310.h" #include "i2c.h" #include "main.h" #include "led.h" #define IST8310_ADDR (0x0E << 1) // 7 位地址 0x0E,HAL 使用 8 位格式 #define IST8310_WHO_AM_I 0x00 #define IST8310_CNTL1 0x0A #define IST8310_CNTL2 0x0B #define IST8310_AVGCNTL 0x41 #define IST8310_PDCNTL 0x42 #define IST8310_DATA_START 0x03 #define IST8310_WHO_AM_I_VALUE 0x10 #define IST8310_POLL_PERIOD_MS 5 // 200Hz 读取节奏 float ist8310_magnetic_field[3]; float ist8310_temperature; uint8_t ist8310_online = 0; uint8_t ist8310_last_who = 0; static uint8_t raw_buf[6]; static uint8_t read_error_count = 0; // 连续读失败计数(运行中总线异常监测) /* RSTN(PG6):低电平复位芯片,每次改变需等待生效 */ static void ist8310_rstn(uint8_t level) { HAL_GPIO_WritePin(RSTN_IST8310_GPIO_Port, RSTN_IST8310_Pin, level ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_Delay(1); } static uint8_t ist8310_read_who(void) { uint8_t who = 0; if (HAL_I2C_Mem_Read(&hi2c3, IST8310_ADDR, IST8310_WHO_AM_I, I2C_MEMADD_SIZE_8BIT, &who, 1, 10) != HAL_OK) return 0; return who; } void ist8310_init(void) { /* 关键:先释放 RSTN(CubeMX 默认输出低电平会把芯片按在复位态, * WHO_AM_I 将永远读不到) */ HAL_GPIO_WritePin(RSTN_IST8310_GPIO_Port, RSTN_IST8310_Pin, GPIO_PIN_SET); HAL_Delay(2); /* 有界重试:最多 40 次(约 1s),失败则放弃并保持系统可运行 */ for (uint8_t retry = 0; retry < 40; retry++) { ist8310_last_who = ist8310_read_who(); if (ist8310_last_who == IST8310_WHO_AM_I_VALUE) { ist8310_online = 1; HAL_I2C_Mem_Write(&hi2c3, IST8310_ADDR, IST8310_CNTL1, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0x03}, 1, 10); // 连续模式 200Hz HAL_I2C_Mem_Write(&hi2c3, IST8310_ADDR, IST8310_CNTL2, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0x08}, 1, 10); // DRDY 下降沿 HAL_I2C_Mem_Write(&hi2c3, IST8310_ADDR, IST8310_AVGCNTL, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0x12}, 1, 10); // 4 次采样平均 HAL_I2C_Mem_Write(&hi2c3, IST8310_ADDR, IST8310_PDCNTL, I2C_MEMADD_SIZE_8BIT, (uint8_t[]){0xC0}, 1, 10); // 正常脉冲时长 ist8310_rstn(0); ist8310_rstn(1); return; } /* IST8310 连接异常报警:绿灯 1s 周期闪烁(经 TIM5 PWM, * 引脚复用模式下直接写 GPIO 寄存器无效) */ static uint8_t counter = 0; counter++; if (counter == 1) led_set_green(1); else if (counter == 5) led_set_green(0); else if (counter == 40) counter = 0; HAL_Delay(25); } } void ist8310_poll(void) { static uint32_t last_poll_tick = 0; uint32_t now = HAL_GetTick(); if (now - last_poll_tick < IST8310_POLL_PERIOD_MS) return; last_poll_tick = now; if (!ist8310_online) return; if (HAL_I2C_Mem_Read(&hi2c3, IST8310_ADDR, IST8310_DATA_START, I2C_MEMADD_SIZE_8BIT, raw_buf, 6, 2) != HAL_OK) { /* 连续 100 次(约 0.5s)失败判定离线,交由监控任务绿灯报警 */ if (++read_error_count > 100) ist8310_online = 0; return; } read_error_count = 0; int16_t raw_x = (int16_t)(((uint16_t)raw_buf[1] << 8) | raw_buf[0]); int16_t raw_y = (int16_t)(((uint16_t)raw_buf[3] << 8) | raw_buf[2]); int16_t raw_z = (int16_t)(((uint16_t)raw_buf[5] << 8) | raw_buf[4]); ist8310_magnetic_field[0] = raw_x * 0.3f; ist8310_magnetic_field[1] = raw_y * 0.3f; ist8310_magnetic_field[2] = raw_z * 0.3f; }