Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 3552

Interfacing (DSI, CSI, I2C, etc.) • Memory mapped i2c read issues (rpi 4B)

$
0
0
Hi all!

I've been trying to get memory mapped i2c (using mmap() to initialize peripherals) working for my Raspberry pi 4B. I've gotten i2c write to work (able to control servos via a PCA9685), but I'm struggling with i2c read.

Here is my current implementation:

Code:

// From the bcm2711 datasheet#define BSC1_BASE   0xFE804000#define BSC1_LENGTH 0x0020#define BSC_C    (0x00 / 4)#define BSC_S    (0x04 / 4)#define BSC_DLEN (0x08 / 4)#define BSC_A    (0x0C / 4)#define BSC_FIFO (0x10 / 4)#define BSC_C_CLEAR ((1 << 4) | (1 << 5))#define BSC_C_ST     (1 << 7)#define BSC_C_I2EN   (1 << 15)#define BSC_C_READ   (1 << 0)#define BSC_S_DONE (1 << 1)#define BSC_S_TXD  (1 << 4)#define BSC_S_ERR  (1 << 8)#define BSC_S_CLKT (1 << 9)(...)static uint32_t i2c_read_register(volatile uint32_t *bsc, uint8_t device_address, uint8_t register_address, uint32_t *register_value){    bsc[BSC_A] = device_address; // set target device    bsc[BSC_DLEN] = 1;                   // 1 byte    // Write register address    bsc[BSC_C]   |= BSC_C_CLEAR; // clear fifo    bsc[BSC_FIFO] = register_address;     bsc[BSC_S]    = BSC_S_DONE;// reset done    bsc[BSC_C]   |= BSC_C_ST;// start write    while (!(bsc[BSC_S] & BSC_S_DONE)) {;}    // Read from register address    bsc[BSC_C] |= BSC_C_CLEAR;                       // clear fifo    bsc[BSC_S]  = BSC_S_DONE;                         // reset done    bsc[BSC_C] |= BSC_C_ST | BSC_C_READ;   // start read    while (!(bsc[BSC_S] & BSC_S_DONE)) {;}    *register_value = bsc[BSC_FIFO];     return bsc[BSC_S];}(...)internal uint8 i2c_error_check(uint32 status){    if (status & BSC_S_ERR)    {        return 1;    }    else if (status & BSC_S_CLKT)    {        return 1;    }    else    {        return 0;    }}
The issue is this: If i read from a register, the first value is correct, but any reads after returns the an incorrect value. If i read from the same register 10 times in a row:

Code:

// device address is 0x40, register address is 0x00i2c_write_register(i2c1, 0x40, 0x00, 1 << 5); // 1 << 5 = 32 in decimaluint32 value = 0;for (uint8 i = 0; i < 10; i++){     status = i2c_read_register(i2c1, 0x40, 0x00, &value);     ASSERT(i2c_error_check(status) == 0); // does not fail     printf("value: %u\n", value); }(...)value: 32  <- first read, correctvalue: 226value:232value: 0value: 0value: 59value: 0value: 0value: 59value: 0
...and I have no idea why.

I've tried adding small delays (100us) after each fifo reset, but nothing. I've also tried adding delays between reads and writes, but nothing. I've also check the error bit (bit 8) and the clock streching bit (bit 9) in the status register after reading, but there does not seem to be any issues.

If anyone could point me in the right direction or help me understand what is wrong here, it would be greatly appreciated.

First time posting, so please let me know if any info is missing or if I can make the post better/more understandable.

-bud

Statistics: Posted by bud92 — Sat Mar 16, 2024 7:10 pm



Viewing all articles
Browse latest Browse all 3552

Trending Articles