Compare commits
6 commits
use_upstre
...
main
Author | SHA1 | Date | |
---|---|---|---|
8e6bf5cf3d | |||
0996c9bca5 | |||
d8f88b7636 | |||
919c69cc5c | |||
6a3d159a72 | |||
27b1bac061 |
20 changed files with 1332 additions and 0 deletions
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
.pio
|
||||
*~
|
||||
*credential.h
|
||||
# -*- mode: gitignore; -*-
|
||||
*~
|
||||
\#*\#
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
*.elc
|
||||
auto-save-list
|
||||
tramp
|
||||
.\#*
|
||||
|
25
esp32/include/badge_pins.h
Normal file
25
esp32/include/badge_pins.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
// HSPI pins
|
||||
#define HSPI_MISO 12
|
||||
#define HSPI_MOSI 13
|
||||
#define HSPI_SCLK 14
|
||||
#define HSPI_SS 15
|
||||
|
||||
// ePaper display
|
||||
#define EPD_DC 25
|
||||
#define EPD_CS 27
|
||||
#define EPD_BUSY 35
|
||||
#define SRAM_CS -1
|
||||
#define EPD_RESET 26
|
||||
#define EPD_SPI &SPI3
|
||||
|
||||
// I2C
|
||||
#define ESP_SDA 22
|
||||
#define ESP_SCL 38
|
||||
|
||||
// ATMEL UART Bridge
|
||||
#define UART_RXD (33u)
|
||||
#define UART_TXD (32U)
|
||||
|
||||
// IMU
|
||||
#define ESP32_I2C_IMU_SDA ((int)22)
|
||||
#define ESP32_I2C_IMU_SCL ((int)19)
|
344
esp32/include/icm20602.h
Normal file
344
esp32/include/icm20602.h
Normal file
|
@ -0,0 +1,344 @@
|
|||
#ifndef _ICM20602_H
|
||||
#define _ICM20602_H
|
||||
|
||||
/***** Includes *****/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/***** Macros *****/
|
||||
|
||||
/** This initializer will zero out the ICM20602 struct for initialization
|
||||
* purposes. This is advised as to avoid having uninitialized garbage values
|
||||
* left within the struct */
|
||||
#define ICM20602_INIT() \
|
||||
{ \
|
||||
.id = 0, \
|
||||
.hal_wr = NULL, \
|
||||
.hal_rd = NULL, \
|
||||
.hal_sleep = NULL, \
|
||||
.mutex_lock = NULL, \
|
||||
.mutex_unlock = NULL, \
|
||||
.use_accel = false, \
|
||||
.accel_fifo = false, \
|
||||
.accel_dlpf = 0, \
|
||||
.accel_g = 0, \
|
||||
.use_gyro = false, \
|
||||
.gyro_fifo = false, \
|
||||
.gyro_dlpf = 0, \
|
||||
.gyro_dps = 0, \
|
||||
.sample_rate_div = 1, \
|
||||
.i2c_disable = false, \
|
||||
}
|
||||
|
||||
/** This initializer will configure the ICM20602 with settings that should
|
||||
* yield some actual output on both the gyroscope and the accelerometer. All
|
||||
* that the developer should need to set manually are the "hal_wr", "hal_rd",
|
||||
* and "hal_sleep" function pointers. It is recommended to use this for
|
||||
* testing purposes. */
|
||||
#define ICM20602_DEFAULT_INIT() \
|
||||
{ \
|
||||
.id = 0, \
|
||||
.hal_wr = NULL, \
|
||||
.hal_rd = NULL, \
|
||||
.hal_sleep = NULL, \
|
||||
.mutex_lock = NULL, \
|
||||
.mutex_unlock = NULL, \
|
||||
.use_accel = true, \
|
||||
.accel_fifo = false, \
|
||||
.accel_dlpf = ICM20602_ACCEL_DLPF_10_2_HZ, \
|
||||
.accel_g = ICM20602_ACCEL_RANGE_4G, \
|
||||
.use_gyro = true, \
|
||||
.gyro_fifo = false, \
|
||||
.gyro_dlpf = ICM20602_GYRO_DLPF_10_HZ, \
|
||||
.gyro_dps = ICM20602_GYRO_RANGE_2000_DPS, \
|
||||
.sample_rate_div = 100, \
|
||||
.i2c_disable = false, \
|
||||
}
|
||||
|
||||
/***** Typedefs *****/
|
||||
|
||||
/** \brief Function pointer for write function.
|
||||
* \param id the ID value of the icm20602 device struct
|
||||
* \param reg ICM20602 register address to target
|
||||
* \param data pointer to data to write
|
||||
* \param len number of bytes to write
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
typedef int8_t (*icm20602_hal_wr)(uint8_t id, uint8_t reg, uint8_t * data,
|
||||
uint16_t len);
|
||||
|
||||
/** \brief Function pointer for read function.
|
||||
* \param id the ID value of the icm20602 device struct
|
||||
* \param reg ICM20602 register address to target
|
||||
* \param data pointer to data to read
|
||||
* \param len number of bytes to read
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
typedef int8_t (*icm20602_hal_rd)(uint8_t id, uint8_t reg, uint8_t * data,
|
||||
uint16_t len);
|
||||
|
||||
/** \brief Function pointer for sleep function.
|
||||
* \param ms the total number of milliseconds to sleep for
|
||||
* \return void
|
||||
*/
|
||||
typedef void (*icm20602_hal_sleep)(uint32_t ms);
|
||||
|
||||
/** \brief Function pointer for mutex locking function.
|
||||
* \param id the ID value of the icm20602 device struct
|
||||
* \return void
|
||||
*/
|
||||
typedef void (*icm20602_mutex_lock)(uint8_t id);
|
||||
|
||||
/** \brief Function pointer for mutex unlocking function.
|
||||
* \param id the ID value of the icm20602 device struct
|
||||
* \return void
|
||||
*/
|
||||
typedef void (*icm20602_mutex_unlock)(uint8_t id);
|
||||
|
||||
/***** Enums *****/
|
||||
|
||||
/** Enumerated value corresponds with A_DLPF_CFG in the ACCEL_CONFIG2 register
|
||||
* unless BYPASS is specified in the name. If BYPASS is used, the DLPF is
|
||||
* removed from the signal path and ACCEL_FCHOICE_B is set in the
|
||||
* ACCEL_CONFIG2 register. */
|
||||
enum icm20602_accel_dlpf {
|
||||
ICM20602_ACCEL_DLPF_218_1_HZ = 0, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_99_HZ = 2, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_44_8_HZ = 3, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_21_2_HZ = 4, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_10_2_HZ = 5, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_5_1_HZ = 6, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_420_HZ = 7, // data clocked at 1kHz
|
||||
ICM20602_ACCEL_DLPF_BYPASS_1046_HZ, // no filter, data clocked at 4kHz
|
||||
};
|
||||
|
||||
/** Enumerated value corresponds with ACCEL_FS_SEL in the ACCEL_CONFIG
|
||||
* register. Values listed are the full +/- G range. */
|
||||
enum icm20602_accel_g {
|
||||
ICM20602_ACCEL_RANGE_2G = 0,
|
||||
ICM20602_ACCEL_RANGE_4G = 1,
|
||||
ICM20602_ACCEL_RANGE_8G = 2,
|
||||
ICM20602_ACCEL_RANGE_16G = 3,
|
||||
};
|
||||
|
||||
/** Enumerated value corresponds with DLPF_CFG in the CONFIG register unless
|
||||
* BYPASS is specified in the name. If BYPASS is used, the DLPF is removed
|
||||
* from the signal path and FCHOICE_B is set in GYRO_CONFIG register. */
|
||||
enum icm20602_gyro_dlpf {
|
||||
ICM20602_GYRO_DLPF_250_HZ = 0, // data clocked at 8kHz
|
||||
ICM20602_GYRO_DLPF_176_HZ = 1, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_92_HZ = 2, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_41_HZ = 3, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_20_HZ = 4, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_10_HZ = 5, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_5_HZ = 6, // data clocked at 1kHz
|
||||
ICM20602_GYRO_DLPF_3281_HZ = 7, // data clocked at 8kHz
|
||||
ICM20602_GYRO_DLPF_BYPASS_3281_HZ, // no filter, data clocked at 32kHz
|
||||
ICM20602_GYRO_DLPF_BYPASS_8173_HZ, // no filter, data clocked at 32kHz
|
||||
};
|
||||
|
||||
/** Enumerated value corresponds with FS_SEL in the GYRO_CONFIG register.
|
||||
* Values listed are the full +/- DPS range. */
|
||||
enum icm20602_gyro_dps {
|
||||
ICM20602_GYRO_RANGE_250_DPS = 0,
|
||||
ICM20602_GYRO_RANGE_500_DPS = 1,
|
||||
ICM20602_GYRO_RANGE_1000_DPS = 2,
|
||||
ICM20602_GYRO_RANGE_2000_DPS = 3,
|
||||
};
|
||||
|
||||
/***** Structs *****/
|
||||
|
||||
struct icm20602_dev {
|
||||
/// Identifier, can be I2C address, SPI CS line, or some other unique value.
|
||||
uint8_t id;
|
||||
|
||||
/// Required function pointer for register write function.
|
||||
icm20602_hal_wr hal_wr;
|
||||
/// Required function pointer for register read function.
|
||||
icm20602_hal_rd hal_rd;
|
||||
/// Required function pointer for system sleep/delay.
|
||||
icm20602_hal_sleep hal_sleep;
|
||||
|
||||
/// Optional function pointer to mutex lock if needed, NULL otherwise.
|
||||
icm20602_mutex_lock mutex_lock;
|
||||
/// Optional function pointer to mutex unlocking if needed, NULL otherwise.
|
||||
icm20602_mutex_lock mutex_unlock;
|
||||
|
||||
/// Set to "true" to configure the accelerometer.
|
||||
bool use_accel;
|
||||
/// Enable or disable fifo for accelerometer.
|
||||
bool accel_fifo;
|
||||
/// Select the digital low pass filter to use with the accelerometer.
|
||||
enum icm20602_accel_dlpf accel_dlpf;
|
||||
/// Select the accelerometer's g-force range.
|
||||
enum icm20602_accel_g accel_g;
|
||||
|
||||
/// Set to "true" to configure the gyroscope.
|
||||
bool use_gyro;
|
||||
/// Enable or disable fifo for gyroscope.
|
||||
bool gyro_fifo;
|
||||
/// Select the digital low pass filter to use with the gyroscope.
|
||||
enum icm20602_gyro_dlpf gyro_dlpf;
|
||||
/// Select the gyroscope's degrees per second range.
|
||||
enum icm20602_gyro_dps gyro_dps;
|
||||
|
||||
/// Divides the data clock for both the accelerometer and gyroscope.
|
||||
uint8_t sample_rate_div;
|
||||
|
||||
/// Disable hardware I2C communications to chip, recommeded if using SPI.
|
||||
bool i2c_disable;
|
||||
};
|
||||
|
||||
/***** Global Functions *****/
|
||||
|
||||
/** \brief Initializes the ICM20602 sensor.
|
||||
* \param config pointer to configuration struct
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_init(struct icm20602_dev * dev);
|
||||
|
||||
/** \brief Reads current G-force values of accelerometer.
|
||||
* \param p_x destination for x G value
|
||||
* \param p_y destination for y G value
|
||||
* \param p_z destination for z G value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_accel(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z);
|
||||
|
||||
/** \brief Reads current degrees per second values of gyroscope.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_gyro(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z);
|
||||
|
||||
/** \brief Reads current values of accelerometer and gyroscope.
|
||||
* \param p_ax destination for accelerometer x G value
|
||||
* \param p_ay destination for accelerometer y G value
|
||||
* \param p_az destination for accelerometer z G value
|
||||
* \param p_gx destination for gyroscope x DPS value
|
||||
* \param p_gy destination for gyroscope y DPS value
|
||||
* \param p_gz destination for gyroscope z DPS value
|
||||
* \param p_t destination for temperature degrees C value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_data(struct icm20602_dev * dev, float * p_ax, float * p_ay,
|
||||
float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t);
|
||||
|
||||
/** \brief Reads current raw values of accelerometer.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_accel_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y,
|
||||
int16_t * p_z);
|
||||
|
||||
/** \brief Reads current raw values of gyroscope.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y,
|
||||
int16_t * p_z);
|
||||
|
||||
/** \brief Reads current raw values of accelerometer and gyroscope.
|
||||
* \param p_ax destination for accelerometer x value
|
||||
* \param p_ay destination for accelerometer y value
|
||||
* \param p_az destination for accelerometer z value
|
||||
* \param p_gx destination for gyroscope x value
|
||||
* \param p_gy destination for gyroscope y value
|
||||
* \param p_gz destination for gyroscope z value
|
||||
* \param p_t destination for temperature value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_data_raw(struct icm20602_dev * dev, int16_t * p_ax,
|
||||
int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy,
|
||||
int16_t * p_gz, int16_t * p_t);
|
||||
|
||||
/** \brief Reads FIFO G-force values of accelerometer.
|
||||
* \param p_x destination for x G value
|
||||
* \param p_y destination for y G value
|
||||
* \param p_z destination for z G value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_accel_fifo(struct icm20602_dev * dev, float * x, float * y,
|
||||
float * z);
|
||||
|
||||
/** \brief Reads FIFO degrees per second values of gyroscope.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_gyro_fifo(struct icm20602_dev * dev, float * x, float * y,
|
||||
float * z);
|
||||
|
||||
/** \brief Reads FIFO values of accelerometer and gyroscope. Note, both
|
||||
* accelerometer and gyroscope fifos should be enabled if this
|
||||
* function is to be used.
|
||||
* \param p_ax destination for accelerometer x G value
|
||||
* \param p_ay destination for accelerometer y G value
|
||||
* \param p_az destination for accelerometer z G value
|
||||
* \param p_gx destination for gyroscope x DPS value
|
||||
* \param p_gy destination for gyroscope y DPS value
|
||||
* \param p_gz destination for gyroscope z DPS value
|
||||
* \param p_t destination for temperature degrees C value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_fifo_data(struct icm20602_dev * dev, float * p_ax, float * p_ay,
|
||||
float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t);
|
||||
|
||||
/** \brief Reads FIFO raw values of accelerometer.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_fifo_accel_raw(struct icm20602_dev * dev, int16_t * p_x,
|
||||
int16_t * p_y, int16_t * p_z);
|
||||
|
||||
/** \brief Reads FIFO raw values of gyroscope.
|
||||
* \param p_x destination for x value
|
||||
* \param p_y destination for y value
|
||||
* \param p_z destination for z value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_fifo_gyro_raw(struct icm20602_dev * dev, int16_t * p_x,
|
||||
int16_t * p_y, int16_t * p_z);
|
||||
|
||||
/** \brief Reads FIFO raw values of accelerometer and gyroscope. Note, both
|
||||
* accelerometer and gyroscope fifos should be enabled if this
|
||||
* function is to be used.
|
||||
* \param p_ax destination for accelerometer x value
|
||||
* \param p_ay destination for accelerometer y value
|
||||
* \param p_az destination for accelerometer z value
|
||||
* \param p_gx destination for gyroscope x value
|
||||
* \param p_gy destination for gyroscope y value
|
||||
* \param p_gz destination for gyroscope z value
|
||||
* \param p_t destination for temperature value
|
||||
* \return zero on success, anything else is an error
|
||||
*/
|
||||
extern int8_t
|
||||
icm20602_read_fifo_data_raw(struct icm20602_dev * dev, int16_t * p_ax,
|
||||
int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy,
|
||||
int16_t * p_gz, int16_t * p_t);
|
||||
|
||||
#endif
|
549
esp32/src/icm20602.c
Normal file
549
esp32/src/icm20602.c
Normal file
|
@ -0,0 +1,549 @@
|
|||
/***** Includes *****/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "icm20602.h"
|
||||
|
||||
/***** Defines *****/
|
||||
|
||||
#define REG_XG_OFFS_TC_H 0x04
|
||||
#define REG_XG_OFFS_TC_L 0x05
|
||||
#define REG_YG_OFFS_TC_H 0x07
|
||||
#define REG_YG_OFFS_TC_L 0x08
|
||||
#define REG_ZG_OFFS_TC_H 0x0A
|
||||
#define REG_ZG_OFFS_TC_L 0x0B
|
||||
#define REG_SELF_TEST_X_ACCEL 0x0D
|
||||
#define REG_SELF_TEST_Y_ACCEL 0x0E
|
||||
#define REG_SELF_TEST_Z_ACCEL 0x0F
|
||||
#define REG_XG_OFFS_USRH 0x13
|
||||
#define REG_XG_OFFS_USRL 0x14
|
||||
#define REG_YG_OFFS_USRH 0x15
|
||||
#define REG_YG_OFFS_USRL 0x16
|
||||
#define REG_ZG_OFFS_USRH 0x17
|
||||
#define REG_ZG_OFFS_USRL 0x18
|
||||
#define REG_SMPLRT_DIV 0x19
|
||||
#define REG_CONFIG 0x1A
|
||||
#define REG_GYRO_CONFIG 0x1B
|
||||
#define REG_ACCEL_CONFIG 0x1C
|
||||
#define REG_ACCEL_CONFIG_2 0x1D
|
||||
#define REG_LP_MODE_CFG 0x1E
|
||||
#define REG_ACCEL_WOM_X_THR 0x20
|
||||
#define REG_ACCEL_WOM_Y_THR 0x21
|
||||
#define REG_ACCEL_WOM_Z_THR 0x22
|
||||
#define REG_FIFO_EN 0x23
|
||||
#define REG_FSYNC_INT 0x36
|
||||
#define REG_INT_PIN_CFG 0x37
|
||||
#define REG_INT_ENABLE 0x38
|
||||
#define REG_FIFO_WM_INT_STATUS 0x39
|
||||
#define REG_INT_STATUS 0x3A
|
||||
#define REG_ACCEL_XOUT_H 0x3B
|
||||
#define REG_ACCEL_XOUT_L 0x3C
|
||||
#define REG_ACCEL_YOUT_H 0x3D
|
||||
#define REG_ACCEL_YOUT_L 0x3E
|
||||
#define REG_ACCEL_ZOUT_H 0x3F
|
||||
#define REG_ACCEL_ZOUT_L 0x40
|
||||
#define REG_TEMP_OUT_H 0x41
|
||||
#define REG_TEMP_OUT_L 0x42
|
||||
#define REG_GYRO_XOUT_H 0x43
|
||||
#define REG_GYRO_XOUT_L 0x44
|
||||
#define REG_GYRO_YOUT_H 0x45
|
||||
#define REG_GYRO_YOUT_L 0x46
|
||||
#define REG_GYRO_ZOUT_H 0x47
|
||||
#define REG_GYRO_ZOUT_L 0x48
|
||||
#define REG_SELF_TEST_X_GYRO 0x50
|
||||
#define REG_SELF_TEST_Y_GYRO 0x51
|
||||
#define REG_SELF_TEST_Z_GYRO 0x52
|
||||
#define REG_FIFO_WM_TH1 0x60
|
||||
#define REG_FIFO_WM_TH2 0x61
|
||||
#define REG_SIGNAL_PATH_RESET 0x68
|
||||
#define REG_ACCEL_INTEL_CTRL 0x69
|
||||
#define REG_USER_CTRL 0x6A
|
||||
#define REG_PWR_MGMT_1 0x6B
|
||||
#define REG_PWR_MGMT_2 0x6C
|
||||
#define REG_I2C_IF 0x70
|
||||
#define REG_FIFO_COUNTH 0x72
|
||||
#define REG_FIFO_COUNTL 0x73
|
||||
#define REG_FIFO_R_W 0x74
|
||||
#define REG_WHO_AM_I 0x75
|
||||
#define REG_XA_OFFSET_H 0x77
|
||||
#define REG_XA_OFFSET_L 0x78
|
||||
#define REG_YA_OFFSET_H 0x7A
|
||||
#define REG_YA_OFFSET_L 0x7B
|
||||
#define REG_ZA_OFFSET_H 0x7D
|
||||
#define REG_ZA_OFFSET_L 0x7E
|
||||
|
||||
#define REG_WHO_AM_I_CONST 0X12
|
||||
|
||||
/***** Macros *****/
|
||||
|
||||
#define ON_ERROR_GOTO(cond, symbol) \
|
||||
if (!(cond)) { goto symbol; }
|
||||
|
||||
// extra steps, but I'm paranoid about some compilers/systems not handling the
|
||||
// conversion from uint8_t to int16_t correctly
|
||||
#define UINT8_TO_INT16(dst, src_high, src_low) \
|
||||
do { \
|
||||
dst = (src_high); \
|
||||
dst <<= 8; \
|
||||
dst |= (src_low); \
|
||||
} while (0);
|
||||
|
||||
/***** Local Data *****/
|
||||
|
||||
// TODO: Look into getting real temp sensitivity.
|
||||
static float _temp_sensitivity = 326.8;
|
||||
|
||||
/***** Local Functions *****/
|
||||
|
||||
/// Used to convert raw accelerometer readings to G-force.
|
||||
float
|
||||
_get_accel_sensitivity(enum icm20602_accel_g accel_g)
|
||||
{
|
||||
float f = 0.0;
|
||||
|
||||
switch (accel_g) {
|
||||
case (ICM20602_ACCEL_RANGE_2G):
|
||||
f = 16384.0;
|
||||
break;
|
||||
case (ICM20602_ACCEL_RANGE_4G):
|
||||
f = 8192.0;
|
||||
break;
|
||||
case (ICM20602_ACCEL_RANGE_8G):
|
||||
f = 4096.0;
|
||||
break;
|
||||
case (ICM20602_ACCEL_RANGE_16G):
|
||||
f = 2048.0;
|
||||
break;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/// Used to convert raw gyroscope readings to degrees per second.
|
||||
float
|
||||
_get_gyro_sensitivity(enum icm20602_gyro_dps gyro_dps)
|
||||
{
|
||||
float f = 0;
|
||||
|
||||
switch (gyro_dps) {
|
||||
case (ICM20602_GYRO_RANGE_250_DPS):
|
||||
f = 131.0;
|
||||
break;
|
||||
case (ICM20602_GYRO_RANGE_500_DPS):
|
||||
f = 65.5;
|
||||
break;
|
||||
case (ICM20602_GYRO_RANGE_1000_DPS):
|
||||
f = 32.8;
|
||||
break;
|
||||
case (ICM20602_GYRO_RANGE_2000_DPS):
|
||||
f = 16.4;
|
||||
break;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int8_t
|
||||
_read_data(struct icm20602_dev * dev, uint8_t reg, uint8_t * buf, uint32_t len)
|
||||
{
|
||||
int8_t r = 0;
|
||||
|
||||
if ((!dev->hal_wr) || (!dev->hal_rd) || (!dev->hal_sleep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dev->mutex_lock) {
|
||||
dev->mutex_lock(dev->id);
|
||||
}
|
||||
|
||||
r = dev->hal_rd(dev->id, reg, buf, len);
|
||||
|
||||
if (dev->mutex_unlock) {
|
||||
dev->mutex_unlock(dev->id);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/***** Global Functions *****/
|
||||
|
||||
int8_t
|
||||
icm20602_init(struct icm20602_dev * dev)
|
||||
{
|
||||
uint8_t tmp = 0;
|
||||
int8_t r = 0;
|
||||
|
||||
if ((!dev->hal_wr) || (!dev->hal_rd) || (!dev->hal_sleep)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// General Procedure:
|
||||
// 1. reset chip
|
||||
// 2. set clock for PLL for optimum performance as documented in datasheet
|
||||
// 3. place accelerometer and gyroscope into standby
|
||||
// 4. disable fifo
|
||||
// 5. configure chip
|
||||
// 6. enable accelerometer and gyroscope
|
||||
|
||||
if (dev->mutex_lock) {
|
||||
dev->mutex_lock(dev->id);
|
||||
}
|
||||
|
||||
// full reset of chip
|
||||
tmp = 0x80;
|
||||
r = dev->hal_wr(dev->id, REG_PWR_MGMT_1, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
// TODO: better reset delay value
|
||||
dev->hal_sleep(1000);
|
||||
|
||||
// verify we are able to read from the chip
|
||||
r = dev->hal_rd(dev->id, REG_WHO_AM_I, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
if (REG_WHO_AM_I_CONST != tmp) {
|
||||
r = -1;
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
|
||||
// set clock to internal PLL
|
||||
tmp = 0x01;
|
||||
r = dev->hal_wr(dev->id, REG_PWR_MGMT_1, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
// place accel and gyro on standby
|
||||
tmp = 0x3F;
|
||||
r = dev->hal_wr(dev->id, REG_PWR_MGMT_2, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
// disable fifo
|
||||
tmp = 0x00;
|
||||
r = dev->hal_wr(dev->id, REG_USER_CTRL, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
if (dev->i2c_disable) {
|
||||
// disable chip I2C communications
|
||||
tmp = 0x40;
|
||||
r = dev->hal_wr(dev->id, REG_I2C_IF, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
|
||||
if (dev->use_accel) {
|
||||
if (ICM20602_ACCEL_DLPF_BYPASS_1046_HZ == dev->accel_dlpf) {
|
||||
tmp = (1 << 3);
|
||||
r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG_2, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
else {
|
||||
tmp = dev->accel_dlpf;
|
||||
r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG_2, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
|
||||
tmp = (dev->accel_g) << 2;
|
||||
r = dev->hal_wr(dev->id, REG_ACCEL_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
|
||||
if (dev->use_gyro) {
|
||||
if (ICM20602_GYRO_DLPF_BYPASS_3281_HZ == dev->gyro_dlpf) {
|
||||
// bypass dpf and set dps
|
||||
tmp = 0x00;
|
||||
r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
tmp = (dev->gyro_dps << 3) | 0x02; // see table page 37 of datasheet
|
||||
r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
else if (ICM20602_GYRO_DLPF_BYPASS_8173_HZ == dev->gyro_dlpf) {
|
||||
// bypass dpf and set dps
|
||||
tmp = 0x00;
|
||||
r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
tmp = (dev->gyro_dps << 3) | 0x01; // see table page 37 of datasheet
|
||||
r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
else {
|
||||
// configure dpf and set dps
|
||||
tmp = dev->gyro_dlpf;
|
||||
r = dev->hal_wr(dev->id, REG_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
tmp = dev->gyro_dps << 3;
|
||||
r = dev->hal_wr(dev->id, REG_GYRO_CONFIG, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
}
|
||||
}
|
||||
|
||||
// enable FIFO if requested
|
||||
tmp = ((dev->use_accel) && (dev->accel_fifo)) ? 0x08 : 0x00;
|
||||
tmp |= ((dev->use_gyro) && (dev->gyro_fifo)) ? 0x10 : 0x00;
|
||||
r = dev->hal_wr(dev->id, REG_FIFO_EN, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
// configure sample rate divider (TODO: is this gyro only?)
|
||||
// note: SAMPLE_RATE = INTERNAL_SAMPLE_RATE / (1 + SMPLRT_DIV)
|
||||
tmp = (0 != dev->sample_rate_div) ? dev->sample_rate_div - 1 : 1;
|
||||
r = dev->hal_wr(dev->id, REG_SMPLRT_DIV, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
tmp = 0;
|
||||
tmp |= (dev->use_gyro) ? 0 : 0x07; // 0 - on, 1 - disabled
|
||||
tmp |= (dev->use_accel) ? 0 : 0x38; // 0 - on, 1 - disabled
|
||||
r = dev->hal_wr(dev->id, REG_PWR_MGMT_2, &tmp, 1);
|
||||
ON_ERROR_GOTO((0 == r), return_err);
|
||||
|
||||
return_err:
|
||||
|
||||
if (dev->mutex_unlock) {
|
||||
dev->mutex_unlock(dev->id);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_accel(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z)
|
||||
{
|
||||
float accel_sensitivity;
|
||||
int16_t x, y, z;
|
||||
int8_t r = 0;
|
||||
|
||||
accel_sensitivity = _get_accel_sensitivity(dev->accel_g);
|
||||
|
||||
r = icm20602_read_accel_raw(dev, &x, &y, &z);
|
||||
if (0 == r) {
|
||||
*p_x = ((float) x) / accel_sensitivity;
|
||||
*p_y = ((float) y) / accel_sensitivity;
|
||||
*p_z = ((float) z) / accel_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_gyro(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z)
|
||||
{
|
||||
float gyro_sensitivity;
|
||||
int16_t x, y, z;
|
||||
int8_t r = 0;
|
||||
|
||||
gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps);
|
||||
|
||||
r = icm20602_read_gyro_raw(dev, &x, &y, &z);
|
||||
if (0 == r) {
|
||||
*p_x = ((float) x) / gyro_sensitivity;
|
||||
*p_y = ((float) y) / gyro_sensitivity;
|
||||
*p_z = ((float) z) / gyro_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_data(struct icm20602_dev * dev, float * p_ax, float * p_ay,
|
||||
float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t)
|
||||
{
|
||||
float accel_sensitivity;
|
||||
float gyro_sensitivity;
|
||||
int16_t ax, ay, az, gx, gy, gz, t;
|
||||
int8_t r = 0;
|
||||
|
||||
accel_sensitivity = _get_accel_sensitivity(dev->accel_g);
|
||||
gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps);
|
||||
|
||||
r = icm20602_read_data_raw(dev, &ax, &ay, &az, &gx, &gy, &gz, &t);
|
||||
if (0 == r) {
|
||||
*p_ax = ((float) ax) / accel_sensitivity;
|
||||
*p_ay = ((float) ay) / accel_sensitivity;
|
||||
*p_az = ((float) az) / accel_sensitivity;
|
||||
*p_gx = ((float) gx) / gyro_sensitivity;
|
||||
*p_gy = ((float) gy) / gyro_sensitivity;
|
||||
*p_gz = ((float) gz) / gyro_sensitivity;
|
||||
*p_t = ((float) t) / _temp_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_accel_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y,
|
||||
int16_t * p_z)
|
||||
{
|
||||
uint8_t buf[8] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_ACCEL_XOUT_H, buf, 8);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_x, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_y, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_z, buf[4], buf[5]);
|
||||
// buf[6] and buf[7] hold temperature
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_gyro_raw(struct icm20602_dev * dev, int16_t * p_x, int16_t * p_y,
|
||||
int16_t * p_z)
|
||||
{
|
||||
uint8_t buf[6] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_GYRO_XOUT_H, buf, 6);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_x, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_y, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_z, buf[4], buf[5]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_data_raw(struct icm20602_dev * dev, int16_t * p_ax,
|
||||
int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy,
|
||||
int16_t * p_gz, int16_t * p_t)
|
||||
{
|
||||
uint8_t buf[14] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_ACCEL_XOUT_H, buf, 14);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_ax, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_ay, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_az, buf[4], buf[5]);
|
||||
UINT8_TO_INT16(*p_t, buf[6], buf[7]);
|
||||
UINT8_TO_INT16(*p_gx, buf[8], buf[9]);
|
||||
UINT8_TO_INT16(*p_gy, buf[10], buf[11]);
|
||||
UINT8_TO_INT16(*p_gz, buf[12], buf[13]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_accel_fifo(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z)
|
||||
{
|
||||
float accel_sensitivity;
|
||||
int16_t x, y, z;
|
||||
int8_t r = 0;
|
||||
|
||||
accel_sensitivity = _get_accel_sensitivity(dev->accel_g);
|
||||
|
||||
r = icm20602_read_fifo_accel_raw(dev, &x, &y, &z);
|
||||
if (0 == r) {
|
||||
*p_x = ((float) x) / accel_sensitivity;
|
||||
*p_y = ((float) y) / accel_sensitivity;
|
||||
*p_z = ((float) z) / accel_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_gyro_fifo(struct icm20602_dev * dev, float * p_x, float * p_y,
|
||||
float * p_z)
|
||||
{
|
||||
float gyro_sensitivity;
|
||||
int16_t x, y, z;
|
||||
int8_t r = 0;
|
||||
|
||||
gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps);
|
||||
|
||||
r = icm20602_read_fifo_gyro_raw(dev, &x, &y, &z);
|
||||
if (0 == r) {
|
||||
*p_x = ((float) x) / gyro_sensitivity;
|
||||
*p_y = ((float) y) / gyro_sensitivity;
|
||||
*p_z = ((float) z) / gyro_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_fifo_data(struct icm20602_dev * dev, float * p_ax, float * p_ay,
|
||||
float * p_az, float * p_gx, float * p_gy, float * p_gz, float * p_t)
|
||||
{
|
||||
float accel_sensitivity;
|
||||
float gyro_sensitivity;
|
||||
int16_t ax, ay, az, gx, gy, gz, t;
|
||||
int8_t r = 0;
|
||||
|
||||
accel_sensitivity = _get_accel_sensitivity(dev->accel_g);
|
||||
gyro_sensitivity = _get_gyro_sensitivity(dev->gyro_dps);
|
||||
|
||||
r = icm20602_read_fifo_data_raw(dev, &ax, &ay, &az, &gx, &gy, &gz, &t);
|
||||
if (0 == r) {
|
||||
*p_ax = ((float) ax) / accel_sensitivity;
|
||||
*p_ay = ((float) ay) / accel_sensitivity;
|
||||
*p_az = ((float) az) / accel_sensitivity;
|
||||
*p_gx = ((float) gx) / gyro_sensitivity;
|
||||
*p_gy = ((float) gy) / gyro_sensitivity;
|
||||
*p_gz = ((float) gz) / gyro_sensitivity;
|
||||
*p_t = ((float) t) / _temp_sensitivity;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_fifo_accel_raw(struct icm20602_dev * dev, int16_t * p_x,
|
||||
int16_t * p_y, int16_t * p_z)
|
||||
{
|
||||
uint8_t buf[6] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_FIFO_R_W, buf, 6);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_x, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_y, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_z, buf[4], buf[5]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_fifo_gyro_raw(struct icm20602_dev * dev, int16_t * p_x,
|
||||
int16_t * p_y, int16_t * p_z)
|
||||
{
|
||||
uint8_t buf[6] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_FIFO_R_W, buf, 6);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_x, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_y, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_z, buf[4], buf[5]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int8_t
|
||||
icm20602_read_fifo_data_raw(struct icm20602_dev * dev, int16_t * p_ax,
|
||||
int16_t * p_ay, int16_t * p_az, int16_t * p_gx, int16_t * p_gy,
|
||||
int16_t * p_gz, int16_t * p_t)
|
||||
{
|
||||
uint8_t buf[14] = {0};
|
||||
int8_t r = 0;
|
||||
|
||||
r = _read_data(dev, REG_FIFO_R_W, buf, 14);
|
||||
if (0 == r) {
|
||||
UINT8_TO_INT16(*p_ax, buf[0], buf[1]);
|
||||
UINT8_TO_INT16(*p_ay, buf[2], buf[3]);
|
||||
UINT8_TO_INT16(*p_az, buf[4], buf[5]);
|
||||
UINT8_TO_INT16(*p_t, buf[6], buf[7]);
|
||||
UINT8_TO_INT16(*p_gx, buf[8], buf[9]);
|
||||
UINT8_TO_INT16(*p_gy, buf[10], buf[11]);
|
||||
UINT8_TO_INT16(*p_gz, buf[12], buf[13]);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
39
samd/include/README
Normal file
39
samd/include/README
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
64
samd/include/RgbDriver.h
Normal file
64
samd/include/RgbDriver.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* rgbDriver.h - Library for controlling the TI LT5024 RGB LED driver on the BSides Badge 2020
|
||||
* Reference: https://www.ti.com/lit/ds/symlink/lp5024.pdf
|
||||
* Created by Jordan Johnson, 23 February 2020
|
||||
*/
|
||||
|
||||
#ifndef RGB_DRIVER_H_
|
||||
#define RGB_DRIVER_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
class RgbDriver
|
||||
{
|
||||
public:
|
||||
// Set the slave address of the LP5024 driver
|
||||
RgbDriver(char address);
|
||||
// Set Chip_EN=0 to enter STANDBY mode
|
||||
int selectStandbyMode();
|
||||
// Set Chip_EN=1 to enter normal mode
|
||||
int selectNormalMode();
|
||||
// Reset the LP5024
|
||||
int reset();
|
||||
// Set the LP5024 configuration
|
||||
int setDeviceConfig(bool Log_Scale_EN,
|
||||
bool Power_Save_EN,
|
||||
bool Auto_Incr_EN,
|
||||
bool PWM_Dithering_EN,
|
||||
bool Max_Current_Option,
|
||||
bool LED_Global_Off);
|
||||
// Enable or disable individual LEDs
|
||||
int setLedConfig(bool LED7_Bank_EN,
|
||||
bool LED6_Bank_EN,
|
||||
bool LED5_Bank_EN,
|
||||
bool LED4_Bank_EN,
|
||||
bool LED3_Bank_EN,
|
||||
bool LED2_Bank_EN,
|
||||
bool LED1_Bank_EN,
|
||||
bool LED0_Bank_EN);
|
||||
// Set the brightness for all LEDs
|
||||
int setBankBrightness(char bank_brightness);
|
||||
// Set the colour for all LEDs
|
||||
int setBankColour(char red, char green, char blue);
|
||||
// Set the brightness for an individual LED
|
||||
int setLedBrightness(char led, char brightness);
|
||||
// Set the colour for an individual LED
|
||||
int setLedColour(char led, char red, char green, char blue);
|
||||
private:
|
||||
// Transmit data to the LP5025 via I2C
|
||||
int transmit(char addr, char data);
|
||||
|
||||
// Address registers
|
||||
const char DEVICE_CONFIG0 = 0x00;
|
||||
const char DEVICE_CONFIG1 = 0x01;
|
||||
const char LED_CONFIG0 = 0x02;
|
||||
const char BANK_BRIGHTNESS = 0x03;
|
||||
const char BANK_A_COLOR = 0x04;
|
||||
const char BANK_B_COLOR = 0x05;
|
||||
const char BANK_C_COLOR = 0x06;
|
||||
const char RESET = 0x027;
|
||||
// The address of the LP5024
|
||||
char slaveAddress;
|
||||
};
|
||||
|
||||
#endif // RGB_DRIVER_H_
|
46
samd/lib/README
Normal file
46
samd/lib/README
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
19
samd/platformio.ini
Normal file
19
samd/platformio.ini
Normal file
|
@ -0,0 +1,19 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:samd21g18a]
|
||||
platform = atmelsam
|
||||
board = samd21g18a
|
||||
framework = arduino
|
||||
|
||||
[env:mkrzero]
|
||||
platform = atmelsam
|
||||
board = mkrzero
|
||||
framework = arduino
|
127
samd/src/RgbDriver.cpp
Normal file
127
samd/src/RgbDriver.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* rgbDriver.h - Library for controlling the TI LT5024 RGB LED driver on the BSides Badge 2020
|
||||
* Reference: https://www.ti.com/lit/ds/symlink/lp5024.pdf
|
||||
* Created by Jordan Johnson, 23 February 2020
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
#include "RgbDriver.h"
|
||||
|
||||
// Set the slave address of the LP5024 driver
|
||||
RgbDriver::RgbDriver(char address)
|
||||
{
|
||||
slaveAddress = address;
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
|
||||
// Set Chip_EN=0 to enter STANDBY mode
|
||||
int RgbDriver::selectStandbyMode() {
|
||||
return transmit(DEVICE_CONFIG0, 0x00);
|
||||
}
|
||||
|
||||
// Set Chip_EN=1 to enter normal mode
|
||||
int RgbDriver::selectNormalMode() {
|
||||
Wire.begin();
|
||||
return transmit(DEVICE_CONFIG0, 0x40);
|
||||
}
|
||||
|
||||
// Reset the LP5024
|
||||
int RgbDriver::reset() {
|
||||
int status = transmit(RESET, 0xFF);
|
||||
if (status == 0) {
|
||||
status = transmit(RESET, 0x00);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Set the LP5024 configuration
|
||||
int RgbDriver::setDeviceConfig(bool Log_Scale_EN,
|
||||
bool Power_Save_EN,
|
||||
bool Auto_Incr_EN,
|
||||
bool PWM_Dithering_EN,
|
||||
bool Max_Current_Option,
|
||||
bool LED_Global_Off) {
|
||||
char config = Log_Scale_EN * 32 +
|
||||
Power_Save_EN * 16 +
|
||||
Auto_Incr_EN * 8 +
|
||||
PWM_Dithering_EN * 4 +
|
||||
Max_Current_Option * 2 +
|
||||
LED_Global_Off;
|
||||
return transmit(DEVICE_CONFIG1, config);
|
||||
}
|
||||
|
||||
// Enable or disable individual LEDs
|
||||
int RgbDriver::setLedConfig(bool LED7_Bank_EN,
|
||||
bool LED6_Bank_EN,
|
||||
bool LED5_Bank_EN,
|
||||
bool LED4_Bank_EN,
|
||||
bool LED3_Bank_EN,
|
||||
bool LED2_Bank_EN,
|
||||
bool LED1_Bank_EN,
|
||||
bool LED0_Bank_EN) {
|
||||
char config = LED7_Bank_EN * 128 +
|
||||
LED6_Bank_EN * 64 +
|
||||
LED5_Bank_EN * 32 +
|
||||
LED4_Bank_EN * 16 +
|
||||
LED3_Bank_EN * 8 +
|
||||
LED2_Bank_EN * 4 +
|
||||
LED1_Bank_EN * 2 +
|
||||
LED0_Bank_EN;
|
||||
return transmit(LED_CONFIG0, config);
|
||||
}
|
||||
|
||||
// Set the brightness for all LEDs
|
||||
int RgbDriver::setBankBrightness(char bank_brightness) {
|
||||
return transmit(BANK_BRIGHTNESS, bank_brightness);
|
||||
}
|
||||
|
||||
// Set the colour for all LEDs
|
||||
int RgbDriver::setBankColour(char red, char green, char blue) {
|
||||
// RED
|
||||
int status = transmit(BANK_A_COLOR, red);
|
||||
// GREEN
|
||||
if (status == 0) {
|
||||
transmit(BANK_B_COLOR, green);
|
||||
}
|
||||
// BLUE
|
||||
if (status == 0) {
|
||||
transmit(BANK_C_COLOR, blue);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Set the brightness for an individual LED
|
||||
int RgbDriver::setLedBrightness(char led, char brightness) {
|
||||
char addr = led + 0x07;
|
||||
return transmit(addr, brightness);
|
||||
}
|
||||
|
||||
// Set the colour for an individual LED
|
||||
int RgbDriver::setLedColour(char led, char red, char green, char blue) {
|
||||
char redAddr = led * 3 + 0x0F;
|
||||
char greenAddr = led * 3 + 0x10;
|
||||
char blueAddr = led * 3 + 0x11;
|
||||
// RED
|
||||
int status = transmit(redAddr, red);
|
||||
// GREEN
|
||||
if (status == 0) {
|
||||
transmit(greenAddr, green);
|
||||
}
|
||||
// BLUE
|
||||
if (status == 0) {
|
||||
transmit(blueAddr, blue);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Private Methods
|
||||
|
||||
// Transmit data to the LP5025 via I2C
|
||||
int RgbDriver::transmit(char addr, char data) {
|
||||
Wire.beginTransmission(slaveAddress);
|
||||
Wire.write(addr);
|
||||
Wire.write(data);
|
||||
return Wire.endTransmission();
|
||||
}
|
95
samd/src/main.cpp
Normal file
95
samd/src/main.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include <Arduino.h>
|
||||
#include "RgbDriver.h"
|
||||
|
||||
RgbDriver rgbDriver(0b0101000);
|
||||
|
||||
int mapLEDIndex(int idx) {
|
||||
switch(idx) {
|
||||
case 0: return 1;
|
||||
case 1: return 0;
|
||||
case 2: return 7;
|
||||
case 3: return 6;
|
||||
case 4: return 5;
|
||||
case 5: return 4;
|
||||
case 6: return 3;
|
||||
case 7: return 2;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int r = 255;
|
||||
int g = 0;
|
||||
int b = 200;
|
||||
|
||||
|
||||
void setup() {
|
||||
int idx;
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
delay(5000);
|
||||
|
||||
Serial.println("Starting up!");
|
||||
rgbDriver.selectNormalMode();
|
||||
rgbDriver.setDeviceConfig(true, true, true, true, false, false);
|
||||
rgbDriver.setLedConfig(false, false, false, false, false, false, false, false);
|
||||
|
||||
Serial.println("Lighting LEDS");
|
||||
|
||||
for (int i = 0; i< 8; i++) {
|
||||
idx = mapLEDIndex(i);
|
||||
rgbDriver.setLedBrightness(idx, 0x1f);
|
||||
rgbDriver.setLedColour(idx, r, g, b);
|
||||
delay(500);
|
||||
}
|
||||
Serial.println("LEDS Lit!");
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
int idx;
|
||||
if (Serial.available()) {
|
||||
char ch = Serial.read();
|
||||
switch (ch) {
|
||||
case 'r':
|
||||
r += 10;
|
||||
if (r > 255) {r = 255;}
|
||||
case 'R':
|
||||
r -= 10;
|
||||
if (r < 0) {r=0;}
|
||||
case 'g':
|
||||
g += 10;
|
||||
if (g > 255) {g = 255;}
|
||||
case 'G':
|
||||
g -= 10;
|
||||
if (g < 0) {g=0;}
|
||||
case 'b':
|
||||
b += 10;
|
||||
if (b > 255) {b = 255;}
|
||||
case 'B':
|
||||
b -= 10;
|
||||
if (b < 0) {b=0;}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.print("R: "); Serial.print(r);
|
||||
Serial.print(" B: "); Serial.print(g);
|
||||
Serial.print(" G: "); Serial.println(b);
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i<8; i++) {
|
||||
idx = mapLEDIndex(i);
|
||||
rgbDriver.setLedBrightness(idx, 0x1f);
|
||||
rgbDriver.setLedColour(idx, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
11
samd/test/README
Normal file
11
samd/test/README
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Reference in a new issue