Commit 522c8925 authored by Projects's avatar Projects

Initial (*not finished*) version of the fuel gauge driver.

I2C driver sometimes chokes on transfers - it has to be fixed yet.
parent 60d149a2
/***************************************************************************//**
* @file
* @brief I2C1 poll based driver for master mode operation on FreeWatch.
* @author Energy Micro AS
* @version 3.20.0
*******************************************************************************
* @section License
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
* microcontrollers and "EFR4" radios.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
* obligation to support this Software. Energy Micro AS is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Energy Micro AS will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
*****************************************************************************/
#include <stddef.h>
#include "em_cmu.h"
#include "em_gpio.h"
#include "i2cdrv.h"
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Initalize basic I2C master mode driver for use on the DK.
*
* @details
* This driver only supports master mode, single bus-master. In addition
* to configuring the EFM32 I2C peripheral module, it also configures DK
* specific setup in order to use the I2C bus.
*
* @param[in] init
* Pointer to I2C initialization structure.
******************************************************************************/
void I2CDRV_Init(const I2C_Init_TypeDef *init)
{
int i;
CMU_ClockEnable(cmuClock_HFPER, true);
CMU_ClockEnable(cmuClock_I2C1, true);
/* Use location #1: SDA - Pin B11, SCL - Pin B12 */
/* Output value must be set to 1 to not drive lines low... We set */
/* SCL first, to ensure it is high before changing SDA. */
GPIO_PinModeSet(gpioPortB, 12, gpioModeWiredAnd, 1);
GPIO_PinModeSet(gpioPortB, 11, gpioModeWiredAnd, 1);
/* In some situations (after a reset during an I2C transfer), the slave */
/* device may be left in an unknown state. Send 9 clock pulses just in case. */
for (i = 0; i < 9; i++)
{
/*
* TBD: Seems to be clocking at appr 80kHz-120kHz depending on compiler
* optimization when running at 14MHz. A bit high for standard mode devices,
* but DK only has fast mode devices. Need however to add some time
* measurement in order to not be dependable on frequency and code executed.
*/
GPIO_PinModeSet(gpioPortB, 12, gpioModeWiredAnd, 0);
GPIO_PinModeSet(gpioPortB, 12, gpioModeWiredAnd, 1);
}
/* Enable pins at location 1 */
I2C1->ROUTE = I2C_ROUTE_SDAPEN |
I2C_ROUTE_SCLPEN |
(1 << _I2C_ROUTE_LOCATION_SHIFT);
I2C_Init(I2C1, init);
}
/***************************************************************************//**
* @brief
* Perform I2C transfer.
*
* @details
* This driver only supports master mode, single bus-master. It does not
* return until the transfer is complete, polling for completion.
*
* @param[in] seq
* Pointer to sequence structure defining the I2C transfer to take place. The
* referenced structure must exist until the transfer has fully completed.
******************************************************************************/
I2C_TransferReturn_TypeDef I2CDRV_Transfer(I2C_TransferSeq_TypeDef *seq)
{
I2C_TransferReturn_TypeDef ret;
uint32_t timeout = 300000;
/* Do a polled transfer */
ret = I2C_TransferInit(I2C1, seq);
while (ret == i2cTransferInProgress && timeout--)
{
ret = I2C_Transfer(I2C1);
}
return(ret);
}
/***************************************************************************//**
* @file
* @brief I2C1 poll based driver for master mode operation on FreeWatch.
* @author Energy Micro AS
* @version 3.20.0
*******************************************************************************
* @section License
* <b>(C) Copyright 2012 Energy Micro AS, http://www.energymicro.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
* 4. The source and compiled code may only be used on Energy Micro "EFM32"
* microcontrollers and "EFR4" radios.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Energy Micro AS has no
* obligation to support this Software. Energy Micro AS is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Energy Micro AS will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
*****************************************************************************/
#ifndef __I2CDRV_H
#define __I2CDRV_H
#include "em_i2c.h"
/***************************************************************************//**
* @addtogroup Drivers
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup I2c
* @{
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
void I2CDRV_Init(const I2C_Init_TypeDef *init);
I2C_TransferReturn_TypeDef I2CDRV_Transfer(I2C_TransferSeq_TypeDef *seq);
#ifdef __cplusplus
}
#endif
/** @} (end group I2c) */
/** @} (end group Drivers) */
#endif /* __I2CDRV_H */
/*
* Copyright (C) 2014 Julian Lewis
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @brief Fuel gauge driver (MAX17047)
*/
#include "max17047.h"
#include "i2cdrv.h"
uint8_t max17047_read_reg(uint8_t address, uint8_t length, uint8_t* buffer)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
seq.addr = MAX17047_ADDRESS;
seq.flags = I2C_FLAG_WRITE_READ; // write/read sequence
// Select offset to start reading from
seq.buf[0].data = &address;
seq.buf[0].len = 1;
// Select location/length of data to be read
seq.buf[1].data = buffer;
seq.buf[1].len = length;
ret = I2CDRV_Transfer(&seq);
if(ret != i2cTransferDone)
{
return((uint8_t) ret);
}
return length;
}
uint8_t max17047_write_reg(uint8_t address, uint8_t length, uint8_t* buffer)
{
I2C_TransferSeq_TypeDef seq;
I2C_TransferReturn_TypeDef ret;
seq.addr = MAX17047_ADDRESS;
seq.flags = I2C_FLAG_WRITE_WRITE; // write/write sequence
// Select offset to start reading from
seq.buf[0].data = &address;
seq.buf[0].len = 1;
// Select location/length of data to be read
seq.buf[1].data = buffer;
seq.buf[1].len = length;
ret = I2CDRV_Transfer(&seq);
if(ret != i2cTransferDone)
{
return((uint8_t) ret);
}
return length;
// TODO ack polling to determine if the write operation is finished?
}
uint16_t max17047_get_status(void)
{
uint16_t status;
max17047_read_reg(MAX17047_REG_STATUS, 2, (uint8_t*) &status);
return status;
}
uint16_t max17047_get_voltage(void)
{
uint16_t vcell;
max17047_read_reg(MAX17047_REG_VCELL, 2, (uint8_t*) &vcell);
// convert to mV
vcell >>= 3;
vcell *= 5;
return vcell;
}
uint16_t max17047_get_current(void)
{
uint16_t current;
max17047_read_reg(MAX17047_REG_CURRENT, 2, (uint8_t*) &current);
// convert to mA
// TODO
return current;
}
int8_t max17047_get_temperature(void)
{
// TODO requires configuration of TOFF and TGAIN registers
uint8_t temperature[2];
max17047_read_reg(MAX17047_REG_TEMPERATURE, 2, temperature);
return temperature[0];
}
uint8_t max17047_get_charge(void)
{
uint8_t charge[2];
max17047_read_reg(MAX17047_REG_SOC_REP, 2, charge);
return charge[0];
}
uint16_t max17047_get_time_left(void)
{
// TODO see what is missing?
return 0;
}
/*
* Copyright (C) 2014 Julian Lewis
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @brief Fuel gauge driver (MAX17047)
*/
#ifndef __MAX17047_H_
#define __MAX17047_H_
#include <stdint.h>
// Two-wire protocol address
#define MAX17047_ADDRESS 0x6C
// Sense resistor value (milliohm)
#define MAX17047_SENS_RES 10
// Register addresses
#define MAX17047_REG_STATUS 0x00
#define MAX17047_REG_VALRT_TH 0x01
#define MAX17047_REG_TALRT_TH 0x02
#define MAX17047_REG_SALRT_TH 0x03
#define MAX17047_REG_AT_RATE 0x04
#define MAX17047_REG_REM_CAP_REP 0x05
#define MAX17047_REG_SOC_REP 0x06
#define MAX17047_REG_AGE 0x07
#define MAX17047_REG_TEMPERATURE 0x08
#define MAX17047_REG_VCELL 0x09
#define MAX17047_REG_CURRENT 0x0A
#define MAX17047_REG_AVR_CURRENT 0x0B
#define MAX17047_REG_SOC_MIX 0x0D
#define MAX17047_REG_SOC_AV 0x0E
#define MAX17047_REG_REM_CAP_MIX 0x0F
#define MAX17047_REG_FULL_CAP 0x10
#define MAX17047_REG_TIME_TO_EMPTY 0x11
#define MAX17047_REG_QRESIDUAL_00 0x12
#define MAX17047_REG_FULL_SOC_THR 0x13
#define MAX17047_REG_AVG_TEMP 0x16
#define MAX17047_REG_CYCLES 0x17
#define MAX17047_REG_DESIGN_CAP 0x18
#define MAX17047_REG_AVG_VCELL 0x19
#define MAX17047_REG_MAX_MIN_TEMP 0x1A
#define MAX17047_REG_MAX_MIN_VCELL 0z1B
#define MAX17047_REG_MAX_MIN_CURRENT 0x1C
#define MAX17047_REG_CONFIG 0x1D
#define MAX17047_REG_ICHG_TERM 0x1E
#define MAX17047_REG_REM_CAP_AV 0x1F
#define MAX17047_REG_VERSION 0x21
#define MAX17047_REG_QRESIDUAL_10 0x22
#define MAX17047_REG_FULL_CAP_NOM 0x23
#define MAX17047_REG_TEMP_NOM 0x24
#define MAX17047_REG_TEMP_LIM 0x25
#define MAX17047_REG_AIN 0x27
#define MAX17047_REG_LEARN_CFG 0x28
#define MAX17047_REG_FILTER_CFG 0x29
#define MAX17047_REG_RELAX_CFG 0x30
#define MAX17047_REG_MISC_CFG 0x2B
#define MAX17047_REG_TGAIN 0x2C
#define MAX17047_REG_TOFF 0x2D
#define MAX17047_REG_CGAIN 0x2E
#define MAX17047_REG_COFF 0x2F
#define MAX17047_REG_QRESIDUAL_20 0x32
#define MAX17047_REG_IAVG_EMPTY 0x36
#define MAX17047_REG_FCTC 0x37
#define MAX17047_REG_RCOMP 0x38
#define MAX17047_REG_TEMP_CO 0x39
#define MAX17047_REG_V_EMPTY 0x3A
#define MAX17047_REG_FSTAT 0x3D
#define MAX17047_REG_TIMER 0x3E
#define MAX17047_REG_SHDN_TIMER 0x3F
#define MAX17047_REG_QRESIDUAL_30 0x42
#define MAX17047_REG_DQACC 0x45
#define MAX17047_REG_DPACC 0x46
#define MAX17047_REG_QH 0x4D
#define MAX17047_REG_CHAR_TABLE_START 0x80
#define MAX17047_REG_CHAR_TABLE_END 0xAF
#define MAX17047_REG_VFOCV 0xFB
#define MAX17047_REG_SOC_VF 0xFF
// Status register bits
// Power-On Reset (1 == hw/sw POR event occurred; needs reconfig)
#define MAX17047_STS_POR 0x0002
// Battery Status (0 == present, 1 == absent)
#define MAX17047_STS_BST 0x0008
// Minimum Valrt Threshold Exceeded (1 == Vcell < min Valrt)
#define MAX17047_STS_VMN 0x0100
// Minimum Talrt Threshold Exceeded (1 == temperature < min Talrt)
#define MAX17047_STS_TMN 0x0200
// Minimum SOCalrt Threshold Exceeded (1 == SOC < min SOCalrt)
#define MAX17047_STS_SMN 0x0400
// Battery Insertion (1 == battery has been inserted; has to be cleared manually)
#define MAX17047_STS_BI 0x0800
// Maximum Valrt Threshold Exceeded (1 == Vcell > max Valrt)
#define MAX17047_STS_VMX 0x1000
// Maximum Talrt Threshold Exceeded (1 == temperature > max Talrt)
#define MAX17047_STS_TMX 0x2000
// Maximum SOC Threshold Exceeded (1 == SOC > max SOCalrt)
#define MAX17047_STS_SMX 0x4000
// Battery Removal (1 == battery has been removed; has to be cleared manually)
#define MAX17047_STS_BR 0x8000
/**
* @brief Reads a register from max17047.
* @param uint8_t reg Register number (the starting one, if you read more than one).
* @param uint8_t length Number of bytes to read.
* @param uint8_t* buffer Buffer to save the read data.
* @return Length of the read data in case of success, error code otherwise.
* @see I2C_TransferSeq_TypeDef
*/
uint8_t max17047_read_reg(uint8_t address, uint8_t length, uint8_t* buffer);
/**
* @brief Writes a register to max17047.
* @param uint8_t reg Register number (the starting one, if you write more than one).
* @param uint8_t length Number of bytes to write.
* @param uint8_t* buffer Buffer with data to be written.
* @return Length of the written data in case of success, error code otherwise.
* @see I2C_TransferSeq_TypeDef
*/
uint8_t max17047_write_reg(uint8_t address, uint8_t length, uint8_t* buffer);
/**
* @brief Reads the status.
* @return Status of max17047.
*/
uint16_t max17047_get_status(void);
/**
* @brief Reads the battery voltage.
* @return Battery voltage (in millivolts).
*/
uint16_t max17047_get_voltage(void);
/**
* @brief Reads current from the battery.
* @return Current (in milliampers).
*/
uint16_t max17047_get_current(void);
/**
* @brief Reads temperature sensor.
* @return Temperature (*C).
*/
int8_t max17047_get_temperature(void);
/**
* @brief Reads the current state of charge.
* @return State of charge (expressed as percentage: 0-100).
*/
uint8_t max17047_get_charge(void);
/**
* @brief Reads remaining time to empty the battery.
* @return Time to empty (in minutes).
*/
uint16_t max17047_get_time_left(void);
#endif /*__MAX17047_H_ */
......@@ -143,6 +143,8 @@ INCLUDEPATHS += \
C_SRC += \
../common/Device/EnergyMicro/EFM32GG/Source/system_efm32gg.c \
../common/drivers/lcd.c \
../common/drivers/i2cdrv.c \
../common/drivers/max17047.c \
../common/emlib/src/em_assert.c \
../common/emlib/src/em_cmu.c \
../common/emlib/src/em_emu.c \
......
......@@ -28,7 +28,10 @@
#include <em_cmu.h>
#include <em_gpio.h>
#include <drivers/lcd.h>
#include <drivers/i2cdrv.h>
#include <drivers/max17047.h>
#include <gfx/graphics.h>
#include <stdio.h>
/* Counts 1ms timeTicks */
volatile uint32_t msTicks;
......@@ -60,6 +63,10 @@ void Delay(uint32_t dlyTicks)
int main(void)
{
int x, y;
char buf[16];
I2C_Init_TypeDef i2c_init = I2C_INIT_DEFAULT;
uint16_t version = 0;
uint8_t ret = 0;
/* Setup SysTick Timer for 1 msec interrupts */
if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1);
......@@ -72,12 +79,13 @@ int main(void)
GPIO_PinModeSet(gpioPortE, 12, gpioModePushPull, 0);
lcd_init();
I2CDRV_Init(&i2c_init);
for(x = 0; x < LCD_WIDTH / 2; ++x)
for(x = 0; x < LCD_WIDTH / 4; ++x)
{
for(y = 0; y < LCD_HEIGHT / 2; ++y)
for(y = 0; y < LCD_HEIGHT / 4; ++y)
{
lcd_set_pixel(x, y, (x >> 4 ^ y >> 4) % 2);
lcd_set_pixel(x, y, (x >> 3 ^ y >> 3) % 2);
}
}
......@@ -90,14 +98,20 @@ int main(void)
box(100, 100, 120, 120, 1);
line(100, 40, 120, 70, 1);
lcd_update();
/* Infinite blink loop */
while (1) {
GPIO_PinOutToggle(gpioPortE, 11);
Delay(200);
GPIO_PinOutToggle(gpioPortE, 12);
Delay(200);
// Print the version of the fuel gauge chip
ret = max17047_read_reg(MAX17047_REG_VERSION, 2, (uint8_t*)&version);
sprintf(buf, "ver %d", version);
text(&font_helv17, 64, 0, buf);
version = 0; // be sure that it is read every time
lcd_update();
}
}
File mode changed from 100644 to 100755
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment