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

 

  1.   1
  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 マイコン
    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.
 *
 * 修正のあるなしに関わらず、ソース形式またはバイナリ形式での
 * 再配布および使用は、以下の条件を満たしている場合に
 * 許可されます。
 *
 * *  ソース・コードの再配布は上記の著作権表示、この条件のリスト
 *    および以下の免責事項を保持している必要があります。
 *
 * *  バイナリ形式での再配布は上記の著作権表示、この条件のリスト
 *    、および以下の免責事項を配布に付属のドキュメント
 *    および / またはその他の資料に再現する必要があります。
 *
 * *  テキサス・インスツルメンツまたはその貢献者のいずれの名前も
 *    特に事前の書面による許可なく、本ソフトウェアに由来の
 *    製品を宣伝または販売促進することはできません。
 *
 * 本ソフトウェアはその著作権保有者およびその貢献者により「現状のまま」提供され、
 * 明示あるいは黙示を問わず、これに限定されることなく
 * 商品性の黙示保証、特定目的への適合性に対して
 * 一切保証しないものとします。いかなる場合にも、著作権保有者または
 * 貢献者は、直接的、間接的、付随的、特別、拡大、懲罰的または結果的損害
 * (商品またはサービスの代替品の調達、使用、データ、または利益の逸失
 * または業務の中断を含むがこれに限りません)
 * の可能性を忠告されていたにもかかわらず本ソフトウェアの使用により生じた
 * 当該損害について、その原因を問わず
 * 契約上の責任、厳格責任、または不法行為責任 (その他の過失を含む) 
 * の法理に基づいて、一切の責任を負わないものとします。
 * --/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 <msp430.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 固有の関数
#include "USB_API/USB_CDC_API/UsbCdc.h"
#include "USB_app/usbConstructs.h"
#include "OLED/Oled_SSD1306.h"
#include "StdPollI2C.h"
#include "hal.h"
// 関数の宣言
uint8_t retInString(char* string);
void initTimer(void);
void setTimer_A_Parameters(void);
// イベントによって設定されたグローバル・フラグ
volatile uint8_t bCDCDataReceived_event = FALSE; // open rx 演算なくデータが rx された
// ことを示します
char str[50];
#define NUM_SAMPLES 8
#define clkspeed 3          // 24Mhz クロック選択
//#define clkspeed 1        // 8Mhz クロック選択
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;                     // RX データへのポインタ
unsigned char RXByteCtr;
volatile unsigned char RxBuffer[128];       // 128 バイトの RAM を割り当てます
unsigned char* PTxData;                     //  TX データへのポインタ
unsigned char TXByteCtr;
const unsigned char TxData[] =              // 転送するデータのテーブル
{
 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;
// 発信文字列を保持します
char outString[MAX_STR_LENGTH] = "";
uint8_t connectedflag = 0;
uint8_t echoflag = 1;
int ubtncounter = 0;
uint8_t RegValueLSB = 0;
uint8_t RegValueMSB = 0;
uint8_t VbatMSB = 0;
uint8_t ADCCheck = 0;
uint32_t stobusf;
uint8_t ADCcount = 0;
uint8_t VinReadA = 0;
uint8_t VinReadB = 0;
uint8_t VinReadC = 0;
uint8_t VinLow = 0;
double vIn = 0;
char vBat[];
//uint8_t RegValueM = 0;
//uint8_t RegValueL = 0;
uint32_t stobuf;
uint32_t stobuf1;
double stobuf2;
uint8_t RegValues = 0;
//__delay_cycles(1000); 1000 = 100us
uint8_t rthex;
// トグル遅延を設定 / 宣言します
//uint16_t SlowToggle_Period = 20000 - 1;
//uint16_t FastToggle_Period = 1000 - 1;
/*
 * ======== main ========
 */
void main(void)
{
    WDT_A_hold(WDT_A_BASE); // ウォッチドッグ・タイマを停止します
    // USB API に必要な最低 Vcore 設定は PMM_CORE_LEVEL_2 です。
    PMM_setVCore(PMM_CORE_LEVEL_2);
    USBHAL_initPorts();           // ローパワー (出力 Low) の GPIOS を構成します
    USBHAL_initClocks(8000000 * clkspeed);   // クロックを構成します。MCLK=SMCLK=FLL=8MHz; ACLK=REFO=32kHz
    //USBHAL_initClocks(24000000);
    initTimer();           // LED トグルのタイマを準備します
    //USB_setup(TRUE, TRUE); // USB およびイベントを初期化し、ホストが存在する場合は、接続します
    initI2C();
//  ======== UART Setup ========
    P3SEL = BIT3+BIT4;                        // P3.4,5 = USCI_A0 TXD/RXD
    __delay_cycles(20000);
    UCA0CTL1 |= UCSWRST;                      // **ステート・マシンをリセットにします**
    UCA0CTL1 |= UCSSEL_2;                     // SMCLK
    UCA0BR0 = 6;                              // 1MHz 9600 (ユーザー・ガイドを参照)
    UCA0BR1 = 0;                              // 1MHz 9600
    UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;   // Modln UCBRSx=0, UCBRFx=0,
                                              // オーバー・サンプリング
    UCA0CTL1 &= ~UCSWRST;                     // **USCI ステート・マシンを初期化します**
//  ======== GPIO Setup ========
    //LED Setup
    GPIO_setAsOutputPin(LED_1);
    GPIO_setOutputLowOnPin(LED_1);
    GPIO_setAsOutputPin(LED_2);
    GPIO_setOutputLowOnPin(LED_2);
    GPIO_setAsOutputPin(LED_3);
    GPIO_setOutputLowOnPin(LED_3);
    //GPIO のセットアップ
    GPIO_setAsInputPinWithPullUpResistor(BQ_INT);
    GPIO_setAsInputPin(BQ_PG);
    GPIO_setAsInputPinWithPullUpResistor(BQ_START);
    GPIO_setAsOutputPin(BQ_CE);
    GPIO_setOutputLowOnPin(BQ_CE);
    GPIO_setAsOutputPin(BQ_LP);
    GPIO_setOutputHighOnPin(BQ_LP);
    GPIO_setAsOutputPin(BQ_G1);
    GPIO_setOutputLowOnPin(BQ_G1);
    GPIO_toggleOutputOnPin(LED_1);
    waitms(500);
    GPIO_toggleOutputOnPin(LED_1);
    waitms(500);
    GPIO_toggleOutputOnPin(LED_1);
    waitms(500);
    GPIO_toggleOutputOnPin(LED_1);
//  ======== BQ25155 Register Setup ========
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_MASK0, 0x5E, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_MASK1, 0xBF, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_MASK2, 0xF1, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_MASK3, 0x77, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_VBAT_CTRL, 0x3C, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ICHG_CTRL, 0x50, &Err);//Ichg を 200mA に設定し、0xA0 には 200mA、0x50 には 100mA、0x20 には 40mA を設定します
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_PCHRGCTRL, 0x02, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TERMCTRL, 0x14, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_BUVLO, 0x00, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_CHARGERCTRL0, 0x92, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_CHARGERCTRL1, 0xC2, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ILIMCTRL, 0x06, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_MRCTRL, 0x2A, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ICCTRL0, 0x10, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ICCTRL1, 0x00, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ICCTRL2, 0x40, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCCTRL0, 0x40, &Err); //0x58 は ADC を 3ms conv の連続に設定し、0x40 は 24ms conv の連続に設定します。
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCCTRL1, 0x00, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP1_M, 0x23, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP1_L, 0x20, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP2_M, 0x38, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP2_L, 0x90, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP3_M, 0x00, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADCALARM_COMP3_L, 0x00, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_ADC_READ_EN, 0xFE, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TS_FASTCHGCTRL, 0x34, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TS_COLD, 0x7C, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TS_COOL, 0x6D, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TS_WARM, 0x38, &Err);
    StdI2C_TX_Single(BQ25150_ADDR, BQ25150_TS_HOT, 0x28, &Err);
//  ======== Ready while loop ========
    //この while ループは割り込みをディスエーブルした状態でプログラムを保持します。これによりケースと同期できます
    //BQ_START ピン 3.7 をグランドに短絡させ、ループを終了します
    while(GPIO_getInputPinValue(BQ_START) == 1) //割り込みをイネーブルにする前に開始状態で待機します
    {
        GPIO_toggleOutputOnPin(LED_2);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_2);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_2);
        __delay_cycles(3000000);
        GPIO_toggleOutputOnPin(LED_2);
        __delay_cycles(24000000);
    }
    GPIO_setOutputLowOnPin(LED_2);
//  ======== Interrupt Enables ========
    __enable_interrupt();  // 割り込みをグローバルにイネーブルします
    GPIO_enableInterrupt(BQ_INT);
    GPIO_selectInterruptEdge(BQ_INT, GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_clearInterrupt(BQ_INT);
//  ======== Main while loop ========
    //Vbat を読み取り、ケースが Vin を Low に駆動するのを待機します
    while(1)
    {
         StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_ADCDATA_VBAT_M, &VbatMSB, &Err); //Vbat を読み取ります
         StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_ADCDATA_VIN_M, &RegValueMSB, &Err); //Vin を読み取ります
         GPIO_toggleOutputOnPin(LED_1);
         __delay_cycles(12000000);
    }
}
/*
 * ======== 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);
}
//  ======== BQ25155 Interrupt ========
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(PORT1_VECTOR)))
#endif
void Port_1(void)
{
    switch(__even_in_range(P1IV,0x03))
    {
    case P1IV_P1IFG3: 
        StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_STAT0, &RegValueMSB, &Err); //STAT0 REG を読み取ります
        RegValueMSB &= 0x01; // VIN_PGOOD_STAT がアサートされているか確認します
        if(RegValueMSB == 0x00){ //VIN_PGOOD_STAT がアサートされていない場合、VIN が Low に駆動されているか確認します
//                __delay_cycles(6000000);
//
//                StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_ADCDATA_VIN_M, &RegValueMSB, &Err); //Vin を読み取ります
//                stobuf = RegValueMSB;
//                stobuf1 = stobuf * 6;
//                vIn = (double)stobuf1 / 256;
          ADCcount = 0;
          VinLow = 0;
          VinReadA = 5;
          VinReadB = 5;
          VinReadC = 5;
          while(ADCcount < 85 && VinLow == 0){
            __delay_cycles(120000);
            StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_ADCDATA_VIN_M, &RegValueMSB, &Err); //VIN を読み取ります
            stobuf = RegValueMSB;
            stobuf1 = stobuf * 6;
            vIn = (double)stobuf1 / 256;
            VinReadC = VinReadB;
            VinReadB = VinReadA;
            VinReadA = vIn;
            ADCcount++;
            if(VinReadA < 3 && VinReadB < 3 && VinReadC < 3){
                VinLow = 1;
                VinReadA = 0;
                VinReadB = 0;
                VinReadC = 0;
                vIn = 0;
            }
          }
                if(VinLow == 1){//Vin が 3V 未満の場合、通信プロセスを開始します
                    StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_STAT0, &RegValueMSB, &Err); //STAT0 REG を読み取ります
                    RegValueMSB &= 0x20; // CHARGE_DONE_STAT がアサートされているか確認します
//                    RegValueMSB = 0x20; //コメント解除して、テストのため充電完了ビットをアサートします
                    if(RegValueMSB){                       // CHARGE_DONE_STAT が transmit 0xD5, 0xD5 = Vbat = 5v にアサートされている場合、分かりやすくするため、これは任意の充電完了ビットとして選択されます
                        GPIO_setOutputHighOnPin(BQ_G1);    // 通信モードに入ります
                        __delay_cycles(4000);
                        while (!(UCA0IFG&UCTXIFG));        // USCI_A0 TX バッファの準備は完了していますか? 
                        UCA0TXBUF = 0xD5;                  // TX -> 0xD5 = 5V、充電範囲外
                        __delay_cycles(4000);
                        GPIO_toggleOutputOnPin(LED_3);
                        GPIO_setOutputLowOnPin(BQ_G1);     //パワー・モードに入ります
                        GPIO_toggleOutputOnPin(LED_2);
                        __delay_cycles(4000000);
                        GPIO_toggleOutputOnPin(LED_2);
                        __delay_cycles(4000000);
                        GPIO_setOutputHighOnPin(LED_2);
                    }
                    else{
                    stobuf = VbatMSB;
                    stobuf1 = stobuf * 6;
                    stobuf2 = (double)stobuf1 / 256; //stobuf2 = Vbat の 2 倍
                    GPIO_setOutputHighOnPin(BQ_G1);    // 通信モードに入ります
                    __delay_cycles(4000);
                    while (!(UCA0IFG&UCTXIFG));        // USCI_A0 TX バッファの準備は完了していますか? 
                    UCA0TXBUF = VbatMSB;               // TX -> vBat MSB
                    __delay_cycles(4000);
                    GPIO_toggleOutputOnPin(LED_3);
                    GPIO_setOutputLowOnPin(BQ_G1);     //パワー・モードに入ります
                    }
                }
        }
        //すべての割り込みフラグをクリアします
        StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_FLAG0, &RegValues, &Err);
        StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_FLAG1, &RegValues, &Err);
        StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_FLAG2, &RegValues, &Err);
        StdI2C_P_RX_Single(BQ25150_ADDR, BQ25150_FLAG3, &RegValues, &Err);
        GPIO_clearInterrupt(BQ_INT);
        break;
    default: 
        break;
    }
}
//Released_Version_5_10_00_17