Quadrocopter 450 BLC

March 2nd, 2010

 

The Quadrocopter 450 contains 2 PCB’s with 2 BLC each. Those BLC’s are complete independent units that share nothing but the PCB and the connector to the Main Control Unit. This Connector also defines the MSB of the Motor Address. The LSB is define by the A0 resistor (Zero Ohm).

Important Notice:
The first few Conrad Copter are sold without a boot loader on teh BLC’s and the software is using a slightly different protocol.  To determine which Software is used by your Quadrocopter you can make a simple test.: Start the engines and let them run in idle mode. Stop one Propeller by hand. If the other Propeller stop automatically as well the BLC have the new Software. In this case refer to the protocol information below.   

 If you want to use the BLC with e.g. the Mikrokopter FlightControl you can use  the Pads to connect the I2C Bus. In addition The MSB of the motor address need to be set correctly as well  

blc2c

 The Motor Addresses are defined as follows:

AD0 = 0, AD1 = 0 -> resulting i2C Addressvalue = B0

AD0 = 1, AD1 = 0 -> resulting i2C Addressvalue = B1

AD0 = 0, AD1 = 1 -> resulting i2C Addressvalue = B2

AD0 = 1, AD1 = 1 -> resulting i2C Addressvalue = B3

The Protocol to start the engine is very simple:

Old Version:
0×00 = Stop Engine
0×01 = Start Engine
0×10…0xff = Engine Value

New Version (currently sold by Conrad):
This Version requires to send all command twice (in separate transactions!) to be accepted by the BLC.
0×09, 0×09 = Stop Engine
0×06, 0×06 = Start Engine
0×10,0×10….0xff,0xff = Engine Value

This Version also requires a wakeup message to activate the BLC’s
0×07- 0×07
need to be send to all BLC’s (in a single two data byte transaction). In addition the i2c address value is now 0×00…0×03 

The following code is the sartup code for the BLC’s used by the GCOPTER as an example:
// —– mon interrupt driven TWI —–

void TWI_NI__Init(unsigned char BitRate)

{

  DEBUG(”\n\r init NI TWI..”);

  TWBR = BitRate;

  TWSR = 0;

  TWDR = 0×0ff;

  TWCR = (1<<TWEN)|

         (0<<TWIE)|(1<<TWINT)|

         (0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|

         (0<<TWWC);

}                       

void TWI_NI__Start(void)

{

  DEBUG(”s”);

  TWCR = (1<<TWEN)|             // Enable TWI Pins

         (1<<TWINT)|            // Reset Interrut Flag

         (1<<TWSTA);            // Send Start Condition

  while(!(TWCR & (1<<TWINT)));  // Wait for Int Flag 

}

void TWI_NI__Stop(void)

{  

  DEBUG(”t”);

  TWCR = (1<<TWEN)|             // Enable TWI Pins

         (1<<TWINT)|            // Reset Interrups Flags

         (1<<TWSTO);            // Send Stop Condition

}

void TWI_NI__Write(unsigned char b)

{                                                   

  DEBUG(”d”);

  TWDR = b;                     // Write Data Register

  TWCR = (1<<TWEN)|             // Enable TWI Pins

         (1<<TWINT);            // Reset Interrup Flag

  while(!(TWCR & (1<<TWINT)));  // Wait for Int Flag 

}

void TWI_NI__StartBLC(void)

{

  unsigned char i;

  DEBUG(”\n\r Start BLC..”);

  TWI_NI__Init(15);

  for(i=1;i<5;i++) {

    TWI_NI__Start();

    TWI_NI__Write(i<<1);

    TWI_NI__Write(0×07);

    TWI_NI__Write(0×07);

    TWI_NI__Stop();

  }

}

 

The Contol Code to send out Motor Values can look like as follows:
volatile unsigned char twi_state = 0;
volatile unsigned int twi_timeout;

volatile unsigned char motor = 0;

 

unsigned char motor_started0 = 0;

unsigned char motor_started1 = 0;

unsigned char motor_started2 = 0;

unsigned char motor_started3 = 0;

 

volatile unsigned char Motor_Vorne=0;

volatile unsigned char Motor_Hinten=0;

volatile unsigned char Motor_Rechts=0;

volatile unsigned char Motor_Links=0;

 

 

// TWI Parameter

#define SCL_CLOCK  200000L

#define I2C_TIMEOUT 30000

#define I2C_START          0×08

#define I2C_REPEATED_START 0×10

#define I2C_TX_SLA_ACK     0×18

#define I2C_TX_DATA_ACK    0×28

#define I2C_RX_SLA_ACK     0×40

#define I2C_RX_DATA_ACK    0×50

 

char TWI__Update(void)

{

  if(!twi_timeout) {

    twi_timeout = 5;

    TWI__Reset();

    return TWI__ERROR_TIMEOUT;

  }

  else {

    twi_timeout–;

    twi_state = 0;

    motor = 0;

    TWI__Start(); 

    return TWI__ERROR_OK;

  }

   

}

 

void TWI__Init(void)

{

  DEBUG(”\n\r init TWI..”);

  TWSR = 0;

  TWBR = ((SYSCLK/SCL_CLOCK)-16)/2;

  twi_timeout = 5000;

}   

 

char TWI__Start(void)

{

  TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT) | (1<<TWIE);

  return(0);

}

 

void TWI__Stop(void)

{

  TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT);

}

 

void TWI__Reset(void)

{

  TWI__Stop();               

  twi_state = 0;

  motor = TWDR;

  motor = 0;

  TWCR = 0×80;

  //TWAMR = 0;

  TWAR = 0;

  TWDR = 0;

  TWSR = 0;

  TWBR = 0;

  TWI__Init();

  TWI__Start();

 

  TWI__WriteByte(0);

}

 

char TWI__WriteByte(char byte)

{

  TWSR = 0×00;

  TWDR = byte;

  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);

  return(0);

}       

 

 

volatile unsigned char repeat=0;

 

interrupt [TWI] void twi_isr(void)

{

  switch (twi_state++) {

    case 0:

        TWI__WriteByte(0xb0+(motor*2));

        break;

                                  

    case 1:

        switch(motor++) {

          case 3:

                if(Motor_Vorne==0) {

//                 TWI__WriteByte(0×00);

                   TWI__WriteByte(0×09);

                   motor_started0=0;

                 }

                 else {

//                 if(motor_started0==0) {

                   if(motor_started0<2) {

//                   TWI__WriteByte(0×01);

                     TWI__WriteByte(0×06);

                      motor_started0++;

                   }

                   else {

                     TWI__WriteByte(Motor_Vorne);

                   }

                 }

                

                break;

          case 1:

                 if(Motor_Hinten==0) {

//                 TWI__WriteByte(0×00);

                   TWI__WriteByte(0×09);

                   motor_started1=0;

                }

                 else {

//                  if(motor_started1==0) {

                  if(motor_started1<2) {

//                   TWI__WriteByte(0×01);

                     TWI__WriteByte(0×06);

                     motor_started1++;

                  }

                   else {

                     TWI__WriteByte(Motor_Hinten);

                   }

                 }

                break;

          case 0:

                 if(Motor_Rechts==0) {

//                  TWI__WriteByte(0×00);

                   TWI__WriteByte(0×09);

                    motor_started2=0;

                 }

                 else {

//                 if(motor_started2==0) {

                   if(motor_started2<2) {

//                   TWI__WriteByte(0×01);

                     TWI__WriteByte(0×06);

                      motor_started2++;

                    }

                   else {

                     TWI__WriteByte(Motor_Rechts);

                   }

                 }

                break;

          case 2:

                 if(Motor_Links==0) {

//                 TWI__WriteByte(0×00);

                   TWI__WriteByte(0×09);

                   motor_started3=0;

                 }

                 else {

//                 if(motor_started3==0) {

                   if(motor_started3<2) {

//                   TWI__WriteByte(0×01);

                     TWI__WriteByte(0×06);

                     motor_started3++;

                   }

                   else {

                     TWI__WriteByte(Motor_Links);

                   }

                 }

                break;

        }

        break;

    case 2:

        TWI__Stop();

        if (motor<4) {

                 twi_state = 0;

                 TWI__Start();

        }

        else {

                 motor = 0;

                 twi_timeout = 10;

                 twi_state = 0;

                 if(repeat==0) {

                   repeat++;

                   TWI__Start();

                 }            

                 else {

                   repeat=0;

                 }

        }

        break;

  }

  TWCR |= 0×80;

}

 

The following source show how the TWIMASTER.C of the Mikrokopter Project can be updated to use the Conrad BLC’s (old BLC’s!)

 

#define conrad

#ifdef conrad

unsigned char motor_started0 = 0;

unsigned char motor_started1 = 0;

unsigned char motor_started2 = 0;

unsigned char motor_started3 = 0;

#endif

….

//############################################################################

//Start I2C

SIGNAL (TWI_vect)

//############################################################################

{

    switch (twi_state++) {

#ifdef conrad

          case 0:  i2c_write_byte(0xb0+(motor*2));

                    break;

          case 1:  switch(motor++)

                  {

                    case 1:    if(Motor_Vorne==0) {

                                 i2c_write_byte(0×00);

                                 motor_started0=0;

                               }

                              else {

                                 if(motor_started0==0) {

                                   i2c_write_byte(0×01);

                                   motor_started0++;

                                 }

                                 else {

                                   i2c_write_byte(Motor_Vorne);

                                 }

                               }

                               break;

                      case 3: if(Motor_Hinten==0) {

                                 i2c_write_byte(0×00);

                                 motor_started1=0;

                               }

                               else {

                                 if(motor_started1==0) {

                                   i2c_write_byte(0×01);

                                   motor_started1++;

                                  }

                                 else {

                                   i2c_write_byte(Motor_Hinten);

                                  }

                               }

                               break;

                    case 2:    if(Motor_Rechts==0) {

                                 i2c_write_byte(0×00);

                                 motor_started2=0;

                               }

                               else {

                                 if(motor_started2==0) {

                                   i2c_write_byte(0×01);

                                   motor_started2++;

                                 }

                                 else {

                                   i2c_write_byte(Motor_Rechts);

                                 }

                               }

                               break;

                    case 0:    if(Motor_Links==0) {

                                 i2c_write_byte(0×00);

                                motor_started3=0;

                               }

                               else {

                                 if(motor_started3==0) {

                                   i2c_write_byte(0×01);

                                   motor_started3++;

                                 }

                                 else {

                                   i2c_write_byte(Motor_Links);

                                  }

                               }

                               break;

                    }

                    break;

          case 2:   i2c_stop();

                    if (motor<4){

                      twi_state = 0;

                      i2c_start();

                    }

                    else {

                      motor = 0;

                      I2CTimeout = 10;

                      twi_state = 0;

                    }

                    break;

#endif        case 0:          i2c_write_byte(0×52+(motor*2));

                    break;

        case 1:     switch(motor++) {

                    case 0:

                      i2c_write_byte(Motor_Vorne);

                      break;

                    case 1:

                      i2c_write_byte(Motor_Hinten);

                      break;

                    case 2:

                      i2c_write_byte(Motor_Rechts);

                      break;

                    case 3:

                      i2c_write_byte(Motor_Links);

                      break;

                    }

                    break;

        case 2:     i2c_stop();

                    if (motor<4) twi_state = 0;

                    else motor = 0;

                    i2c_start();

                    break;

#endif

#ifndef conrad

 

The case values define the relationship between the motor state and the actual motor address. This can be different and depends on the orientation of the BLC and the FC in the Frame.

 

The code of the BLC are not available but if you like to write your own one the ISP can be used

 

blc1c

  1. No comments yet.
  1. No trackbacks yet.