feat: KT mBMS 펌웨어 3종(HW1/2/3) 및 통합 빌드 환경 초기 커밋 (V4.0.0.1)

This commit is contained in:
2026-11-05 14:31:31 +09:00
commit c52dc2f348
10803 changed files with 4642514 additions and 0 deletions

View File

@@ -0,0 +1,605 @@
/*
* AD7280A Lithium Ion Battery Monitoring System
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <includes.h>
#include "ad7280a.h"
#include "spi2.h"
#include "delay.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ad7280_state ad7280;
/* Private function prototypes -----------------------------------------------*/
static void ad7280_crc8_build_table(u8 *crc_tab);
/* Private functions ---------------------------------------------------------*/
static void ad7280a_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //Enables GPIOB clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //Enables GPIOD clock
//GPIOD8, D10 initialization settings
GPIO_InitStructure.GPIO_Pin = AD_CHIP_PD|AD_CHIP_CONV; //PD8, PD10 function output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Multiplexing function
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Pull-up
GPIO_Init(GPIOD, &GPIO_InitStructure); //Initialize
//GPIOB12 initialization settings
GPIO_InitStructure.GPIO_Pin = AD_CHIP_CS; //PB12 function output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Multiplexing function
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //Push-pull output
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Pull-up
GPIO_Init(GPIOB, &GPIO_InitStructure); //Initialize
//GPIOD9 initialization settings
GPIO_InitStructure.GPIO_Pin = AD_CHIP_ALERT; //PD9 function output
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; //Multiplexing function
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //Pull-up
GPIO_Init(GPIOD, &GPIO_InitStructure); //Initialize
AD7280A_CS_HIGH;
AD7280A_PD_HIGH;
}
void ad7280_init(void)
{
OS_ERR err;
s32 data = -1;
ad7280a_gpio_init();
memset(&ad7280, 0x00, sizeof(ad7280));
OSTimeDlyHMSM(0, 0, 2, 0,
OS_OPT_TIME_HMSM_STRICT,
&err);
while (1)
{
AD7280A_CS_HIGH; //SPI2 FLASH is not selected
SPI2_Init(); //Initialize the SPI2
SPI2_SetSpeed(SPI_BaudRatePrescaler_64); //Set to 42M clock high-speed mode
memset(&ad7280, 0x00, sizeof(ad7280_state));
ad7280_crc8_build_table(ad7280.crc_tab);
data = ad7280_chain_setup();
if (data == 3)
{
printf("\r\nInitialized AD7280A (n = %d)", data);
break;
}
else
{
// printf("\r\nInitialize fail AD7280A (n = %d)", data);
}
OSTimeDlyHMSM(0, 0, 2, 0,
OS_OPT_TIME_HMSM_STRICT,
&err);
}
ad7280.init = 1;
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_AUX_ADC_OVERVOLTAGE, true, 0x00); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_ALERT , true, 0x47); // 10100100
// ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_PD_TIMER , true, 0x18); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB1_TIMER , true, 0x08); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB2_TIMER , true, 0x08); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB3_TIMER , true, 0x08); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB4_TIMER , true, 0x08); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB5_TIMER , true, 0x08); // 10100100
ad7280_write_register(AD7280A_DEVADDR_MASTER, AD7280A_CB6_TIMER , true, 0x08); // 10100100
printf("AD7280A Chain Setup (MAX Device = %d)\r\n", data);
}
void set_pd_status(u8 status)
{
ad7280.pd_status = status;
if (ad7280.pd_status == true)
GPIO_SetBits (AD_CHIP_IO_GPIO, AD_CHIP_PD);
else
GPIO_ResetBits(AD_CHIP_IO_GPIO, AD_CHIP_PD);
}
u8 get_pd_status(void)
{
return ad7280.pd_status;
}
static void ad7280_crc8_build_table(u8 *crc_tab)
{
u8 bit, crc;
u16 cnt, i;
for (cnt = 0; cnt < 256; cnt++) {
crc = cnt;
for (i = 0; i < 8; i++) {
bit = crc & HIGHBIT;
crc <<= 1;
if (bit)
crc ^= POLYNOM;
}
crc_tab[cnt] = crc;
}
}
static u8 ad7280_calc_crc8(u8 *crc_tab, u32 val)
{
u8 crc;
crc = crc_tab[val >> 16 & 0xFF];
crc = crc_tab[crc ^ (val >> 8 & 0xFF)];
return crc ^ (val & 0xFF);
}
static s32 ad7280_check_crc(ad7280_state *st, u32 val)
{
u8 crc = ad7280_calc_crc8(st->crc_tab, val >> 10);
// printf("\r\n CRC1 = 0x%X", crc);
// printf("\r\n CRC2 = 0x%X", ((val >> 2) & 0xFF));
if (crc != ((val >> 2) & 0xFF))
return -EIO;
return 0;
}
void Print_CRC_TABLE(void)
{
u16 i, j;
for (i = 0; i < 16; i++) {
printf("\r\n");
for (j = 0; j < 16; j++) {
printf("0x%02X, ", ad7280.crc_tab[(i * 16) + j]);
}
}
}
/* After initiating a conversion sequence we need to wait until the
* conversion is done. The delay is typically in the range of 15..30 us
* however depending an the number of devices in the daisy chain and the
* number of averages taken, conversion delays and acquisition time options
* it may take up to 250us, in this case we better sleep instead of busy
* wait.
*/
static void ad7280_delay(u16 ms)
{
delay_ms(ms);
}
s32 __ad7280_read32(u32 *val)
{
s32 result = -1;
u16 rx_tmp[2] = {0, 0};
u32 rx_buf;
/* Select the FLASH: Chip Select low */
AD7280A_CS_LOW;
if (SPI2_ReadWriteByte(DUMMY_BYTE, &rx_tmp[0], 1000) != 0) goto __ad7280_read32_end;
if (SPI2_ReadWriteByte(DUMMY_BYTE, &rx_tmp[1], 1000) != 0) goto __ad7280_read32_end;
rx_buf = 0;
rx_buf |= (u32)rx_tmp[0] << 16;
rx_buf |= (u32)rx_tmp[1] << 0;
/* Deselect the FLASH: Chip Select high */
*val = rx_buf;
result = 0;
__ad7280_read32_end:
AD7280A_CS_HIGH;
return result;
}
s32 spi_write(u32 reg)
{
s32 result = -1;
u16 rx_tmp[2] = {0, 0};
u32 rx_buf;
AD7280A_CS_LOW;
if (SPI2_ReadWriteByte((u16)(reg >> 16), &rx_tmp[0], 200) != 0) goto spi_write_end;
if (SPI2_ReadWriteByte((u16)(reg >> 0), &rx_tmp[1], 200) != 0) goto spi_write_end;
rx_buf = 0;
rx_buf |= (u32)rx_tmp[0] << 16;
rx_buf |= (u32)rx_tmp[1] << 0;
result = 0;
spi_write_end:
AD7280A_CS_HIGH;
return result;
}
void PrintWriteCycle(u32 reg)
{
P32BitWriteCycle Write;
Write = (P32BitWriteCycle)&reg;
printf("\r\n -------32Bit Write Cycle-------");
printf("\r\n DeviceAddr : 0x%X", Write->DeviceAddr );
printf("\r\n RegisterAddr : 0x%X", Write->RegisterAddr);
printf("\r\n RegisterData : 0x%X", Write->RegisterData);
printf("\r\n AddrAllParts : 0x%X", Write->AddrAllParts);
printf("\r\n Reserved : 0x%X", Write->Reserved );
printf("\r\n Bit8CRC : 0x%X", Write->Bit8CRC );
printf("\r\n BitPattern : 0x%X", Write->BitPattern );
printf("\r\n -------------------------------");
}
void PrintReadRegisterCycle(u32 reg)
{
P32BitReadRegisterDataCycle Read;
Read = (P32BitReadRegisterDataCycle)&reg;
printf("\r\n -------32Bit Read Register Cycle-------");
printf("\r\n DeviceAddr : 0x%X", Read->DeviceAddr );
printf("\r\n RegisterAddr : 0x%X", Read->RegisterAddr);
printf("\r\n RegisterData : 0x%X", Read->RegisterData);
printf("\r\n Reserved : 0x%X", Read->Reserved );
printf("\r\n WriteAck : 0x%X", Read->WriteAck );
printf("\r\n Bit8CRC : 0x%X", Read->Bit8CRC );
printf("\r\n BitPattern : 0x%X", Read->BitPattern );
printf("\r\n ---------------------------------------");
}
u8 ad7280_devaddr_reverse(u8 devaddr)
{
u8 result = 0;
result |= ((devaddr >> 4)& 0x01) << 0;
result |= ((devaddr >> 3)& 0x01) << 1;
result |= ((devaddr >> 2)& 0x01) << 2;
result |= ((devaddr >> 1)& 0x01) << 3;
result |= ((devaddr >> 0)& 0x01) << 4;
return result;
}
u32 ad7280_write(ad7280_state *st, u32 devaddr,
u32 addr, u8 all, u32 val)
{
u32 reg = (ad7280_devaddr_reverse(devaddr) << 27 | addr << 21 | (val & 0xFF) << 13 | all << 12);
reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2;
return spi_write(reg);
}
s8 ad7280_write_register(u8 devaddr, u8 addr, u8 all, u8 data)
{
/* 0x01A6151A
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 00110000 (0x30)
* Bit 12-13 ; Read conversion results ; 11 = no-read operation
* Write All
*/
/* turns off the read operation on all parts */
if (all == true)
ad7280_write(&ad7280, devaddr, addr, true , data);
else
ad7280_write(&ad7280, devaddr, addr, false, data);
return 0;
}
s8 ad7280_read_register(u8 devaddr, u8 addr)
{
u32 tmp;
ad7280_state *st;
st = &ad7280;
/* 0x01A6151A
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 00110000 (0x30)
* Bit 12-13 ; Read conversion results ; 11 = no-read operation
* Write All
*/
/* turns off the read operation on all parts */
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, true,
AD7280A_CTRL_HB_CONV_RES_READ_NO |
st->ctrl_hb);
/* turns on the read operation on the addressed part */
ad7280_write(st, devaddr, AD7280A_READ, false, addr << 2);
/* 0x01AC86F2
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 01100100 (0x64)
* Bit 9-10 ; Conversion averaging ; 10 = average by 4
* Bit 12-13 ; Read conversion results ; 10 = six cell voltages only
* Bit 14-15 ; Select conversion inputs ; 01 = six cell voltages and AUX1, AUX3, and AUX5
*/
ad7280_write(st, devaddr, AD7280A_CONTROL_HB, false,
AD7280A_CTRL_HB_CONV_INPUT_6CELL |
AD7280A_CTRL_HB_CONV_RES_READ_6CELL |
AD7280A_CTRL_HB_CONV_AVG_8 |
st->ctrl_hb);
ad7280_delay(1);
__ad7280_read32(&tmp);
if (ad7280_check_crc(st, tmp))
return -EIO;
if ((ad7280_devaddr_reverse((u8)(tmp >> 27)) != devaddr) || (((tmp >> 21) & 0x3F) != addr))
return -EFAULT;
return (tmp >> 13) & 0xFF;
}
s32 ad7280_read_all_channels(u16 cnt, u32 *array)
{
int i;
u32 tmp, sum = 0;
ad7280_state *st;
st = &ad7280;
/* 0x038011CA
* Register Addr ; 011100 (0x1C), Read
* Data ; 00000000 (0x00), Address ; 00
* Write All
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, true, AD7280A_CELL_VOLTAGE_1 << 2);
/* 0x038011CA
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 00000000 (0x00)
* Write All
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, true,
AD7280A_CTRL_HB_CONV_INPUT_6CELL |
st->ctrl_hb);
/* 0x01C2B6E2
* Register Addr ; 001110 (0x1D), CNVST Control
* Data ; 00010101 (0x02)
* Bit 0 - 1 ; Allow single CNVST pulse. Additional CNVST pulses are gated.
* Write All
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CNVST_CONTROL, true, 0x02);
AD7280A_CONV;
for (i = 0; i < cnt; i++) {
__ad7280_read32(&tmp);
if (ad7280_check_crc(st, tmp))
return -EIO;
if (array)
array[i] = tmp;
/* only sum cell voltages */
if (((tmp >> 23) & 0xF) <= AD7280A_CELL_VOLTAGE_6)
sum += ((tmp >> 11) & 0xFFF);
ad7280_delay(1);
}
return sum;
}
s32 ad7280_chain_setup(void)
{
u32 val, n;
ad7280_state *st;
st = &ad7280;
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, true,
AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN |
AD7280A_CTRL_LB_LOCK_DEV_ADDR |
AD7280A_CTRL_LB_MUST_SET |
st->ctrl_lb);
ad7280_delay(10);
for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, true,
AD7280A_CTRL_HB_CONV_RES_READ_NO |
st->ctrl_hb);
ad7280_write(st, n, AD7280A_READ, false,
AD7280A_CONTROL_LB << 2);
ad7280_write(st, n, AD7280A_CONTROL_HB, false,
AD7280A_CTRL_HB_CONV_INPUT_6CELL |
AD7280A_CTRL_HB_CONV_RES_READ_6CELL |
AD7280A_CTRL_HB_CONV_AVG_8 |
st->ctrl_hb);
ad7280_delay(10);
__ad7280_read32(&val);
if (val == 0)
return n;
if (ad7280_check_crc(st, val))
return -EIO;
if (n != ad7280_devaddr_reverse((u8)(val >> 27))) {
return -EIO;
}
}
return -EFAULT;
}
// The self-test conversion result typically varies between Code 970 and Code 990.
s32 ad7280_self_test(unsigned devaddr)
{
u32 val;
ad7280_state *st;
st = &ad7280;
/* 0x01BF0782
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 11111000 (0xF8)
* Bit 11 ; Conversion start format ; 1 = rising edge of CS
* Bit 12-13 ; Read conversion results ; 11 = no-read operation
* Bit 14-15 ; Select conversion inputs ; 11 = ADC self-test
*/
ad7280_write(st, devaddr, AD7280A_CONTROL_HB, false,
AD7280A_CTRL_HB_CONV_START_CS |
AD7280A_CTRL_HB_CONV_RES_READ_NO |
AD7280A_CTRL_HB_CONV_INPUT_SELF_TEST |
st->ctrl_hb);
ad7280_delay(1);
/* 0x01A6151A
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 00110000 (0x30)
* Bit 12-13 ; Read conversion results ; 11 = no-read operation
* Write All
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, true,
AD7280A_CTRL_HB_CONV_RES_READ_NO |
st->ctrl_hb);
/* 0x038607DA
* Register Addr ; 011100 (0x1C), Read
* Data ; 00110000 (0x30), Address ; 0C
* [D7:D2] 6-bit binary address for the register to be read
* [D1:D0] Reserved; set to 00
*/
ad7280_write(st, devaddr, AD7280A_READ, false, AD7280A_SELF_TEST << 2);
/* 0x01AC86F2
* Register Addr ; 001101 (0x0D), Control MSB
* Data ; 01100100 (0x64)
* Bit 9-10 ; Conversion averaging ; 10 = average by 4
* Bit 12-13 ; Read conversion results ; 10 = six cell voltages only
* Bit 14-15 ; Select conversion inputs ; 01 = six cell voltages and AUX1, AUX3, and AUX5
*/
ad7280_write(st, devaddr, AD7280A_CONTROL_HB, false,
AD7280A_CTRL_HB_CONV_INPUT_6CELL |
AD7280A_CTRL_HB_CONV_RES_READ_6CELL |
AD7280A_CTRL_HB_CONV_AVG_8 |
st->ctrl_hb);
ad7280_delay(1);
__ad7280_read32(&val);
if (ad7280_check_crc(st, val))
return -EIO;
if (ad7280_devaddr_reverse((u8)(val >> 27)) != devaddr)
return -EFAULT;
return (val >> 11) & 0xFFF;
}
s32 ad7280_sw_reset(void)
{
ad7280_state *st;
st = &ad7280;
/* 0x01D274D2
* Register Addr ; 001110 (0x0E), Control LSB
* Data ; 10010011 (0x93)
* Bit 0 ; Daisy-chain register readback
* Bit 1 ; Increment device address
* Bit 4 ; Reserved; set to 1
* Bit 7 ; Software reset
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, true,
AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN |
AD7280A_CTRL_LB_INC_DEV_ADDR |
AD7280A_CTRL_LB_MUST_SET |
AD7280A_CTRL_LB_SWRST |
st->ctrl_lb);
ad7280_delay(10);
/* 0x01C2B6E2
* Register Addr ; 001110 (0x0E), Control LSB
* Data ; 00010101 (0x15)
* Bit 0 ; Daisy-chain register readback
* Bit 2 ; Lock device address
* Bit 4 ; Reserved; set to 1
*/
ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, true,
AD7280A_CTRL_LB_DAISY_CHAIN_RB_EN |
AD7280A_CTRL_LB_LOCK_DEV_ADDR |
AD7280A_CTRL_LB_MUST_SET |
st->ctrl_lb);
ad7280_delay(10);
return 0;
}
void SetCellbalanceBuff(u8 dev_addr, u8 value)
{
ad7280.cb_mask[dev_addr] = value & 0xFC;
}
u8 GetCellbalanceBuff(u8 dev_addr)
{
return ad7280.cb_mask[dev_addr];
}
u16 SetCellBalance(u16 cno, u8 onoff)
{
u8 addr, id;
u8 cdata;
addr = cno / 5;
id = cno % 5;
cdata = ad7280.cb_mask[addr];
if (onoff == true)
{
cdata = cdata | (1 << cno);
}
else
{
cdata = cdata & ~(1 << cno);
}
ad7280.cb_mask[addr] = cdata;
}