Trying to control an S90 servo using a BeagleBone Black and a PCA9685 board using the I2C bus. Is there a C program driver out there that will do this? I am using CCS and a TI XDS 100V2 JTAG Emulator as well.
The code here is just trying to get a voltage coming out of the 15 pin of the PWM PCA9685 from the BeagleBone Black. Trying to turn the LED15 to full ON. When I run this code I do not get a reading. Using I2C2 bus on the BBB.
Here is my code so far:
// Define Indirect Addressing Macro for Registers
#define HWREG(x) (*((volatile unsigned int *)(x)))
// Common Defines
#define TRUE 1
#define FALSE 0
#define DELAY_COUNT 100000
// Base Module Defines
#define CTRLMOD_BASE 0x44E10000
#define CM_PER_BASE 0x44E00000
#define I2C2_BASE 0x4819C000
// Control Module Defines
#define CONF_I2C2_SCL 0x97C
#define CONF_I2C2_SDA 0x978
#define MODE3 0x3B
// Peripheral Control Module Defines
#define CM_PER_I2C2_CLKCTRL 0x44
#define CLK_ENABLE 0x2
// DRM Register Offset Defines
#define I2C_2_SUSPEND_CTRL 0x230
// Register Address Offset Defines
#define I2C_SA 0xAC
#define I2C_CNT 0x98
#define I2C_DATA 0x9C
#define I2C_IRQSTATUS_RAW 0x24
#define I2C_CON 0xA4
#define I2C_PSC 0xB0
#define I2C_SCLL 0xB4
#define I2C_SCLH 0xB8
#define I2C_BUFSTAT 0xC0
#define I2C_IRQENABLE_SET 0x2C
// I2C Register Values
#define _12MHZ_CLK 0x03
#define _tLOW_ 0x08
#define _tHIGH_ 0x0A
#define I2C2_ENABLE 0x8603
#define IRQ_DISABLED 0x0000
// Mask Defines
#define DCOUNT_VAL 0x0000FFFF
#define XRDY_RDY 0x00000010
#define XRDY_BIT 0x00000010
#define RRDY_BIT 0x00000008
#define RRDY_RDY 0x00000008
#define BF_BIT 0x00001000
#define BUS_IS_FREE 0
#define DATA_VAL 0xFF
#define BUFSTAT_VAL 0x0000003F
//I2C Communication Defines
#define SLAVE_ADDR 0x40
#define NUM_OF_DBYTES 10
#define START_COND 0x00000001
#define STOP_COND 0x00000002
#define MASTER_TX_MODE 0x600
#define NAME_BYTE_LENGTH 13
// General registers
#define PCA9685 0x80 // I2C address for PCA9865 with all inputs at zero
#define Reset 0x01 // Reset the device
#define MODE1 0x00 // 0x00 location for Mode1 register address
#define MODE2 0x01 // 0x01 location for Mode2 register address
#define PRE_SCALE 0xFE // Prescaler address
#define P_S_VALUE 0x79 // PWM frequency value
// MODE1 bits PCA9685
#define PCA96_INIT 0x11
#define LED15_ADD 0x43
// Variables
unsigned int x;
unsigned int y;
volatile unsigned int USR_STACK[100];
volatile unsigned int IRQ_STACK[100];
void wait(void){
while(1){
// Endless loop
};
}
void delay(unsigned long int y){
while(y>0){
y--;
}
}
void stack_init(void){
//SET UP STACKS
//init USR stack
asm("LDR R13, =USR_STACK");
asm("ADD R13, R13, #0x1000");
//init IRQ stack
asm("CPS #0x12"); //Switch to IRQ mode
asm("LDR R13, =IRQ_STACK");
asm("ADD R13, R13, #0x1000");
asm("CPS #0x13"); //Switch to User Mode
}
void irq_enable(void){
asm("mrs r0, CPSR");
asm("bic r0, r0, #0x80");
asm("msr CPSR_c, R0");
}
//Do Not use in polling
void int_handler(void){
if(HWREG(0x482000D8) == 0x20000000)
{
}
asm("LDMFD SP!, {LR}");
asm("LDMFD SP!, {LR}");
asm("SUBS PC, LR, #0x4");
}
int is_bus_free(void){
x = HWREG(I2C2_BASE + I2C_IRQSTATUS_RAW); //Read mask 0x00001000 from I2C_IRQSTATUS_RAW (I2C Status Raw Register) offset 0x24 to check bus status.
x = (x & BF_BIT); //Mask.
if(x == BUS_IS_FREE) return 1;
else return 0;
}
int is_i2c_write_ready(void){
x = HWREG(I2C2_BASE + I2C_IRQSTATUS_RAW); //Read mask 0x00000010 from I2C_IRQSTATUS_RAW (I2C Status Raw Register) offset 0x24 to see if write ready
x = (x & XRDY_BIT); //Mask.
if(x == XRDY_RDY) return 1;
else return 0;
}
int is_i2c_read_ready(void){
x = HWREG(I2C2_BASE + I2C_IRQSTATUS_RAW); //Read mask 0x00000008 I2C_IRQSTATUS_RAW (I2C Status Raw Register) offset 0x24 see if data is ready.
x = (x & RRDY_BIT); //Mask.
if(x == RRDY_RDY) return 1;
else return 0;
}
void startstop_condition(void){
x = HWREG(I2C2_BASE + I2C_CON) = x; //Read-Modify-Write 0x8603 to I2C_CON (Configuration Register) offset 0xA4 to queue Start/Stop Condition.
x = (x | START_COND | STOP_COND); //Mask.
HWREG(I2C2_BASE + I2C_CON) = x; //Write back. //Write back.
}
void config_master_transmitter(void){
x = HWREG(I2C2_BASE + I2C_CON); //Read-Modify-Write 0xE00 to I2C_CON (Configuration Register)offset 0xA4 to configure mode.
x = (x | MASTER_TX_MODE); //Mask.
HWREG(I2C2_BASE + I2C_CON) = x; //Write back.
}
void set_num_databytes(unsigned int y){
y = (y & DCOUNT_VAL);
//Number of Data Bytes pre-transmission.
HWREG(I2C2_BASE + I2C_CNT) = y; //Write 0x9 to I2C_CNT (Data Count Register) offset 0x98 to set number of transmission Bytes
}
void write_to_bus(unsigned char x){
x = (x & DATA_VAL );
HWREG(I2C2_BASE + I2C_DATA) = x; //Write to data bus.
delay(2000);
}
void set_slave_addr(unsigned int x){
//Slave address pre-transmission.
HWREG(I2C2_BASE + I2C_SA) = x; //Write 0x40 to I2C_SA (Slave Address Register) offset 0xAC Slave address value
}
void i2c_init(void){
//P9 Connector settings.
HWREG(CTRLMOD_BASE + CONF_I2C2_SCL) = 0x3B; //Write 0x3B to conf_uart1_rtsn offset 0x97C to enable (SCL) for MODE3 w/o pullup
HWREG(CTRLMOD_BASE + CONF_I2C2_SDA) = 0x3B; //Write 0x3B to conf_uart1_ctsn offset 0x978 to enable (SDA) for MODE3 w/o pullup
//Enable Clock to I2C2.
HWREG(CM_PER_BASE + CM_PER_I2C2_CLKCTRL) = CLK_ENABLE; //Write 0x2 to CM_PER_I2C2_CLKCTRL offset 0x48 to enable I2C2 Clock.
//Configure I2C2.
HWREG(I2C2_BASE + I2C_PSC) = _12MHZ_CLK; //Write 0x03 to I2C_PSC (Clock Prescalar Register) offset 0xB0 for ICLK of 12 MHz
HWREG(I2C2_BASE + I2C_SCLL) = _tLOW_; //Write 0x08 to I2C_SCLL (SCL Low Time Register) offset 0xB4 for tLOW to get 400kbps (1.25usec)
HWREG(I2C2_BASE + I2C_SCLH) = _tHIGH_; //Write 0x0A to I2C_SCLH (SCL High Time Register) offset 0xB8 for tHIGH to get 400kbps (1.25usec)
HWREG(I2C2_BASE + I2C_CON) = I2C2_ENABLE; //Write 0x8603 to I2C_CON (Configuration Register) offset 0xA4 to take out of reset, enable I2C2 module
config_master_transmitter();
HWREG(I2C2_BASE + I2C_IRQENABLE_SET) = IRQ_DISABLED;
set_slave_addr(SLAVE_ADDR);
}
void init_pwm(void){
//HWREG(I2C2_BASE + I2C_IRQSTATUS_RAW) = 0x00000114;
HWREG(I2C2_BASE + I2C_CON) = I2C2_ENABLE; //Write 0x8603 to I2C_CON (Configuration Register) offset 0xA4 to take out of reset, enable I2C2 module
config_master_transmitter();
unsigned int current_DCOUNT;
set_slave_addr(SLAVE_ADDR);
set_num_databytes(NAME_BYTE_LENGTH);
while(is_bus_free() != TRUE){
}
startstop_condition();
while((HWREG(I2C2_BASE + I2C_BUFSTAT) & BUFSTAT_VAL) > 0){
current_DCOUNT = HWREG(I2C2_BASE + I2C_BUFSTAT) & BUFSTAT_VAL;
if(is_i2c_write_ready()){//If ready to write
switch(NAME_BYTE_LENGTH-current_DCOUNT){
case 0:
write_to_bus(MODE1);
break;
case 1:
write_to_bus(PCA96_INIT);
break;
case 2:
write_to_bus(PRE_SCALE);
break;
case 3:
write_to_bus(P_S_VALUE);
break;
case 4:
write_to_bus(MODE1);
break;
case 5:
write_to_bus(0x81); //Send 0x81 to enable RESTART,ALLCALL,INT_CLK,NORM_MODE
break;
case 6:
write_to_bus(MODE2);
break;
case 7:
write_to_bus(0x04); //Send 0x20 to enable Totem pole structure, non-inverted
break;
case 8:
write_to_bus(0x10);
break;
case 9:
write_to_bus(0x45);
break;
case 10:
write_to_bus(0x08);
break;
case 11:
write_to_bus(0x43);
break;
case 12:
write_to_bus(0x00);
break;
}
}
}
}
int main(void){
stack_init();
i2c_init();
init_pwm();
wait();
return 1;
}
User contributions licensed under CC BY-SA 3.0