我有一个 MIPS板AR9341 ,其中我想从u boot本身而不是从内核添加对 bit-banging i2c 总线的支持。
我还有两个 GPIO ,它们是免费的,可以用于SDA和SCL Pin。
我还阅读了一些文档以及用户指南,了解如何在u boot中添加支持bit-banging i2c总线,但没有得到正确的想法。
是否有任何人有关于如何使用u boot中的GPIO添加bit-banging i2c总线支持的文档或想法?
如果有人对此有所了解,请帮助我。
我尝试使用u boot中的两个 LED 设置并清除两个 GPIO ,它可以正常工作而没有任何问题。现在我想将这两个GPI连接为 SDA 和 SCL 行,以便进行软件位冲击。
是否有人知道如何将 GPIO 配置为 SDA 和 SCL 在您的启动代码中排队?
答案 0 :(得分:3)
您可以尝试获取Wikipedia上列出的I²C主协议的位冲击示例,并将其移植(适应)到您的MCU硬件。
以下是将I²C协议作为I²C主机进行位操作的示例。该示例使用伪C编写。它说明了之前描述的所有I²C功能(时钟延长,仲裁,启动/停止位,确认/ nack)
// Hardware-specific support functions that MUST be customized:
#define I2CSPEED 100
void I2C_delay() { volatile int v; int i; for (i=0; i < I2CSPEED/2; i++) v; }
bool read_SCL(void); // Set SCL as input and return current level of line, 0 or 1
bool read_SDA(void); // Set SDA as input and return current level of line, 0 or 1
void clear_SCL(void); // Actively drive SCL signal low
void clear_SDA(void); // Actively drive SDA signal low
void arbitration_lost(void);
bool started = false; // global data
void i2c_start_cond(void) {
if (started) { // if started, do a restart cond
// set SDA to 1
read_SDA();
I2C_delay();
while (read_SCL() == 0) { // Clock stretching
// You should add timeout to this loop
}
// Repeated start setup time, minimum 4.7us
I2C_delay();
}
if (read_SDA() == 0) {
arbitration_lost();
}
// SCL is high, set SDA from 1 to 0.
clear_SDA();
I2C_delay();
clear_SCL();
started = true;
}
void i2c_stop_cond(void){
// set SDA to 0
clear_SDA();
I2C_delay();
// Clock stretching
while (read_SCL() == 0) {
// add timeout to this loop.
}
// Stop bit setup time, minimum 4us
I2C_delay();
// SCL is high, set SDA from 0 to 1
if (read_SDA() == 0) {
arbitration_lost();
}
I2C_delay();
started = false;
}
// Write a bit to I2C bus
void i2c_write_bit(bool bit) {
if (bit) {
read_SDA();
} else {
clear_SDA();
}
I2C_delay();
while (read_SCL() == 0) { // Clock stretching
// You should add timeout to this loop
}
// SCL is high, now data is valid
// If SDA is high, check that nobody else is driving SDA
if (bit && read_SDA() == 0) {
arbitration_lost();
}
I2C_delay();
clear_SCL();
}
// Read a bit from I2C bus
bool i2c_read_bit(void) {
bool bit;
// Let the slave drive data
read_SDA();
I2C_delay();
while (read_SCL() == 0) { // Clock stretching
// You should add timeout to this loop
}
// SCL is high, now data is valid
bit = read_SDA();
I2C_delay();
clear_SCL();
return bit;
}
// Write a byte to I2C bus. Return 0 if ack by the slave.
bool i2c_write_byte(bool send_start,
bool send_stop,
unsigned char byte) {
unsigned bit;
bool nack;
if (send_start) {
i2c_start_cond();
}
for (bit = 0; bit < 8; bit++) {
i2c_write_bit((byte & 0x80) != 0);
byte <<= 1;
}
nack = i2c_read_bit();
if (send_stop) {
i2c_stop_cond();
}
return nack;
}
// Read a byte from I2C bus
unsigned char i2c_read_byte(bool nack, bool send_stop) {
unsigned char byte = 0;
unsigned bit;
for (bit = 0; bit < 8; bit++) {
byte = (byte << 1) | i2c_read_bit();
}
i2c_write_bit(nack);
if (send_stop) {
i2c_stop_cond();
}
return byte;
}
然后您需要要做在上面的代码中注释的所有地方{GP}都设置了1
或0
,取决于您在设备。
顺便说一句,我已经为MSP430做了这个并且它可以工作。
此外,您可以在网络实现中找到许多其他MCU并进行比较,如下所示,但我会从上面的代码开始。
#include "pic16lf1947.h" #include "PIC16_I2C_BITBANG.h" #include "xc.h" //.................................................................... // This function generates an I2C Start Condition //.................................................................... void i2c_start(void) { unsigned int i; SDA_TRIS = 1; // ensure SDA & SCL are high SCL = 1; SDA_TRIS = 0; // SDA = output SDA = 0; // pull SDA low for (i=0;i<2;i++) NOP(); SCL = 0; // pull SCL low } //.................................................................... // This function generates an I2C Stop Condition //.................................................................... void i2c_stop(void) { unsigned int i; SCL = 0; // ensure SCL is low SDA_TRIS = 0; // SDA = output SDA = 0; // SDA low for (i=0;i<3;i++) NOP(); SCL = 1; // pull SCL high SDA_TRIS = 1; // allow SDA to be pulled high for (i=0;i<3;i++) NOP(); SCL=0; // ensure SCL is low } //.......................................................... AR9341.......... // Outputs a bit to the I2C bus //.................................................................... void bit_out(unsigned char data) { unsigned int i; SCL = 0; // ensure SCL is low SDA_TRIS=0; // configure SDA as an output SDA= (data>>7); // output the MSB for (i=0;i<2;i++) NOP(); SCL = 1; // pull SCL high to clock bit for (i=0;i<3;i++) NOP(); SCL = 0; // pull SCL low for next bit } //.................................................................... // Inputs a bit from the I2C bus //.................................................................... void bit_in(unsigned char *data) { unsigned int i; SCL = 0; // ensure SCL is low SDA_TRIS = 1; // configure SDA as an input SCL = 1; // bring SCL high to begin transfer for (i=0;i<3;i++) NOP(); *data |= SDA; // input the received bit SCL = 0; // bring SCL low again. } //.................................................................... // Writes a byte to the I2C bus //.................................................................... unsigned char i2c_wr(unsigned char data) { unsigned char i; // loop counter unsigned char ack; // ACK bit ack = 0; for (i = 0; i < 8; i++) // loop through each bit { bit_out(data); // output bit data = data << 1; // shift left for next bit } bit_in(&ack); // input ACK bit return ack; } //.................................................................... // Reads a byte from the I2C bus //.................................................................... unsigned char i2c_rd(unsigned char ack) { unsigned char i; // loop counter unsigned char ret=0; // return value for (i = 0; i < 8; i++) // loop through each bit { ret = ret << 1; // shift left for next bit bit_in(&ret); // input bit } bit_out(ack); // output ACK/NAK bit return ret; } //............................................................................. // Polls the bus for ACK from device //............................................................................. void ack_poll (unsigned char control) { unsigned char result=1; while(result) { i2c_start(); // generate Restart condition result=i2c_wr(control); // send control byte (WRITE command) } i2c_stop(); // generate Stop condition }
祝你好运!// Port for the I2C #define I2C_DDR DDRD #define I2C_PIN PIND #define I2C_PORT PORTD // Pins to be used in the bit banging #define I2C_CLK 0 #define I2C_DAT 1 #define I2C_DATA_HI()\ I2C_DDR &= ~ (1 << I2C_DAT);\ I2C_PORT |= (1 << I2C_DAT); #define I2C_DATA_LO()\ I2C_DDR |= (1 << I2C_DAT);\ I2C_PORT &= ~ (1 << I2C_DAT); #define I2C_CLOCK_HI()\ I2C_DDR &= ~ (1 << I2C_CLK);\ I2C_PORT |= (1 << I2C_CLK); #define I2C_CLOCK_LO()\ I2C_DDR |= (1 << I2C_CLK);\ I2C_PORT &= ~ (1 << I2C_CLK); void I2C_WriteBit(unsigned char c) { if (c > 0) { I2C_DATA_HI(); } else { I2C_DATA_LO(); } I2C_CLOCK_HI(); delay(1); I2C_CLOCK_LO(); delay(1); if (c > 0) { I2C_DATA_LO(); } delay(1); } unsigned char I2C_ReadBit() { I2C_DATA_HI(); I2C_CLOCK_HI(); delay(1); unsigned char c = I2C_PIN; I2C_CLOCK_LO(); delay(1); return (c >> I2C_DAT) & 1; } // Inits bitbanging port, must be called before using the functions below // void I2C_Init() { I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); I2C_CLOCK_HI(); I2C_DATA_HI(); delay(1); } // Send a START Condition // void I2C_Start() { // set both to high at the same time I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); delay(1); I2C_DATA_LO(); delay(1); I2C_CLOCK_LO(); delay(1); } // Send a STOP Condition // void I2C_Stop() { I2C_CLOCK_HI(); delay(1); I2C_DATA_HI(); delay(1); } // write a byte to the I2C slave device // unsigned char I2C_Write(unsigned char c) { for (char i = 0; i < 8; i++) { I2C_WriteBit(c & 128); c <<= 1; } //return I2C_ReadBit(); return 0; } // read a byte from the I2C slave device // unsigned char I2C_Read(unsigned char ack) { unsigned char res = 0; for (char i = 0; i < 8; i++) { res <<= 1; res |= I2C_ReadBit(); } if (ack > 0) { I2C_WriteBit(0); } else { I2C_WriteBit(1); } delay(1); return res; }