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:
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:
...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
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; }}
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
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