Hi so i have an issue, and I have tried debugging it for quite some time now but still no luck.
What I am trying to do is connect my beaglebone black with adafruit ads1115 16 bit gravity module. I want to use my PRU1 to drive the adc module and they both communicate through i2c2. The readings that come back from the adc then get stored into a shared memory between the linux and the pru and my python code then reads from that shared memory. I implemented the register values and everything from the bealgbone manual and the ads1115 manual, and wrote a small code for the driver and the main code, but I don’t know what I am doing wrong, code wise or setting wise that fails this communication.
I read somewhere that I need to completely disconnect my i2c2 from linnux so my pru can claim that and I created a small overlay for that, but it still doesn’t work.
I also read, that I need to set my i2c2 pin 19 and 20 in mode 3 and my overlay does that, but when I check manually using the devmem2 commands the values of my pin 19 and 20 I still get 0x37 which is mode 7 and I don’t know why its doing that.
I connected my scl and sda lines with an oscilloscope to see if I get any clock but I get no clock at all, the lines are always high at 3.3v
Morevoer, my adc module works since when I use the linux inbuilt commands such as i2cget I see that the i2c 2 bus is connected to a 0x48 register device. There are not many good resources out there either, and I have scavenged the whole internet but couldn’t find anything that would help me work this i2c module.
Can someone please have a look at my code or tell me what I might be doing wrong, which causes this issue. Any help would be appreciated pleaseee. thanks so much
PRU_MAIN.C code:
#include <stdint.h>
#include <pru_cfg.h>
#include "pru_driver.h"
#define PRU_SHARED_MEM 0x00010000
void main(void) {
// Enable OCP master port
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
volatile uint32_t* shared_mem = (volatile uint32_t*)PRU_SHARED_MEM;
init_I2C();
// Configure ADS1115: AIN0, single-shot, 2.048V, 128SPS
I2C_Write(0x48, 0x01, 0xC583);
__delay_cycles(2000000); // Wait ~8ms
// Read conversion register
uint16_t adc = I2C_Read_Register(0x48, 0x00);
// Store result in PRU shared memory
shared_mem[0] = adc;
while (1) {
__delay_cycles(1000000);
}
}
PRU_Driver.c code:
#include "pru_driver.h"
// Initialize I2C2 module
void init_I2C(void) {
I2C_CON = 0; // Disable I2C
I2C_SYSC = (1 << 1); // Soft reset
while (!(I2C_SYSS & 0x1)); // Wait for reset done
I2C_PSC = 23; // Prescaler for 2MHz
I2C_SCLL = 13; // SCL low time
I2C_SCLH = 15; // SCL high time
I2C_IRQENABLE_SET = 0x00; // Disable interrupts
I2C_CON = I2C_EN; // Enable I2C module
while (!(I2C_SYSS & 0x1)); // Confirm ready
}
// Write 2-byte data to I2C slave
void I2C_Write(uint8_t addr, uint8_t reg, uint16_t data) {
while (I2C_IRQSTATUS_RAW & (1 << 12)); // Wait for bus free
I2C_SA = addr;
I2C_CNT = 3; // reg + 2 bytes
I2C_CON = I2C_EN | I2C_MST | I2C_TRX | I2C_STT;
while (!(I2C_IRQSTATUS_RAW & (1 << 4)));
I2C_DATA = reg;
I2C_IRQSTATUS = (1 << 4);
while (!(I2C_IRQSTATUS_RAW & (1 << 4)));
I2C_DATA = (data >> 8) & 0xFF;
I2C_IRQSTATUS = (1 << 4);
while (!(I2C_IRQSTATUS_RAW & (1 << 4)));
I2C_DATA = data & 0xFF;
I2C_CON |= I2C_STP;
I2C_IRQSTATUS = (1 << 4);
while (I2C_IRQSTATUS_RAW & (1 << 12));
I2C_IRQSTATUS = 0xFFFF;
}
// Read 2 bytes from a register
uint16_t I2C_Read_Register(uint8_t addr, uint8_t reg) {
uint16_t val = 0;
while (I2C_IRQSTATUS_RAW & (1 << 12));
I2C_SA = addr;
I2C_CNT = 1;
I2C_CON = I2C_EN | I2C_MST | I2C_TRX | I2C_STT | I2C_STP;
while (!(I2C_IRQSTATUS_RAW & (1 << 4)));
I2C_DATA = reg;
I2C_IRQSTATUS = (1 << 4);
while (!(I2C_IRQSTATUS_RAW & (1 << 2)));
I2C_IRQSTATUS = (1 << 2);
I2C_SA = addr;
I2C_CNT = 2;
I2C_CON = I2C_EN | I2C_MST | I2C_STT | I2C_STP;
while (!(I2C_IRQSTATUS_RAW & (1 << 3)));
val = (I2C_DATA << 8);
I2C_IRQSTATUS = (1 << 3);
while (!(I2C_IRQSTATUS_RAW & (1 << 3)));
val |= I2C_DATA;
I2C_IRQSTATUS = (1 << 3);
while (I2C_IRQSTATUS_RAW & (1 << 12));
I2C_IRQSTATUS = 0xFFFF;
return val;
}
PRU_Driver.h file
#ifndef PRU_DRIVER_H
#define PRU_DRIVER_H
#include <stdint.h>
#define I2C_BASE_ADDR 0x4819C000 // I2C2 base address
#define I2C_REVNB_LO (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x00))
#define I2C_SYSC (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x90))
#define I2C_SYSS (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x94))
#define I2C_CNT (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x98))
#define I2C_DATA (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x9C))
#define I2C_CON (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xA4))
#define I2C_SA (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xAC))
#define I2C_PSC (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xB0))
#define I2C_SCLL (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xB4))
#define I2C_SCLH (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xB8))
#define I2C_BUF (*(volatile uint32_t*)(I2C_BASE_ADDR + 0xA8))
#define I2C_IRQSTATUS_RAW (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x24))
#define I2C_IRQSTATUS (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x28))
#define I2C_IRQENABLE_SET (*(volatile uint32_t*)(I2C_BASE_ADDR + 0x2C))
#define I2C_EN (1 << 15)
#define I2C_MST (1 << 10)
#define I2C_TRX (1 << 9)
#define I2C_STP (1 << 1)
#define I2C_STT (1 << 0)
void init_I2C(void);
void I2C_Write(uint8_t addr, uint8_t reg, uint16_t data);
uint16_t I2C_Read_Register(uint8_t addr, uint8_t reg);
#endif