BQ27510 電量計的校準 的 C語言實現,bq27510電量計
根據TI官方MSP430平台移植修改過來的,在Omap37xx(wince)平台測試,理論上和平台無關,可以使用
/*================================================================================* Texas Instruments OMAP(TM) Platform Software* (c) Copyright Texas Instruments, Incorporated. All Rights Reserved.** Use of this software is controlled by the terms and conditions found* in the license agreement under which this software has been supplied.*================================================================================*///// File: bqtool.c//#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <i2cproxy.h>#include "bq27500.h"#define CMD_MAX_DATA_SIZE512#define MAX_LINE_LEN((CMD_MAX_DATA_SIZE + 4) * 3)#define CMD_RETRY_DELAY100 /* in ms */#define RETRY_LIMIT3typedef enum {CMD_INVALID = 0,CMD_R,/* Read */CMD_W,/* Write */CMD_C,/* Compare */CMD_X,/* Delay */} cmd_type_t;/* * DO NOT change the order of fields - particularly reg * should be immediately followed by data */typedef struct {cmd_type_t cmd_type;unsigned char addr;unsigned char reg;union {unsigned char bytes[CMD_MAX_DATA_SIZE + 1];UINT delay;} data;unsigned char data_len;UINT32 line_num;CHAR*line;}cmd_t;static UINT32 line_num;/* Parse S into tokens separated by characters in DELIM. If S is NULL, the saved pointer in SAVE_PTR is used as the next starting point. For example: char s[] = "-abc-=-def"; char *sp; x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def" x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL x = strtok_r(NULL, "=", &sp); // x = NULL // s = "abc/0-def/0" */ static char *strtok_r(char *s, const char *delim, char **save_ptr) { char *token; if (s == NULL) s = *save_ptr; /* Scan leading delimiters. */ s += strspn(s, delim); if (*s == '\0') return NULL; /* Find the end of the token. */ token = s; s = strpbrk(token, delim); if (s == NULL) /* This token finishes the string. */ *save_ptr = strchr(token, '\0'); else { /* Terminate the token and make *SAVE_PTR point past it. */ *s = '\0'; *save_ptr = s + 1; } return token; }static char *strtok(char *s, const char *delim) { static char *last; return strtok_r(s, delim, &last);}//寫I2C,根據自己平台修改相關實現static BOOL i2c_write(HANDLE hI2C, cmd_t *cmd){int ret;DWORD udwTemp;if(hI2C){udwTemp=cmd->addr >>1; DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);SetFilePointer(hI2C,LOWORD(cmd->reg),NULL,FILE_BEGIN);if(!WriteFile(hI2C, cmd->data.bytes, cmd->data_len, &udwTemp, NULL)){RETAILMSG(1,(TEXT("ERROR: i2c_write: I2c WriteFile failed.\r\n")));}}return TRUE;}//讀I2C,根據自己平台修改相關實現static BOOL i2c_Read(HANDLE hI2C, cmd_t *cmd){int ret;DWORD udwTemp;if(hI2C){udwTemp=cmd->addr >>1; DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);SetFilePointer(hI2C,LOWORD(cmd->reg),NULL,FILE_BEGIN);if(!ReadFile(hI2C, cmd->data.bytes, cmd->data_len,&udwTemp, NULL)){RETAILMSG(1,(TEXT("ERROR: i2c_Read: I2c ReadFile failed.\r\n")));return FALSE;}else{cmd->data_len=udwTemp;}}return TRUE;}static BOOL do_exec_cmd(HANDLE i2c_file, cmd_t *cmd){unsigned char tmp_buf[CMD_MAX_DATA_SIZE];int j=0;switch (cmd->cmd_type) {case CMD_R:return i2c_Read(i2c_file, cmd);case CMD_W:return i2c_write(i2c_file, cmd);case CMD_C:memcpy(tmp_buf, cmd->data.bytes, cmd->data_len);if (!i2c_Read(i2c_file, cmd))return FALSE;if (memcmp(tmp_buf, cmd->data.bytes, cmd->data_len)) {RETAILMSG(1, (TEXT("Command C failed at line %d\r\n"),cmd->line_num));return FALSE;}return TRUE;case CMD_X:Sleep(cmd->data.delay);return TRUE;default:RETAILMSG(1, (TEXT("Unsupported command at line %d\r\n"),cmd->line_num));return FALSE;}}static BOOL execute_cmd(HANDLE i2c_file, cmd_t *cmd){int i = 1,j=0;BOOL ret;RETAILMSG(0,(TEXT("cmd:cmd_type=%d;addr=%02x,reg=%02x,cmd->data_len=%d,"),cmd->cmd_type,cmd->addr,cmd->reg,cmd->data_len));#if 0//only for debug TODO:deleteRETAILMSG(1,(TEXT("line=%d:"),cmd->line_num));for(j=0;j<cmd->data_len;j++){RETAILMSG(1,(TEXT("%02x "),cmd->data.bytes[j]));}RETAILMSG(1,(TEXT("\r\n")));#endifret = do_exec_cmd(i2c_file, cmd);//if execute failed,retry three timeswhile (!ret && i < RETRY_LIMIT) {Sleep(CMD_RETRY_DELAY);ret = do_exec_cmd(i2c_file, cmd);i++;}if (!ret) {RETAILMSG(1, (TEXT("Command execution failed at line %d addr=0x%02x reg=0x%02x\r\n"),cmd->line_num, cmd->addr, cmd->reg));}return ret;}static BOOL get_delay(UINT *delay){char *tok;UINT temp;tok = strtok(NULL, " ");if (!tok)return FALSE; /*end of line or file */if (1 != sscanf(tok, "%u", &temp)) {RETAILMSG(1, (TEXT("Syntax error while parsing delay at line %d\r\n"),line_num));return FALSE; /* syntax error */}*delay = (UINT)temp;return TRUE;}/* * Returns: * 0: success * 1: EOF *-1: Parse error */static int get_byte(unsigned char *byte){char *tok;unsigned char temp;tok = strtok(NULL, " ");if (!tok)return 1; /*end of line or file */if ((strlen(tok) != 2) || (sscanf(tok, "%2x", &temp) != 1)) {RETAILMSG(1, (TEXT("Syntax error at line %d\r\n"), line_num));return -1; /* syntax error */}*byte = (unsigned char)temp;return 0;/* success */}static BOOL get_addr_n_reg(cmd_t *cmd){if (get_byte(&cmd->addr))return FALSE;if (get_byte(&cmd->reg))return FALSE;return TRUE;}static BOOL get_data_bytes(cmd_t *cmd){int ret, i = 0;cmd->data_len = 0;do {ret = get_byte(&cmd->data.bytes[i++]);} while ((ret == 0) && (i <= CMD_MAX_DATA_SIZE));if (ret == 0) {RETAILMSG(1, (TEXT("More than allowed number of data bytes at line %d, data_len %d, i %d\r\n"), cmd->line_num,cmd->data_len, i));return FALSE;}cmd->data_len = i - 1;return TRUE;}static BOOL get_line(FILE *bqfs_file, char **buffer){int c;int i = 0;BOOL ret = TRUE;char *buf;buf = malloc(MAX_LINE_LEN);line_num++;while (1) {c = fgetc(bqfs_file);if (feof(bqfs_file)) {break;} else if (ferror(bqfs_file)) {RETAILMSG(1, (TEXT("File read error\r\n")));ret = FALSE;break;}if (((c == '\r') || (c == '\n') || (c == '\t')|| (c == ' ')) && (i == 0)) {/* * Skip leading white space, if any, at the beginning * of the line because this interferes with strtok */RETAILMSG(1, (TEXT("Leading whitespace at line %d\r\n"),line_num));if (c == '\n')line_num++;continue;/* blank line, let's continue */} else if (c == '\n') {/* We've reached end of line */break;}buf[i++] = c;if (i == MAX_LINE_LEN) {/* * Re-allocate in case the line is longer than * expected */buf = realloc(buf, MAX_LINE_LEN * 2);RETAILMSG(1, (TEXT("Line %d longer than expected,reallocating..\r\n"), line_num));} else if (i == MAX_LINE_LEN * 2) {/* * The line is already twice the expected maximum length * - maybe the bqfs/dffs needs to be fixed */RETAILMSG(1, (TEXT("Line %d too long, abort parsing..\r\n"),line_num));ret = FALSE;break;}}*buffer = buf;buf[i] = '\0';if (i < 1)ret = FALSE;return ret;}static BOOL get_cmd(FILE *bqfs_file, cmd_t *cmd){char *res;char *tok;char *buf = NULL;BOOL ret;while ((ret = get_line(bqfs_file, &buf))) {if (buf[0] == ';') {/* * Comment line - ignore it and get the * next line */RETAILMSG(0, (TEXT("Comment line,line_num=%d\r\n"),line_num));free(buf);} else {break;}}if (!ret)goto error;cmd->line_num = line_num;tok = strtok(buf, ":");if (!tok || (strlen(tok) != 1)) {RETAILMSG(1, (TEXT("Error parsing command at line %d\r\n"),line_num));goto error;}switch (tok[0]) {case 'R':case 'r':cmd->cmd_type = CMD_R;if (!get_addr_n_reg(cmd))goto error;break;case 'W':case 'w':cmd->cmd_type = CMD_W;if (!get_addr_n_reg(cmd))goto error;if (!get_data_bytes(cmd))goto error;break;case 'C':case 'c':cmd->cmd_type = CMD_C;if (!get_addr_n_reg(cmd))goto error;if (!get_data_bytes(cmd))goto error;break;case 'X':case 'x':cmd->cmd_type = CMD_X;cmd->data_len = 1;//only one dataif (!get_delay(&cmd->data.delay))goto error;break;default:RETAILMSG(1, (TEXT("No command or unexpected command at line %d.\r\n"),line_num));goto error;}if(buf){free(buf);}return TRUE;error:RETAILMSG(1, (TEXT("get_line error,line_num=%d\r\n"),line_num));cmd->cmd_type = CMD_INVALID;free(buf);return FALSE;}//Param:char *fname//File to flash BQ27510 generate by TI's engineer.//for example:bq27510G3.bqfs(with G2 update G3 firmware)int bqfs_flash(char *fname){FILE *bqfs_file = NULL;cmd_t *cmd = NULL;int ret = 0;DWORD udwTemp;HANDLE hI2C=NULL;RETAILMSG(0,(TEXT("bqfs_flush beging...\r\n")));bqfs_file = fopen(fname, "r");if (!bqfs_file) {RETAILMSG(1,(TEXT("bqfs_flush fopen failed.\r\n")));ret = -1;goto end;}hI2C=CreateFile(BATT_I2C_PORT, GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, 0, NULL);if(!hI2C){RETAILMSG(1,(TEXT("bqfs_flash: I2c CreateFile failed.\r\n")));ret = -1;goto end;}//I2C相關配置定址,根據自己平台修改相關實現//set slave addressudwTemp=I2CSLAVEADDR; DeviceIoControl(hI2C, IOCTL_I2C_SET_SLAVE_ADDRESS, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);//set i2c work modeudwTemp=I2C_SUBADDRESS_MODE_8;DeviceIoControl(hI2C, IOCTL_I2C_SET_SUBADDRESS_MODE, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);//set i2c transfer speedudwTemp=SLOWSPEED_MODE;DeviceIoControl(hI2C, IOCTL_I2C_SET_BAUD_INDEX, &udwTemp, sizeof(udwTemp), NULL, 0, NULL, NULL);cmd = malloc(sizeof(cmd_t));if(!cmd){RETAILMSG(1, (TEXT("bqfs_flash malloc failed.\r\n")));ret=-1;goto end;}while (get_cmd(bqfs_file, cmd) && execute_cmd(hI2C, cmd));if (feof(bqfs_file)) {RETAILMSG(1, (TEXT("programmed successfully!\r\n")));ret = 0;} else {RETAILMSG(1, (TEXT("programming failed!!\r\n")));ret = -1;}end:if (cmd)free(cmd);if(hI2C){CloseHandle(hI2C);hI2C=NULL;}if (bqfs_file)fclose(bqfs_file);return ret;}