ZHCACK6A june   2020  – may 2023 BQ25150 , BQ25155 , BQ25618 , BQ25619 , TS5A12301E , TS5A3157 , TS5A3159A , TS5A6542

 

  1.   1
  2.   使用 2 引脚接口为 TWS 高效充电
  3.   商标
  4. 引言
  5. 系统概述
    1. 2.1 充电盒
      1. 2.1.1 BQ25619
      2. 2.1.2 TLV62568P
      3. 2.1.3 TPS22910A
      4. 2.1.4 TS5A12301E
      5. 2.1.5 MCU
    2. 2.2 耳塞
      1. 2.2.1 BQ25155
      2. 2.2.2 TPS22910A
      3. 2.2.3 TS5A12301E
      4. 2.2.4 BT/SOC
  6. 充电盒算法实现方案
    1. 3.1 初始化和主代码
    2. 3.2 UART 中断和输出电压调节
  7. 耳塞算法实现方案
    1. 4.1 初始化和主代码
    2. 4.2 中断和传输
  8. 测试步骤
  9. 测试结果
    1. 6.1 动态电压调节
    2. 6.2 具有 4.6V 输出的 BQ25619
    3. 6.3 具有 5V 输出的标准升压
  10. 总结
  11. 原理图
  12. PCB 布局
  13. 10软件
    1. 10.1 充电盒 main.c
    2. 10.2 耳塞 main.c
  14. 11修订历史记录

充电盒 main.c

/* --COPYRIGHT--,BSD
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met: 
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
/*
 * ======== main.c ========
*/
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include "board_functions.h"
#include <stdlib.h>
#include "driverlib.h"
#include "StdI2C.h"
#include "BQ25150.h"
//#include "board_timer.h"
#include "USB_config/descriptors.h"
#include "USB_API/USB_Common/device.h"
#include "USB_API/USB_Common/usb.h"                 // USB-specific functions
#include "USB_API/USB_CDC_API/UsbCdc.h"
#include "USB_app/usbConstructs.h"
#include "OLED/Oled_SSD1306.h"
#include "StdPollI2C.h"
//#include <Wire.h>
/*
 * your own board.
 */
#include "hal.h"
//#include "Energia.h"
//#include "pins_energia.h"
// Function declarations
uint8_t retInString(char* string);
void initTimer(void);
void setTimer_A_Parameters(void);
// Global flags set by events
volatile uint8_t bCDCDataReceived_event = FALSE; // Indicates data has been rx'ed
// without an open rx operation
char str[50];
#define NUM_SAMPLES 8
#define clkspeed 3          // 24Mhz Clock Select
//#define clkspeed 1        // 8Mhz Clock Select
short samples[NUM_SAMPLES] ;
int sample_index = 0 ;
char str[50];
char cmdstring[5];
char cs2[3];
uint8_t response = 0;
//unsigned char buffer[10]={1,2,3,4,5,6,7,8,9,10};
volatile char wholeString[MAX_STR_LENGTH] = "";
volatile uint8_t modecounter = 0;
volatile uint8_t pluscounter = 0;
///Timer_A_initUpModeParam Timer_A_params = {0};
int i;
unsigned char* PRxData;                     // Pointer to RX data
unsigned char RXByteCtr;
volatile unsigned char RxBuffer[128];       // Allocate 128 byte of RAM
unsigned char* PTxData;                     // Pointer to TX data
unsigned char TXByteCtr;
const unsigned char TxData[] =              // Table of data to transmit
{
 0x11,
 0x22,
 0x33,
 0x44,
 0x55
};
volatile uint8_t Button_Released = 0;
unsigned int result;
const char* hexstring = "0xabcdef0";
int raddr;
int rdata;
char buf[5];
uint8_t uraddr;
uint8_t urdata;
uint16_t Err;
// Holds the outgoing string
char outString[MAX_STR_LENGTH] = "";
uint8_t connectedflag = 0;
uint8_t echoflag = 1;
int ubtncounter = 0;
uint8_t RegValuesL = 0;
uint8_t RegValuesM = 0;
uint8_t RegValueMSB = 0;
uint8_t ADCCheck = 0;
uint32_t stobusf;
char vBat;
char vBatString;
uint32_t stobuf;
uint32_t stobuf1;
double stobuf2;
double PwmDuty;
uint8_t RegValues = 0;
double batteryVoltageCheck = 0;
//__delay_cycles(1000); 1000 = 100us
uint8_t rthex;
// Set/declare toggle delays
//uint16_t SlowToggle_Period = 20000 - 1;
//uint16_t FastToggle_Period = 1000 - 1;
//  ======== main ========
void main(void)
{
    WDT_A_hold(WDT_A_BASE); // Stop watchdog timer
    // Minumum Vcore setting required for the USB API is PMM_CORE_LEVEL_2 .
    PMM_setVCore(PMM_CORE_LEVEL_2);
    USBHAL_initPorts();           // Config GPIOS for low-power (output low)
    USBHAL_initClocks(8000000 * clkspeed);   // Config clocks.MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
    initTimer();           // Prepare timer for LED toggling
    initI2C();
//  ======== UART Setup ========
    GPIO_setAsInputPinWithPullDownResistor(GPIO_PORT_P3,GPIO_PIN4); // P3.4 = Input With pulldown
    P3SEL = BIT3+BIT4;                        // P3.4,5 = USCI_A0 TXD/RXD
    UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
    UCA0CTL1 |= UCSSEL_2;                     // SMCLK
    UCA0BR0 = 6;                              // 1MHz 9600 (see User's Guide)
    UCA0BR1 = 0;                              // 1MHz 9600
    UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;   // Modln UCBRSx=0, UCBRFx=0,
                                              // over sampling
    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
//  ======== GPIO Setup ========
    GPIO_setAsOutputPin(LED_4);
    GPIO_setOutputLowOnPin(LED_4);
    GPIO_setAsInputPin(CASE_PMID_GOOD);
    GPIO_setAsInputPinWithPullUpResistor(CASE_INT);
    GPIO_setAsInputPin(CASE_BUCK_PG);
    GPIO_setAsInputPinWithPullUpResistor(CASE_START);
    GPIO_setAsOutputPin(CASE_FB);
    GPIO_setOutputLowOnPin(CASE_FB);
    GPIO_setAsOutputPin(CASE_PSEL);
    GPIO_setOutputLowOnPin(CASE_PSEL);
    GPIO_setAsOutputPin(CASE_QON);
    GPIO_setOutputHighOnPin(CASE_QON);
    GPIO_setAsOutputPin(CASE_CE);
    GPIO_setOutputLowOnPin(CASE_CE);
    GPIO_setAsOutputPin(CASE_G1);
    GPIO_setOutputLowOnPin(CASE_G1);
    GPIO_setAsOutputPin(LED_5);
    GPIO_setOutputLowOnPin(LED_5);
//    GPIO_setAsOutputPin(LED_6);
//    GPIO_setOutputLowOnPin(LED_6);
//  ======== PWM Setup ========
    P2DIR |= BIT5; //Set pin 2.5 to the output direction.
    P2SEL |= BIT5; //Select pin 2.5 as our PWM output.
    TA2CCTL2 = OUTMOD_7;
    TA2CCR0 = 40; //Set the period in the Timer A0 Capture/Compare 0 register to 40 us.
    TA2CCR2 = 14; //The period in microseconds that the power is ON, default 14 = 35%, ~= 4.5v OUTPUT
    TA2CTL = (TASSEL_2 | MC_1); //TASSEL_2 selects SMCLK as the clock source, and MC_1 tells it to count up to the value in TA0CCR0.
 //  ======== BQ25619 Register Setup ========
    StdI2C_P_TX_Single(BQ25619_ADDR, BQ25619_REG01, 0x3A, &Err); // BST_CONFIG = 1, Boost mode Enable, REG01 = 01h, value = 0x3A
    StdI2C_P_RX_Single(BQ25619_ADDR, BQ25619_REG01, &RegValues, &Err);
    StdI2C_P_TX_Single(BQ25619_ADDR, BQ25619_REG05, 0x8E, &Err); // Disable Watchdog
    StdI2C_P_RX_Single(BQ25619_ADDR, BQ25619_REG05, &RegValues, &Err);
    StdI2C_P_TX_Single(BQ25619_ADDR, BQ25619_REG06, 0xC6, &Err); // Set Boost voltage to 0xE6 =  5V, 0xC6 for 4.6V
    StdI2C_P_RX_Single(BQ25619_ADDR, BQ25619_REG06, &RegValues, &Err);
    GPIO_setOutputHighOnPin(LED_4);
    waitms(500);
    GPIO_setOutputLowOnPin(LED_4);
    waitms(500);
//  ======== Ready while loop ========
    //This while loop holds the program with the interrupts disabled.This allows synchronization with the ear bud
    //short BQ_START pin 4.3 to ground to exit loop
    while(GPIO_getInputPinValue(CASE_START) == 1)
    {
        GPIO_toggleOutputOnPin(LED_5);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_5);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_5);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_5);
        __delay_cycles(15000000);
    }
    GPIO_setOutputLowOnPin(LED_5);
//  ======== Interrupt Enables ========
    __enable_interrupt();  // Enable interrupts globally
    UCA0IE |= UCRXIE;
//  ======== Main while loop ========
    //Allows adjustment of the communication cycle time
    while(1)
    {
        GPIO_toggleOutputOnPin(LED_4);
//        __delay_cycles(24000000); //delay 1s
            __delay_cycles(120000000); //delay 5s
//        __delay_cycles(240000000); //delay 10s
//        __delay_cycles(1440000000); //delay 60s
        if(batteryVoltageCheck >= 3.8){
            __delay_cycles(120000000); //delay 5s
        }
        if(batteryVoltageCheck >= 3.85){
            __delay_cycles(240000000); //delay 10s
        }
        if(batteryVoltageCheck >= 3.95){
            __delay_cycles(240000000); //delay 10s
        //    __delay_cycles(240000000); //delay 10s
        //    __delay_cycles(240000000); //delay 10s
        }
        if(batteryVoltageCheck >= 4.05){
            __delay_cycles(1440000000); //delay 60s
        //    __delay_cycles(1440000000); //delay 60s
        }
        if(batteryVoltageCheck >= 4.19){
            __delay_cycles(1440000000); //delay 60s
            __delay_cycles(1440000000); //delay 60s
            __delay_cycles(1440000000); //delay 60s
            __delay_cycles(1440000000); //delay 60s
//            __delay_cycles(1440000000); //delay 60s
//            __delay_cycles(1440000000); //delay 60s
//            __delay_cycles(1440000000); //delay 60s
        }
        GPIO_setOutputHighOnPin(CASE_G1);      //enter communication mode
    }
}
/*
 * ======== TIMER1_A0_ISR ========
 */
#if defined(__TI_COMPILER_VERSION__) || (__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR (void)
#elif defined(__GNUC__) && (__MSP430__)
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) TIMER0_A0_ISR (void)
#else
#error Compiler not found! 
#endif
{
    // wake on CCR0 count match
    TA0CCTL0 = 0;
    __bic_SR_register_on_exit(LPM0_bits|GIE);
}
//  ======== UART RX Interrupt ========
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported! 
#endif
{
  switch(__even_in_range(UCA0IV,4))
  {
  case 0:break;                             // Vector 0 - no interrupt
  case 2:                                   // Vector 2 - RXIFG
      GPIO_toggleOutputOnPin(LED_5);
      RegValueMSB = UCA0RXBUF;              //Assigns reveived byte to RegValueMSB
      if (RegValueMSB == 0xD5){ //checks for charge complete byte
          StdI2C_P_TX_Single(BQ25619_ADDR,0x01 , 0x1A, &Err);//disable BQ25619 boost mode on charge complete
      }
      else{
      stobuf1 = RegValueMSB * 6;
      stobuf2 = (double)stobuf1 / 256;       //calculate Vbat
      batteryVoltageCheck = stobuf2;
      if(batteryVoltageCheck <= 4.05){
          //PwmDuty = 40-((stobuf2-2.6)/.095);
          PwmDuty =((7.606829268 - (1.434146341*(stobuf2 + .33)))*(40/3.3)); //~= .3v headroom for longer intervals
      }
      // stobuf2  is holder for Vbat
      //PwmDuty can range from 0 = 0% = 5.3V to 40 = 100% = 3V
      if (PwmDuty >= 14 && PwmDuty <= 40){ //qualify PwmDuty, never raise voltage past 4.5
          TA2CCR2 = PwmDuty; //assign PwmDuty cycle
      }
      else{
      TA2CCR2 = 14;
      }
      __delay_cycles(40000);
      GPIO_setOutputLowOnPin(CASE_G1);      //enter power mode
      }
    break;
  case 4:break;                             // Vector 4 - TXIFG
  default: break;
  }
}
//Released_Version_5_10_00_17