I implement GPIO via mmap in C. Now I need to use GPIO to simulate I2C, but when I change the output of one pin, the level of the other pin is pulled low. I think I use AND and OR operations to change the value of a pin will not change the value of other pins, what is wrong with my operation? here is my code and pic:
void i2cSDA(u8* map_base, bool isHigh)
{
(*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT)) = (isHigh) ?
((PE_DAT & 0XFFFFEFFF) | 0X00001000):
((PE_DAT & 0XFFFFEFFF));
}
void i2cSCL(u8* map_base, bool isHigh)
{
(*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT)) = (isHigh) ?
((PE_DAT & 0XFFFFF7FF) | 0X00000800):
((PE_DAT & 0XFFFFF7FF));
}
and in main.c:
int main(int argc, char** argv)
{
static int dev_fd;
unsigned char *map_base;
dev_fd = open("/dev/mem", O_RDWR);
map_base = (unsigned char *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, GPIO_PAGE_OFFSET);
i2cInit(map_base);
i2cSCL(map_base, 1);
i2cDely();
i2cSDA(map_base, 1);
i2cDely();
i2cSDA(map_base, 0);
i2cDely();
i2cSDA(map_base, 1);
i2cDely();
close(dev_fd);
return 0;
}
and PE_DAT is defined as u32 PE_DAT = (*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT));
I use PE12 and PE11, the data register is 32 bits, 0:12 is data for PE0 to PE12, and 13:32 is reserved.
When I try to pull the yellow line to high, the green line get low. Full Code is Here, mainly used I2C.h and GPIO.h.
CodePudding user response:
Your funcktions to set/clear bits are wrong:
void i2cSDA(u8* map_base, bool isHigh)
{
(*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT)) = (isHigh) ?
((PE_DAT & 0XFFFFEFFF) | 0X00001000):
((PE_DAT & 0XFFFFEFFF));
}
You never update PE_DAT
which makes it contain old invalid values.
Also your expressions are too complicated.
This function should looke like this:
void i2cSDA(u8* map_base, bool isHigh)
{
if (isHigh != 0)
{
(*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT)) |= 0X00001000;
}
else
{
(*(volatile u32*)(map_base GPIO_BASE_OFFSET rPE_DAT)) &= 0XFFFFEFFF;
}
}