Last active
April 14, 2022 09:43
-
-
Save ksvbka/fec1f28ce40c276334fb to your computer and use it in GitHub Desktop.
I2C Bit-Bangging - MSP430
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************** | |
Module : I2C_SW | |
Author : 05/04/2015, by KienLTb - https://kienltb.wordpress.com/ | |
Description : I2C software using bit-banging. | |
********************************************************************************/ | |
/*-----------------------------------------------------------------------------*/ | |
/* Header inclusions */ | |
/*-----------------------------------------------------------------------------*/ | |
#include "msp430g2553.h" | |
#include "i2c_sw.h" | |
/*-----------------------------------------------------------------------------*/ | |
/* Local Macro definitions */ | |
/*-----------------------------------------------------------------------------*/ | |
/*-----------------------------------------------------------------------------*/ | |
/* Function prototypes */ | |
/*-----------------------------------------------------------------------------*/ | |
unsigned char Read_SCL(void); | |
unsigned char Read_SDA(void); | |
void Clear_SCL(void); | |
void Clear_SDA(void); | |
void I2C_Init(void); | |
void I2C_Start(void); | |
void I2C_Stop(void); | |
void I2C_Writebit(unsigned char bit); | |
unsigned char I2C_ReadByte(void); | |
void I2C_WriteByte(unsigned char Data); | |
unsigned char I2C_ReadByte(void); | |
void I2C_WriteData(unsigned char *Data, unsigned char DevideAddr, unsigned char Register, unsigned char nLength); | |
void I2C_ReadData(unsigned char *Buff, unsigned char DevideAddr, unsigned char Register, unsigned char nLength); | |
/*-----------------------------------------------------------------------------*/ | |
/* Function implementations */ | |
/*-----------------------------------------------------------------------------*/ | |
/*-------------------------------------------------------------------------------- | |
Function : Read_SCL | |
Purpose : Set SCL as input and return current Logic level of SCL (0 or 1) | |
nomal is 1 because pullup by resistor | |
Parameters : None | |
Return : Logic level of SCL pin | |
--------------------------------------------------------------------------------*/ | |
unsigned char Read_SCL(void) | |
{ | |
I2C_PxDIR &= ~SCL; | |
return((I2C_PxIN & SCL) != 0); | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : Read_SDA | |
Purpose : Set SDA as input and return current Logic level of SDA (0 or 1), | |
nomal is 1 because pullup by resistor | |
Parameters : None | |
Return : Logic level of SDA pin | |
--------------------------------------------------------------------------------*/ | |
unsigned char Read_SDA(void) | |
{ | |
I2C_PxDIR &= ~SDA; | |
return((I2C_PxIN & SDA) != 0); | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : Clear_SCL | |
Purpose : Set SCL as Out put, logic Low | |
Parameters : None | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void Clear_SCL(void) | |
{ | |
I2C_PxDIR |= SCL; | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : Clear_SDA | |
Purpose : Set SDA as Out put, logic LOW | |
Parameters : None | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void Clear_SDA(void) | |
{ | |
I2C_PxDIR |= SDA; | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_Init | |
Purpose : Initialize I2C block | |
Parameters : None | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_Init(void) | |
{ | |
// Conffig SCL and SDA as GPIO | |
I2C_PxSEL &= ~(SCL + SDA); | |
I2C_PxSEL2 &= ~(SCL + SDA); | |
// Set SCL and SDA is logic HIGH | |
I2C_PxDIR &= ~(SCL + SDA); | |
I2C_PxOUT &= ~(SCL + SDA); | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_Start | |
Purpose : Send start signal | |
Parameters : None | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_Start(void) | |
{ | |
Read_SDA(); //set SDA to 1 | |
I2C_DELAY(); | |
Clear_SDA(); //set SDA to 0, currently SCL is 1 | |
I2C_DELAY(); | |
Clear_SCL(); //set SCL to 0 | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_Stop | |
Purpose : Send Stop signal | |
Parameters : None | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_Stop(void) | |
{ | |
Clear_SDA(); //set SDA to 0 | |
I2C_DELAY(); | |
Read_SCL(); //set SCL to 1 | |
I2C_DELAY(); | |
Read_SDA(); //set SDA to 1 | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_Writebit | |
Purpose : Write bit to I2C bus | |
Parameters : a bit need to write | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_Writebit(unsigned char bit) | |
{ | |
if(bit) | |
Read_SDA(); | |
else | |
Clear_SDA(); | |
I2C_DELAY(); | |
Read_SCL(); | |
I2C_DELAY(); | |
Clear_SCL(); | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_Readbit | |
Purpose : Read bit to I2C bus | |
Parameters : None | |
Return : unsigned char | |
--------------------------------------------------------------------------------*/ | |
unsigned char I2C_Readbit(void) | |
{ | |
unsigned char bit; | |
//Let the slave driver data | |
Read_SDA(); | |
I2C_DELAY(); | |
Read_SCL(); | |
bit = Read_SDA(); | |
I2C_DELAY(); | |
Clear_SCL(); | |
return bit; | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_WriteByte | |
Purpose : Write a Byte to I2C bus | |
Parameters : unsigned char Data | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_WriteByte(unsigned char Data) | |
{ | |
unsigned char nBit; | |
for(nBit = 0; nBit < 8; nBit++) | |
{ | |
I2C_Writebit((Data & 0x80) != 0); | |
Data <<= 1; | |
} | |
I2C_Readbit(); // Waite NACK | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_ReadByte | |
Purpose : Read a Byte to I2C bus | |
Parameters : None | |
Return : unsigned char | |
--------------------------------------------------------------------------------*/ | |
unsigned char I2C_ReadByte(void) | |
{ | |
unsigned char Buff = 0; | |
unsigned char nBit; | |
for(nBit = 0; nBit < 8; nBit++) | |
{ | |
Buff = (Buff << 1) | I2C_Readbit(); | |
} | |
return Buff; | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_WriteData | |
Purpose : Write n Byte to I2C bus | |
Parameters : Data - Pointer to Data need to write | |
DevideAddr - Devide Address | |
Register - Register Address | |
nLength - Number of Byte need to write | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_WriteData(unsigned char *Data, unsigned char DevideAddr, unsigned char Register, unsigned char nLength) | |
{ | |
unsigned char nIndex; | |
I2C_Start(); | |
I2C_WriteByte(DevideAddr << 1); // byDeviceAddr is 7 bit and command is write | |
I2C_WriteByte(Register); | |
for(nIndex = 0; nIndex < nLength; nIndex++) | |
{ | |
I2C_WriteByte(*(Data + nIndex)); | |
} | |
I2C_Readbit(); | |
I2C_Stop(); | |
} | |
/*-------------------------------------------------------------------------------- | |
Function : I2C_ReadData | |
Purpose : Read n Byte from I2C bus | |
Parameters : Buff - Pointer to Buffer store value | |
DevideAddr - Devide Address | |
Register - Register Address | |
nLength - Number of Byte need to read | |
Return : None | |
--------------------------------------------------------------------------------*/ | |
void I2C_ReadData(unsigned char *Buff, unsigned char DevideAddr, unsigned char Register, unsigned char nLength) | |
{ | |
unsigned char nIndex; | |
I2C_Start(); | |
I2C_WriteByte(DevideAddr << 1); | |
I2C_WriteByte(Register); | |
I2C_Stop(); | |
_NOP(); // Short delay | |
I2C_Start(); | |
_NOP(); // Short delay | |
I2C_WriteByte((DevideAddr << 1) | 1); | |
for(nIndex = 0; nIndex < nLength; nIndex++) | |
{ | |
*(Buff + nIndex) = I2C_ReadByte(); | |
if(nIndex > 0)I2C_Writebit(ACK); | |
} | |
I2C_Writebit(NACK); | |
I2C_Stop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************** | |
Module : I2C_SW | |
Author : 05/04/2015, by KienLTb - https://kienltb.wordpress.com/ | |
Description : I2C software using bit-banging. | |
********************************************************************************/ | |
#ifndef _I2C_SW_H_ | |
#define _I2C_SW_H_ | |
/*-----------------------------------------------------------------------------*/ | |
/* Macro definitions */ | |
/*-----------------------------------------------------------------------------*/ | |
/*-----------------------------------------------------------------------------*/ | |
/* Local Macro definitions */ | |
/*-----------------------------------------------------------------------------*/ | |
#define I2C_PxSEL P1SEL | |
#define I2C_PxSEL2 P1SEL2 | |
#define I2C_PxDIR P1DIR | |
#define I2C_PxOUT P1OUT | |
#define I2C_PxIN P1IN | |
#define SCL BIT6 | |
#define SDA BIT7 | |
#define ACK 0x00 | |
#define NACK 0x01 | |
#define TIME_DELAY 100 | |
#define I2C_DELAY() __delay_cycles(TIME_DELAY) | |
/*-----------------------------------------------------------------------------*/ | |
/* Function prototypes */ | |
/*-----------------------------------------------------------------------------*/ | |
//NOTE: Need custom Read_SCL(), Read_SDA(), Clear_SCL(), Clear_SDA() to compatible Hardware. | |
unsigned char Read_SCL(void); // Set SCL as input and return current level of line, 0 or 1, nomal is 1 because pullup by res | |
unsigned char Read_SDA(void); // Set SDA as input and return current level of line, 0 or 1, nomal is 0 because pull by res | |
void Clear_SCL(void); // Actively drive SCL signal Low | |
void Clear_SDA(void); // Actively drive SDA signal Low | |
void I2C_Init(void); | |
void I2C_Start(void); | |
void I2C_Stop(void); | |
void I2C_Writebit(unsigned char bit); | |
unsigned char I2C_Readbit(void); | |
void I2C_WriteByte(unsigned char Data); | |
unsigned char I2C_ReadByte(void); | |
void I2C_WriteData(unsigned char *Data, unsigned char DevideAddr, unsigned char Register, unsigned char nLength); | |
void I2C_ReadData(unsigned char *Buff, unsigned char DevideAddr, unsigned char Register, unsigned char nLength); | |
#endif // _I2C_SW_H_ | |
https://gist.github.com/ksvbka/fec1f28ce40c276334fb#file-i2c_sw-c-L248
Multibyte read also fails on the I2C EEPROM. This like should look like this:
if(nIndex < nLength - 1) I2C_Writebit(ACK);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Additional call of I2C_Readbit on the line 222 is causing issues on some I2C devices such as EEPROM (I wasn't able to write anything into the EEPROM until I've removed this line).
I2C_Readbit is called in the I2C_WriteByte function and doesn't need to be called again...