gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 12:03:32 25 4
gpt4 key购买 nike

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

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

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

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

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

我尝试从 u boot 设置和清除两个 GPIO 和两个 LED,它工作正常,没有任何问题。现在我想将这两个 GPIos 连接为 SDASCL 线以进行软件位转换。

有没有人知道如何将 GPIO 配置为 SDASCL 引导代码本身的线路?

最佳答案

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

以下是将 I²C 协议(protocol)作为 I²C 主设备进行位拆分的示例。该示例是用伪 C 语言编写的。它说明了之前描述的所有 I²C 功能(时钟延展、仲裁、开始/停止位、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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com