linux - 如何在 MIPS 板的 u 启动代码中添加对 bit-banging i2c 总线的支持

标签 linux mips i2c u-boot

我有一个MIPS板AR9341,我想在其中添加对bit-banging i2c总线的支持,从u启动本身而不是从内核。

我还有两个免费的GPIO,可用于 SDA 和 SCL 引脚。

我还阅读了一些有关如何在 u boot 中添加支持 bit-banging i2c 总线的文档以及用户指南,但没有得到正确的想法。

有没有人有任何关于如何使用 u boot 中的 GPIO 添加对 bit-banging i2c 总线的支持的文档或想法?

如果有人对此有任何想法,请尽快帮助我。

我尝试通过 u boot 设置和清除两个 GPIO 以及两个 LED,并且工作正常,没有任何问题。现在我想将这两个 GPIO 连接为 SDASCL 线以进行软件位操作。

有人知道如何在 u 启动代码本身中将 GPIO 配置为 SDASCL 行吗?

最佳答案

您可以尝试获取 Wikipedia 上列出的 I²C 主协议(protocol)的位碰撞示例。并将其移植(适应)到您的 MCU 硬件。

下面是作为 I2C 主设备对 I2C 协议(protocol)进行位操作的示例。该示例是用伪 C 语言编写的。它说明了之前描述的所有 I²C 功能(时钟拉伸(stretch)、仲裁、启动/停止位、ack/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;
}

然后您将需要TO DO在上面代码中注释的所有位置,其中10设置在正确的GPIO上,具体取决于您在设备上选择哪些。

顺便说一句,我已经为 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;
}

祝你好运!

关于linux - 如何在 MIPS 板的 u 启动代码中添加对 bit-banging i2c 总线的支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25278788/

相关文章:

mips - 为什么对无符号数的 MIPS 运算会给出有符号结果?

c++ - 如何向 MIPS 中的函数添加 4 个以上的参数?

stack - 如何从 MIPS 程序集中的堆栈中弹出?

stm32 - STM32硬件I2C有什么bug?

arm - 如何正确初始化 I2C stm32?

python - 属性错误 : 'module' object has no attribute 'SMBus'

Linux命令行如何接受没有pin的蓝牙设备配对

java - 如何以 root 用户身份运行 tomcat - 为什么 tomcat 通常在自己的用户下运行?

c - 在 c 中实现 tar 命令

linux - 关闭 getopt_long (optarg.h) 中的缩写?