/*
* Sport Kit Companion v1.0
* Author: Nghia Nguyen
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include "fsl_debug_console.h"
#include "board.h"
#include "fsl_adc16.h"
#include "fsl_i2c.h"
#include "pin_mux.h"
#include "clock_config.h"
/*******************************************************************************
* Definitions
******************************************************************************/
//========== ADC =================================================================
#define DEMO_ADC16_BASE ADC0
#define DEMO_ADC16_CHANNEL_GROUP 0U
#define ADC_CH0 8U //
#define ADC_CH1 9U // Light sensor
#define ADC_CH2 15U
//#define ADC_CH3 4U
//========== I2C =================================================================
#define ACCEL_I2C_CLK_SRC I2C3_CLK_SRC
#define I2C_BAUDRATE 400000U
#define FXOS8700_WHOAMI 0xC7U
#define MMA8451_WHOAMI 0x1AU
#define ACCEL_STATUS 0x00U
#define ACCEL_XYZ_DATA_CFG 0x0EU
#define ACCEL_CTRL_REG1 0x2AU
/* FXOS8700 and MMA8451 have the same who_am_i register address. */
#define ACCEL_WHOAMI_REG 0x0DU
#define ACCEL_READ_TIMES 2
/*
* @ ADC0 Channels (SE0-31)
* 23: DAC0_OUT
* 8: PTB0 - Arduino A0
* 9: PTB1 - Arduino A1
* 15:PTC1 - Arduino A2
* 4b:PTC2 - Arduino A3
* 12:PTB2
* 13: PTB3
*
* @ Resolution: 12bits
*
*/
/*******************************************************************************
* Prototypes
******************************************************************************/
void delayms(uint16_t milisecs);
static bool I2C_ReadAccelWhoAmI(void);
static bool I2C_initLidar(void);
static bool I2C_WriteAccelReg(I2C_Type *base, uint8_t device_addr, uint8_t reg_addr, uint8_t value);
static bool I2C_ReadAccelRegs(I2C_Type *base, uint8_t device_addr, uint8_t reg_addr, uint8_t *rxBuff, uint32_t rxSize);
/*******************************************************************************
* Variables
******************************************************************************/
uint16_t adc_raw;
uint16_t count=0;
uint16_t distance;
uint8_t lidar_buff[2];
/* FXOS8700 and MMA8451 device address */
const uint8_t g_accel_address[] = {0x1CU, 0x1DU, 0x1EU, 0x1FU};
/* Lidar lite device address: 0x62 */
const uint8_t lidar_address = 0x62U;
i2c_master_handle_t g_m_handle;
uint8_t g_accel_addr_found = 0x00;
volatile bool completionFlag = false;
volatile bool nakFlag = false;
/*******************************************************************************
* Code
******************************************************************************/
void delayms(uint16_t milisecs)
{
// 8000000 ~= 1sec
volatile uint32_t i = 0;
for (i = 0; i < milisecs*8000; ++i)
{
__asm("NOP"); /* delay */
}
}
static void i2c_master_callback(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData)
{
/* Signal transfer success when received success status. */
if (status == kStatus_Success)
{
completionFlag = true;
}
/* Signal transfer success when received success status. */
if (status == kStatus_I2C_Nak)
{
nakFlag = true;
}
}
static bool I2C_ReadAccelWhoAmI(void)
{
/*
How to read the device who_am_I value ?
Start + Device_address_Write , who_am_I_register;
Repeart_Start + Device_address_Read , who_am_I_value.
*/
uint8_t who_am_i_reg = ACCEL_WHOAMI_REG;
uint8_t who_am_i_value = 0x00;
uint8_t accel_addr_array_size = 0x00;
bool find_device = false;
uint8_t i = 0;
uint32_t sourceClock = 0;
i2c_master_config_t masterConfig;
/*
* masterConfig.baudRate_Bps = 100000U;
* masterConfig.enableHighDrive = false;
* masterConfig.enableStopHold = false;
* masterConfig.glitchFilterWidth = 0U;
* masterConfig.enableMaster = true;
*/
I2C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Bps = I2C_BAUDRATE;
sourceClock = CLOCK_GetFreq(ACCEL_I2C_CLK_SRC);
I2C_MasterInit(BOARD_ACCEL_I2C_BASEADDR, &masterConfig, sourceClock);
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = g_accel_address[0];
masterXfer.direction = kI2C_Write;
masterXfer.subaddress = 0;
masterXfer.subaddressSize = 0;
masterXfer.data = &who_am_i_reg;
masterXfer.dataSize = 1;
masterXfer.flags = kI2C_TransferNoStopFlag;
accel_addr_array_size = sizeof(g_accel_address) / sizeof(g_accel_address[0]);
for (i = 0; i < accel_addr_array_size; i++)
{
masterXfer.slaveAddress = g_accel_address[i];
I2C_MasterTransferNonBlocking(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, &masterXfer);
/* wait for transfer completed. */
while ((!nakFlag) && (!completionFlag))
{
}
nakFlag = false;
if (completionFlag == true)
{
completionFlag = false;
find_device = true;
g_accel_addr_found = masterXfer.slaveAddress;
break;
}
}
if (find_device == true)
{
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = 0;
masterXfer.subaddressSize = 0;
masterXfer.data = &who_am_i_value;
masterXfer.dataSize = 1;
masterXfer.flags = kI2C_TransferRepeatedStartFlag;
I2C_MasterTransferNonBlocking(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, &masterXfer);
/* wait for transfer completed. */
while ((!nakFlag) && (!completionFlag))
{
}
nakFlag = false;
if (completionFlag == true)
{
completionFlag = false;
return true;
}
else
{
PRINTF("Not a successful i2c communication \r\n");
}
}
return false;
}
static bool I2C_initLidar(void)
{
uint32_t sourceClock = 0;
i2c_master_config_t masterConfig;
/*
* masterConfig.baudRate_Bps = 100000U;
* masterConfig.enableHighDrive = false;
* masterConfig.enableStopHold = false;
* masterConfig.glitchFilterWidth = 0U;
* masterConfig.enableMaster = true;
*/
I2C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Bps = I2C_BAUDRATE;
sourceClock = CLOCK_GetFreq(ACCEL_I2C_CLK_SRC);
I2C_MasterInit(BOARD_ACCEL_I2C_BASEADDR, &masterConfig, sourceClock);
return true;
}
static bool I2C_WriteAccelReg(I2C_Type *base, uint8_t device_addr, uint8_t reg_addr, uint8_t value)
{
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = device_addr;
masterXfer.direction = kI2C_Write;
masterXfer.subaddress = reg_addr;
masterXfer.subaddressSize = 1;
masterXfer.data = &value;
masterXfer.dataSize = 1;
masterXfer.flags = kI2C_TransferDefaultFlag;
/* direction=write : start+device_write;cmdbuff;xBuff; */
/* direction=recive : start+device_write;cmdbuff;repeatStart+device_read;xBuff; */
I2C_MasterTransferNonBlocking(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, &masterXfer);
/* wait for transfer completed. */
while ((!nakFlag) && (!completionFlag))
{
}
nakFlag = false;
if (completionFlag == true)
{
completionFlag = false;
return true;
}
else
{
return false;
}
}
static bool I2C_ReadAccelRegs(I2C_Type *base, uint8_t device_addr, uint8_t reg_addr, uint8_t *rxBuff, uint32_t rxSize)
{
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = device_addr;
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = reg_addr;
masterXfer.subaddressSize = 1;
masterXfer.data = rxBuff;
masterXfer.dataSize = rxSize;
masterXfer.flags = kI2C_TransferDefaultFlag;
/* direction=write : start+device_write;cmdbuff;xBuff; */
/* direction=recive : start+device_write;cmdbuff;repeatStart+device_read;xBuff; */
I2C_MasterTransferNonBlocking(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, &masterXfer);
/* wait for transfer completed. */
while ((!nakFlag) && (!completionFlag))
{
}
nakFlag = false;
if (completionFlag == true)
{
completionFlag = false;
return true;
}
else
{
return false;
}
}
/*!
* @brief Main function
*/
int main(void)
{
adc16_config_t adc16ConfigStruct;
adc16_channel_config_t adc16ChannelConfigStruct;
bool isThereAccel = false;
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("\r\nFreedom Sport Companion Demonstration:\r\n");
PRINTF("- Read sound sensor to detect motion\r\n");
PRINTF("- Use Lidar Lite to measure distance\r\n");
PRINTF("- Monitor Heartbeat \r\n");
/*
* adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
* adc16ConfigStruct.clockSource = kADC16_ClockSourceAsynchronousClock;
* adc16ConfigStruct.enableAsynchronousClock = true;
* adc16ConfigStruct.clockDivider = kADC16_ClockDivider8;
* adc16ConfigStruct.resolution = kADC16_ResolutionSE12Bit;
* adc16ConfigStruct.longSampleMode = kADC16_LongSampleDisabled;
* adc16ConfigStruct.enableHighSpeed = false;
* adc16ConfigStruct.enableLowPower = false;
* adc16ConfigStruct.enableContinuousConversion = false;
*/
ADC16_GetDefaultConfig(&adc16ConfigStruct);
ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE, false); /* Make sure the software trigger is used. */
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE))
{
PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
}
else
{
PRINTF("ADC16_DoAutoCalibration() Failed.\r\n");
}
#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
PRINTF("Press any key to get user channel's ADC value ...\r\n");
adc16ChannelConfigStruct.channelNumber = ADC_CH0;
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
adc16ChannelConfigStruct.enableDifferentialConversion = false;
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
GETCHAR();
while (1)
{
I2C_MasterTransferCreateHandle(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, i2c_master_callback, NULL);
isThereAccel = I2C_ReadAccelWhoAmI();
/* read the accel xyz value if there is accel device on board */
if (true == isThereAccel)
{
uint8_t databyte = 0;
uint8_t write_reg = 0;
uint8_t readBuff[7];
int16_t x, y, z;
uint8_t status0_value = 0;
uint32_t i = 0U;
/* please refer to the "example FXOS8700CQ Driver Code" in FXOS8700 datasheet. */
/* write 0000 0000 = 0x00 to accelerometer control register 1 */
/* standby */
/* [7-1] = 0000 000 */
/* [0]: active=0 */
write_reg = ACCEL_CTRL_REG1;
databyte = 0;
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, g_accel_addr_found, write_reg, databyte);
/* write 0000 0001= 0x01 to XYZ_DATA_CFG register */
/* [7]: reserved */
/* [6]: reserved */
/* [5]: reserved */
/* [4]: hpf_out=0 */
/* [3]: reserved */
/* [2]: reserved */
/* [1-0]: fs=01 for accelerometer range of +/-4g range with 0.488mg/LSB */
/* databyte = 0x01; */
write_reg = ACCEL_XYZ_DATA_CFG;
databyte = 0x01;
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, g_accel_addr_found, write_reg, databyte);
/* write 0000 1101 = 0x0D to accelerometer control register 1 */
/* [7-6]: aslp_rate=00 */
/* [5-3]: dr=001 for 200Hz data rate (when in hybrid mode) */
/* [2]: lnoise=1 for low noise mode */
/* [1]: f_read=0 for normal 16 bit reads */
/* [0]: active=1 to take the part out of standby and enable sampling */
/* databyte = 0x0D; */
write_reg = ACCEL_CTRL_REG1;
databyte = 0x0d;
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, g_accel_addr_found, write_reg, databyte);
for (i = 0; i < ACCEL_READ_TIMES; i++)
{
status0_value = 0;
/* wait for new data are ready. */
while (status0_value != 0xff)
{
I2C_ReadAccelRegs(BOARD_ACCEL_I2C_BASEADDR, g_accel_addr_found, ACCEL_STATUS, &status0_value, 1);
}
/* Multiple-byte Read from STATUS (0x00) register */
I2C_ReadAccelRegs(BOARD_ACCEL_I2C_BASEADDR, g_accel_addr_found, ACCEL_STATUS, readBuff, 7);
status0_value = readBuff[0];
x = ((int16_t)(((readBuff[1] * 256U) | readBuff[2]))) / 4U;
y = ((int16_t)(((readBuff[3] * 256U) | readBuff[4]))) / 4U;
z = ((int16_t)(((readBuff[5] * 256U) | readBuff[6]))) / 4U;
PRINTF("I2C: x = %5d , y = %5d , z = %5d \r\n", x, y, z);
}
}
/*
* read Lidar lite
*/
I2C_initLidar();
// I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x00, 0x04);
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x45, 0xC8); //10Hz
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x04, 0x21);
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x11, 0xFF); //continuos
I2C_WriteAccelReg(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x00, 0x04); //start
delayms(500);
/* Multiple-byte Read from distance register */
I2C_ReadAccelRegs(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x8f, lidar_buff, 2);
// I2C_ReadAccelRegs(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x0f, &lidar_buff[0], 1);
// I2C_ReadAccelRegs(BOARD_ACCEL_I2C_BASEADDR, lidar_address, 0x10, &lidar_buff[1], 1);
distance = (lidar_buff[0] << 8) + lidar_buff[1];
PRINTF("distance: %4d \r\n",lidar_buff[0],lidar_buff[1],distance);
/*
When in software trigger mode, each conversion would be launched once calling the "ADC16_ChannelConfigure()"
function, which works like writing a conversion command and executing it. For another channel's conversion,
just to change the "channelNumber" field in channel's configuration structure, and call the
"ADC16_ChannelConfigure() again.
*/
/*
* Get ADC value and print counter in console
*/
// CH0: potentiometer
adc16ChannelConfigStruct.channelNumber = ADC_CH0;
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{}
adc_raw = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
if(adc_raw > 40000){
count++;
PRINTF("Counter: %d\r\n",count);
delayms(200);
// Clear counter
if(count == 20)
count=0;
}
else{
PRINTF("ADCval0: %4d ",adc_raw);
}
// CH1: sound sensor
adc16ChannelConfigStruct.channelNumber = ADC_CH1;
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{}
adc_raw = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
PRINTF("ADCval1: %4d ",adc_raw);
// CH2: light sensor
adc16ChannelConfigStruct.channelNumber = ADC_CH2;
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
{}
adc_raw = ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
PRINTF("ADCval2: %4d\r\n",adc_raw);
delayms(50);
}
}
Comments