当前位置: 首页 > news >正文

国民技术N32G003实现PMBus从机及使用STM32F103模拟I2C主机访问从机

最近有项目用到PMBus通信,经过一段时间的调试已满足客户的要求,先将代码贴上,再解释下基本的思路。

从机程序:

PMBusSlave.c

/********************************************************************************* PMBusSlave.c -   This program is a software implementation of PMBus over I2C,*                  with the N32G031C8 device acting as the PMBus slave.** Copyright (c) 2025 ASTO Incorporated.  All rights reserved.* Software License Agreement** ASTO is supplying this software for use solely and* exclusively on ASTO's microcontroller products. The software is owned by* ASTO and/or its suppliers, and is protected under applicable copyright* laws. You may not combine this software with "viral" open-source* software in order to form a larger program.** THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.* NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT* NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR* A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY* CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL* DAMAGES, FOR ANY REASON WHATSOEVER.*******************************************************************************/
#include "PMBusSlave.h"
#include "PMBus.h"
#include "n32g003_i2c.h"
#include "n32g003.h"
#include <string.h>volatile struct STATUS_REGS StatusRegs;//This array contains all of the PMBus command bytes (according to the PMBus spec)
//indexed by the command indeces defined in PMBus.h
/////////////// The last three commmands are the new added ones/////////////////
/*
const unsigned char PMBus_Commands[123] = {0x00, // dummy byte0x19, 0x78, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x98,0x79, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,0x93, 0x94, 0x95, 0x96, 0x97, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,0xA7, 0xA8, 0xA9, 0x13, 0x14, 0x17, 0x18, 0x3, 0x11, 0x12, 0x15, 0x16,0x0, 0x1, 0x2, 0x4, 0x10, 0x20, 0x3A, 0x3D, 0x41, 0x45, 0x47, 0x49,0x4C, 0x50, 0x54, 0x56, 0x5A, 0x5C, 0x63, 0x69, 0x21, 0x22, 0x23, 0x24,0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x31, 0x32, 0x33, 0x35, 0x36, 0x37,0x38, 0x39, 0x3B, 0x3C, 0x3E, 0x3F, 0x40, 0x42, 0x43, 0x44, 0x46, 0x48,0x4A, 0x4B, 0x4F, 0x51, 0x52, 0x53, 0x55, 0x57, 0x58, 0x59, 0x5B, 0x5D,0x5E, 0x5F, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x68, 0x6A, 0x6B,0x99, 0x9A, 0x9B,
};
*///The CRC8 table needed to accelarate the calculation of CRC8
/*
static const uint8_t crc8_table[256] = {0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,0xD9,0xDE,0xD7,0xD0,0xC5,0xC2,0xCB,0xCC,0xE1,0xE6,0xEF,0xE8,0xFD,0xFA,0xF3,0xF4,0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3
};*///The CRC8 table needed to accelerate the calculation of CRC8
static const uint8_t crc8_table[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
};uint8_t CRC8_Calculate(const uint8_t *data, uint16_t length) {uint8_t crc = 0x00; //CRC8_INIT;while (length--) {crc = crc8_table[crc ^ *data++];}return crc;
}const uint8_t _MFR_ID[20] = {0x44, 0x53, 0x50, 0x4F, 0x57, 0x45, 0x52, 0xF7};// "DSPOWER";
const uint8_t _MFR_MODEL[20] = {0x4E, 0x50, 0x36, 0x30, 0x2D, 0x32, 0x32, 0x30, 0x57, 0x31, 0x31, 0x4D, 0x2D, 0x31, 0x43, 0xDD};//"NP60-220W11M-1C";
const uint8_t _MFR_REVISION[20] = {0x31, 0x2E, 0x30, 0xFD};//"1.0";static unsigned char slave_address;uint8_t PMBusSlave_ReceiveBuffer[4] = { 0, 0, 0, 0 };
uint8_t PMBusSlave_TransmitBuffer[20] = { 0, 0, 0, 0 };
uint16_t PMBusSlave_Index = 0;
uint16_t PMBusSlave_DummyCommand = 0;
volatile _iicSlave iicSlave;   // useIT for I2C
uint8_t PMBus_timeout = 0;
unsigned char block_len = 0;//used to save the length of the block data
unsigned char block_loop = 0;
static __IO uint32_t I2CTimeout;
uint16_t uI2C_error_cnt = 0;///////////external variables///////////
extern float pin;//defined in main.c
extern float p12_out;
extern float vin;
extern float iin;
//extern float v54;
//extern float i54;
extern float v12_out;
extern float i12_out;
extern float i12_warn_out;extern signed char TEMP_OUT;//defined in adc.c
//extern uint16_t IOUT;
//extern uint16_t VOUT;////////////USER CODE////////////
//Example variables, should be changed by user to be application specific
#warning    "User should declare application specific PMBus registers or variables."
//initial values
unsigned char Temperature = 0x12;   //STATUS_TEMPERATURE command (R byte)
unsigned char Default_Code = 0;     //STORE_DEFAULT_CODE command (W byte)
unsigned char Operation = 0x34;     //OPERATION command (R/W byte)
unsigned int Status_Word = 0x5678;  //STATUS_WORD command (R word)
unsigned char Status_Byte = 0x00;   //STATUS_BYTE command (R byte)
unsigned char Status_Cml = 0x00;    //STATUS_CML command (R byte)
unsigned int Vout_Command = 0x90AB; //VOUT_COMMAND command (R/W word)
unsigned int ot_warn_limit = 0xEA80;  //80C, linear11 format////////////END USER CODE//////////
// Defines
//
#define MAX_BUFFER_SIZE     0x10
#define I2C_NUMBYTES        0x10void I2C_ResetBusy(void);
void CommTimeOut_CallBack(ErrCode_t errcode);//
// Globals
//
unsigned char PMBusSlave_Command = 0, PMBusSlave_CommandType = 0;/**
*\*\name    TIM6_IRQHandler.
*\*\fun     This function handles TIM6 global interrupt request.
*\*\param   none
*\*\return  none
**/
void TIM6_IRQHandler(void)
{if (TIM_Interrupt_Status_Get(TIM6, TIM_INT_UPDATE) != RESET){TIM_Interrupt_Status_Clear(TIM6, TIM_INT_UPDATE);if (++PMBus_timeout >= PMBUS_TIME_OUT){PMBus_timeout = PMBUS_TIME_OUT;}}
}//Start TIM6
void StartCpuTimer0(void)
{TIM6->CNT = 0;TIM6->CTRL1 |= TIM_CTRL1_CNTEN;
}//Disable TIM6 and clear the counter
void StopCpuTimer0(void)
{TIM6->CNT = 0;TIM6->CTRL1 &= (uint32_t)(~((uint32_t)TIM_CTRL1_CNTEN));//disable timerPMBus_timeout = 0;
}//Enable the TIM6 auto reload period, that is, the shadow register
void ReloadCpuTimer0(void)
{TIM6->CTRL1 |= TIM_CTRL1_ARPEN;
}/*
0x20, use the default format
mode: 000
parameter: -9, 10111
*/
void PMBus_Cmd_Vout_Mode(void)
{/*uint8_t temp, u8VoutMode;//temp = pmb->rxBuffer[0];VoutMode.bit.Parameter = -9;VoutMode.bit.Mode = 0;*///pmb->txBuffer[0] = VoutMode.all;      // Sends low byte first//pmb->txLength = 1;// PEC calculated//pmb->state = PMB_STATE_WRITE_READ_REQUESTED;
}/**
@name: PMBus_Read_Vin
@description: 0x88: read the input voltage, convert the real voltage to Linear11 format
@input: vin, the actual input voltage(V)
@output: none
**/
void PMBus_Read_Vin(float vin)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -1;//EXPI to make sure the accuracy//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(vin * 2)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;          // Sends upper byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;         // And then sends lower byte//////////////////////////Linear16 is NOT used////////////////////////////////////////////////////////////    //int16_t exponent;//    //int16_t i16var;//    int16_t mantissa;//    //exponent = -6;//0x1A, mode = 000, linear format, N = -6//    mantissa = (int16_t)(((int16_t)(vin * 64)) & 0xFFFF);  // Get the mantissa in the LINEAR16, 0xFFFF//    PMBusSlave_TransmitBuffer[0] = mantissa % 256;      // Sends low byte first//    PMBusSlave_TransmitBuffer[1] = mantissa >> 8;       // And then sends high byte////////////////////////////////////////////////////////////////////////////////////////////////////////
}/**
@name: PMBus_Read_Iin
@description: 0x89, read the input current, convert the real voltage to Linear11 format
@input: iin, the actual input current(A)
@output: none
**/
void PMBus_Read_Iin(float iin)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -7;//EXPI to make sure the accuracy // 0.0078125 A//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(iin * 128)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;          // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;         // And then sends high byte
}/**
@name: PMBus_Read_Pin
@description: 0x97, read the input power, convert the real voltage to Linear11 format
@input: pin, the actual input power(W)
@output: none
**/
void PMBus_Read_Pin(float pin)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -2;//EXPI to make sure the accuracy // 0.25 W//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(pin * 4)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;       // And then sends high byte
}/**
@name: PMBus_Read_Pout
@description: 0x96, read the output power, convert the real voltage to Linear11 format
@input: pin, the actual output power(W)
@output: none
**/
void PMBus_Read_Pout(float pout)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -2;//EXPI to make sure the accuracy // 0.25 W//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(pout * 4)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;       // And then sends high byte
}/**
@name: PMBus_Read_V54_Vout
@description: 0x8B: read the output voltage of 12V, convert the real voltage to Linear16 format
@input: vout, the actual output voltage(V)
@output: none
**/
void PMBus_Read_V12_Vout(float vout)
{//int16_t exponent;//int16_t i16var;int16_t mantissa;//exponent = -9;//0x17, mode = 000, linear format, N = -9//exponent = -11;//0x15, mode = 000, linear format, N = -11mantissa = (int16_t)(((int16_t)(vout * 512)) & 0xFFFF);  // Get the mantissa in the LINEAR16, 0xFFFF//PMBusSlave_TransmitBuffer[0] = mantissa % 256;      // Sends low byte firstPMBusSlave_TransmitBuffer[0] = mantissa & 0x00FF;PMBusSlave_TransmitBuffer[1] = mantissa >> 8;     // And then sends high byte
}/**
@name: PMBus_Read_V54_Vout
@description: 0x8B: read the output voltage of 54V, convert the real voltage to Linear16 format
@input: vout, the actual output voltage(V)
@output: none
**/
void PMBus_Read_V54_Vout(float vout)
{// LINEAR16 is used, for example as the following:// X = mantissa * 2^N//int16_t exponent;//int16_t i16var;int16_t mantissa;//exponent = -9;//0x17, mode = 000, linear format, N = -9mantissa = (int16_t)(((int16_t)(vout * 512)) & 0xFFFF);  // Get the mantissa in the LINEAR16, 0xFFFF//i16var = (exponent << 16) + mantissa; // Test OK//i16var = mantissa; // Test OK//the result//PMBusSlave_TransmitBuffer[0] = mantissa % 256;      // Sends low byte firstPMBusSlave_TransmitBuffer[0] = mantissa & 0x00FF;PMBusSlave_TransmitBuffer[1] = mantissa >> 8;       // And then sends high byte
}/**
@name: PMBus_Read_V54_Iout
@description: 0x8C, read the output current of 12V, 54V: 9A, 12V: 16.8A
@input: iout, the actual output current(A)
@output: none
**/
void PMBus_Read_V54_Iout(float iout)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -7;//EXPI to make sure the accuracy // 0.0078125 A//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(iout * 128)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;         // And then sends high byte
}/**
@name: PMBus_Read_V12_Iout
@description: 0x8C, read the output current of 12V, 54V: 9A, 12V: 16.8A
@input: iout, the actual output current(A)
@output: none
**/
void PMBus_Read_V12_Iout(float iout)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -7;//EXPI to make sure the accuracy // 0.0078125 A//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(iout * 128)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;       // And then sends high byte
}/**
@name: PMBus_Read_Sec_Temp
@description: 0x8F, read the secondary side temperature
@input: tmp, the actual temperature(C)
@output: none
**/
void PMBus_Read_Sec_Temp(signed char tmp)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;if (tmp >= 0){exponent = -3;//11100,EXPI to make sure the accuracy}else{exponent = -4;//11010}//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11if (tmp >= 0){mantissa = (int16_t)(((int16_t)(tmp * 8)) & 0x7FF);  // Get the mantissa in the LINEAR11}else{//for example, -35C, mantissa = -35*16 = -560 & 0x7FF = 101 1101 0000//since the exponent = -4, that is, 11100, so the final result is below://11100 101 1101 0000, hex format: 0xE5D0mantissa = (int16_t)(((int16_t)(tmp * 16)) & 0x7FF);}i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;       // And then sends high byte
}/**
@name: PMBus_Read_V12_Iout_OC_Warn
@description: 0x4A, read the 12V output over current warning threshold value
@input: iout, the actual output current(A)
@output: none
**/
void PMBus_Read_V12_Iout_OC_Warn(float iout)
{// LINEAR11 is used, for example as the following:// X = mantissa * 2^Nint16_t exponent, mantissa, i16var;exponent = -7;//EXPI to make sure the accuracy // 0.0078125 A//mantissa = (int16_t)(iout & 0x7FF);   // Get the mantissa in the LINEAR11mantissa = (int16_t)(((int16_t)(iout * 128)) & 0x7FF);  // Get the mantissa in the LINEAR11i16var = (exponent << 11) + mantissa;       // Test OK//PMBusSlave_TransmitBuffer[0] = i16var % 256;        // Sends low byte firstPMBusSlave_TransmitBuffer[0] = i16var & 0x00FF;PMBusSlave_TransmitBuffer[1] = i16var >> 8;       // And then sends high byte
}#if PEC
/*
// The slave reponds to the master(read) using PEC
tmp[0] = (slave_addr << 1);     // slave address(write)
tmp[1] = reg;                   // register
tmp[2] = (slave_addr << 1) | 1; // slave address(read)
crc = _psu_crc8(0, tmp, 3);     // data
crc = _psu_crc8(crc, data, 2);  // data
*/
/***************************************************************************//*** @brief   Calculate the Packet Error Checking byte.* @param   PMBusSlave_CRC Initial value.* @param   PMBusSlave_Poly The polynomial to use for the calculation.* @param   *PMBusSlave_PMsg Pointer to the bytes from the PMBus transaction.* @param   PMBusSlave_MsgSize Number of bytes in the last transaction.* @return  The PEC byte.******************************************************************************/
static unsigned short PMBusSlave_Crc8MakeBitwise(unsigned char PMBusSlave_CRC, unsigned char PMBusSlave_Poly, unsigned char* PMBusSlave_Pmsg, unsigned int PMBusSlave_MsgSize)
{unsigned int i, j, carry;unsigned char msg;PMBusSlave_CRC = *PMBusSlave_Pmsg++;            // first byte loaded in "crc"for (i = 0 ; i < PMBusSlave_MsgSize - 1 ; i ++){msg = *PMBusSlave_Pmsg++;                   // next byte loaded in "msg"for (j = 0 ; j < 8 ; j++){carry = PMBusSlave_CRC & 0x80;                          // check if MSB=1PMBusSlave_CRC = (PMBusSlave_CRC << 1) | (msg >> 7);    // Shift 1 bit of next byte into crcif (carry) PMBusSlave_CRC ^= PMBusSlave_Poly;           // If MSB = 1, perform XORmsg <<= 1;                                              // Shift left msg byte by 1msg &= 0x00FF;}}// The previous loop computes the CRC of the input bit stream. To this,// 8 trailing zeros are padded and the CRC of the resultant value is// computed. This gives the final CRC of the input bit stream.for (j = 0 ; j < 8 ; j++){carry = PMBusSlave_CRC & 0x80;PMBusSlave_CRC <<= 1;if (carry) PMBusSlave_CRC ^= PMBusSlave_Poly;}PMBusSlave_CRC &= 0x00FF;   //We only want one byte (lower)return (PMBusSlave_CRC);
}/***************************************************************************//*** @brief   Calculate the Packet Error Checking byte.* @param   data: the data buffer to be calculated.* @param   data_len: data length of the buffer.* @return  The PEC byte.******************************************************************************/
static unsigned char CRC8(unsigned char* data, int data_len) {unsigned char data_in;unsigned char i = 0;unsigned char crc = 0x00; //initial valueunsigned char crc_poly = 0x07; //the polynomialwhile (data_len--) {data_in = *data++;crc = crc ^ data_in;for (i = 0; i < 8; i++) {if (crc & 0x80)//the bit 7 is 1 then we XOR the polynomial and then left shift one bit{crc = (crc << 1) ^ crc_poly;} else//directly left shift one bit{crc = crc << 1;}}}return (crc ^ 0x00);
}
#endif/***************************************************************************//*** @brief   Determine what type of PMBus command was received from the master.**          The function also prepares data in the transmit buffer to send to*          the master for supported READ and READ/WRITE commands. Users should modify*          the code to implement their application's supported PMBus commands.* @param   PMBusSlave_RxCommand The command byte received from the master.* @return  Command group of the received command.******************************************************************************/
unsigned char PMBusSlave_DecodeCommand(unsigned char PMBusSlave_RxCommand)
{//unsigned char i = 0;unsigned char result = 0;////////////USER CODE////////////
#warning "User should change code to implement their application's supported PMBus commands."switch (PMBusSlave_RxCommand)//should include all user supported commands{case CAPABILITY:PMBusSlave_TransmitBuffer[0] = 0x80;//PEC check, 100KHz, no SMBAlertresult = 1;break;case STATUS_TEMPERATURE://0x7DPMBusSlave_TransmitBuffer[0] = StatusRegs.StatusTemperature.all;result = 1;break;case STORE_DEFAULT_CODE:result = 0;break;case OPERATION://PMBusSlave_TransmitBuffer[0] = Operation;result = 0;break;case OT_WARN_LIMIT://0x51PMBusSlave_TransmitBuffer[0] = ot_warn_limit & 0x00FF;//upper byte firstPMBusSlave_TransmitBuffer[1] = ot_warn_limit >> 8;result = 2;break;case STATUS_VOUT://0x7APMBusSlave_TransmitBuffer[0] = StatusRegs.StatusVout.all;result = 1;break;case STATUS_IOUT://0x7BPMBusSlave_TransmitBuffer[0] = StatusRegs.StatusIout.all;result = 1;break;case STATUS_INPUT://0x7CPMBusSlave_TransmitBuffer[0] = StatusRegs.StatusInput.all;result = 1;break;case STATUS_BYTE://0x78PMBusSlave_TransmitBuffer[0] = StatusRegs.StatusWord.all;result = 1;break;case STATUS_CML://0x7EPMBusSlave_TransmitBuffer[0] = StatusRegs.StatusCml.all;result = 1;break;case STATUS_WORD://0x79PMBusSlave_TransmitBuffer[0] = StatusRegs.StatusWord.all & 0x00FF; //upper byte firstPMBusSlave_TransmitBuffer[1] = StatusRegs.StatusWord.all >> 8;//lower byteresult = 2;break;case STATUS_MFR_SPECIFIC://0x80, input typePMBusSlave_TransmitBuffer[0] = 0x01; //0x00: no input, 0x01: AC inputresult = 1;break;case IOUT_OC_WARN_LIMIT://0x4APMBus_Read_V12_Iout_OC_Warn(i12_warn_out);result = 2;break;case VOUT_COMMAND://NOT supported yetPMBusSlave_TransmitBuffer[0] = Vout_Command & 0x00FF;    //upper bytePMBusSlave_TransmitBuffer[1] = Vout_Command >> 8;//lower byteresult = 2;break;case PAGE:result = 0;break;//the implemented commandscase READ_VIN://0x88PMBus_Read_Vin(vin);result = 2;break;case READ_IIN://0x89PMBus_Read_Iin(iin);result = 2;break;case READ_PIN://0x97PMBus_Read_Pin(pin);result = 2;break;case READ_VOUT://0x8BPMBus_Read_V12_Vout(v12_out);result = 2;break;case READ_IOUT://0x8CPMBus_Read_V12_Iout(i12_out);result = 2;break;case READ_TEMPERATURE_3://secondary side temperaturePMBus_Read_Sec_Temp(TEMP_OUT);result = 2;break;case READ_POUT://0x96PMBus_Read_Pout(p12_out);result = 2;break;case VOUT_MODE://read only here supportedPMBusSlave_TransmitBuffer[0] = 0x17;//0 00 10111, absolute value, Linear16 mode, step value: 2^-9result = 1;break;///////////////////Manufacture related commands//////////////////case MFR_ID:/*block_len = strlen(_MFR_ID);for (block_loop = 0; block_loop < block_len; block_loop++){PMBusSlave_TransmitBuffer[block_loop] = _MFR_ID[block_loop];}*/result = 7;break;case MFR_MODEL:/*block_len = strlen(_MFR_MODEL);for (block_loop = 0; block_loop < block_len; block_loop++){PMBusSlave_TransmitBuffer[block_loop] = _MFR_MODEL[block_loop];}*/result = 15;break;case MFR_REVISION:/*block_len = strlen(_MFR_REVISION);for (block_loop = 0; block_loop < block_len; block_loop++){PMBusSlave_TransmitBuffer[block_loop] = _MFR_REVISION[block_loop];}*/result = 3;break;case MFR_VIN_MIN://maximum input voltagePMBusSlave_TransmitBuffer[0] = 0xD0;//lower byte, 90V, Linear11 format: 0xEAD0PMBusSlave_TransmitBuffer[1] = 0xEA;result = 2;break;case MFR_VIN_MAX://minimum input voltagePMBusSlave_TransmitBuffer[0] = 0x10;//lower byte, 264V, Linear11 format: 0xFA10PMBusSlave_TransmitBuffer[1] = 0xFA;result = 2;break;case MFR_IIN_MAX://maximum input currentPMBusSlave_TransmitBuffer[0] = 0xC0;//lower byte, 1.5A, Linear11 format: 0xC8C0PMBusSlave_TransmitBuffer[1] = 0xC8;result = 2;break;case MFR_PIN_MAX://maximum input powerPMBusSlave_TransmitBuffer[0] = 0x30;//lower byte, 70W, Linear11 format: 0xEA30PMBusSlave_TransmitBuffer[1] = 0xEA;result = 2;break;case MFR_VOUT_MAX://maximum output voltagePMBusSlave_TransmitBuffer[0] = 0xCC;//lower byte, 11.2V, Linear11 format: 0xD2CCPMBusSlave_TransmitBuffer[1] = 0xD2;result = 2;break;case MFR_VOUT_MIN://minimum output voltagePMBusSlave_TransmitBuffer[0] = 0xB3;//lower byte, 10.8V, Linear11 format: 0xD2B3PMBusSlave_TransmitBuffer[1] = 0xD2;result = 2;break;case MFR_IOUT_MAX://maximum output currentPMBusSlave_TransmitBuffer[0] = 0xC0;//lower byte, 5.5A, Linear11 format: 0xCAC0PMBusSlave_TransmitBuffer[1] = 0xCA;result = 2;break;case MFR_POUT_MAX://maximum output powerPMBusSlave_TransmitBuffer[0] = 0xF0;//lower byte, 62W, Linear11 format: 0xE9F0PMBusSlave_TransmitBuffer[1] = 0xE9;result = 2;break;case MFR_TAMBIENT_MAX://maximum work temperaturePMBusSlave_TransmitBuffer[0] = 0x90;//lower byte, 50C, Linear11 format: 0xE990PMBusSlave_TransmitBuffer[1] = 0xE9;result = 2;break;case MFR_TAMBIENT_MIN://minimum work temperaturePMBusSlave_TransmitBuffer[0] = 0xC0;//lower byte, -20C, Linear11 format: 0xE6C0PMBusSlave_TransmitBuffer[1] = 0xE6;result = 2;break;case PMBUS_REVISION://PMBus versionPMBusSlave_TransmitBuffer[0] = 0x11;//V1.1result = 1;break;case 0xAA://for test purposeresult = 2;PMBusSlave_TransmitBuffer[0] = uI2C_error_cnt & 0x00FF;PMBusSlave_TransmitBuffer[1] = uI2C_error_cnt >> 8;break;default://PMBusSlave_DummyCommand = 1;    //command not supported by this slaveresult = 0;break;}return result;
}/*** =======================================================================================* =======================================================================================*/void I2C_ResetBusy(void)
{I2C->CTRL1 |= 0x8000;  // Reset Busy__NOP();__NOP();__NOP();__NOP();__NOP();I2C->CTRL1 &= ~0x8000;
}/**
*\*\name    Delay.
*\*\fun     system ms delay function.
*\*\param   nCount
*\*\return  none
**/
void Delay(uint32_t nCount)
{uint32_t tcnt;while (nCount--){tcnt = 48000 / 5;//48M/48000 = 1000Hz, 1ms, one instruction needs about 5 system clockswhile (tcnt--) {;} //instruction count per milli-second}
}/**
*\*\name    I2C_NVIC_Config.
*\*\fun     NVIC Configuration.
*\*\param   none
*\*\return  result
**/
void I2C_NVIC_Config(void)
{NVIC_InitType NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel           = I2C_EV_IRQn;NVIC_InitStructure.NVIC_IRQChannelPriority   = 0;NVIC_InitStructure.NVIC_IRQChannelCmd        = ENABLE;NVIC_Initializes(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel           = I2C_ER_IRQn; /* test err */NVIC_InitStructure.NVIC_IRQChannelPriority   = 1;NVIC_InitStructure.NVIC_IRQChannelCmd        = DISABLE;NVIC_Initializes(&NVIC_InitStructure);/*NVIC_InitType NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel    = I2C2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPriority = 0x01;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel++;  // I2Cx_ER_IRQnNVIC_Init(&NVIC_InitStructure);I2C_ConfigInt(I2C2, I2C_INT_EVENT | I2C_INT_BUF | I2C_INT_ERR, NVIC_InitStructure.NVIC_IRQChannelCmd);*/
}/**
*@name: I2C_Config
*@description: for the main communication with the upper machine
*@input: I2CSlave_OwnAddress: the slave device address
*@output: none
**/
void I2C_Config(uint16_t I2CSlave_OwnAddress)
{I2C_InitType I2C_InitStructure;GPIO_InitType i2c2_gpio;RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_I2C);RCC_APB_Peripheral_Clock_Enable(RCC_APB_PERIPH_IOPA | RCC_APB_PERIPH_AFIO);GPIO_Structure_Initialize(&i2c2_gpio);//PA4 -- SCL; PA5 -- SDAi2c2_gpio.Pin        = I2C_SCL_PIN | I2C_SDA_PIN;i2c2_gpio.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;i2c2_gpio.GPIO_Mode  = GPIO_MODE_AF_OD;//alternate open-draini2c2_gpio.GPIO_Alternate = GPIO_AF_I2C;GPIO_Peripheral_Initialize(GPIOy, &i2c2_gpio);I2C_Reset(I2C);I2C_Initializes_Structure(&I2C_InitStructure);I2C_ResetBusy();I2C_InitStructure.OwnAddr1 = I2CSlave_OwnAddress;I2C_InitStructure.DutyCycle   = I2C_SMDUTYCYCLE_1;I2C_InitStructure.AckEnable   = I2C_ACKEN;I2C_InitStructure.AddrMode    = I2C_ADDR_MODE_7BIT;I2C_InitStructure.ClkSpeed    = 100000;  // 100Kbits/sI2C_Initializes(I2C, &I2C_InitStructure);// Initial and Enable I2Cx/* int enable */I2C_Interrupts_Enable(I2C, I2C_INT_EVENT | I2C_INT_BUF | I2C_INT_ERR);I2C_NVIC_Config();// #define I2Cx_UseITI2C_ON(I2C);//power on the I2C module
}/***************************************************************************//*** @brief   Initialize I2C module in slave mode.* @param   I2CSlave_OwnAddress The slave device's own address.* @return  None******************************************************************************/
void I2CSlave_Init(uint16_t I2CSlave_OwnAddress)
{I2C_Config(I2CSlave_OwnAddress);//I2C_NVIC_Config();//I2C_ResetBusy();
}/***************************************************************************//*** @brief   Configure the N32G031C8 device as a PMBus slave.* @param   PMBusSlave_DeviceAddress The slave device's own address.* @return  None******************************************************************************/
#warning "Change the GPIOs used for Alert and Control lines to match the desired GPIOs for the application."
void PMBusSlave_Init(unsigned char PMBusSlave_DeviceAddress)
{//StatusRegs.StatusWord.all = 0; //Clear status bits for the status registers we are using//StatusRegs.StatusCml.all = 0;//StatusRegs.StatusVout.all = 0;//StatusRegs.StatusIout.all = 0;//StatusRegs.StatusInput.all = 0;//StatusRegs.StatusTemperature.all = 0;slave_address = PMBusSlave_DeviceAddress;I2CTimeout = I2CT_LONG_TIMEOUT * 1000;I2CSlave_Init(slave_address);     // Initialize USCI module
}/***************************************************************************//*** @brief   Handles timeouts. Triggered if BYTESENT held low > 2ms.*          Need to reset the I2C* @param   None* @return  None******************************************************************************/#if PEC
unsigned char PMBusSlave_CrcMsgSize = 0;
//unsigned char PMBusSlave_CrcMsg[5];
unsigned char PMBusSlave_CrcMsg[20];//the maximum data length is 18
unsigned char PMBusSlave_CrcMasterGenerated = 0;
unsigned char PMBusSlave_CrcSlaveGenerated = 0;
//PMBusSlave_CrcMsg[0] = slave_address << 1;
#endifstatic unsigned char PMBusMaster_RWFlag = 1;//0: write, 1: read/*** @brief  I2C interrupt callback function* @param I2Cx I2C*/
void I2C_EV_IRQHandler(void)
{uint8_t timeout_flag = 0;uint32_t last_event = I2C_Last_Event_Get(I2C);
#if PEC//unsigned char PMBusSlave_CrcMsgSize = 0;//unsigned char PMBusSlave_CrcMsg[5];//unsigned char PMBusSlave_CrcMasterGenerated = 0;//unsigned char PMBusSlave_CrcSlaveGenerated = 0;//PMBusSlave_CrcMsg[0] = slave_address << 1;PMBusSlave_CrcMsg[0] = slave_address;
#endifStartCpuTimer0(); // each time the interrupt is triggered, we start the timer to check the timeout event.if ((last_event & I2C_ROLE_MASTER) != I2C_ROLE_MASTER){switch (last_event) {/* Slave Tx */case I2C_EVT_SLAVE_SEND_ADDR_MATCHED:  // 0x00060082.EV1.EV3_1 (ADDRF TXDATE), the slave address(read) sent by the master is matched, then we can send out data to the master.iicSlave.ptr2 = 0;iicSlave.t_data_len = 0;PMBusMaster_RWFlag = 1;StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)PMBusSlave_CommandType = PMBusSlave_DecodeCommand(PMBusSlave_Command);//return length: 0, 1, 2if (PMBusSlave_CommandType > 0)//send/receive according to command{switch(PMBusSlave_CommandType){case READ_BYTE_LEN:PMBusSlave_CrcMsg[1] = PMBusSlave_Command;              // store first rx bytePMBusSlave_CrcMsg[2] = slave_address + 1;				// store slave address + R/W=1PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0];    // store tx byte 1PMBusSlave_CrcMsgSize = 4;PMBusSlave_CrcSlaveGenerated = CRC8_Calculate(PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);//PMBusSlave_CrcSlaveGenerated = CRC8(PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);                            //iicSlave.t_data_len = 2;PMBusSlave_TransmitBuffer[1] = PMBusSlave_CrcSlaveGenerated;iicSlave.t_data_len = PMBusSlave_CommandType;I2C_Data_Send(I2C, PMBusSlave_TransmitBuffer[iicSlave.ptr2++]);//send the first bytebreak;case READ_WORD_LEN:PMBusSlave_CrcMsg[1] = PMBusSlave_Command;              // store first rx byte       PMBusSlave_CrcMsg[2] = slave_address + 1;				// store slave address + R/W=1PMBusSlave_CrcMsg[3] = PMBusSlave_TransmitBuffer[0];    // store tx byte 1PMBusSlave_CrcMsg[4] = PMBusSlave_TransmitBuffer[1];    // store tx byte 2PMBusSlave_CrcMsgSize = 5;PMBusSlave_CrcSlaveGenerated = CRC8_Calculate(PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);//PMBusSlave_CrcSlaveGenerated = CRC8(PMBusSlave_CrcMsg, PMBusSlave_CrcMsgSize);                            //iicSlave.t_data_len = 3;PMBusSlave_TransmitBuffer[2] = PMBusSlave_CrcSlaveGenerated;iicSlave.t_data_len = PMBusSlave_CommandType;I2C_Data_Send(I2C, PMBusSlave_TransmitBuffer[iicSlave.ptr2++]);//send the first bytebreak;case READ_MFR_ID_LEN://const value							//PMBusSlave_TransmitBuffer[READ_MFR_ID_LEN] = 0xF7;//the last byte, i.e, the CRC byte//iicSlave.t_data_len = PMBusSlave_CommandType;I2C_Data_Send(I2C, _MFR_ID[iicSlave.ptr2++]);//send the first bytebreak;case READ_MFR_MODEL_LEN://PMBusSlave_TransmitBuffer[READ_MFR_MODEL_LEN] = 0xDD;//const valueI2C_Data_Send(I2C, _MFR_MODEL[iicSlave.ptr2++]);//send the first bytebreak;case READ_MFR_REV_LEN:							//PMBusSlave_TransmitBuffer[READ_MFR_REV_LEN] = 0xFD;//the last byte, i.e, the CRC byteI2C_Data_Send(I2C, _MFR_REVISION[iicSlave.ptr2++]);//send the first bytebreak;default:break;}}else{                    I2C_Data_Send(I2C,0xFF);iicSlave.ptr2 = 0;PMBusSlave_DummyCommand = 0;}break;//The master wants to read the next byte from slave devicecase I2C_EVT_SLAVE_DATA_SENDING:       // 0x00060080.EV3 (TXDATE)//I2C_Flag_Status_Clear(I2C, I2C_FLAG_TXDATE);StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)break;case I2C_EVT_SLAVE_DATA_SENDED:        // 0x00060084.EV3_2 (TXDATE BSF)StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)if (iicSlave.ptr2 < IIC_Slave_BufSize)//IIC_Slave_BufSize{switch(PMBusSlave_CommandType){case READ_BYTE_LEN:case READ_WORD_LEN:I2C_Data_Send(I2C, PMBusSlave_TransmitBuffer[iicSlave.ptr2++]); //send the next data byte and clear TXDATE flagbreak;case READ_MFR_ID_LEN:I2C_Data_Send(I2C, _MFR_ID[iicSlave.ptr2++]);break;case READ_MFR_MODEL_LEN:I2C_Data_Send(I2C, _MFR_MODEL[iicSlave.ptr2++]);break;case READ_MFR_REV_LEN:I2C_Data_Send(I2C, _MFR_REVISION[iicSlave.ptr2++]);break;default:iicSlave.ptr2 = 0;I2C_Data_Send(I2C, 0xFF);  //clear TXDATE flagbreak;}}                else{iicSlave.ptr2 = 0;I2C_Data_Send(I2C, 0xFF);  //clear TXDATE flag}break;/* Slave Rx *///The slave address(write) sent by the master is matched, here we are prepare for the coming data.case I2C_EVT_SLAVE_RECV_ADDR_MATCHED:  // 0x00020002.EV1 (ADDRF),StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)iicSlave.ptr = 0;      //Clear the receive pointer and transmit pointeriicSlave.ptr2 = 0;PMBusMaster_RWFlag = 0;//write modePMBusSlave_Command = I2C_Data_Recv(I2C);break;//The slave has received data from the master and all here we need to do is to save all of them.case I2C_EVT_SLAVE_DATA_RECVD:  // 0x00020040.EV2 (RXDATNE)StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)if (iicSlave.ptr < IIC_Slave_BufSize){iicSlave.buf[iicSlave.ptr++] = I2C_Data_Recv(I2C);  //receive data and clear RXDATNE flag//iicSlave2.bufSt                = 1;   //data is updating now...}else{I2C_Data_Recv(I2C);  // clear RXDATNE flag}PMBusSlave_Command = iicSlave.buf[0];break;//The master sends out a STOP condition to end the communication and release the BUS.//The STOPF bit is not set after a NACK receptioncase I2C_EVT_SLAVE_STOP_RECVD:   // 0x00000010.EV4 (STOPF)StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)I2C_ON(I2C);           // clear STOPFif(PMBusSlave_Command == CLEAR_FAULTS){					StatusRegs.StatusWord.all = 0;StatusRegs.StatusCml.all = 0;StatusRegs.StatusVout.all = 0;StatusRegs.StatusIout.all = 0;StatusRegs.StatusInput.all = 0;StatusRegs.StatusTemperature.all = 0;}iicSlave.ptr2 = 0;//send pointeriicSlave.ptr = 0;//receive pointerPMBusMaster_RWFlag = 0;//write mode by defaultbreak;case I2C_EVT_SLAVE_ACK_MISS://I2C_ON(I2C);StopCpuTimer0();       //No timeout, so stop the timerReloadCpuTimer0();     //Reload the period value (35 ms timeout)I2C_Flag_Status_Clear(I2C, I2C_FLAG_ACKFAIL);break;default:I2C_ON(I2C);StopCpuTimer0();           //No timeout, so stop the timerReloadCpuTimer0();         //Reload the period value (35 ms timeout)                CommTimeOut_CallBack(SLAVE_UNKNOW);//PMBusMaster_RWFlag = 1;//write mode by defaultbreak;}}if ((last_event & 0x00000100) == 0x00000100){CommTimeOut_CallBack(SLAVE_UNKNOW);}/*if (timeout_flag){if ((I2CTimeout--) == 0){CommTimeOut_CallBack(SLAVE_UNKNOW);}}else{I2CTimeout = I2CT_LONG_TIMEOUT;}*///EV3_2: When the master sends a NACK in order to tell slave that data transmission//shall end (before sending the STOP condition). In this case slave has to stop sending//data bytes and expect a Stop condition on the bus./*if (last_event == I2C_EVT_SLAVE_ACK_MISS){I2C_ClrFlag(I2C2, I2C_FLAG_ACKFAIL);if (iicSlave.ptr2 != 0){//flag_slave_send_finish = 1;}else{}}*///StopCpuTimer0();                //No timeout, so stop the timer//ReloadCpuTimer0();              //Reload the period value (35 ms timeout)
}/**
*\*\name    PMBus_Error_Detect.
*\*\fun     check whether the I2C module is timeout.
*\*\param   none
*\*\return  none
**/
void PMBus_Error_Detect(void)
{if (PMBus_timeout >= PMBUS_TIME_OUT){PMBus_timeout = 0;CommTimeOut_CallBack(SLAVE_UNKNOW);}
}/**
*\*\name    I2C_ER_IRQHandler.
*\*\fun     i2c error interrupt service function.
*\*\param   none
*\*\return  none
**/
void I2C_ER_IRQHandler(void)
{uint32_t last_event;last_event = I2C_Last_Event_Get(I2C);/*EV3_2: When the master sends a NACK in order to tell slave that data transmissionshall end (before sending the STOP condition). In this case slave has to stop sendingdata bytes and expect a Stop condition on the bus.*/if (last_event == I2C_EVT_SLAVE_ACK_MISS){I2C_Flag_Status_Clear(I2C, I2C_FLAG_ACKFAIL);if (iicSlave.ptr2 != 0) /*slave send the last data and recv NACK  */{//flag_slave_send_finish = 1;}else /*not the last data recv nack, send fail */{}}
}/**
*\*\name    SystemNVICReset.
*\*\fun     System software reset.
*\*\param   none
*\*\return  none
**/
void SystemNVICReset(void)
{__disable_irq();//log_info("***** NVIC system reset! *****\r\n");NVIC_SystemReset();
}/**
*\*\name    IIC_RCCReset.
*\*\fun     RCC clock reset.
*\*\param   none
*\*\return  none
**/
void IIC_RCCReset(void)
{RCC_Peripheral_Reset(RCC_RST_I2CRST);RCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_I2C);GPIOy->PMODE &= 0xFFFFF0FF; /*input *///RCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_AFIO);//RCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_IOPA);RCC_Peripheral_Reset(RCC_RST_I2CRST);PMBusSlave_Init(I2C_SLAVE_ADDR);/*if (RCC_RESET_Flag >= 3){SystemNVICReset();}else{RCC_RESET_Flag++;RCC_Peripheral_Reset(RCC_RST_I2CRST);RCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_I2C);GPIOx->PMODE &= 0xFFFFF0FF; //inputRCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_AFIO);RCC_APB_Peripheral_Clock_Disable(RCC_APB_PERIPH_IOPA);RCC_Peripheral_Reset(RCC_RST_I2CRST);//log_info("***** IIC module by RCC reset! *****\r\n");i2c_slave_init();}*/
}/**
*\*\name    IIC_SWReset.
*\*\fun     I2c software reset.
*\*\param   none
*\*\return  none
**/
void IIC_SWReset(void)
{GPIO_InitType i2cx_gpio;GPIO_Structure_Initialize(&i2cx_gpio);i2cx_gpio.Pin            = I2C_SCL_PIN | I2C_SDA_PIN;i2cx_gpio.GPIO_Slew_Rate = GPIO_SLEW_RATE_FAST;i2cx_gpio.GPIO_Mode      = GPIO_MODE_OUT_OD;GPIO_Peripheral_Initialize(GPIOy, &i2cx_gpio);//I2CTimeout = I2CT_LONG_TIMEOUT;for (;;){if ((I2C_SCL_PIN | I2C_SDA_PIN) == (GPIOy->PID & (I2C_SCL_PIN | I2C_SDA_PIN))){I2C->CTRL1 |= 0x8000;__NOP();__NOP();__NOP();__NOP();__NOP();I2C->CTRL1 &= ~0x8000;//log_info("***** IIC module self reset! *****\r\n");break;}else{IIC_RCCReset();//if ((I2CTimeout--) == 0)//{//IIC_RCCReset();//}}}
}/**
*\*\name    CommTimeOut_CallBack.
*\*\fun     Callback function.
*\*\param   none
*\*\return  none
**/
void CommTimeOut_CallBack(ErrCode_t errcode)
{//log_info("...ErrCode:%d\r\n", errcode);#if (COMM_RECOVER_MODE == MODULE_SELF_RESET)if(++uI2C_error_cnt >= 65530){uI2C_error_cnt = 0;}IIC_RCCReset();//IIC_SWReset();
#elif (COMM_RECOVER_MODE == MODULE_RCC_RESET)IIC_RCCReset();
#elif (COMM_RECOVER_MODE == SYSTEM_NVIC_RESET)SystemNVICReset();
#endif
}

PMBusSlave.h

/*******************************************************************************Filename:       PMBusSlave.hCopyright 2025 ASTO, Inc.*******************************************************************************/
#ifndef PMBUSSLAVE_H_
#define PMBUSSLAVE_H_#include "n32g003.h"//
// I2C GPIO pins
//
//#define I2C_SLAVE_ADDR      0x6AU  // I2C Slave Address
//#define GPIO_AF_I2C 		GPIO_AF6_I2C1
#define I2C_SCL_PIN 		GPIO_PIN_4	// GPIO number for I2C SDAA
#define I2C_SDA_PIN 		GPIO_PIN_5	// GPIO number for I2C SCLA
#define GPIOy        		GPIOA
#define GPIO_AF_I2C  		GPIO_AF6_I2C
#define I2C_SLAVE_ADDR  	(0x21<<1)
//#define I2C_SLAVE_ADDR  	(0x21)#define BUFFER_SIZE  		15
#define IIC_Slave_BufSize 	20//the package size is 32
#define	PMBUS_TIME_OUT		35//typically 35 milli-seconds
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
#define SCL_STATUS()        GPIO_Input_Pin_Data_Get(GPIOy, I2C_SCL_PIN)#define	READ_BYTE_LEN		1
#define	READ_WORD_LEN		2
#define	READ_MFR_ID_LEN		7
#define	READ_MFR_MODEL_LEN	15
#define	READ_MFR_REV_LEN	3typedef enum
{MASTER_OK = 0,MASTER_BUSY,MASTER_MODE,MASTER_TXMODE,MASTER_RXMODE,MASTER_SENDING,MASTER_SENDED,MASTER_RECVD,MASTER_BYTEF,MASTER_BUSERR,MASTER_UNKNOW,SLAVE_OK = 20,SLAVE_BUSY,SLAVE_MODE,SLAVE_BUSERR,SLAVE_UNKNOW,}ErrCode_t;#define MODULE_SELF_RESET       1
#define MODULE_RCC_RESET        2
#define SYSTEM_NVIC_RESET       3
#define COMM_RECOVER_MODE       1//0void I2CSlave_Init(uint16_t Own_Address);
void PMBusSlave_Init(unsigned char PMBusSlave_DeviceAddress);
unsigned char PMBusSlave_DecodeCommand(unsigned char PMBusSlave_RxCommand);
void PMBus_Error_Detect(void);static unsigned short PMBusSlave_Crc8MakeBitwise(
unsigned char PMBusSlave_CRC, unsigned char PMBusSlave_Poly,
unsigned char *PMBusSlave_Pmsg, unsigned int PMBusSlave_MsgSize);
void CommTimeOut_CallBack(ErrCode_t errcode);extern volatile struct STATUS_REGS StatusRegs;typedef struct {uint8_t buf[IIC_Slave_BufSize];  //  receive and send bufferuint16_t ptr;                    //  data receive pointeruint16_t ptr2;                   //  data transmit pointeruint8_t bufSt;                   uint8_t ptrSt;uint8_t t_data_len;				 //  transmit data length
} _iicSlave;#endif /*PMBUSSLAVE_H_*/

PMBus.h

/*******************************************************************************Filename:       PMBus.hCopyright 2025 ASTO, Inc.
*******************************************************************************/
#ifndef PMBUS_H
#define PMBUS_H#include "n32g003.h"
////////////USER CODE////////////
// The user should change the value of PEC to match their implementation's
// desired Packet Error Checking capability. This will cause all associated
// files to build either with or without PEC capability, accordingly.
#warning	"User should change PEC value to build with or without PEC capability."
#define PEC		1	//PEC 0: Disable Packet Error Checking//PEC 1: Enable Packet Error Checking
////////////END USER CODE////////					#if PEC#define PEC_PASS           	1#define PEC_FAIL           	0#define CRC8_POLY	   		0x07#define CRC8_INIT_REM      	0x0
#endif#define READBYTE      0
#define READWORD      2
#define WRITEBYTE     4
#define SENDBYTE      6
#define WRITEWORD     8
#define RWBYTE		  1
#define RWWORD		  3#define READBLOCK	  5//New customized group//GROUP#0
#define CAPABILITY                          0x19 //1
#define STATUS_BYTE                         0x78 //2
#define STATUS_VOUT                         0x7A //3
#define STATUS_IOUT                         0x7B //4
#define STATUS_INPUT                        0x7C //5
#define STATUS_TEMPERATURE                  0x7D //6
#define STATUS_CML                          0x7E //7
#define STATUS_OTHER                        8
#define STATUS_MFR_SPECIFIC                 0x80 //9
#define STATUS_FANS_1_2                     10
#define STATUS_FANS_3_4                     11
#define PMBUS_REVISION                      0x98 //12// GROUP #2 
#define STATUS_WORD                         0x79 //13
#define READ_VIN                            0x88 //14
#define READ_IIN                            0x89 //15
#define READ_VCAP                           16
#define READ_VOUT                           0x8B //17
#define READ_IOUT                           0x8C //18
#define READ_TEMPERATURE_1                  19	 //Primary side heat sink temperature by degree C
#define READ_TEMPERATURE_2                  20	 //Inlet ambient temperature by degree C
#define READ_TEMPERATURE_3                  0x8F //21 //Secondary side heat sink temperature by degree C
#define READ_FAN_SPEED_1                    22
#define READ_FAN_SPEED_2                    23
#define READ_FAN_SPEED_3                    24
#define READ_FAN_SPEED_4                    25
#define READ_DUTY_CYCLE                     26
#define READ_FREQUENCY                      27
#define READ_POUT                           0x96 //28
#define READ_PIN                            0x97 //29
#define MFR_VIN_MIN                         0xA0 //30
#define MFR_VIN_MAX                         0xA1 //31
#define MFR_IIN_MAX                         0xA2 //32
#define MFR_PIN_MAX                         0xA3 //33
#define MFR_VOUT_MIN                        0xA5 //34
#define MFR_VOUT_MAX                        0xA4 //35
#define MFR_IOUT_MAX                        0xA6 //36
#define MFR_POUT_MAX                        0xA7 //37
#define MFR_TAMBIENT_MAX                    0xA8 //38
#define MFR_TAMBIENT_MIN                    0xA9 //39// GROUP #4
#define STORE_DEFAULT_CODE                  40
#define RESTORE_DEFAULT_CODE                41
#define STORE_USER_CODE                     42
#define RESTORE_USER_CODE                   43// GROUP#6
#define CLEAR_FAULTS                        0x03 //44	//If the fault is still present after 03h is issued, the system needs to be able to report the fault and set the corresponding register.
#define STORE_DEFAULT_ALL                   45
#define RESTORE_DEFAULT_ALL                 46
#define STORE_USER_ALL                      47
#define RESTORE_USER_ALL                    48//GROUP#8//#define PAGE/ GENERAL CALL                  49//The old statement
#define PAGE                  				0x00 //49	//GENERAL CALL
#define OPERATION                           50	//switch machine flag,0x80: means power on (default),0x00: means power off.
#define ON_OFF_CONFIG                       51	//command code: 0x02, parameter, 0x15: means PSU on/off only by PS_ON# control(default).0x19: means PSU on/off only by PMBus control.
#define PHASE                               52
#define WRITE_PROTECT                       53
#define VOUT_MODE                           0x20 //54
#define FAN_CONFIG_1_2                      55
#define FAN_CONFIG_3_4                      56
#define VOUT_OV_FAULT_RESPONSE              57
#define VOUT_UV_FAULT_RESPONSE              58
#define IOUT_OC_FAULT_RESPONSE              59
#define IOUT_OC_LV_FAULT_RESPONSE           60
#define IOUT_UC_FAULT_RESPONSE              61
#define OT_FAULT_RESPONSE                   62
#define UT_FAULT_RESPONSE                   63
#define VIN_OV_FAULT_RESPONSE               64
#define VIN_UV_FAULT_RESPONSE               65
#define IIN_OC_FAULT_RESPONSE               66
#define TON_MAX_FAULT_RESPONSE              67
#define POUT_OP_FAULT_RESPONSE              68//GROUP#10 
#define VOUT_COMMAND                        0x21 //69
#define VOUT_TRIM                           70
#define VOUT_CAL_OFFSET                     71
#define VOUT_MAX                            72
#define VOUT_MARGIN_HIGH                    73
#define VOUT_MARGIN_LOW                     74
#define VOUT_TRANSITION_RATE                75
#define VOUT_DROOP                          76
#define VOUT_SCALE_LOOP                     77
#define VOUT_SCALE_MONITOR                  78
#define POUT_MAX                            79
#define MAX_DUTY                            80
#define FREQUENCY_SWITCH                    81
#define VIN_ON                              82
#define VIN_OFF                             83
#define INTERLEAVE                          84
#define IOUT_CAL_GAIN                       85
#define IOUT_CAL_OFFSET                     86
#define FAN_COMMAND_1                       87
#define FAN_COMMAND_2                       88
#define FAN_COMMAND_3                       89
#define FAN_COMMAND_4                       90
#define VOUT_OV_FAULT_LIMIT                 91
#define VOUT_OV_WARN_LIMIT                  92
#define VOUT_UV_WARN_LIMIT                  93
#define VOUT_UV_FAULT_LIMIT                 94
#define IOUT_OC_FAULT_LIMIT                 95
#define IOUT_OC_LV_FAULT_LIMIT              96
#define IOUT_OC_WARN_LIMIT                  0x4A //97
#define IOUT_UC_FAULT_LIMIT                 98
#define OT_FAULT_LIMIT                      99
#define OT_WARN_LIMIT                       0x51 //100
#define UT_WARN_LIMIT                       101
#define UT_FAULT_LIMIT                      102
#define VIN_OV_FAULT_LIMIT                  103
#define VIN_OV_WARN_LIMIT                   104
#define VIN_UV_WARN_LIMIT                   105
#define VIN_UV_FAULT_LIMIT                  106
#define IIN_OC_FAULT_LIMIT                  107
#define IIN_OC_WARN_LIMIT                   108
#define POWER_GOOD_ON                       109
#define POWER_GOOD_OFF                      110
#define TON_DELAY                           111
#define TON_RISE                            112
#define TON_MAX_FAULT_LIMIT                 113
#define TOFF_DELAY                          114
#define TOFF_FALL                           115
#define TOFF_MAX_WARN_LIMIT                 116
#define POUT_OP_FAULT_LIMIT                 117
#define POUT_OP_WARN_LIMIT                  118
#define PIN_OP_WARN_LIMIT                   119 
#define	MFR_ID								0x99 //120 //New added command
#define	MFR_MODEL							0x9A //121
#define	MFR_REVISION						0x9B //122/*
struct VOUT_MODE_BITS
{signed Parameter:5;						// 0 - 4unsigned Mode:3;        				// 5 - 7
};union VOUT_MODE_REG 
{unsigned char 					all;struct VOUT_MODE_BITS 	bit;
};
union VOUT_MODE_REG VoutMode;
*///----------------------------------------------------
//	Status registers
//	STATUS_BYTE and STATUS_WORD register bit definitions */
//lower byte
struct STATUS_LOWER_BITS {		// bitsuint16_t NONE_OF_THE_ABOVE:1;// 0uint16_t CML:1;        		// 1 A communications, memory or logic fault has occurreduint16_t TEMPERATURE:1;      // 2 A temperature fault or warning has occurreduint16_t VIN_UV:1;        	// 3 An input under voltage fault has occurreduint16_t IOUT_OC:1;        	// 4 An output over current fault has occureduint16_t VOUT_OV:1;        	// 5 An output over voltage fault has occureduint16_t OFF:1;        		// 6 This bit is asserted if the unit is not providing power to the output, regardless of the reason, including simply not being enabled.uint16_t BUSY:1;        		// 7
};
//upper byte
struct STATUS_UPPER_BITS {		// bitsuint16_t UNKNOWN:1;  		// 8uint16_t OTHER:1;        	// 9uint16_t FANS:1;        		// 10 A fan or airflow fault or warning has occurreduint16_t POWER_GOOD:1;       // 11 The POWER_GOOD signal, if present, is negateduint16_t MFR:1;        		// 12 A manufacturer specific fault or warning has occurred(PS ON or soft power off)uint16_t INPUT:1;        	// 13 An input voltage, input current, or input power fault or warning has occurreduint16_t IOUT_POUT:1;        // 14 An output current or output power fault or warning has occurreduint16_t VOUT:1;        		// 15 An output voltage fault or warning has occurred};union STATUS_BYTE_REG {uint16_t              all;struct STATUS_LOWER_BITS bit;
};struct STATUS_WORD_BITS
{uint16_t NONE_OF_THE_ABOVE:1;// 0uint16_t CML:1;        		// 1 A communications, memory or logic fault has occurreduint16_t TEMPERATURE:1;      // 2 A temperature fault or warning has occurreduint16_t VIN_UV:1;        	// 3 An input under voltage fault has occurreduint16_t IOUT_OC:1;        	// 4 An output over current fault has occureduint16_t VOUT_OV:1;        	// 5 An output over voltage fault has occureduint16_t OFF:1;        		// 6 This bit is asserted if the unit is not providing power to the output, regardless of the reason, including simply not being enabled.uint16_t BUSY:1;        		// 7uint16_t UNKNOWN:1;  		// 8uint16_t OTHER:1;        	// 9uint16_t FANS:1;        		// 10 A fan or airflow fault or warning has occurreduint16_t POWER_GOOD:1;       // 11 The POWER_GOOD signal, if present, is negateduint16_t MFR:1;        		// 12 A manufacturer specific fault or warning has occurred(PS ON or soft power off)uint16_t INPUT:1;        	// 13 An input voltage, input current, or input power fault or warning has occurreduint16_t IOUT_POUT:1;        // 14 An output current or output power fault or warning has occurreduint16_t VOUT:1;        		// 15 An output voltage fault or warning has occurred    
};//New defined struct
union STATUS_WORD_REG {uint16_t              all;      struct STATUS_WORD_BITS bit;
};/*
union STATUS_WORD_REG {uint16_t              all;union STATUS_BYTE_REG StatusByte;   struct STATUS_UPPER_BITS bit;
};
*///----------------------------------------------------
//	STATUS_VOUT register bit definitions */
struct STATUS_VOUT_BITS {		// bitsuint16_t POWER_ON_TRACKING_ERROR:1;	// 0uint16_t TOFF_MAX_WARNING:1;        	// 1uint16_t TON_MAX_WARNING:1;        	// 2uint16_t VOUT_MAX_WARNING:1;        	// 3 NOT USED, VOUT_MAX Warning (An attempt has been made to set the output voltage to value higher than allowed by the VOUT_MAX commanduint16_t VOUT_UV_FAULT:1;        	// 4 VOUT Under voltage Faultuint16_t VOUT_UV_WARNING:1;        	// 5 VOUT Under voltage Warninguint16_t VOUT_OV_WARNING:1;        	// 6 VOUT Over voltage Warninguint16_t VOUT_OV_FAULT:1;        	// 7 VOUT Over voltage Fault
};union STATUS_VOUT_REG {uint16_t              all;struct STATUS_VOUT_BITS bit;
};//----------------------------------------------------
//	STATUS_IOUT register bit definitions */
struct STATUS_IOUT_BITS {		// bitsuint16_t POUT_OP_WARNING:1;			// 0 POUT Overpower Warninguint16_t POUT_OP_FAULT:1;        	// 1 POUT Overpower Faultuint16_t IN_POWER_LIMITING_MODE:1;   // 2uint16_t CURRENT_SHARE_FAULT:1;      // 3uint16_t IOUT_UC_FAULT:1;        	// 4uint16_t IOUT_OC_WARNING:1;        	// 5 IOUT Over current Warninguint16_t IOUT_OC_FAULT_LV_SHUTDOWN:1;// 6 NOT USED, IOUT Over current And Low Voltage Shutdown Faultuint16_t IOUT_OC_FAULT:1;        	// 7 IOUT Over current Fault
};union STATUS_IOUT_REG {uint16_t              all;struct STATUS_IOUT_BITS bit;
};//----------------------------------------------------
//	STATUS_TEMPERATURE register bit definitions */
struct STATUS_TEMPERATURE_BITS {		// bitsuint16_t rsvd:4;						// 0:3uint16_t UT_FAULT:1;					// 4uint16_t UT_WARNING:1;				// 5uint16_t OT_WARNING:1;     			// 6 Over temperature Warninguint16_t OT_FAULT:1;       			// 7 Over temperature Fault
};union STATUS_TEMPERATURE_REG {uint16_t              all;struct STATUS_TEMPERATURE_BITS bit;
};//----------------------------------------------------
//	STATUS_CML register bit definitions */
struct STATUS_CML_BITS {		// bitsuint16_t OTHER_MEMORY_OR_LOGIC_FAULT:1;	// 0uint16_t OTHER_COMMUNICATION_FAULT:1;    // 1uint16_t rsvd:1;        					// 2uint16_t PROCESSOR_FAULT_DETECTED:1;		// 3uint16_t MEMORY_FAULT_DETECTED:1;		// 4uint16_t PACKET_ERROR_CHECK_FAILED:1;	// 5uint16_t INVALID_DATA:1;        			// 6uint16_t INVALID_COMMAND:1;        		// 7
};union STATUS_CML_REG {uint16_t              all;struct STATUS_CML_BITS bit;
};//----------------------------------------------------
//	STATUS_INPUT register bit definitions */
struct STATUS_INPUT_BITS {		// bitsuint16_t PIN_OP_WARNING:1;					// 0uint16_t IIN_OC_WARNING:1;        			// 1uint16_t IIN_OC_FAULT:1;        				// 2uint16_t UNIT_OFF_FOR_LOW_INPUT_VOLTAGE:1;   // 3 Unit is Off For Insufficient Input Voltage [1]uint16_t VIN_UV_FAULT:1;        				// 4 VIN under voltage Faultuint16_t VIN_UV_WARNING:1;        			// 5 VIN under voltage Warninguint16_t VIN_OV_WARNING:1;        			// 6 VIN Over voltage Warninguint16_t VIN_OV_FAULT:1;        				// 7 VIN Over voltage Fault
};union STATUS_INPUT_REG {uint16_t              all;struct STATUS_INPUT_BITS bit;
};//----------------------------------------------------
//	STATUS_FANS_1_2 register bit definitions */
struct STATUS_FANS_1_2_BITS {			// bitsuint16_t AIR_FLOW_WARNING:1;			// 0uint16_t AIR_FLOW_FAULT:1;        	// 1uint16_t FAN2_SPEED_OVERRIDE:1;		// 2uint16_t FAN1_SPEED_OVERRIDE:1;    	// 3 Fan 1 Speed Overridden, which means that the Fan is controlled by external means, not the one designateduint16_t FAN2_WARNING:1;        		// 4uint16_t FAN1_WARNING:1;        		// 5uint16_t FAN2_FAULT:1;        		// 6 Fan 1 Warninguint16_t FAN1_FAULT:1;        		// 7 Fan 1 Fault
};union STATUS_FANS_1_2_REG {uint16_t              all;struct STATUS_FANS_1_2_BITS bit;
};//----------------------------------------------------
//	STATUS_FANS_3_4 register bit definitions */
struct STATUS_FANS_3_4_BITS {		// bitsuint16_t rsvd:2;					// 0:1uint16_t FAN4_SPEED_OVERRIDE:1;	// 2uint16_t FAN3_SPEED_OVERRIDE:1;    // 3uint16_t FAN4_WARNING:1;        	// 4uint16_t FAN3_WARNING:1;        	// 5uint16_t FAN4_FAULT:1;        		// 6uint16_t FAN3_FAULT:1;        		// 7
};union STATUS_FANS_3_4_REG {uint16_t              all;struct STATUS_FANS_3_4_BITS bit;
};//----------------------------------------------------
//	STATUS_OTHER register bit definitions */
struct STATUS_OTHER_BITS {		// bitsuint16_t rsvd1:1;						// 0uint16_t OUTPUT_OR_DEVICE_FAULT:1;     // 1uint16_t INPUTB_OR_DEVICE_FAULT:1;		// 2uint16_t INPUTA_OR_DEVICE_FAULT:1;  	// 3uint16_t INPUTB_FUSE_FAULT:1;        	// 4uint16_t INPUTA_FUSE_FAULT:1;        	// 5uint16_t rsvd2:2;        				// 6:7
};union STATUS_OTHER_REG {uint16_t              all;struct STATUS_OTHER_BITS bit;
};//----------------------------------------------------
//	STATUS registers */
struct STATUS_REGS {union  STATUS_WORD_REG			StatusWord; union  STATUS_VOUT_REG			StatusVout; union  STATUS_IOUT_REG			StatusIout;union  STATUS_TEMPERATURE_REG	StatusTemperature;union  STATUS_CML_REG     		StatusCml;union  STATUS_INPUT_REG     		StatusInput;union  STATUS_FANS_1_2_REG     	StatusFans12;union  STATUS_FANS_3_4_REG     	StatusFans34;union  STATUS_OTHER_REG			StatusOther;
};//---------------------------------------------------------------------------
// Status Registers External References & Function Declarations:
///*------------------------------------------------------------------------------
ISR for the XINT1 interrupt triggered from GPIO2 (Alert line) 
SMBAlert interrupt
------------------------------------------------------------------------------*/
//interrupt void xint1_isr(void);#endif

主机程序:

iic.c

#include "iic.h"
#include "stm32f10x_tim.h"/*
设置SDA信号为输出模式
*/
void IIC_SDA_OUTMODE(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = IIC_SDA;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}/*
设置SDA信号为输入模式
*/
void IIC_SDA_INPUTMODE(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = IIC_SDA;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB, &GPIO_InitStructure);
}/*
void delay_us(u32 nus)
{u32 temp;nus -= 1;SysTick->LOAD=nus*9;SysTick->VAL=0x00;SysTick->CTRL = 0X01 ;do{temp=SysTick->CTRL;} while((temp&0x01)&&!(temp&(1<<16)));SysTick->CTRL = 0X00;SysTick->VAL =0X00;
}
*//*
If DELAY_TIME is equal to 300, the delay time is about 72us
*/
static void I2C_Delay(void)
{uint16_t i;for (i = 0; i < DELAY_TIME; i++);
}/*
函数功能:IIC接口初始化
硬件连接:
SDA:PB7
SCL:PB6
*/
void IIC_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = IIC_SDA | IIC_SCL;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}/*
函数功能:IIC总线起始信号
*/
void IIC_Start(void)
{IIC_SDA_OUTMODE();  //初始化SDA为输出模式IIC_SDA_OUT(1);     //数据线拉高IIC_SCL_OUT(1);     //时钟线拉高I2C_Delay();        //电平保持时间IIC_SDA_OUT(0);     //数据线拉低I2C_Delay();        //电平保持时间IIC_SCL_OUT(0);     //时钟线拉低
}/*
函数功能:IIC总线停止信号
*/
void IIC_Stop(void)
{IIC_SDA_OUTMODE();  //初始化SDA为输出模式IIC_SDA_OUT(0);     //数据线拉低IIC_SCL_OUT(0);     //时钟线拉低I2C_Delay();        //电平保持时间IIC_SCL_OUT(1);     //时钟线拉高I2C_Delay();        //电平保持时间IIC_SDA_OUT(1);     //数据线拉高
}/*
函数功能:获取应答信号
返 回 值:1表示失败,0表示成功
*/
u8 IIC_GetACK(void)
{u8 cnt = 0;IIC_SDA_INPUTMODE();    //初始化SDA为输入模式IIC_SDA_OUT(1);         //数据线上拉I2C_Delay();            //电平保持时间IIC_SCL_OUT(0);         //时钟线拉低,告诉从机,主机需要数据I2C_Delay();            //电平保持时间,等待从机发送数据IIC_SCL_OUT(1);         //时钟线拉高,告诉从机,主机现在开始读取数据while (IIC_SDA_IN)      //等待从机应答信号{cnt++;if (cnt > 250)return 1;}IIC_SCL_OUT(0);         //时钟线拉低,告诉从机,主机需要数据return 0;
}/*
函数功能:主机向从机发送应答信号
函数形参:0表示应答,1表示非应答
*/
void IIC_SendACK(uint8_t stat)
{IIC_SDA_OUTMODE();          //初始化SDA为输出模式IIC_SCL_OUT(0);             //时钟线拉低,告诉从机,主机需要发送数据if (stat)IIC_SDA_OUT(1);    //数据线拉高,发送非应答信号else IIC_SDA_OUT(0);        //数据线拉低,发送应答信号I2C_Delay();                //电平保持时间,等待时钟线稳定IIC_SCL_OUT(1);             //时钟线拉高,告诉从机,主机数据发送完毕I2C_Delay();                //电平保持时间,等待从机接收数据IIC_SCL_OUT(0);             //时钟线拉低,告诉从机,主机需要数据
}/*
函数功能:IIC发送1个字节数据
函数形参:将要发送的数据
*/
void IIC_WriteOneByteData(uint8_t data)
{u8 i;IIC_SDA_OUTMODE();                  //初始化SDA为输出模式IIC_SCL_OUT(0);                     //时钟线拉低,告诉从机,主机需要发送数据for (i = 0; i < 8; i++){if (data & 0x80)IIC_SDA_OUT(1); //数据线拉高,发送1else IIC_SDA_OUT(0);            //数据线拉低,发送0IIC_SCL_OUT(1);                 //时钟线拉高,告诉从机,主机数据发送完毕I2C_Delay();                    //电平保持时间,等待从机接收数据IIC_SCL_OUT(0);                 //时钟线拉低,告诉从机,主机需要发送数据I2C_Delay();                    //电平保持时间,等待时钟线稳定data <<= 1;                     //先发高位}
}/*
函数功能:IIC接收1个字节数据
返 回 值:收到的数据
*/
u8 IIC_Read_One_Byte(void)
{u8 i, data;IIC_SDA_INPUTMODE();            //初始化SDA为输入模式for (i = 0; i < 8; i++){IIC_SCL_OUT(0);             //时钟线拉低,告诉从机,主机需要数据I2C_Delay();                //电平保持时间,等待从机发送数据IIC_SCL_OUT(1);             //时钟线拉高,告诉从机,主机现在正在读取数据data <<= 1;if (IIC_SDA_IN)data |= 0x01;I2C_Delay();                //电平保持时间,等待时钟线稳定}IIC_SCL_OUT(0);                 //时钟线拉低,告诉从机,主机需要数据 (必须拉低,否则将会识别为停止信号)return data;
}/**
@funcation name: pmbus_read_byte
@description: read one byte from PMBus slave device
@param: cmd_code: PMBus command
@buff: to store the data
@return: 0: OK, 1: error
*/
uint8_t pmbus_read_byte(uint8_t cmd_code, uint8_t* buff)
{IIC_Start();IIC_WriteOneByteData(PMBus_SLAVE_ADDR);//send the slave address, W/R = 0if (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_WriteOneByteData(cmd_code);//send the commandif (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_Start();IIC_WriteOneByteData(PMBus_SLAVE_ADDR | 0x01);//send the slave address, W/R = 1if (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}//*buff = 2;//total data length: one byte + the PEC byte*(buff + 0) = IIC_Read_One_Byte();IIC_SendACK(0);//0:ACK, 1: NACK*(buff + 1) = IIC_Read_One_Byte();IIC_SendACK(1);//0:ACK, 1: NACKIIC_Stop();return IIC_OK;
}/**
@funcation name: pmbus_write_byte
@description: write one byte to the PMBus slave device
@param: cmd_code: PMBus command, param: the parameter of the current command
@return: 0: OK, 1: error
*/
uint8_t pmbus_write_byte(uint8_t cmd_code, uint8_t param)
{IIC_Start();IIC_WriteOneByteData(PMBus_SLAVE_ADDR);//send the slave address, W/R = 0if (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_WriteOneByteData(cmd_code);//send the commandif (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_WriteOneByteData(param);//send the parameterif (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_Stop();return IIC_OK;
}/**
@funcation name: pmbus_read_word
@description: read one word from PMBus slave device
@param: cmd_code: PMBus command
@buff: to store the data
@return: 0: OK, 1: error
*/
uint8_t pmbus_read_word(uint8_t cmd_code, uint8_t* buff)
{IIC_Start();IIC_WriteOneByteData(PMBus_SLAVE_ADDR);//send the slave address, W/R = 0if (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_WriteOneByteData(cmd_code);//send the commandif (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}IIC_Start();IIC_WriteOneByteData(PMBus_SLAVE_ADDR | 0x01);//send the slave address, W/R = 1if (IIC_GetACK() == 1) //error{IIC_Stop();return IIC_ERROR;}//*buff = 3;//total data length: one word + the PEC byte*(buff + 0) = IIC_Read_One_Byte();IIC_SendACK(0);//0:ACK, 1: NACK*(buff + 1) = IIC_Read_One_Byte();IIC_SendACK(0);//0:ACK, 1: NACK*(buff + 2) = IIC_Read_One_Byte();IIC_SendACK(1);//0:ACK, 1: NACKIIC_Stop();return IIC_OK;
}

iic.h

#include "stm32f10x.h"#define IIC_SDA GPIO_Pin_7
#define IIC_SCL GPIO_Pin_6#define IIC_SDA_OUT(a)  if (a)  \GPIO_SetBits(GPIOB, IIC_SDA);\else        \GPIO_ResetBits(GPIOB, IIC_SDA)#define IIC_SCL_OUT(a)  if (a)  \
GPIO_SetBits(GPIOB, IIC_SCL);\
else        \
GPIO_ResetBits(GPIOB, IIC_SCL)#define IIC_SDA_IN GPIO_ReadInputDataBit(GPIOB, IIC_SDA)#define PMBus_SLAVE_ADDR (0x21<<1)
#define IIC_OK      0
#define IIC_ERROR   1
#define DELAY_TIME  100////////////USER CODE////////////
// The user should change the value of PEC to match their implementation's
// desired Packet Error Checking capability. This will cause all associated
// files to build either with or without PEC capability, accordingly.
#warning    "User should change PEC value to build with or without PEC capability."
#define PEC     1   //PEC 0: Disable Packet Error Checking
//PEC 1: Enable Packet Error Checking
////////////END USER CODE////////#if PEC
#define PEC_PASS            1
#define PEC_FAIL            0
#define CRC8_POLY           0x07
#define CRC8_INIT_REM       0x0
#endif#define READBYTE      0
#define READWORD      2
#define WRITEBYTE     4
#define SENDBYTE      6
#define WRITEWORD     8
#define RWBYTE        1
#define RWWORD        3#define READBLOCK     5//New customized group//GROUP#0
#define CAPABILITY                          0x19 //1
#define STATUS_BYTE                         0x78 //2
#define STATUS_VOUT                         0x7A //3
#define STATUS_IOUT                         0x7B //4
#define STATUS_INPUT                        0x7C //5
#define STATUS_TEMPERATURE                  0x7D //6
#define STATUS_CML                          0x7E //7
#define STATUS_OTHER                        8
#define STATUS_MFR_SPECIFIC                 0x80 //9
#define STATUS_FANS_1_2                     10
#define STATUS_FANS_3_4                     11
#define PMBUS_REVISION                      0x98 //12// GROUP #2
#define STATUS_WORD                         0x79 //13
#define READ_VIN                            0x88 //14
#define READ_IIN                            0x89 //15
#define READ_VCAP                           16
#define READ_VOUT                           0x8B //17
#define READ_IOUT                           0x8C //18
#define READ_TEMPERATURE_1                  19   //Primary side heat sink temperature by degree C
#define READ_TEMPERATURE_2                  20   //Inlet ambient temperature by degree C
#define READ_TEMPERATURE_3                  0x8F //21 //Secondary side heat sink temperature by degree C
#define READ_FAN_SPEED_1                    22
#define READ_FAN_SPEED_2                    23
#define READ_FAN_SPEED_3                    24
#define READ_FAN_SPEED_4                    25
#define READ_DUTY_CYCLE                     26
#define READ_FREQUENCY                      27
#define READ_POUT                           0x96 //28
#define READ_PIN                            0x97 //29
#define MFR_VIN_MIN                         0xA0 //30
#define MFR_VIN_MAX                         0xA1 //31
#define MFR_IIN_MAX                         0xA2 //32
#define MFR_PIN_MAX                         0xA3 //33
#define MFR_VOUT_MIN                        0xA5 //34
#define MFR_VOUT_MAX                        0xA4 //35
#define MFR_IOUT_MAX                        0xA6 //36
#define MFR_POUT_MAX                        0xA7 //37
#define MFR_TAMBIENT_MAX                    0xA8 //38
#define MFR_TAMBIENT_MIN                    0xA9 //39// GROUP #4
#define STORE_DEFAULT_CODE                  40
#define RESTORE_DEFAULT_CODE                41
#define STORE_USER_CODE                     42
#define RESTORE_USER_CODE                   43// GROUP#6
#define CLEAR_FAULTS                        0x03 //44   //If the fault is still present after 03h is issued, the system needs to be able to report the fault and set the corresponding register.
#define STORE_DEFAULT_ALL                   45
#define RESTORE_DEFAULT_ALL                 46
#define STORE_USER_ALL                      47
#define RESTORE_USER_ALL                    48//GROUP#8//#define PAGE/ GENERAL CALL                  49//The old statement
#define PAGE                                0x00 //49   //GENERAL CALL
#define OPERATION                           50  //switch machine flag,0x80: means power on (default),0x00: means power off.
#define ON_OFF_CONFIG                       51  //command code: 0x02, parameter, 0x15: means PSU on/off only by PS_ON# control(default).0x19: means PSU on/off only by PMBus control.
#define PHASE                               52
#define WRITE_PROTECT                       53
#define VOUT_MODE                           0x20 //54
#define FAN_CONFIG_1_2                      55
#define FAN_CONFIG_3_4                      56
#define VOUT_OV_FAULT_RESPONSE              57
#define VOUT_UV_FAULT_RESPONSE              58
#define IOUT_OC_FAULT_RESPONSE              59
#define IOUT_OC_LV_FAULT_RESPONSE           60
#define IOUT_UC_FAULT_RESPONSE              61
#define OT_FAULT_RESPONSE                   62
#define UT_FAULT_RESPONSE                   63
#define VIN_OV_FAULT_RESPONSE               64
#define VIN_UV_FAULT_RESPONSE               65
#define IIN_OC_FAULT_RESPONSE               66
#define TON_MAX_FAULT_RESPONSE              67
#define POUT_OP_FAULT_RESPONSE              68//GROUP#10
#define VOUT_COMMAND                        0x21 //69
#define VOUT_TRIM                           70
#define VOUT_CAL_OFFSET                     71
#define VOUT_MAX                            72
#define VOUT_MARGIN_HIGH                    73
#define VOUT_MARGIN_LOW                     74
#define VOUT_TRANSITION_RATE                75
#define VOUT_DROOP                          76
#define VOUT_SCALE_LOOP                     77
#define VOUT_SCALE_MONITOR                  78
#define POUT_MAX                            79
#define MAX_DUTY                            80
#define FREQUENCY_SWITCH                    81
#define VIN_ON                              82
#define VIN_OFF                             83
#define INTERLEAVE                          84
#define IOUT_CAL_GAIN                       85
#define IOUT_CAL_OFFSET                     86
#define FAN_COMMAND_1                       87
#define FAN_COMMAND_2                       88
#define FAN_COMMAND_3                       89
#define FAN_COMMAND_4                       90
#define VOUT_OV_FAULT_LIMIT                 91
#define VOUT_OV_WARN_LIMIT                  92
#define VOUT_UV_WARN_LIMIT                  93
#define VOUT_UV_FAULT_LIMIT                 94
#define IOUT_OC_FAULT_LIMIT                 95
#define IOUT_OC_LV_FAULT_LIMIT              96
#define IOUT_OC_WARN_LIMIT                  0x4A //97
#define IOUT_UC_FAULT_LIMIT                 98
#define OT_FAULT_LIMIT                      99
#define OT_WARN_LIMIT                       0x51//100
#define UT_WARN_LIMIT                       101
#define UT_FAULT_LIMIT                      102
#define VIN_OV_FAULT_LIMIT                  103
#define VIN_OV_WARN_LIMIT                   104
#define VIN_UV_WARN_LIMIT                   105
#define VIN_UV_FAULT_LIMIT                  106
#define IIN_OC_FAULT_LIMIT                  107
#define IIN_OC_WARN_LIMIT                   108
#define POWER_GOOD_ON                       109
#define POWER_GOOD_OFF                      110
#define TON_DELAY                           111
#define TON_RISE                            112
#define TON_MAX_FAULT_LIMIT                 113
#define TOFF_DELAY                          114
#define TOFF_FALL                           115
#define TOFF_MAX_WARN_LIMIT                 116
#define POUT_OP_FAULT_LIMIT                 117
#define POUT_OP_WARN_LIMIT                  118
#define PIN_OP_WARN_LIMIT                   119
#define MFR_ID                              0x99 //120 //New added command
#define MFR_MODEL                           0x9A //121
#define MFR_REVISION                        0x9B //122void IIC_Init(void);uint8_t pmbus_read_word(uint8_t cmd_code, uint8_t* buff);
uint8_t pmbus_read_byte(uint8_t cmd_code, uint8_t* buff);
uint8_t pmbus_write_byte(uint8_t cmd_code, uint8_t param);

从机程序只实现了部分PMBus指令,使用中断方法来处理PMBus通信,主要是以下几个事件的处理:

从机接收有关的事件:

I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:

主机要向从机发送数据,这里一般作一些初始化操作,例如:接收数据长度指针清零,数据接收缓冲初始化等等

I2C_EVENT_SLAVE_BYTE_RECEIVED:

从机接收到主机发送来的数据,从机此时一般的操作就是使用接收缓存保存所有数据

从机发送有关的事件:
I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED:

主机读取从机数据,此时可以将数据发送指针清零,准备好要发送的数据缓冲并且发送第一个数据


I2C_EVENT_SLAVE_BYTE_TRANSMITTED:

从机发送的数据主机已收到并收到ACK,主机如果没有发送NACK则从机继续发送下一个数据

I2C_EVT_SLAVE_ACK_MISS:

主机在接收最后一个数据后会发送一个NACK,通知从机数据已全部接收完成,准备要发送STOP释放I2C总线,这里要做的就是清除这个中断标志位


I2C_EVENT_SLAVE_STOP_DETECTED:

收到主机发送来的停止信号,这里有两种情况:

1、如果主机向从机发送数据,这里表示从机接收数据完成了,此时从机可根据主机发送的寄存器信息及参数执行相应的操作;
2、如果主机读取从机数据,主机发送STOP信号之前会发送一个NACK,表示主机已最读取最后一个数据,从机不必要再发送数据

其实理解了I2C的通信时序后这些都很简单了,换了其他的单片机也是类似的原理。

之前使用TI提供的PMBus例程来设计从机程序,在使用N32G003上发现了如下几个问题:

1、在解析命令时,它每次都会使用for循环在指令表数组中搜索匹配指令,如果指令表数组很长这样会消耗很多时间;

2、如果程序要求PEC校验,使用之前的CRC8方法,即从机代码中的PMBusSlave_Crc8MakeBitwise函数,执行速度也会慢很多;

3、最终的结果就是:从机设置的速率为100Kbit/s,实际客户验证(使用模拟I2C)只能在低于14Kbit/s左右时才可正确读取数据,远远低于他们要求的60-80Kbit/s速率

于是对代码进行了如下优化:

1、修改函数PMBusSlave_DecodeCommand,只列出小部分需要的指令并准备好相应的数据,Linear16或Linear11格式,对于一些固定的字符串数据,例如:厂家信息,模块型号等,则直接使用单独的发送缓存并计算好PEC值;

2、由于N32G003系列RAM一般都较充足,CRC8使用了查表方法,对比测试通信速率大大提高;

3、通信出错机制除了TI提供的35毫秒超时重启,还有厂家推荐的出错机制,确保从机在出现异常时可以自行恢复。

主机端程序使用的是STM32F103系列,并且使用模拟方式(我们必须要模拟客户的真实使用环境),有以下要注意:

1、I2C_Delay()函数我测试过,如果宏DELAY_TIME设置为300,在STM32F103主频72MHz的情况下,函数的延时时间约为71微秒,用逻辑分析仪查看此时的I2C时钟频率约为14KHz;

2、IIC_GetACK函数必须要加超时出错机制,如果从机在指定时间内没有将SDA拉低,则认为通信有异常,主机必须结束此次通信;

3、主机程序中的pmbus_read_word写读函数也是和客户那边的软件工程师沟通得知是他们常用的方法,经测试时序完全没问题;

4、调整DELAY_TIME的值为50-60之间,实际观察到的频率约为70KHz,通信稳定。

以下是STM32F103主机使用的实例,通过USART接收上位机发送来的PMBus指令,通过I2C总线读写从机并将数据通过USART1返回给上位机。

main.c

/******************** (C) COPYRIGHT 2023 **************************
* @name: main.c* @brief: RS485 and PMBus Communication* @platform: STM32F103RBT6 Series MCU* @library version: ST3.5.0* @author: Power
**********************************************************************************/#include "BSP.H"
#include "key.h"
#include "iic.h"
#include "usart1.h"//TIM3 prescaler
#define TIM3_DIV1     (1-1)
#define TIM3_DIV18    (18-1)
#define TIM3_DIV72    (72-1)#define I2C_Slave_Address   (0x54)uint16_t led_cnt = 0;//LED test
volatile uint8_t Flag_1ms;      //1 milli-second overflow flag
volatile uint16_t cDelay_1Ms;   //80 milli-seconds counter
volatile struct UART_Data_Struct UART1_STRUCT;//USART interfaceuint16_t i2c_time = 0;
uint8_t pmbus_buff[20] = {0, 0, 0};
uint16_t no_data_error = 0;
uint8_t key = 0xFF;//*************************************
// 函数名:TIM3_NVIC_Configuration
// 描述  :TIM3中断优先级配置
// 输入  :无
// 输出  :无
//*************************************
void TIM3_NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/**
*@name: TIM3_BASEInitSys
*@description: timer3 initialization
*@params: none
*@return: none
*/
void TIM3_Configuration(int16_t tcon, uint16_t psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_DeInit(TIM3);TIM_TimeBaseStructure.TIM_Period = tcon;  //periodTIM_TimeBaseStructure.TIM_Prescaler = psc ;         //prescalerTIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //counter modeTIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);TIM_ClearFlag(TIM3, TIM_FLAG_Update);TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);TIM_Cmd(TIM3, ENABLE);
}/**
*@name: Process_1MS
*@description: 1 milli-second overflow process
*@params: none
*@return: none
*/
static void Process_1Ms(void)
{if (Flag_1ms == 0){return;}Flag_1ms = 0;if (++i2c_time >= 300){i2c_time = 300;}if (++no_data_error > 1000) no_data_error = 1000;if (++led_cnt >= 500) //LED Toggle Test{led_cnt = 0;GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)));}
}void Key_Process(void)
{//key = KEY_Scan(1);key = Key_Scan(GPIOC, GPIO_Pin_13);if (key == 1){key = 0;//can_id_index++;//if (++can_id_index > 6)//{//can_id_index = 1;//}//AlarmStatus.alarm.KEY_ERASE_PRESSED = 1;//AlarmStatus.alarm.CLONE_DONE = 0;//Copy_Data_Process();}
}/**
*@name: Parse_PMBus_Command
*@description: Parse the PMBus command from the UART interface and send the command to the PMBus slave
*@params: none
*@return: none
*/
static uint8_t Parse_PMBus_Command(uint8_t command, uint8_t param)
{uint8_t result = IIC_ERROR;switch (command){case STATUS_BYTE://read bytecase CAPABILITY:case STATUS_VOUT:case STATUS_IOUT:case STATUS_INPUT:case STATUS_MFR_SPECIFIC:case STATUS_TEMPERATURE:case PMBUS_REVISION:case VOUT_MODE:result = pmbus_read_byte(command, pmbus_buff);break;case STATUS_WORD://read wordcase READ_VIN:case READ_IIN:case READ_VOUT:case READ_IOUT:case READ_TEMPERATURE_3:case READ_POUT:case READ_PIN:case MFR_VIN_MIN:case MFR_VIN_MAX:case MFR_IIN_MAX:case MFR_PIN_MAX:case MFR_VOUT_MIN:case MFR_VOUT_MAX:case MFR_IOUT_MAX:case MFR_POUT_MAX:case MFR_TAMBIENT_MAX:case MFR_TAMBIENT_MIN:case VOUT_COMMAND:case IOUT_OC_WARN_LIMIT:case OT_WARN_LIMIT:result = pmbus_read_word(command, pmbus_buff);break;case MFR_ID://block read, NOT processed herecase MFR_MODEL:case MFR_REVISION:result = IIC_OK;break;case PAGE://write byteresult = pmbus_write_byte(command, param);break;case CLEAR_FAULTS://clear the error flagsbreak;default:result = IIC_ERROR;break;}return result;
}/**
*@name: PMBus_Process
*@description: Process the data received from the upper machine
*@params: none
*@return: none
*/
void PMBus_Process(void)
{uint8_t i;uint8_t counter = 0;if (UART1_STRUCT.R_Flag == 1) //send out the command received from UART to the PMBus slave{uint8_t result = Parse_PMBus_Command(UART1_STRUCT.R_Buffer[1], UART1_STRUCT.R_Buffer[2]);if (result == IIC_OK){//0x7E 0xD0 0xEA 0xEA 0x00 0x0D, for exampleUART1_STRUCT.T_Buffer[counter++] = UART_START;UART1_STRUCT.T_Buffer[counter++] = UART1_STRUCT.R_Buffer[1];//the commandfor (i = 0; i < 3; i++){UART1_STRUCT.T_Buffer[counter++] = pmbus_buff[i];}UART1_STRUCT.T_Buffer[counter++] = result;UART1_STRUCT.T_Buffer[counter++] = UART_STOP;}else{UART1_STRUCT.T_Buffer[counter++] = UART_START;UART1_STRUCT.T_Buffer[counter++] = UART1_STRUCT.R_Buffer[1];for (i = 0; i < 3; i++){UART1_STRUCT.T_Buffer[counter++] = 0xEE;}UART1_STRUCT.T_Buffer[counter++] = result;UART1_STRUCT.T_Buffer[counter++] = UART_STOP;}USART1_SendData((uint8_t*)UART1_STRUCT.T_Buffer, counter);//send the data back to the upper machine, total 6 bytesUART1_STRUCT.R_Flag = 0;}
}/**@* name:main@* description: main process@* The hardware IC2 slave mode has been proved correct, and nowwe are testing the PMBus slave.@* input: none@* output: none*/
int main(void)
{BSP_Init();IIC_Init();SysTick_Init();TIM3_Configuration(1000, TIM3_DIV72) ; //72M/72 = 1M 1m中断一次TIM3_NVIC_Configuration();while (1){Process_1Ms();        PMBus_Process();}
}

usart1.c

#include "usart1.h"extern uint8_t send_buffer[10];
extern uint8_t Tx_flag;
volatile uint8_t Rx_ptr = 0;
volatile uint8_t UART_Rx_flag = 0;extern volatile struct UART_Data_Struct UART1_STRUCT;//USART interface/**@* 函数名:USART1_Config@* 描述  :USART1 GPIO 配置,工作模式配置。9600 8-N-1@* 输入  :无@* 输出  : 无@* 调用  :外部调用*/
void USART1_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;/* config USART1 clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);/* USART1 GPIO config *//* Configure USART1 Tx (PA.09) as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);/* Configure USART1 Rx (PA.10) as input floating */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);/* USART1 mode config */USART_InitStructure.USART_BaudRate = 9600;//115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure);//中断优先级:/* Configure the NVIC Preemption Priority Bits */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);// Enable the USART1 InterruptNVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开串口1接收中断USART_Cmd(USART1, ENABLE);
}void USART1_Data_Receive(void)
{uint8_t data = USART_ReceiveData(USART1);if (UART1_STRUCT.R_Flag) return;if (UART1_STRUCT.R_InPtr == 0 && data != UART_START) {return;}if (UART1_STRUCT.R_InPtr < RECEIVE_DATA_LEN) {UART1_STRUCT.R_Buffer[UART1_STRUCT.R_InPtr++] = data;}if (UART1_STRUCT.R_InPtr >= RECEIVE_DATA_LEN) {if (UART1_STRUCT.R_Buffer[0] == UART_START &&UART1_STRUCT.R_Buffer[RECEIVE_DATA_LEN - 1] == UART_STOP) {UART1_STRUCT.R_Flag = 1;}UART1_STRUCT.R_InPtr = 0;}
}/**@* 函数名:USART1_IRQHandler@* 描述  :串口1中断接收到数据后保存在数据缓冲区@* 输入  :无@* 输出  :无@* 注意  :中断处理函数除了在stm32f10x_it.c中还可以放在其他位置,只要名称不重复
*/
void USART1_IRQHandler(void)
{uint8_t cTemp = cTemp;if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收到数据{USART_ClearITPendingBit(USART1, USART_IT_RXNE);     //清除中断标志位,以免重复进入中断USART1_Data_Receive();}//溢出-如果发生溢出需要先读SR,再读DR寄存器 则可清除不断入中断的问题if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) == SET){USART_ClearFlag(USART1, USART_FLAG_ORE);//读SRUSART_ReceiveData(USART1);//读DR}
}/**@* 函数名:USART1_SendData@* 描述  : 利用串口1发送数据,主要是调试用@* 输入  :data:要发送的数据@*         len:要发送数据长度@* 输出  : 无*/
void USART1_SendData(uint8_t* data, uint8_t len)
{while (len > 0) //开始发送数据{while (RESET == USART_GetFlagStatus(USART1, USART_FLAG_TC));USART_SendData(USART1, *data++);len--;}while (RESET == USART_GetFlagStatus(USART1, USART_FLAG_TC)); //等待发送完成*///  u8 i=0;//  for(i=0;i<len;i++)//开始发送数据//  {//      while(RESET == USART_GetFlagStatus(USART1, USART_FLAG_TXE));//      USART_SendData(USART1, data[i]);//  }//  while(RESET == USART_GetFlagStatus(USART1, USART_FLAG_TXE));//等待发送完成*/
}

usart1.h

#ifndef __USART1_H
#define __USART1_H#include "stm32f10x.h"
#include <stdio.h>
#include <stdarg.h>/*串口1初始化*/
void USART1_Config(void);/*串口发送数据*/
void USART1_SendData(u8* data, u8 len);int fputc(int ch, FILE* f);/*重定向系统的printf方法*/
void USART_printf(USART_TypeDef* USARTx, uint8_t* Data, ...);#define RECEIVE_DATA_LEN    4      //接收数据最大长度
#define TRANSMIT_DATA_LEN   10     //发送数据最大长度/*
======================================================起始位和结束位及一些固定值定义======================================================
*/
#define     UART_START                 0x7E    //固定起始位
#define     UART_STOP                  0x0D    //固定结束位struct	UART_Data_Struct
{uint8_t R_Buffer[RECEIVE_DATA_LEN]; //接收缓冲uint8_t R_Length;                   //接收数据的总长度uint8_t R_InPtr;                    //已接收的数据长度uint8_t R_Flag;                     //接收是否完成标志uint8_t R_DTSime;                   //发送超时处理,当需要给主机发送数据时会启用uint8_t T_Buffer[TRANSMIT_DATA_LEN];//发送缓冲uint8_t T_Length;                   //发送数据总长度,在使用串口发送时的数据长度uint8_t T_OutPtr;                   //正在发送数据的指针uint8_t T_Flag;                     //发送是否完成标志uint8_t T_DTSime;                   //发送超时处理,如果在指定时间内没有发送,则证明有问题,重新初始化串口uint8_t T_Time;uint8_t Frame_Buffer[RECEIVE_DATA_LEN];//以下几个成员暂未使用uint8_t Frame_InPtr;uint8_t Frame_OutPtr;uint8_t Frame_Length;
};#endif /* __USART1_H */

http://www.dtcms.com/a/317369.html

相关文章:

  • PostgreSQL 通配符指南:解锁 LIKE 查询的魔法 - % 与 _ 详解
  • 区块链技术在供应链管理中的应用案例
  • C语言的综合案例
  • HIVE 窗口函数处理重复数据
  • WebStorm转VSCode:高效迁移指南
  • 用NAS如何远程访问:详细教程与实用技巧
  • 关于C语言连续强制类型转换,有符号数据位移,以及温度传感器int16有符号数据重组处理问题
  • C++之vector类的代码及其逻辑详解 (下)
  • SELinux加固Linux安全2
  • 【数据结构初阶】--排序(四):归并排序
  • 软考软件设计师考点总结
  • [linux] Linux系统中断机制详解及用户空间中断使用方法
  • Linux部署tp5.1,nginx服务器不管访问那个方法,一直访问index/index问题解决方法
  • 阶段二:1-信息技术概述
  • helm下载tiller失败
  • 【数字图像处理系列笔记】Ch04:灰度变换与空间域图像增强(2)
  • 蚊子咬人问题何时休:深度学习引领智能灭蚊新时代
  • qt窗口--02
  • 无人设备遥控器之跳频技术篇
  • 鹧鸪云:光伏电站的“智慧中枢”,精准调控逆变器
  • 使用 Helm 在 Kubernetes 中安装 Milvus
  • 企业知识库:RAG技术实现流程总览(一)
  • 【motion】标签体系设计与检索 1:HumanML3D 和 KIT Motion-Language(KITML)
  • 河南萌新联赛2025第(四)场【补题】
  • 键帽(dp)
  • 分布式光伏气象站:安装与维护
  • 【运维进阶】DHCP服务配置和DNS域名解析
  • 最长公共子序列-动态规划
  • 如何在linux中使用Makefile构建一个C++工程?
  • 中科米堆CASAIM机加工件来料尺寸自动化三维测量方案