小错误引发大问题 clr_bit的使用

clear_bit(PO2,0x01<<3);  由于0x01<<3没有加括弧,导致位操作影响到其他io口。

#ifndef _SMARTLINK_TYPEDEF_H_ #define _SMARTLINK_TYPEDEF_H_ #endif #include "lib/tppacket.h" //#define DBG_MAJOR(fmt, args...) do{printf("[DBG_MAJOR=====] func %s,line %d: "fmt"\n",__FUNCTION__,__LINE__,##args);}while(0); //#define DBG_ERR(fmt, args...) do{printf("[DBG_ERR=====] func %s,line %d: "fmt"\n",__FUNCTION__,__LINE__,##args);}while(0); //#define DBG(fmt, args...) do{printf("[DBG=====] func %s,line %d: "fmt"\n",__FUNCTION__,__LINE__,##args);}while(0); #define DBG_MAJOR #define DBG_ERR #define DBG #define SMARTLINK_UP_IDX_RANGE (8 + 96) #define PAL_MQ_WAIT_FOREVER (-1) #define TPIMI_REGISTER_COMMAND(funcName) imi_function_register(IMI_TYPE_SMARTLINK, #funcName, (funcName)) #define PFM_IF_FAIL_RET_VAL(expression, ret) \ do{\ if ( OK != expression ){\ return ret;\ }\ }while(0) #define PFM_IF_FAIL_RET(expression) \ do{\ int __rv;\ __rv = (expression);\ if ( OK != __rv ){\ return __rv;\ }\ }while(0) #define PFM_ENSURE_RET_VOID(exp) \ do{\ if (!(exp)){\ DBG_ERR("Ensure %s failed.", #exp);\ return;\ }\ }while(0) /* goto done */ #define PFM_IF_FAIL_DONE(ret, expression) \ do{\ ret = (expression);\ if ( OK != ret ){\ DBG_ERR("E - %d call %s failed.",ret,#expression);\ goto done;\ }\ }while(0) #define FLUSH_TYPE_SEND 0x01 #define FLUSH_TYPE_RSP 0x02 #define MAC_LENGTH 6 #define PORT_LENGTH 2 #define FLASH_TABLE_LENGTH 512 #define MAX_SMARTLINK_GROUP 8 #define PORT_SLAVE 0 #define PORT_MASTER (1) #define NODE_ID_LEN (6) #define SMARTLINK_MAX_PKT_LEN (64) //目前只需要64字节即可,后续如果有改动则再另外加 #define MAX_PORT_PER_RING (2) #define MAX_SMARTLINK_RING (getSmartlinkRingMaxNum()) //ringId从1 开始 #define SMARTLINK_RING_RUNNING_LIMIT (32) // 最多同时运行32个环 #define SMARTLINK_STACK_SIZE (4*8192) #define SMARTLINK_QUEUE_SIZE (256) #define SMARTLINK_MAX_INSTANCE (getMstpInstanceMaxNum()) #define FAILED (1) #define NON_FAILED (0) #define NO_ACTION #define G_P groupId,port #define SMARTLINK_PKT_FS (1<<0) #define SMARTLINK_PKT_EVT (1<<1) #define SMARTLINK_PKT_SF (1<<2) #define SMARTLINK_PKT_MS (1<<3) #define SMARTLINK_PKT_NR (1<<4) #define SMARTLINK_PKT_RB (1<<5) #define SMARTLINK_PKT_DNF (1<<6) //dnf #define SMARTLINK_PKT_BPR (1<<7) //用于说明端口是否为右端口 #define SMARTLINK_BRP_OFFSET (7) #define SMARTLINK_MAX_UTF8_LEN (3) #define SMARTLINK_DES_LEN (16* SMARTLINK_MAX_UTF8_LEN) #define SMARTLINK_DEFAULT_VER (1) #define SMARTLINK_DEFAULT_HOLD (0) #define SMARTLINK_DEFAULT_WTB (7) #define SMARTLINK_DEFAULT_WTR (5) #define SMARTLINK_DEFAULT_GUARD (200) #define SMARTLINK_DEFAULT_MEL (7) #define SMARTLINK_DEFAULT_GUARD_TIME (200) #define SMARTLINK_MAX_GUARD_TIME (200) #define SMARTLINK_MIN_GUARD_TIME (1) #define SMARTLINK_DEFAULT_HOLD_TIME (0) #define SMARTLINK_MAX_HOLD_TIME (100) #define SMARTLINK_MIN_HOLD_TIME (0) #define SMARTLINK_DEFAULT_WTR_TIME (5) #define SMARTLINK_MAX_WTR_TIME (12) #define SMARTLINK_MIN_WTR_TIME (1) #define SMARTLINK_DEFAULT_TC_INTERVAL (2) #define SMARTLINK_MAX_TC_INTERVAL (600) #define SMARTLINK_MIN_TC_INTERVAL (1) #define SMARTLINK_DEFAULT_TC_THRESHOLD (3) #define SMARTLINK_MAX_TC_THRESHOLD (255) #define SMARTLINK_MIN_TC_THRESHOLD (1) #define SMARTLINK_DEFAULT_VC (0) #define RING_ID_VALID(id) (id >= 1 || id <= MAX_SMARTLINK_RING) #define SMARTLINK_ID_ITER(id) for (id = 1; id <= MAX_SMARTLINK_RING; id++) #define SMARTLINK_MAX_ID_LEN (256/8) #define SMARTLINK_ID_BIT_HIT(b, d) do{d[((b) / 8)] |= (1<<((b)%8));}while(0) #define SMARTLINK_ID_BIT_CLR(b, d) do{d[((b) / 8)] &= ~(1<<((b)%8));}while(0) #define SMARTLINK_ID_BIT_HAS_ID(b, d) ((d[b/8] & (1<<(b%8))) != 0) #define SMARTLINK_ID_BIT_ITEM(id, d) \ SMARTLINK_ID_ITER(id)\ if(SMARTLINK_ID_BIT_HAS_ID(id, d)) #ifndef SMARTLINK_TRAP_PROTECT #define SMARTLINK_TRAP_PROTECT #endif // smlk状态机状态数据结构 typedef enum { SMARTLINK_DEFAULT, SMARTLINK_UNINIT, SMARTLINK_SLAVE, SMARTLINK_DOWN, SMARTLINK_BACK_TIME, SMARTLINK_MAX_STATUS }SMARTLINK_STATUS; // msg类型 typedef enum { SMARTLINK_MSG_PACKET, SMARTLINK_STATE_DEFAULT, SMARTLINK_MASTER_PORT_UP, SMARTLINK_SLAVE_PORT_UP, SMARTLINK_MASTER_PORT_DOWN, SMARTLINK_SLAVE_PORT_DOWN, SMARTLINK_FAIL_BACK, SMARTLINK_MSG_END }SMARTLINK_MSG_TYPE; /* Smart Link组配置数据结构 */ typedef struct uc_smartlink_t { int groupId; // 组号 int enabled; // 是否启用此实例 int instanceId; // [KEY] 实例ID (1~10) int masterPort; // 主端口编号(如10表示GE1/0/10) int slavePort; // 备用端口编号 int failBack; // 抢占模式:0-关闭,1-开启 int failBackTime; // 抢占延迟时间(秒),典型值为30 int ctrlVlan; // 控制VLAN }SMARTLINK_CFG_T; typedef struct uc_smart_link_Glb_t { int enable; int flush_send; int flush_receive; int rcv_vlan[MAX_SMARTLINK_GROUP+1];/* 初始或空vlan为 -1*/ }SMARTLINK_Glb_CFG_T; // typedef struct erps_msg // { // SMARTLINK_MSG_TYPE type; // TP_PACKET_T packet; // int groupId; // int port; // user_port up; // }SMARTLINK_MSG; typedef struct smart_link_srvc_msg_s { SMARTLINK_MSG_TYPE type; // TP_PACKET_T packet; SMARTLINK_CFG_T cfg; }SMARTLINK_SRVC_MSG_T; // smlk线程间消息队列数据结构 typedef struct smartLink_msg { SMARTLINK_MSG_TYPE type; TP_PACKET_T packet; SMARTLINK_CFG_T cfg; user_port up; }SMARTLINK_MSG; typedef enum { SMARTLINK_GROUP_NONE, SMARTLINK_GROUP_MASTER, SMARTLINK_GROUP_SLAVE, }SMARTLINK_ROLE; typedef struct smartlink_packet_data { UINT8 destMAC[MAC_LENGTH]; UINT8 srcMAC[MAC_LENGTH]; UINT8 ctrlType; UINT8 ctrlVersion; UINT8 SWID[MAC_LENGTH]; UINT16 ctrlVlan; UINT8 authMode; UINT8 passWord[16]; char map[FLASH_TABLE_LENGTH]; UINT8 FCS[4]; }SMARTLINK_PACKET_DATA; typedef struct rtd_smart_link_t { /* groupid == -1 表示为创建group */ int groupid; SMARTLINK_STATUS status; SMARTLINK_CFG_T cfg; }RTD_SMARTLINK_T; typedef struct smartLink_flush_table { char table[FLASH_TABLE_LENGTH]; }SMARTLINK_MAC_PORT;
最新发布
10-14
#ifndef _SOFT_I2C_H #define _SOFT_I2C_H #ifdef __cplusplus extern "C" { #endif #include "stm32g0xx_hal.h" #define SW_SLAVE_ADDR 0x48 #define SW_SLAVE_SCL_CLK_EN() __HAL_RCC_GPIOB_CLK_ENABLE() #define SW_SLAVE_SDA_CLK_EN() __HAL_RCC_GPIOB_CLK_ENABLE() #define SW_SLAVE_SCL_PRT GPIOB #define SW_SLAVE_SCL_PIN GPIO_PIN_6 #define SW_SLAVE_SDA_PRT GPIOB #define SW_SLAVE_SDA_PIN GPIO_PIN_7 #define GPIO_MODE_MSK 0x00000003U #define I2C_STA_IDLE 0 #define I2C_STA_START 1 #define I2C_STA_DATA 2 #define I2C_STA_ACK 3 #define I2C_STA_NACK 4 #define I2C_STA_STOP 5 #define I2C_READ 1 #define I2C_WRITE 0 #define FRAME_HEADER1 0x01 #define FRAME_HEADER2 0xAA #define HOST_FRAME_LEN 5 // 主机发送帧长度:地址+01+AA+功能码+校验和(地址单独处理,不参与校验) #define SLAVE_FRAME_LEN 12 // 从机响应帧长度:01+AA+功能码+8字节数据+校验和 #define I2C_SDA_Pinx 7 #define BUFFER_SIZE 256 // 缓冲区小定义 #define MAX_RX_INDEX 255 // 最接收索引(BUFFER_SIZE - 1) #define I2C_TIMEOUT_MS 500 // I2C超时时间 typedef struct _SwSlaveI2C_t { uint8_t State; // I2C通信状态 uint8_t Rw; // I2C读写标志:0-写,1-读 uint8_t SclFallCnt; // SCL下降沿计数 uint8_t Flag; // I2C状态标志,BIT0:0-地址无效,1-地址匹配 uint32_t StartMs; // I2C通信起始时间,单位ms,用于判断通信是否超时 uint8_t* RxBuf; // 指向接收缓冲区的指针 uint8_t* TxBuf; // 指向发送缓冲区的指针 uint8_t RxIdx; // 接收缓冲区数据写入索引 uint8_t TxIdx; // 发送缓冲区数据读取索引 uint8_t HostFuncCode; // 存储主机发送的功能码 uint8_t FrameReceived; // 主机帧接收完成标志 uint8_t IgnoreData; // 忽略后续数据标志 }SwSlaveI2C_t; extern SwSlaveI2C_t SwSlaveI2C; void InitSwSlaveI2C(void); void I2cGpioIsr(void); void CheckSwSlaveI2cTimeout(void); void I2C_Slave_Set_SDA_IT(void); void I2C_Slave_Set_SDA_Out(void); void CheckSwSlaveI2cTimeout(void); /* 使用HAL函数操作GPIO */ #define SET_SCL_PIN() HAL_GPIO_WritePin(SW_SLAVE_SCL_PRT, SW_SLAVE_SCL_PIN, GPIO_PIN_SET) #define CLR_SDA_PIN() HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, GPIO_PIN_RESET) #define SET_SDA_PIN() HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, GPIO_PIN_SET) #define READ_SDA_PIN() HAL_GPIO_ReadPin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN) #define READ_SCL_PIN() HAL_GPIO_ReadPin(SW_SLAVE_SCL_PRT, SW_SLAVE_SCL_PIN) // 函数原型声明 void InitSwSlaveI2C(void); void EXTI4_15_IRQHandler(void); void CheckSwSlaveI2cTimeout(void); uint8_t ParseHostFrame(void); void Prepare_TX_Frame(void); // 接收索引,防止缓冲区溢出 inline void IncrementRxIndex(void) { // 如果已接收完整帧,则忽略后续数据 if (SwSlaveI2C.IgnoreData) return; if (SwSlaveI2C.RxIdx < MAX_RX_INDEX) { SwSlaveI2C.RxIdx++; // 检查是否达到帧长度,超过则忽略 if (SwSlaveI2C.RxIdx >= HOST_FRAME_LEN) { SwSlaveI2C.IgnoreData = 1; } } else { SwSlaveI2C.RxIdx = 0; // 可添加缓冲区溢出错误处理 } } #define DEBUG_BUF_SIZE 256 typedef struct { uint8_t data[DEBUG_BUF_SIZE]; uint16_t head; uint16_t tail; uint16_t count; } DebugRingBuffer; void DebugRingBuffer_Write(DebugRingBuffer *buf, uint8_t byte); int DebugRingBuffer_Read(DebugRingBuffer *buf, uint8_t *byte); void DebugRingBuffer_Init(DebugRingBuffer *buf); extern DebugRingBuffer rx_debug_buf; extern DebugRingBuffer tx_debug_buf; extern uint8_t last_prepared_tx_frame[SLAVE_FRAME_LEN]; #ifdef __cplusplus } #endif #endif #include "soft_i2c.h" #include "delay.h" #include <stdio.h> DebugRingBuffer rx_debug_buf; DebugRingBuffer tx_debug_buf; uint8_t last_prepared_tx_frame[SLAVE_FRAME_LEN]; // 初始化环形缓冲区 void DebugRingBuffer_Init(DebugRingBuffer *buf) { buf->head = 0; buf->tail = 0; buf->count = 0; } // 向环形缓冲区写入一个字节,如果满了则覆盖最旧的数据 void DebugRingBuffer_Write(DebugRingBuffer *buf, uint8_t byte) { uint32_t primask = __get_PRIMASK(); __disable_irq(); if (buf->count < DEBUG_BUF_SIZE) { buf->data[buf->head] = byte; buf->head = (buf->head + 1) % DEBUG_BUF_SIZE; buf->count++; } else { // 缓冲区满,覆盖尾部数据 buf->data[buf->head] = byte; buf->head = (buf->head + 1) % DEBUG_BUF_SIZE; buf->tail = (buf->tail + 1) % DEBUG_BUF_SIZE; } __set_PRIMASK(primask); } // 从环形缓冲区读取一个字节,返回0表示成功,-1表示缓冲区空 int DebugRingBuffer_Read(DebugRingBuffer *buf, uint8_t *byte) { if (buf->count == 0) { return -1; } *byte = buf->data[buf->tail]; buf->tail = (buf->tail + 1) % DEBUG_BUF_SIZE; buf->count--; return 0; } // 传感器数据缓存结构 typedef struct { uint16_t reg_11; // 寄存器11的数据 uint8_t updated; // 数据更新标志(1:新数据,0:未更新) uint32_t timestamp; // 数据时间戳 uint8_t valid; // 数据有效标志 uint8_t error_count; // 连续错误计数 } SensorDataCache; // 外部变量声明 extern uint16_t adc_ch4_avg; extern uint16_t adc_ch5_avg; extern uint16_t adc_ch6_avg; extern uint16_t adc_ch7_avg; extern SensorDataCache sensor2_cache; extern SensorDataCache sensor3_cache; extern SensorDataCache sensor4_cache; uint8_t RxDataBuf[BUFFER_SIZE]; uint8_t TxDataBuf[BUFFER_SIZE]; SwSlaveI2C_t SwSlaveI2C = { I2C_STA_IDLE, // State I2C_WRITE, // Rw 0, // SclFallCnt 0, // Flag 0, // StartMs RxDataBuf, // RxBuf TxDataBuf, // TxBuf 0, // RxIdx 0, // TxIdx 0x00, // HostFuncCode - 默认为0x00 0, // FrameReceived 0 // IgnoreData }; // 配置SDA为中断模式(输入) void I2C_Slave_Set_SDA_IT(void) { // 清除当前模式 SW_SLAVE_SDA_PRT->MODER &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); // 设置为输入模式 SW_SLAVE_SDA_PRT->MODER |= (0 << I2C_SDA_Pinx * 2); // 确保为上拉输入 SW_SLAVE_SDA_PRT->PUPDR &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); SW_SLAVE_SDA_PRT->PUPDR |= (1 << I2C_SDA_Pinx * 2); } // 配置SDA为开漏输出 void I2C_Slave_Set_SDA_Out(void) { // 清除当前模式 SW_SLAVE_SDA_PRT->MODER &= ~(GPIO_MODE_MSK << (I2C_SDA_Pinx * 2)); // 设置为输出模式 SW_SLAVE_SDA_PRT->MODER |= (1 << I2C_SDA_Pinx * 2); // 配置为开漏输出 SW_SLAVE_SDA_PRT->OTYPER |= (1 << I2C_SDA_Pinx); } // 异或校验 uint8_t Calculate_XOR_Checksum(uint8_t *buf, uint8_t len) { uint8_t checksum = 0; for (uint8_t i = 0; i < len; i++) { checksum ^= buf[i]; } return checksum; } // 解析主机发送的帧 uint8_t ParseHostFrame(void) { // 检查帧长度(地址+4字节数据) if (SwSlaveI2C.RxIdx != HOST_FRAME_LEN) return 0; // 验证帧头(01 AA) if (SwSlaveI2C.RxBuf[1] != FRAME_HEADER1 || SwSlaveI2C.RxBuf[2] != FRAME_HEADER2) return 0; // 计算校验和:仅包含数据部分(01、AA、功能码),共3字节,与第4字节(校验和)比较 // 不包含地址字节(RxBuf[0]) uint8_t calc_checksum = Calculate_XOR_Checksum(&SwSlaveI2C.RxBuf[1], 3); if (calc_checksum != SwSlaveI2C.RxBuf[4]) return 0; // 存储主机功能码(第3字节) SwSlaveI2C.HostFuncCode = SwSlaveI2C.RxBuf[3]; // 收到功能码后立即准备数据 Prepare_TX_Frame(); return 1; } // 发送帧格式: 01 AA 主机功能码 8字节数据 异或校验 void Prepare_TX_Frame(void) { uint8_t frame_updated=1; //关中断保护全局变量访问 __disable_irq(); // 填充帧头 SwSlaveI2C.TxBuf[0] = FRAME_HEADER1; SwSlaveI2C.TxBuf[1] = FRAME_HEADER2; SwSlaveI2C.TxBuf[2] = SwSlaveI2C.HostFuncCode; // 使用主机功能码 // 清空数据区域 for (uint8_t i = 3; i < 11; i++) { SwSlaveI2C.TxBuf[i] = 0x00; } // 根据主机功能码填充8字节数据 switch (SwSlaveI2C.HostFuncCode) { case 0x01: // ADC数据(4个16位ADC值拆分为8字节) SwSlaveI2C.TxBuf[3] = (adc_ch4_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[4] = adc_ch4_avg & 0xFF; SwSlaveI2C.TxBuf[5] = (adc_ch5_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[6] = adc_ch5_avg & 0xFF; SwSlaveI2C.TxBuf[7] = (adc_ch6_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[8] = adc_ch6_avg & 0xFF; SwSlaveI2C.TxBuf[9] = (adc_ch7_avg >> 8) & 0xFF; SwSlaveI2C.TxBuf[10] = adc_ch7_avg & 0xFF; break; case 0x02: // 传感器数据 // 传感器2数据 if (sensor2_cache.valid) { SwSlaveI2C.TxBuf[3] = (sensor2_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[4] = sensor2_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[3] = 0xFF; SwSlaveI2C.TxBuf[4] = 0xFF; } // 传感器3数据 if (sensor3_cache.valid) { SwSlaveI2C.TxBuf[5] = (sensor3_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[6] = sensor3_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[5] = 0xFF; SwSlaveI2C.TxBuf[6] = 0xFF; } // 传感器4数据 if (sensor4_cache.valid) { SwSlaveI2C.TxBuf[7] = (sensor4_cache.reg_11 >> 8) & 0xFF; SwSlaveI2C.TxBuf[8] = sensor4_cache.reg_11 & 0xFF; } else { SwSlaveI2C.TxBuf[7] = 0xFF; SwSlaveI2C.TxBuf[8] = 0xFF; } // 预留2字节 SwSlaveI2C.TxBuf[9] = 0x00; SwSlaveI2C.TxBuf[10] = 0x00; break; default: // 未知功能码 SwSlaveI2C.TxBuf[2] = 0xFF; // 错误标识 break; } // 计算校验和(前11字节) SwSlaveI2C.TxBuf[11] = Calculate_XOR_Checksum(SwSlaveI2C.TxBuf, 11); // 恢复中断 __enable_irq(); for (int i = 0; i < SLAVE_FRAME_LEN; i++) { last_prepared_tx_frame[i] = SwSlaveI2C.TxBuf[i]; } } void CheckSwSlaveI2cTimeout(void) { uint32_t TimeMs, TimeCurMs; if(SwSlaveI2C.State != I2C_STA_IDLE) { TimeCurMs = HAL_GetTick(); if(TimeCurMs >= SwSlaveI2C.StartMs) { TimeMs = TimeCurMs - SwSlaveI2C.StartMs; } else { TimeMs = ~(SwSlaveI2C.StartMs - TimeCurMs) + 1; } if(I2C_TIMEOUT_MS <= TimeMs) { // 超时重置,释放总线 SwSlaveI2C.State = I2C_STA_IDLE; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.FrameReceived = 0; // 重置功能码 SwSlaveI2C.HostFuncCode = 0x00; // 重置为默认值 // 释放SDA和SCL线,将其设置为高电平 SET_SDA_PIN(); // 释放SDA SET_SCL_PIN(); // 释放SCL // 超时后设置回输入模式以检测新的起始条件 I2C_Slave_Set_SDA_IT(); } } } // 初始化软件I2C从机 void InitSwSlaveI2C(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 使能GPIO时钟 SW_SLAVE_SCL_CLK_EN(); SW_SLAVE_SDA_CLK_EN(); // 配置SCL引脚为输入上拉 GPIO_InitStruct.Pin = SW_SLAVE_SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SW_SLAVE_SCL_PRT, &GPIO_InitStruct); // 配置SDA引脚为输入上拉,带中断 GPIO_InitStruct.Pin = SW_SLAVE_SDA_PIN; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SW_SLAVE_SDA_PRT, &GPIO_InitStruct); // 使能并设置中断优先级 HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); // 初始状态设置为输入模式以检测起始条件 I2C_Slave_Set_SDA_IT(); // 初始化时准备默认功能码的数据 Prepare_TX_Frame(); } void EXTI4_15_IRQHandler(void) { /* USER CODE BEGIN EXTI4_15_IRQn 0 */ /* USER CODE END EXTI4_15_IRQn 0 */ // HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6); // HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7); /* USER CODE BEGIN EXTI4_15_IRQn 1 */ // 保存中断状态 uint32_t scl_it_flag = __HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SCL_PIN); uint32_t sda_it_flag = __HAL_GPIO_EXTI_GET_IT(SW_SLAVE_SDA_PIN); // 清除中断标志 if (scl_it_flag) __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SCL_PIN); if (sda_it_flag) __HAL_GPIO_EXTI_CLEAR_IT(SW_SLAVE_SDA_PIN); SwSlaveI2C.StartMs = HAL_GetTick(); // 先处理SDA中断(起始/停止条件优先) if (sda_it_flag) { if(READ_SDA_PIN() == GPIO_PIN_RESET) { // SDA下降沿且SCL为高电平,检测到起始条件 if(READ_SCL_PIN() == GPIO_PIN_SET) { SwSlaveI2C.State = I2C_STA_START; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.IgnoreData = 0; // 重置忽略标志 // 起始条件后,准备接收地址,设置为输入模式 I2C_Slave_Set_SDA_IT(); } } else { // SDA上升沿且SCL为高电平,检测到停止条件 if(READ_SCL_PIN() == GPIO_PIN_SET) { SwSlaveI2C.State = I2C_STA_IDLE; SwSlaveI2C.RxIdx = 0; SwSlaveI2C.TxIdx = 0; SwSlaveI2C.IgnoreData = 0; // 重置忽略标志 // 停止条件不重置FrameReceived和HostFuncCode,以便支持连续读操作 // 切换回输入模式以检测新的起始条件 I2C_Slave_Set_SDA_IT(); } } } // 处理SCL中断 if (scl_it_flag) { // SCL下降沿处理 if(READ_SCL_PIN() == GPIO_PIN_RESET) { switch(SwSlaveI2C.State) { case I2C_STA_START: SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0; SwSlaveI2C.Rw = I2C_WRITE; SwSlaveI2C.State = I2C_STA_DATA; // 接收地址阶段保持输入模式 I2C_Slave_Set_SDA_IT(); break; case I2C_STA_DATA: SwSlaveI2C.SclFallCnt++; if(SwSlaveI2C.Rw == I2C_READ) { // 发送数据时设置为输出模式 I2C_Slave_Set_SDA_Out(); // 发送数据位(只发送SLAVE_FRAME_LEN字节) if (SwSlaveI2C.TxIdx < SLAVE_FRAME_LEN) { uint8_t bit_val = (SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx] >> (7 - SwSlaveI2C.SclFallCnt)) & 0x01; HAL_GPIO_WritePin(SW_SLAVE_SDA_PRT, SW_SLAVE_SDA_PIN, bit_val ? GPIO_PIN_SET : GPIO_PIN_RESET); } else { SET_SDA_PIN(); // 数据发送完成,释放总线 } } // 接收模式保持输入 else { I2C_Slave_Set_SDA_IT(); } // 8位数据发送/接收完成,准备ACK if(SwSlaveI2C.SclFallCnt == 8) { if(SwSlaveI2C.Rw == I2C_WRITE) { // 地址匹配检查 - 修复了地址比较逻辑 if(SwSlaveI2C.RxIdx == 0) { // 正确的比较方式:将接收的地址与左移后的从机地址比较 if((SwSlaveI2C.RxBuf[0] & 0xFE) == (SW_SLAVE_ADDR << 1)) { SwSlaveI2C.Flag = 1; SwSlaveI2C.Rw = SwSlaveI2C.RxBuf[0] & 0x01; // 对于读操作,确保数据已准备好 if (SwSlaveI2C.Rw == I2C_READ) { // 即使没有新的帧,也使用上次的功能码准备数据 Prepare_TX_Frame(); } } } // 发送ACK,需要输出模式 I2C_Slave_Set_SDA_Out(); if(SwSlaveI2C.Flag) { CLR_SDA_PIN(); // 发送ACK } else { SET_SDA_PIN(); // 发送NACK } } else { // 读操作时释放SDA总线,等待主机的ACK/NACK I2C_Slave_Set_SDA_IT(); } // 添加的调试日志记录代码开始 // 记录接收到的字节(对于写操作) if (SwSlaveI2C.Rw == I2C_WRITE && SwSlaveI2C.Flag) { // 注意:这里记录的是刚刚接收到的完整字节(存储在RxBuf[RxIdx]中) DebugRingBuffer_Write(&rx_debug_buf, SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx]); } // 记录发送的字节(对于读操作) if (SwSlaveI2C.Rw == I2C_READ) { // 注意:我们发送的字节是TxBuf[TxIdx](已经发送完的字节) DebugRingBuffer_Write(&tx_debug_buf, SwSlaveI2C.TxBuf[SwSlaveI2C.TxIdx]); } // 添加的调试日志记录代码结束 SwSlaveI2C.State = I2C_STA_ACK; } break; case I2C_STA_ACK: // ACK状态下的SCL下降沿处理 // 只有在确认主机已检测到ACK后才继续处理 if(SwSlaveI2C.Rw == I2C_WRITE) { // 切换回输入模式接收下一个字节 I2C_Slave_Set_SDA_IT(); SET_SDA_PIN(); // 释放SDA总线 IncrementRxIndex(); // 检查主机帧是否接收完成 if (SwSlaveI2C.RxIdx == HOST_FRAME_LEN) { // 解析主机帧 if (ParseHostFrame()) { SwSlaveI2C.FrameReceived = 1; } SwSlaveI2C.RxIdx = 0; // 重置接收索引 } if (!SwSlaveI2C.IgnoreData && SwSlaveI2C.RxIdx < MAX_RX_INDEX) { SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] = 0; } // 重置SclFallCnt为0 SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.State = I2C_STA_DATA; } else { // 读操作,根据NACK状态决定下一步 if (SwSlaveI2C.State == I2C_STA_NACK) { // 已收到NACK,结束传输 SET_SDA_PIN(); SwSlaveI2C.State = I2C_STA_IDLE; I2C_Slave_Set_SDA_IT(); // 切换回输入模式 } else if (SwSlaveI2C.TxIdx < SLAVE_FRAME_LEN - 1) { // 还有数据要发送,继续 SwSlaveI2C.TxIdx++; SwSlaveI2C.SclFallCnt = 0; SwSlaveI2C.State = I2C_STA_DATA; } else { // 最后一个字节已发送,等待NACK确认 SwSlaveI2C.SclFallCnt = 0; // 保持在ACK状态,等待主机的NACK } } break; case I2C_STA_NACK: SwSlaveI2C.SclFallCnt = 0; SET_SDA_PIN(); // 释放SDA总线 I2C_Slave_Set_SDA_IT(); // 切换回输入模式 SwSlaveI2C.State = I2C_STA_IDLE; // 收到NACK后结束通信 break; } } // SCL上升沿处理 else { switch(SwSlaveI2C.State) { case I2C_STA_DATA: if((SwSlaveI2C.Rw == I2C_WRITE) && (SwSlaveI2C.SclFallCnt < 8) && !SwSlaveI2C.IgnoreData) { // 读取数据位(保持输入模式) if(READ_SDA_PIN() == GPIO_PIN_SET) { SwSlaveI2C.RxBuf[SwSlaveI2C.RxIdx] |= (1 << (7 - SwSlaveI2C.SclFallCnt)); } } break; case I2C_STA_ACK: // 对于写操作,从机已发送ACK,等待SCL上升沿确认主机已接收 if(SwSlaveI2C.Rw == I2C_WRITE) { // ACK信号已被主机检测到,保持状态直到SCL下降沿 } // 对于读操作,检测主机发送的ACK/NACK else { if(READ_SDA_PIN() == GPIO_PIN_SET) { // 主机发送NACK,标记为NACK状态 SwSlaveI2C.State = I2C_STA_NACK; I2C_Slave_Set_SDA_IT(); // 切换回输入模式 } else { // 主机发送ACK但已无更多数据,仍需等待NACK if (SwSlaveI2C.TxIdx >= SLAVE_FRAME_LEN - 1) { SwSlaveI2C.State = I2C_STA_NACK; I2C_Slave_Set_SDA_IT(); } } } break; } } } /* USER CODE END EXTI4_15_IRQn 1 */ } while (1) { CheckSwSlaveI2cTimeout(); HAL_Delay(10); ProcessSensorDataUpdate(); HAL_Delay(10); // 打印接收调试信息 uint8_t byte; while (DebugRingBuffer_Read(&rx_debug_buf, &byte) == 0) { printf("RX: 0x%02X\r\n", byte); } while (DebugRingBuffer_Read(&tx_debug_buf, &byte) == 0) { printf("TX: 0x%02X\r\n", byte); } // 如果检测到有新的帧准备好,可以打印整个帧 uint8_t frame_updated = 0; if (frame_updated) { // frame_updated是一个标志,在Prepare_TX_Frame中置位,这里复位 frame_updated = 0; printf("Prepared TX Frame: "); for (int i = 0; i < SLAVE_FRAME_LEN; i++) { printf("%02X ", last_prepared_tx_frame[i]); } printf("\r\n"); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 检查代码逻辑,特别检查发送逻辑。
10-12
“/* * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved. * Description: pmbus v200 物理层实现源文件 * Create: 2022/05/31 */ #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/types.h> #include <linux/bitfield.h> #include "hisi_pmbus.h" #define STANDARD_MODE 1 #define FAST_MODE 2 #define GPIO_LEVEL_LOW 0 #define GPIO_LEVEL_HIGH 1 #define SET_LOW_HIGH_TIMES 9 #define AVS_WR_OPEN_REG 0x0004 #define AVS_INT_STATUS_REG 0x0008 #define AVS_INT_CLEAR_REG 0x0020 #define TRIGGER_CFG_REG 0x00B8 #define PMBUS_DISABLE 0x00 #define PMBUS_ENABLE 0x01 /* PMBUSIF_REG_GEN Base address of Module's Register */ #define PMBUSIF_REG_GEN_BASE (0x800) #define I2C_CON_REG (PMBUSIF_REG_GEN_BASE + 0x0) /* I2C控制寄存器。 */ #define I2C_CON_MASTER_ENABLE BIT(0) #define I2C_CON_SPEED_MASK (0x6U) #define I2C_CON_RESTART_EN BIT(5) #define I2C_CON_SLAVE_DISABLE BIT(6) #define I2C_DATA_CMD_REG (PMBUSIF_REG_GEN_BASE + 0x10) /* I2C数据操作寄存器。 */ #define I2C_SS_SCL_HCNT_REG (PMBUSIF_REG_GEN_BASE + 0x14) /* I2C标准速度模式SCL高电平配置寄存器。 */ #define I2C_SS_SCL_LCNT_REG (PMBUSIF_REG_GEN_BASE + 0x18) /* I2C标准速度模式SCL低电平配置寄存器。 */ #define I2C_FS_SCL_HCNT_REG (PMBUSIF_REG_GEN_BASE + 0x1C) /* I2C快速模式SCL高电平配置寄存器。 */ #define I2C_FS_SCL_LCNT_REG (PMBUSIF_REG_GEN_BASE + 0x20) /* I2C快速模式SCL低电平配置寄存器。 */ #define I2C_INTR_STAT_REG (PMBUSIF_REG_GEN_BASE + 0x2C) /* I2C屏蔽后中断状态寄存器。 */ #define I2C_INTR_MASK_REG (PMBUSIF_REG_GEN_BASE + 0x30) /* I2C中断屏蔽寄存器。 */ #define I2C_INTR_RAW_REG (PMBUSIF_REG_GEN_BASE + 0x34) /* I2C原始中断状态寄存器。 */ #define I2C_INTR_RAW_TX_ABRT BIT(6) #define I2C_INTR_RAW_ALERT_DET BIT(12) #define I2C_INTR_RAW_SCL_LOW_TOUT BIT(15) #define I2C_INTR_RAW_PMBUS_CMD_FINISH BIT(17) #define I2C_ENABLE_REG (PMBUSIF_REG_GEN_BASE + 0x6C) /* I2C工作使能寄存器。 */ #define I2C_STATUS_REG (PMBUSIF_REG_GEN_BASE + 0x70) /* I2C状态寄存器。 */ #define I2C_RXFLR_REG (PMBUSIF_REG_GEN_BASE + 0x78) /* RX_FIFO有效数据指示寄存器。 */ #define I2C_SDA_HOLD_REG (PMBUSIF_REG_GEN_BASE + 0x7C) /* SDA保持时间配置寄存器。 */ #define I2C_ENABLE_STATUS_REG (PMBUSIF_REG_GEN_BASE + 0x9C) /* I2C状态寄存器。 */ #define I2C_SCL_SWITCH_REG (PMBUSIF_REG_GEN_BASE + 0xA0) /* I2C防挂死SCL使能寄存器。 */ #define I2C_SCL_SIM_REG (PMBUSIF_REG_GEN_BASE + 0xA4) /* I2C防挂死SCL模拟寄存器。 */ #define I2C_LOCK_REG (PMBUSIF_REG_GEN_BASE + 0xAC) /* I2C lock寄存器。 */ #define I2C_SDA_SWITCH_REG (PMBUSIF_REG_GEN_BASE + 0xB0) /* I2C防挂死SDA使能寄存器。 */ #define I2C_SDA_SIM_REG (PMBUSIF_REG_GEN_BASE + 0xB4) /* I2C防挂死SDA模拟寄存器。 */ #define I2C_PMBUS_CTRL_REG (PMBUSIF_REG_GEN_BASE + 0x104) /* PMBUS全局控制寄存器。 */ #define I2C_PMBUS_CTRL_PEC_EN BIT(2) #define I2C_PMBUS_CTRL_ALERT_EN BIT(1) #define I2C_LOW_TIMEOUT_REG (PMBUSIF_REG_GEN_BASE + 0x108) /* SCL低电平超时值配置寄存器。 */ #define I2C_PMBUS_SCL_DET_REG (PMBUSIF_REG_GEN_BASE + 0x12C) /* PMBUS SCL检测寄存器。 */ #define I2C_PMBUS_SCL_DET_IDLE_DET_EN BIT(0) #define I2C_PMBUS_SCL_DET_TIMEOUT_EN BIT(1) #define I2C_PMBUS_IDLECNT_REG (PMBUSIF_REG_GEN_BASE + 0x130) /* SCL高电平空闲值配置寄存器。 */ #define I2C_PMBUS_RST_REG (PMBUSIF_REG_GEN_BASE + 0x134) /* 软件复位配置寄存器。 */ /* PMBUS_PROC_REG_GEN Base address of Module's Register */ #define PMBUS_PROC_REG_GEN_BASE (0xA00) #define PMBUS_WR_OPEN_REG (PMBUS_PROC_REG_GEN_BASE + 0x4) /* PMBUS全局参数保护寄存器。 */ #define PMBUS_INT_CLR_REG (PMBUS_PROC_REG_GEN_BASE + 0x10) /* PMBUS中断清除寄存器 */ #define PMBUS_WAIT_CNT 30000 /* PMU CMD */ #define STOP_EN (1U << 10) #define ADDR_EN (1U << 9) #define CMD_READ (1U << 8) #define SDA_IN BIT(9) #define PMBUS_I2C_RECOVERY_CYCLE_CNT 10 static inline void pmbus_reg_write(struct io_region *reg_region, u32 reg, u32 val) { pr_debug("[iWare][Debug] %s reg=%#x val =%#x\r\n", __FUNCTION__, reg, val); iowrite32(val, reg_region->io_base + reg); } static inline u32 pmbus_reg_read(struct io_region *reg_region, u32 reg) { u32 val; val = ioread32(reg_region->io_base + reg); pr_debug("[iWare][Debug] %s reg=%#x val =%#x\r\n", __FUNCTION__, reg, val); return val; } /* try to recovery the bus if sda locked to low level */ static void pmbus_recovery_bus(struct io_region *reg_region) { int i; u32 status; status = pmbus_reg_read(reg_region, I2C_STATUS_REG); /* if SDA keep low, assume the bus hang up */ if ((status & SDA_IN) == 0) { /* disable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x0); /* enable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x1); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x1); /* output at least 9 clocks to try to recover the bus */ for (i = 0; i < PMBUS_I2C_RECOVERY_CYCLE_CNT; i++) { pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x0); udelay(50); // 延时50us pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x1); udelay(50); // 延时50us } /* disable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x0); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x0); /* enable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x1); pr_info("[iWare][Info] pmbus hang recovery done\n"); } } static int pmbus_wait_write_finish(struct io_region *reg_region) { int i; u32 status = 0; for (i = 0; i < PMBUS_WAIT_CNT; i++) { status = pmbus_reg_read(reg_region, I2C_INTR_RAW_REG); if (((status & I2C_INTR_RAW_SCL_LOW_TOUT) == 0) && ((status & I2C_INTR_RAW_TX_ABRT) == 0) && ((status & I2C_INTR_RAW_PMBUS_CMD_FINISH) != 0)) { // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); return 0; } udelay(1); } pr_err("[iWare][Error] pmbus_write timeout! raw_int_status:0x%x\n", status); // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); pmbus_recovery_bus(reg_region); return -EBUSY; } static int pmbus_send_byte_v200(struct io_region *reg_region, struct pmbus_msg *msg) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); if ((msg->type & PMBUS_FLAG_EXT) != 0) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command_ext); } else { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->command); } return pmbus_wait_write_finish(reg_region); } static int pmbus_write_bytes_v200(struct io_region *reg_region, struct pmbus_msg *msg) { unsigned int i; pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command); if ((msg->type & PMBUS_FLAG_EXT) != 0) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command_ext); } for (i = 0; i < msg->data_len - 1; i++) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->data[i]); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | msg->data[msg->data_len - 1]); return pmbus_wait_write_finish(reg_region); } #define PMBUS_READ_WAIT_TIMEOUT 1000000ULL #define PMUBS_READ_WAIT_DELAY_US 1UL static int pmbus_wait_read_finish(struct io_region *reg_region, u8 read_len) { int ret; u32 data_num; ret = readl_poll_timeout(reg_region->io_base + I2C_RXFLR_REG, data_num, (data_num >= read_len), PMUBS_READ_WAIT_DELAY_US, PMBUS_READ_WAIT_TIMEOUT); if (ret != 0) { pr_err("[iWare][Error] wait read_finish timeout!! read_len[%u] fifo num[%u], raw_int_status:0x%x\n", read_len, data_num, pmbus_reg_read(reg_region, I2C_INTR_RAW_REG)); // 清除所有中断 pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xffffffff); pmbus_recovery_bus(reg_region); return ret; } return 0; } static void pmbus_clear_rx_fifo(struct io_region *reg_region) { u8 rx_fifo_data_num; u8 i; u32 tmp; /* clean rx fifo */ rx_fifo_data_num = (u8)pmbus_reg_read(reg_region, I2C_RXFLR_REG); for (i = 0; i < rx_fifo_data_num; i++) { tmp = pmbus_reg_read(reg_region, I2C_DATA_CMD_REG); // 把fifo读清 } } static int pmbus_read_bytes_v200(struct io_region *reg_region, struct pmbus_msg *msg) { int ret; unsigned int i; u32 status; /* 先把rx fifo读清 */ pmbus_clear_rx_fifo(reg_region); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | msg->slave_addr); pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command); if ((msg->type & PMBUS_FLAG_EXT) != 0) { // 扩展16bit 命令 pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, msg->command_ext); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, ADDR_EN | CMD_READ | msg->slave_addr); for (i = 0; i < msg->data_len - 1; i++) { pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, CMD_READ); } pmbus_reg_write(reg_region, I2C_DATA_CMD_REG, STOP_EN | CMD_READ); ret = pmbus_wait_read_finish(reg_region, msg->data_len); if (ret != 0) { pr_err("[iWare][Error] %s slave_addr(0x%x), cmd(0x%x), time out\n", __func__, msg->slave_addr, msg->command); pmbus_recovery_bus(reg_region); return -EAGAIN; } for (i = 0; i < msg->data_len; i++) { msg->data[i] = (u8)pmbus_reg_read(reg_region, I2C_DATA_CMD_REG); } /* for block read, first read code is data length */ if ((msg->type & PMBUS_FLAG_BLOCK) != 0) { if (msg->data[0] > msg->data_len) { pr_info("[iWare][Info] pmbus read slave[0x%02x] command[0x%02x] block data may lossed, toalLen[%u]\n", msg->slave_addr, msg->command, msg->data[0]); } } // 清中断 status = pmbus_reg_read(reg_region, I2C_INTR_RAW_REG); pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, status); return 0; } static int pmbus_reset_v200(struct io_region *reg_region) { pmbus_reg_write(reg_region, I2C_PMBUS_RST_REG, 1); udelay(1); pmbus_reg_write(reg_region, I2C_PMBUS_RST_REG, 0); udelay(1); return 0; } /* 不同soc解锁码不同, chip dtsi里配置 309a 1260 avs_wr_unlock_key 0x5a5a5a5a 0x1ACCE551 pmbus_wr_unlock_key 0x5a5a5a5a 0x1ACCE551 i2c_unlock_key 0x5a5a5a5a 0x36313832 */ static void pmbus_unlock_reg(struct io_region *reg_region, struct pmbus_unlock_key *key) { /* unlock avs wr */ pmbus_reg_write(reg_region, AVS_WR_OPEN_REG, key->avs_wr_unlock_key); /* unlock pmbus wr */ pmbus_reg_write(reg_region, PMBUS_WR_OPEN_REG, key->pmbus_wr_unlock_key); /* unlock pmbus i2c wr */ pmbus_reg_write(reg_region, I2C_LOCK_REG, key->i2c_unlock_key); } static void pmbus_config_timing_cnt(struct io_region *reg_region, u8 speed_mode, struct pmbus_timings_cfg *pmbus_cfg) { if (speed_mode == STANDARD_MODE) { // 标准模式 pmbus_reg_write(reg_region, I2C_SS_SCL_LCNT_REG, pmbus_cfg->lcnt); pmbus_reg_write(reg_region, I2C_SS_SCL_HCNT_REG, pmbus_cfg->hcnt); } else { // 快速模式 pmbus_reg_write(reg_region, I2C_FS_SCL_LCNT_REG, pmbus_cfg->lcnt); pmbus_reg_write(reg_region, I2C_FS_SCL_HCNT_REG, pmbus_cfg->hcnt); } // 屏蔽所有中断 pmbus_reg_write(reg_region, I2C_INTR_MASK_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, I2C_SDA_HOLD_REG, pmbus_cfg->hold_cnt); // PMBus的SCL低电平超时值(PMBus协议规定为25~35ms) pmbus_reg_write(reg_region, I2C_LOW_TIMEOUT_REG, pmbus_cfg->timeout_cnt); // 默认30ms // PMBus的SCL高电平空闲值(PMBus协议规定为>50us) pmbus_reg_write(reg_region, I2C_PMBUS_IDLECNT_REG, pmbus_cfg->idle_cnt); // 默认100us } static int pmbus_init_v200(struct io_region *reg_region, u32 pec_en, u32 bus_freq_hz, struct pmbus_timings_cfg *cfg, struct pmbus_unlock_key *key) { u32 val = 0; u8 speed_mode; int ret; if (bus_freq_hz > PMBUS_MAX_FAST_MODE_FREQ) { pr_err("[iWare][Error] invalid para bus_freq_hz =%u\r\n", bus_freq_hz); return -EINVAL; } ret = pmbus_reset_v200(reg_region); if (ret != 0) { return ret; } /* unlock */ pmbus_unlock_reg(reg_region, key); /* stop triger */ pmbus_reg_write(reg_region, TRIGGER_CFG_REG, 0x0); /* disable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, PMBUS_DISABLE); speed_mode = (bus_freq_hz <= PMBUS_MAX_STANDARD_MODE_FREQ) ? STANDARD_MODE : FAST_MODE; val |= I2C_CON_MASTER_ENABLE | I2C_CON_SLAVE_DISABLE | I2C_CON_RESTART_EN; val |= (u32)FIELD_PREP(I2C_CON_SPEED_MASK, speed_mode); pmbus_reg_write(reg_region, I2C_CON_REG, val); pmbus_config_timing_cnt(reg_region, speed_mode, cfg); /* config scl detect */ pmbus_reg_write(reg_region, I2C_PMBUS_SCL_DET_REG, I2C_PMBUS_SCL_DET_IDLE_DET_EN | I2C_PMBUS_SCL_DET_TIMEOUT_EN); /* enable pec and alert */ val = I2C_PMBUS_CTRL_ALERT_EN; if (pec_en != 0) { pr_info("[iWare][Info] pmbus enable pec \r\n"); val |= I2C_PMBUS_CTRL_PEC_EN; } pmbus_reg_write(reg_region, I2C_PMBUS_CTRL_REG, val); /* enable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, PMBUS_ENABLE); // 清中断 pmbus_reg_write(reg_region, AVS_INT_CLEAR_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, PMBUS_INT_CLR_REG, 0xFFFFFFFF); pmbus_reg_write(reg_region, I2C_INTR_RAW_REG, 0xFFFFFFFF); return 0; } const struct hisi_pmbus_ops hisi_pmbus_v200_ops = { .init = pmbus_init_v200, .reset = pmbus_reset_v200, .send_byte = pmbus_send_byte_v200, .read_bytes = pmbus_read_bytes_v200, .write_bytes = pmbus_write_bytes_v200, }; const struct hisi_pmbus_ops *hisi_pmbus_get_ops(void) { return &hisi_pmbus_v200_ops; } ” “int kdrv_pmbus_write_word(u32 bus_id, u8 slave_addr, u16 command, u16 data) { struct hisi_pmbus_data *pmbus = NULL; struct pmbus_msg msg = { 0 }; int ret; pmbus = hisi_pmbus_data_get_by_id(bus_id); if (pmbus == NULL) { pr_err("[iWare][Error] kdrv_pmbus_write_word,get pmbus data fail: pmbus_id=%u,\n", bus_id); return -EPERM; } mutex_lock(&pmbus->lock); msg.data = (u8 *)&data; msg.data_len = sizeof(u16); hisi_pmbus_fill_msg(&msg, PMBUS_WRITE_WORD, slave_addr, command); ret = hisi_pmbus_xfer(pmbus, &msg); if (ret != 0) { mutex_unlock(&pmbus->lock); return ret; } mutex_unlock(&pmbus->lock); return 0; } EXPORT_SYMBOL(kdrv_pmbus_write_word);” “int test_kdrv_pmbus_write_word(u32 bus_id, u32 slave_addr, u32 cmd, u32 data) { int ret; ret = kdrv_pmbus_write_word(bus_id, slave_addr, cmd, (u16)data); if (ret) { pr_err("kdrv_pmbus_write_word fail bus_id:%u, addr:%#x, cmd:%#x\n", bus_id, slave_addr, cmd); return ret; } pr_info("write word: bus_id:%#x, addr:%#x, cmd:%#x, data:%#x\n", bus_id, slave_addr, cmd, data); return 0; }” “static void pmbus_recovery_bus(struct io_region *reg_region) { int i; u32 status; status = pmbus_reg_read(reg_region, I2C_STATUS_REG); /* if SDA keep low, assume the bus hang up */ if ((status & SDA_IN) == 0) { /* disable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x0); /* enable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x1); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x1); /* output at least 9 clocks to try to recover the bus */ for (i = 0; i < PMBUS_I2C_RECOVERY_CYCLE_CNT; i++) { pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x0); udelay(50); // 延时50us pmbus_reg_write(reg_region, I2C_SCL_SIM_REG, 0x1); udelay(50); // 延时50us } /* disable output software simulaition */ pmbus_reg_write(reg_region, I2C_SCL_SWITCH_REG, 0x0); pmbus_reg_write(reg_region, I2C_SDA_SWITCH_REG, 0x0); /* enable pmbus */ pmbus_reg_write(reg_region, I2C_ENABLE_REG, 0x1); pr_info("[iWare][Info] pmbus hang recovery done\n"); } }” “ [60585.219727] [iWare][Error] pmbus_write timeout! raw_int_status:0x10 [60585.227034] [iWare][Info] pmbus hang recovery done [60585.231848] kdrv_pmbus_write_word fail bus_id:1, addr:0x70, cmd:0x21 请根据以上几段代码,帮我分析我的报错原因可能是什么,并给出完整解决方案”
08-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值