Files
CHJ/user/MCU/lhl_i2c_slave.c
2026-03-20 21:19:04 +08:00

422 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../main/SystemInclude.h"
#ifndef ENABLE_USER_I2C
#pragma message("[undefined] ENABLE_USER_I2C")
#elif(ENABLE_USER_I2C)
DMA_HandleTypeDef DMA_Handle_IIC_Rx,DMA_Handle_IIC_Tx;
//初始化IIC
//i2c_slave_init(100000 , 0x02);
void I2C_Slave_Init(u32 clockSpeed ,u16 slaveAddress)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* 1. 设置 I2C GPIO复用端口 */
GPIO_InitStructure.Pin = GPIO_PIN_1;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; // I2C SCL开漏输出
GPIO_InitStructure.Current = GPIO_CURRENT_8mA;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.SchmittTrigger = ENABLE;
GPIO_InitStructure.Alternate = GPIO0_1_AF_SCL; // AFIO设置
LHL_GPIO_Init(GPIO0, &GPIO_InitStructure); //P0.1 P2.0 -> SCL
GPIO_InitStructure.Pin = GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; // I2C SDA开漏输出
GPIO_InitStructure.Current = GPIO_CURRENT_8mA;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.SchmittTrigger = ENABLE;
GPIO_InitStructure.Alternate = GPIO0_2_AF_SDA; // AFIO设置
LHL_GPIO_Init(GPIO0, &GPIO_InitStructure); //P0.2 P1.4 -> SDA
/* 2. 配置 I2C 外设 */
I2C_InitStructure.ClockSpeed = clockSpeed; //100KHz Standard I2C Speed
I2C_InitStructure.DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.OwnAddress1 = slaveAddress; //Temporary slave device address
I2C_InitStructure.I2CAck = I2C_Ack_Enable;
I2C_InitStructure.AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
LHL_I2C_Init(&I2C_InitStructure);
// LHL_I2C_StretchClockCmd(DISABLE);//关闭时钟延展
LHL_I2C_ITConfig(I2C_IT_EVT|I2C_IT_BUF|I2C_IT_ERR, ENABLE);
NVIC_SetPriority(I2C1_EV_IRQn,0);
NVIC_EnableIRQ(I2C1_EV_IRQn);
}
/*********************************************************************************************************************************************/
/*中断 方式*/
/*********************************************************************************************************************************************/
I2C_DATA_TypeDef I2CData;
void I2C1_EV_IRQHandler()
{
__IO uint32_t sta1,sta2;
__IO uint32_t R_W;
sta1 = pI2C->SR1;
sta2 = pI2C->SR2; //清除STOPF
R_W = (sta2&I2C_SR2_TRA_Msk)>>I2C_SR2_TRA_Pos; //判断当前是读Master读Slave还是写Master写Slave
if(sta1 & I2C_SR1_ADDR_Msk)//I2C地址匹配
{
LHL_I2C_ClearFlag(I2C_FLAG_ADDR);
LHL_I2C_ClearFlag(I2C_FLAG_TXE);
if(R_W == MASTER_READ_SLAVE) I2CStartWriteProcess(); //更新状态参数 IIC从机开始发送(向主机写)寄存器地址
else I2CStartReadProcess();//更新状态参数 IIC开始接收数据
}
if(sta1 & I2C_SR1_STOPF_Msk)
{
LHL_I2C_ClearFlag(I2C_FLAG_STOPF);
return;
}
if(sta1 & I2C_SR1_AF_Msk) //主机发送NACK
{
I2CResetProcess(); //重置状态参数
LHL_I2C_Cmd(ENABLE);//保持IIC开启
LHL_I2C_ClearFlag(I2C_FLAG_TXE | I2C_FLAG_RXNE | I2C_FLAG_AF);
LHL_I2C_ClearFlag(I2C_FLAG_PECERR | I2C_FLAG_OVR | I2C_FLAG_BERR);
return;
}
if((sta1 & I2C_SR1_RXNE_Msk) && (R_W==MASTER_WRITE_SLAVE)) //IIC写入
{
LHL_I2C_ClearFlag(I2C_FLAG_RXNE);
I2CData.rxData[I2CData.rxCounter++] = LHL_I2C_ReceiveData();
I2CReceiveProcess();//发送处理,准备发送数据(一直收等I2C_SR1_ADDR_Msk变成主机读命令(即从机发)
return;
}
if((sta1 & I2C_SR1_TXE_Msk) && (R_W==MASTER_READ_SLAVE)) //IIC发送(单字节)
{
I2CTransmitProcess();//发送处理,当前设置为每3字节处理一次主机没有停止接收前一直可发
LHL_I2C_SendData(I2CData.txData[I2CData.txCounter++]);
return;
}
if(sta1 & I2C_SR1_BERR_Msk) { LHL_I2C_ClearFlag(I2C_FLAG_BERR); return;} //clear BERR
__DSB();//make sure intterupt flag cleared
}
//中断 测试代码========================================================
#define TEST_BUF_LEN 20
uint8_t iic_tx_buf[TEST_BUF_LEN] = {0} ,iic_tx_len ;
uint8_t iic_rx_buf[TEST_BUF_LEN] = {0};
uint16_t iic_tx_cnt = 0;
uint16_t iic_rx_cnt = 0;
void I2C1_EV_IRQHandler2(void)//
{
__IO uint32_t sta1,sta2;
__IO uint32_t R_W;
sta1 = pI2C->SR1;
sta2 = pI2C->SR2; //清除STOPF
R_W = (sta2&I2C_SR2_TRA_Msk)>>I2C_SR2_TRA_Pos; //判断当前是读Master读Slave还是写Master写Slave
if(sta1 & I2C_SR1_ADDR_Msk)//I2C address match
{
if(R_W == MASTER_READ_SLAVE)iic_tx_cnt = 0;//主机读取数据,从机发送模式
else iic_rx_cnt = 0;//主机写入数据,从机接收模式
}
if(sta1 & I2C_SR1_STOPF_Msk)
{
pI2C->CR1 |= I2C_CR1_STOP_Msk;
}
if(sta1 & I2C_SR1_AF_Msk)
{
pI2C->CR1 |= I2C_SR1_AF_Msk; //主机nack
pI2C->SR1 &= ~I2C_SR1_AF_Msk;
}
if((sta1 & I2C_SR1_RXNE_Msk) && (R_W==0)) // write
{
//接收到写入数据
iic_rx_buf[iic_rx_cnt++] = pI2C->DR;
if(iic_rx_cnt==2)IIC_Cmd_Check_Test();
}
if((sta1 & I2C_SR1_TXE_Msk) && (R_W==1)) //trasmitted one byte
{
pI2C->DR = iic_tx_buf[iic_tx_cnt++];
}
__DSB();//make sure intterupt flag cleared
}
void IIC_Cmd_Check_Test(void)
{
u16 regcmd = (I2CData.rxData[0]<<8) + I2CData.rxData[1];
u8 i;
switch(regcmd)
{
case 0x821A:
iic_tx_buf[0] = 0x00;
iic_tx_buf[1] = 0x01;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_len=3;
break;
case 0x30:
iic_tx_buf[0] = 0x30;
iic_tx_buf[1] = 0x31;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_buf[3] = 0x40;
iic_tx_buf[4] = 0x41;
iic_tx_buf[5] = I2CWordCrc(iic_tx_buf[3], iic_tx_buf[4]);
iic_tx_buf[6] = 0x32;
iic_tx_buf[7] = 0x33;
iic_tx_buf[8] = I2CWordCrc(iic_tx_buf[6], iic_tx_buf[7]);
iic_tx_buf[9] = 0x34;
iic_tx_buf[10] = 0x35;
iic_tx_buf[11] = I2CWordCrc(iic_tx_buf[9], iic_tx_buf[10]);
iic_tx_buf[12] = 0x36;
iic_tx_buf[13] = 0x37;
iic_tx_buf[14] = I2CWordCrc(iic_tx_buf[12], iic_tx_buf[13]);
iic_tx_buf[15] = 0x38;
iic_tx_buf[16] = 0x39;
iic_tx_buf[17] = I2CWordCrc(iic_tx_buf[15], iic_tx_buf[16]);
iic_tx_len=18;
break;
case 0x36:
iic_tx_buf[0] = 0x32;
iic_tx_buf[1] = 0x33;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_len=3;
break;
case 0x81:
iic_tx_buf[0] = 0x01;
iic_tx_buf[1] = 0x41;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_len=3;
break;
case 0x3A:
iic_tx_buf[0] = 0x01;
iic_tx_buf[1] = 0x41;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_buf[3] = 0x40;
iic_tx_buf[4] = 0x41;
iic_tx_buf[5] = I2CWordCrc(iic_tx_buf[3], iic_tx_buf[4]);
iic_tx_len=6;
break;
case 0x3C:
iic_tx_buf[0] = 0x01;
iic_tx_buf[1] = 0x41;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_buf[3] = 0x40;
iic_tx_buf[4] = 0x41;
iic_tx_buf[5] = I2CWordCrc(iic_tx_buf[3], iic_tx_buf[4]);
iic_tx_buf[6] = 0x32;
iic_tx_buf[7] = 0x33;
iic_tx_buf[8] = I2CWordCrc(iic_tx_buf[6], iic_tx_buf[7]);
iic_tx_len=9;
break;
case 0x56:
iic_tx_buf[0] = 0x01;
iic_tx_buf[1] = 0x41;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_len=12;
break;
case 0x85:
iic_tx_buf[0] = 0x01;
iic_tx_buf[1] = 0x41;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_buf[3] = 0x40;
iic_tx_buf[4] = 0x41;
iic_tx_buf[5] = I2CWordCrc(iic_tx_buf[3], iic_tx_buf[4]);
iic_tx_len=6;
break;
default:
iic_tx_buf[0] = 0x30;
iic_tx_buf[1] = 0x31;
iic_tx_buf[2] = I2CWordCrc(iic_tx_buf[0], iic_tx_buf[1]);
iic_tx_len=3;
break;
}
}
void IIC_Cmd_Check_Test1(void)
{
I2CData.readAddr = (I2CData.rxData[0]<<8) + I2CData.rxData[1];
MBBuf.StartAddr = I2CData.readAddr;
MBBuf.ByteNumber = 2 ; //一次读取的数据长度
MBBuf.RxPointer = &I2CData.rxData[2]; // 读取的数据从2开始放01用于存储接收到的地址
MBBuf.Index = 0;
// ModBusReadMultiByte();//根据MBBuf.StartAddr得到对应寄存器数据
// I2CData.rxData[2] = tempL.Word[0];
// I2CData.rxData[3] = tempL.Word[1];
// 获取数据个数
u8 count = 1;
switch(MBBuf.StartAddr) {
case 0x30: count = 6; break;
case 0x3A: count = 2; break;
case 0x3C: count = 3; break;
case 0x56: count = 4; break;
case 0x85: count = 2; break;
case 0xAE: count = 2; break;
default : count = 1;
}
// 生成响应
// UserReadDataProtocol();
u16 index = MBBuf.StartAddr - 0x30;//STD_REG_START
u16 data ;
u8 i , tx_idx = 0;
if(MBBuf.StartAddr > 0x30 && MBBuf.StartAddr <0x130)
{
for( i = 0; i < count; i++)
{
data = MBReg[index + i];
I2CData.txData[tx_idx++] = (data >> 8) & 0xFF;
I2CData.txData[tx_idx++] = data & 0xFF;
I2CData.txData[tx_idx++] = I2CWordCrc((data >> 8) & 0xFF, data & 0xFF);
}
}
else
{
I2CData.txData[tx_idx++] =0x00;
I2CData.txData[tx_idx++] =0x01;
I2CData.txData[tx_idx++] = I2CWordCrc(0x00, 0x01);
}
iic_tx_len = tx_idx;
}
//中断 测试代码 end========================================================
/*********************************************************************************************************************************************/
/*DMA 方式*/
/*********************************************************************************************************************************************/
void DMA_I2C_SlaveRx_Init(void)
{
DMAMUX_InitTypeDef DMAMUX_InitStructure;
/* 配置DMAUX 请求源 RX触发DMA通道0 */
DMAMUX_InitStructure.DMA_Channel = DMA_CHANNEL_0; // 配置DMA0触发源
DMAMUX_InitStructure.Request_Source = REQUEST_SOURCE_I2C0_RX; // 触发源I2C0_RX
DMAMUX_InitStructure.Periodic_Trigger = DISABLE; // 禁用周期触发
DMAMUX_InitStructure.Cmd = ENABLE; // 使能
LHL_DMAMUX_Init(&DMAMUX_InitStructure);
/* 配置DMA通道0负责I2C RX数据搬运到缓存区 */
DMA_Handle_IIC_Rx.Channel = DMA_CHANNEL_0; // DMACH0
DMA_Handle_IIC_Rx.Mode = DMA_DIRECT_MODE; // 直接模式
DMA_Handle_IIC_Rx.Request = DMA_HARDWARE_REQUEST; // 硬件触发
DMA_Handle_IIC_Rx.Init.Direction = DMA_PERIPH_TO_MEMORY; // 外设->内存
DMA_Handle_IIC_Rx.Init.Src_Address = (uint32_t)(&pI2C->DR); // 源I2C DR寄存器
DMA_Handle_IIC_Rx.Init.Dest_Address = (uint32_t)&I2CData.rxData; // 目的:缓存区
DMA_Handle_IIC_Rx.Init.Data_Width = DMA_DATA_WIDTH_1B; // 数据宽度等于寄存器宽度
DMA_Handle_IIC_Rx.Init.Data_Size = 1; // 每次读取1个寄存器
DMA_Handle_IIC_Rx.Init.Repetition = 2; // 重复读取 次
DMA_Handle_IIC_Rx.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION; // 循环模式
if (LHL_DMA_Init(&DMA_Handle_IIC_Rx) != LHL_OK)
{
while(1); // DMA Init Error
}
LHL_DMA_ITConfig(&DMA_Handle_IIC_Rx, DMA_IT_MAJOR, ENABLE); // 开启DMA0主中断
NVIC_EnableIRQ(DMA1_CH0_IRQn);
}
void DMA_I2C_SlaveTx_Init(void)
{
DMAMUX_InitTypeDef DMAMUX_InitStructure;
/* 配置DMAUX 请求源 TX触发DMA通道1 */
DMAMUX_InitStructure.DMA_Channel = DMA_CHANNEL_1; // 配置DMA1触发源
DMAMUX_InitStructure.Request_Source = REQUEST_SOURCE_I2C0_TX; // 触发源I2C0_TX
DMAMUX_InitStructure.Periodic_Trigger = DISABLE;
DMAMUX_InitStructure.Cmd = ENABLE;
LHL_DMAMUX_Init(&DMAMUX_InitStructure);
/* 配置DMA通道1负责缓存区数据搬运到I2C TX数据 */
DMA_Handle_IIC_Tx.Channel = DMA_CHANNEL_1; // 句柄更改为DMA1
DMA_Handle_IIC_Tx.Mode = DMA_DIRECT_MODE;
DMA_Handle_IIC_Tx.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_IIC_Tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // 内存->外设
DMA_Handle_IIC_Tx.Init.Src_Address = (uint32_t)&I2CData.txData; // 源:缓存区
DMA_Handle_IIC_Tx.Init.Dest_Address = (uint32_t)(&pI2C->DR); // 目的I2C DR寄存器
DMA_Handle_IIC_Tx.Init.Data_Width = DMA_DATA_WIDTH_1B;
DMA_Handle_IIC_Tx.Init.Data_Size = 1;
DMA_Handle_IIC_Tx.Init.Repetition = iic_tx_len;
DMA_Handle_IIC_Tx.Init.Trans_Mode = DMA_SINGLE_TRANSMISSION; // 单次模式 DMA_SINGLE_TRANSMISSION DMA_INTERVAL_TRANSMISSION
if (LHL_DMA_Init(&DMA_Handle_IIC_Tx) != LHL_OK)
{
while(1); // DMA Init Error
}
LHL_DMA_ITConfig(&DMA_Handle_IIC_Tx, DMA_IT_MAJOR, ENABLE); // 开启DMA1主中断
NVIC_EnableIRQ(DMA1_CH1_IRQn);
}
void DMA_I2C_Slave_Init(u32 clockSpeed ,u16 slaveAddress)
{
I2C_Slave_Init(clockSpeed,slaveAddress);
LHL_I2C_DMACmd(ENABLE);//DMA请求使能
DMA_I2C_SlaveRx_Init();
iic_tx_len=3;
DMA_I2C_SlaveTx_Init();
LHL_DMA_Start(&DMA_Handle_IIC_Rx);
}
//for DMA
void I2C1_EV_IRQHandler3()//
{
__IO uint32_t sta1,sta2;
uint32_t R_W;
uint8_t data;
sta1 = pI2C->SR1;
sta2 = pI2C->SR2;
R_W = (sta2 & I2C_SR2_TRA_Msk)>>I2C_SR2_TRA_Pos; //write frame or read frame
if(sta1 & I2C_SR1_ADDR_Msk) //I2C address match
{
if (R_W == 1)
{
LHL_DMA_Stop(&DMA_Handle_IIC_Tx);
DMA_I2C_SlaveTx_Init();
LHL_DMA_Start(&DMA_Handle_IIC_Tx);
}
if (R_W == 0)
{
}
}
if(sta1 & I2C_SR1_STOPF_Msk)
{
pI2C->CR1 |= I2C_CR1_STOP_Msk;
}
if(sta1 & I2C_SR1_AF_Msk)
{
pI2C->CR1 |= I2C_SR1_AF_Msk; //主机nack
}
if(sta1 & I2C_SR1_AF_Msk)
{
pI2C->SR1 &= ~I2C_SR1_AF_Msk;
}
__DSB(); //make sure intterupt flag cleared
}
#endif