STM32F4XX interrupt mode simulates I2C bus through IO

Source: Internet
Author: User

At present, most IO analog I2c bus programs on the Internet are query methods, which wastes a lot of CPU cycles for cyclic waiting. The program in this article uses the timer interrupt to push the state machine to simulate I2C bus operations,

The method of interruption is used. Please define the callback function. This program will automatically call the callback function when reading or writing is completed or an error occurs.

Of course, this program can also read and write the I2c bus through the query method. You only need to query IIC_BUSY.

I2c_sim.h

#ifndef __I2C_SIM_H__#define __I2C_SIM_H__#include <stm32f4xx.h>#define MAXFREQ 1000000extern uint8_t I2C_Read7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t *Buf, uint8_t Count);extern uint8_t I2C_Read16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count);extern uint8_t I2C_WriteByte7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t Data);extern uint8_t I2C_Write16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count);extern void IIC_Init(uint8_t IIC, uint16_t MicroSecond);extern void IIC_DeInit(uint8_t IIC);extern void IIC_SetCallback(uint8_t IIC, void(*OnTx)(void), void(*OnRx)(void) ,void(*OnErr)(void));#endif

  

 

I2c_sim.c

#include "stm32f4xx_conf.h"#include <string.h>#define IIC_COUNT 2#if (IIC_COUNT>3) Error! To many IIC#endif/*----------- I2C1 Device -----------*/  #define I2C1_SCL_GPIO_PORT         GPIOB       #define I2C1_SCL_GPIO_CLK          RCC_AHB1Periph_GPIOB #define I2C1_SCL_GPIO_PIN          GPIO_Pin_6#define I2C1_SCL_GPIO_PINSOURCE    GPIO_PinSource6   #define I2C1_SDA_GPIO_PORT         GPIOB       #define I2C1_SDA_GPIO_CLK          RCC_AHB1Periph_GPIOB #define I2C1_SDA_GPIO_PIN          GPIO_Pin_7 #define I2C1_SDA_GPIO_PINSOURCE    GPIO_PinSource7   /*-----------I2C2 Device -----------*/  #define I2C2_SCL_GPIO_PORT         GPIOA       #define I2C2_SCL_GPIO_CLK          RCC_AHB1Periph_GPIOA #define I2C2_SCL_GPIO_PIN          GPIO_Pin_8#define I2C2_SCL_GPIO_PINSOURCE    GPIO_PinSource8 #define I2C2_SDA_GPIO_PORT         GPIOC       #define I2C2_SDA_GPIO_CLK          RCC_AHB1Periph_GPIOC #define I2C2_SDA_GPIO_PIN          GPIO_Pin_9 #define I2C2_SDA_GPIO_PINSOURCE    GPIO_PinSource9  /*-----------I2C3 Device -----------*/  #define I2C3_SCL_GPIO_PORT         GPIOH#define I2C3_SCL_GPIO_CLK          RCC_AHB1Periph_GPIOH#define I2C3_SCL_GPIO_PIN          GPIO_Pin_7#define I2C3_SCL_GPIO_PINSOURCE    GPIO_PinSource7  #define I2C3_SDA_GPIO_PORT         GPIOH#define I2C3_SDA_GPIO_CLK          RCC_AHB1Periph_GPIOH#define I2C3_SDA_GPIO_PIN          GPIO_Pin_8#define I2C3_SDA_GPIO_PINSOURCE    GPIO_PinSource8   GPIO_TypeDef* I2C_SCL_GPIO_PORT[3] = {I2C1_SCL_GPIO_PORT, I2C2_SCL_GPIO_PORT, I2C3_SCL_GPIO_PORT};const uint16_t I2C_SCL_GPIO_PIN[3] = {I2C1_SCL_GPIO_PIN, I2C2_SCL_GPIO_PIN, I2C3_SCL_GPIO_PIN};const uint32_t I2C_SCL_GPIO_CLK[3] = {I2C1_SCL_GPIO_CLK, I2C2_SCL_GPIO_CLK, I2C3_SCL_GPIO_CLK};const uint16_t I2C_SCL_GPIO_PINSOURCE[3] = {I2C1_SCL_GPIO_PINSOURCE, I2C2_SCL_GPIO_PINSOURCE, I2C3_SCL_GPIO_PINSOURCE};GPIO_TypeDef* I2C_SDA_GPIO_PORT[3] = {I2C1_SDA_GPIO_PORT,I2C2_SDA_GPIO_PORT,I2C3_SDA_GPIO_PORT};const uint16_t I2C_SDA_GPIO_PIN[3] = {I2C1_SDA_GPIO_PIN,I2C2_SDA_GPIO_PIN,I2C3_SDA_GPIO_PIN};const uint32_t I2C_SDA_GPIO_CLK[3] = {I2C1_SDA_GPIO_CLK,I2C2_SDA_GPIO_CLK,I2C3_SDA_GPIO_CLK};const uint16_t I2C_SDA_GPIO_PINSOURCE[3] = {I2C1_SDA_GPIO_PINSOURCE,I2C2_SDA_GPIO_PINSOURCE,I2C3_SDA_GPIO_PINSOURCE};TIM_TypeDef* Timer[3] = {TIM5, TIM6, TIM7};const IRQn_Type TimerIRQ[3] = {TIM5_IRQn, TIM6_DAC_IRQn, TIM7_IRQn};const uint32_t RCC_APB1Periph_TIM[3] ={RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7};#define SDA_Clear(IIC) I2C_SDA_GPIO_PORT[IIC]->BSRRH=I2C_SDA_GPIO_PIN[IIC]#define SDA_Set(IIC) I2C_SDA_GPIO_PORT[IIC]->BSRRL=I2C_SDA_GPIO_PIN[IIC]#define SCL_Clear(IIC) I2C_SCL_GPIO_PORT[IIC]->BSRRH=I2C_SCL_GPIO_PIN[IIC]#define SCL_Set(IIC) I2C_SCL_GPIO_PORT[IIC]->BSRRL=I2C_SCL_GPIO_PIN[IIC]#define En_SDA_Input(IIC) I2C_SDA_GPIO_PORT[IIC]->MODER&=~(I2C_SDA_GPIO_PIN[IIC]<<I2C_SDA_GPIO_PINSOURCE[IIC])#define En_SDA_Output(IIC) I2C_SDA_GPIO_PORT[IIC]->MODER|=(I2C_SDA_GPIO_PIN[IIC]<<I2C_SDA_GPIO_PINSOURCE[IIC])#define SDA_Read(IIC) ((I2C_SDA_GPIO_PORT[IIC]->IDR&I2C_SDA_GPIO_PIN[IIC])!=0)?1:0 typedef struct {__IO uint8_t StartState;__IO uint8_t StopState;__IO int8_t ReadByteState;__IO uint8_t TransferByte;__IO uint8_t ReadStop;__IO uint8_t WriteByteState;__IO uint8_t WriteACK;__IO uint8_t Command;//1-Read, 0=Write;__IO uint8_t Device;__IO uint32_t SubAddr;__IO uint8_t SubAddrLen;__IO uint8_t *TransferBuf;__IO uint16_t TransferCount;__IO uint8_t ReadState;__IO uint8_t WriteState;__IO uint8_t dat;__IO uint8_t bit;__IOuint8_t IIC_BUSY;__IO uint8_t ERROR;}IIC_State;static IIC_State iic_state[IIC_COUNT];typedef struct {void(*OnTx)(void);void(*OnRx)(void);void(*OnErr)(void);} IIC_Callback;__IO IIC_Callback iic_callback[IIC_COUNT];#define IN            1#define OUT           0void __INLINE SetIicSdaDir(uint8_t IIC, uint8_t x) {if (x) En_SDA_Input(IIC); else En_SDA_Output(IIC);}void IIC_GPIOInit(uint8_t IIC){    GPIO_InitTypeDef GPIO_InitStructure;    /* Enable I2Cx SCL and SDA Pin Clock */RCC_AHB1PeriphClockCmd((I2C_SCL_GPIO_CLK[IIC] | I2C_SDA_GPIO_CLK[IIC]), ENABLE);       /* Set GPIO frequency to 50MHz */  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    /* Select Alternate function mode */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//?????    /* Select output Open Drain type */  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;    /* Disable internal Pull-up */  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;    /* Initialize I2Cx SCL Pin */   GPIO_InitStructure.GPIO_Pin = I2C_SCL_GPIO_PIN[IIC];    GPIO_Init((GPIO_TypeDef*)I2C_SCL_GPIO_PORT[IIC], &GPIO_InitStructure);    /* Initialize I2Cx SDA Pin */  GPIO_InitStructure.GPIO_Pin = I2C_SDA_GPIO_PIN[IIC];    GPIO_Init((GPIO_TypeDef*)I2C_SDA_GPIO_PORT[IIC], &GPIO_InitStructure);     }static void IIC_DelayTimer_Init(uint8_t IIC){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel = TimerIRQ[IIC];NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ;NVIC_Init(&NVIC_InitStructure);memset((void *)&iic_state[IIC], 0, sizeof(IIC_State));memset((void *)&iic_callback[IIC], 0, sizeof(IIC_Callback));}static void IIC_DelayTimer_DeInit(uint8_t IIC){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel = TimerIRQ[IIC];NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(Timer[IIC], DISABLE);memset(&iic_state[IIC], 0, sizeof(IIC_State));}static void IIC_SetDelay(uint8_t IIC, uint16_t MicroSecond){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;RCC_ClocksTypeDef rccClocks;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM[IIC],ENABLE);RCC_GetClocksFreq(&rccClocks);TIM_DeInit(Timer[IIC]);TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;if (Timer[IIC]==TIM2||Timer[IIC]==TIM3||Timer[IIC]==TIM4||Timer[IIC]==TIM5||Timer[IIC]==TIM6||Timer[IIC]==TIM7||Timer[IIC]==TIM12||Timer[IIC]==TIM13||Timer[IIC]==TIM14) TIM_TimeBaseStructure.TIM_Prescaler=rccClocks.PCLK1_Frequency*2/1000000;else TIM_TimeBaseStructure.TIM_Prescaler=rccClocks.PCLK2_Frequency*2/1000000;TIM_TimeBaseStructure.TIM_ClockDivision=0;TIM_TimeBaseStructure.TIM_Period=MicroSecond;TIM_TimeBaseInit(Timer[IIC], &TIM_TimeBaseStructure);TIM_ClearFlag(Timer[IIC], TIM_FLAG_Update);TIM_ITConfig(Timer[IIC],TIM_FLAG_Update, ENABLE);}void IIC_Init(uint8_t IIC, uint16_t MicroSecond){IIC_GPIOInit(IIC);SDA_Set(IIC);SCL_Set(IIC);IIC_DelayTimer_Init(IIC);IIC_SetDelay(IIC, MicroSecond);     }#define p iic_state[IIC]#define q iic_callback[IIC]void IIC_SetCallback(uint8_t IIC, void(*OnTx)(void), void(*OnRx)(void) ,void(*OnErr)(void)){q.OnErr=OnErr;q.OnTx=OnTx;q.OnRx=OnRx;}void IIC_DeInit(uint8_t IIC){IIC_DelayTimer_DeInit(IIC);     }static uint8_t IIC_StartStateMachine(uint8_t IIC){switch(p.StartState) {case 0:SDA_Set(IIC);SCL_Set(IIC);p.StartState++;break;case 1:SDA_Clear(IIC);//SoftDelay(0); p.StartState++; break; case 2:SCL_Clear(IIC);p.StartState=0;break;}return p.StartState;}static uint8_t IIC_StopStateMachine(uint8_t IIC) {switch(p.StopState) {case 0:SCL_Set(IIC);SDA_Clear(IIC);//SoftDelay(1);p.StopState++;break;case 1:SDA_Set(IIC);p.StopState=0;break;}return p.StopState;}static uint8_t IIC_ReadByteStateMachine(uint8_t IIC){switch(p.ReadByteState) {case 0: SetIicSdaDir(IIC, IN);p.bit=0;p.ReadByteState++;break;case 1:p.dat <<= 1;SCL_Set(IIC);p.ReadByteState++;break;case 2:if(SDA_Read(IIC)){p.dat |= 1;}SCL_Clear(IIC);p.bit++;if (p.bit==8) p.ReadByteState++;else {p.ReadByteState--;break;}case 3:p.TransferByte=p.dat;SetIicSdaDir(IIC, OUT);if (p.ReadStop) SDA_Set(IIC); else SDA_Clear(IIC);   // ReadStop = 0; ask, ReadStop = 1,stopp.ReadByteState++;break;case 4:SCL_Set(IIC);p.ReadByteState++;break;case 5:SCL_Clear(IIC);p.ReadByteState++;case 6:p.ReadByteState=0;break;}return p.ReadByteState;}static uint8_t IIC_WriteByteStateMachine(uint8_t IIC){switch(p.WriteByteState) {case 0: p.dat=p.TransferByte;p.bit=8;p.WriteByteState++;case 1:if(p.dat & 0x80){SDA_Set(IIC);}else{SDA_Clear(IIC);}p.WriteByteState++;break;case 2:SCL_Set(IIC);p.WriteByteState++;break;case 3:p.dat <<= 1;SCL_Clear(IIC);p.bit--;if (p.bit) {p.WriteByteState=1;break;}else p.WriteByteState++;case 4:SetIicSdaDir(IIC, IN);p.WriteByteState++;break;case 5:SCL_Set(IIC);p.WriteByteState++;break;case 6:p.WriteACK = SDA_Read(IIC);SCL_Clear(IIC);SetIicSdaDir(IIC, OUT);p.WriteByteState++;break;case 7:p.WriteByteState=0;break;}return p.WriteByteState;}static uint8_t IIC_ReadStateMachine(uint8_t IIC){switch(p.ReadState) {case 0:p.ReadState++; case 1:if (IIC_StartStateMachine(IIC)==0) p.ReadState++; break;case 2:p.TransferByte=p.Device;p.ReadState++;case 3:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.ReadState=14;//Stop}else {if (p.SubAddrLen)p.ReadState++;//Send Access Addresselse p.ReadState+=3;//No Address}}break;case 4://Send Addressswitch(p.SubAddrLen) {case 4: p.TransferByte=(p.SubAddr >> 24)&0x000000FF; break;case 3: p.TransferByte=(p.SubAddr >> 16)&0x000000FF; break;case 2: p.TransferByte=(p.SubAddr >> 8)&0x000000FF; break;case 1: p.TransferByte=p.SubAddr&0x000000FF; break;}p.SubAddrLen--;p.ReadState++;case 5:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.ReadState=14;//Stop}else {if (p.SubAddrLen==0) p.ReadState++;else p.ReadState--;}}break;case 6:if (IIC_StartStateMachine(IIC)==0) p.ReadState++; break;case 7://Send Device Read p.TransferByte=p.Device|0x01;p.ReadState++;case 8:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.ReadState=14;}else {if (p.TransferCount==1) p.ReadState+=3;else p.ReadState++;}}break;case 9://Read Bytesp.ReadStop=0;p.ReadState++;case 10:if (IIC_ReadByteStateMachine(IIC)==0) {*p.TransferBuf=p.TransferByte;p.TransferBuf++;p.TransferCount--;if (p.TransferCount==1) p.ReadState++;}break;case 11://Read Last Bytep.ReadStop=1;p.ReadState++;case 12://Read Last Byteif (IIC_ReadByteStateMachine(IIC)==0) {*p.TransferBuf=p.TransferByte;p.TransferCount=0;p.ReadState++;}break;case 13:if (IIC_StopStateMachine(IIC)==0) {p.ReadState=0; p.IIC_BUSY=0;p.ERROR=0;if (q.OnRx) q.OnRx();}break;case 14:if (IIC_StopStateMachine(IIC)==0) {p.ReadState=0; p.IIC_BUSY=0;p.ERROR=1;if (q.OnErr) q.OnErr();}break;}return p.ReadState;}static uint8_t IIC_WriteStateMachine(uint8_t IIC){switch(p.WriteState) {case 0:p.WriteState++;case 1:if (IIC_StartStateMachine(IIC)==0) p.WriteState++; break;case 2:p.TransferByte=p.Device;p.WriteState++;case 3:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.WriteState=11;//Stop}else {if (p.SubAddrLen)p.WriteState++;//Send Access Addresselse {if (p.TransferCount) p.WriteState+=5;//Multi-Bytes;else p.WriteState+=3; //Single Byte}}}break;case 4://Send Addressswitch(p.SubAddrLen) {case 4: p.TransferByte=(p.SubAddr >> 24)&0x000000FF; break;case 3: p.TransferByte=(p.SubAddr >> 16)&0x000000FF; break;case 2: p.TransferByte=(p.SubAddr >> 8)&0x000000FF; break;case 1: p.TransferByte=p.SubAddr&0x000000FF; break;}p.SubAddrLen--;p.WriteState++;case 5:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.WriteState=11;//Stop}else {if (p.SubAddrLen==0) {if (p.TransferCount) p.WriteState+=3;//Multi-Bytes;else p.WriteState++; //Single Byte}else p.WriteState--;}}break;case 6://Send Only One Byte p.TransferByte=(uint32_t)p.TransferBuf;p.WriteState++;case 7:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.WriteState=11;//Stop}else {p.WriteState+=3;}}break;case 8://Send Multi-Bytes Data p.TransferByte=*p.TransferBuf; p.TransferBuf++; p.TransferCount--;p.WriteState++;case 9:if (IIC_WriteByteStateMachine(IIC)==0) {if (p.WriteACK==1) {p.WriteState=11;//Stop}else {if (p.TransferCount==0) p.WriteState++;else p.WriteState--;}}break;case 10:if (IIC_StopStateMachine(IIC)==0) {p.WriteState=0;p.IIC_BUSY=0;p.ERROR=0;if (q.OnTx) q.OnTx();}break;case 11:if (IIC_StopStateMachine(IIC)==0) {p.WriteState=0;p.IIC_BUSY=0;p.ERROR=1;if (q.OnErr) q.OnErr();}break;}return p.WriteState;}static uint8_t IIC_StateMachine(uint8_t IIC){if (p.Command) return IIC_ReadStateMachine(IIC);return IIC_WriteStateMachine(IIC);}uint8_t I2C_Read7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t *Buf, uint8_t Count){if (p.IIC_BUSY==0) {memset(&p, 0, sizeof(IIC_State));p.Command=1;//1-Read, 0=Write;p.Device=device;p.SubAddr=Addr;p.SubAddrLen=1;p.TransferBuf=Buf;p.TransferCount=Count;p.IIC_BUSY=1;TIM_Cmd(Timer[IIC], ENABLE);return 1;}else return 0;}uint8_t I2C_Read16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count){if (p.IIC_BUSY==0) {memset(&p, 0, sizeof(IIC_State));p.Command=1;//1-Read, 0=Write;p.Device=device;p.SubAddr=Addr;p.SubAddrLen=2;p.TransferBuf=Buf;p.TransferCount=Count;p.IIC_BUSY=1;TIM_Cmd(Timer[IIC], ENABLE);return 1;}else return 0;}uint8_t I2C_WriteByte7(uint8_t IIC, uint8_t device, uint8_t Addr, uint8_t Data){if (p.IIC_BUSY==0) {memset(&p, 0, sizeof(IIC_State));p.Command=0;//1-Read, 0=Write;p.Device=device;p.SubAddr=Addr;p.SubAddrLen=1;p.TransferBuf=(uint8_t *)Data;p.TransferCount=0;p.IIC_BUSY=1;TIM_Cmd(Timer[IIC], ENABLE);return 1;}else return 0;}uint8_t I2C_Write16(uint8_t IIC, uint8_t device, uint16_t Addr, uint8_t *Buf, uint8_t Count){if (p.IIC_BUSY==0) {memset(&p, 0, sizeof(IIC_State));p.Command=0;//1-Read, 0=Write;p.Device=device;p.SubAddr=Addr;p.SubAddrLen=2;p.TransferBuf=Buf;p.TransferCount=Count;p.IIC_BUSY=1;TIM_Cmd(Timer[IIC], ENABLE);return 1;}else return 0;}#if (IIC_COUNT>=1)void TIM5_IRQHandler(void){if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM5, TIM_IT_Update);if (IIC_StateMachine(0)==0) {if (iic_state[0].IIC_BUSY==0) TIM_Cmd(TIM5, DISABLE);}}}#endif#if (IIC_COUNT>=2)void TIM6_DAC_IRQHandler(void){if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM6, TIM_IT_Update);if (IIC_StateMachine(1)==0) {if (iic_state[1].IIC_BUSY==0) TIM_Cmd(TIM6, DISABLE);}}}#endif#if (IIC_COUNT>=3)void TIM7_IRQHandler(void){if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) {TIM_ClearITPendingBit(TIM7, TIM_IT_Update);if (IIC_StateMachine(2)==0) {if (iic_state[2].IIC_BUSY==0) TIM_Cmd(TIM7, DISABLE);}}}#endif

  

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.