Wrting an I2C driver for a servo controller board

-2

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;
                            }
c
i2c
beagleboneblack
pwm
servo
asked on Stack Overflow Aug 6, 2020 by CEStudent • edited Aug 14, 2020 by CEStudent

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0