From 1ce5e9386aca99aa4d351233af095bbcb4114b1d Mon Sep 17 00:00:00 2001 From: IOsetting Date: Mon, 17 Jan 2022 00:55:12 +0800 Subject: [PATCH] feat: adxl345 demo (4-wire spi) --- demo/spi/adxl345/adxl345.c | 80 +++++++++++++++++ demo/spi/adxl345/adxl345.h | 176 +++++++++++++++++++++++++++++++++++++ demo/spi/adxl345/main.c | 129 +++++++++++++++++++++++++++ src/fw_uart.c | 7 ++ 4 files changed, 392 insertions(+) create mode 100644 demo/spi/adxl345/adxl345.c create mode 100644 demo/spi/adxl345/adxl345.h create mode 100644 demo/spi/adxl345/main.c diff --git a/demo/spi/adxl345/adxl345.c b/demo/spi/adxl345/adxl345.c new file mode 100644 index 0000000..0989610 --- /dev/null +++ b/demo/spi/adxl345/adxl345.c @@ -0,0 +1,80 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include "adxl345.h" + +uint8_t xbuf[2]; + +uint8_t ADXL345_ReadByte(uint8_t addr) +{ + ADXL345_CS = 0; + xbuf[0] = addr | 0x80; + xbuf[1] = 0xFF; + SPI_TxRxBytes(xbuf, 2); + ADXL345_CS = 1; + return xbuf[1]; +} + +void ADXL345_WriteByte(uint8_t addr, uint8_t dat) +{ + ADXL345_CS = 0; + xbuf[0] = addr; + xbuf[1] = dat; + SPI_TxRxBytes(xbuf, 2); + ADXL345_CS = 1; +} + +HAL_StatusTypeDef ADXL345_Init( + ADXL345_DataRate_t dataRate, + ADXL345_SPI_Wire_t spiWire, + ADXL345_IntActive_t intLevel, + ADXL345_DataResolve_t resolve, + ADXL345_DataAlignment_t alignment, + ADXL345_G_Range_t range) +{ + if (ADXL345_ReadByte(ADXL345_REG_DEVID) == ADXL345_DEVICE_ID) + { + ADXL345_WriteByte(ADXL345_REG_BW_RATE, dataRate); + ADXL345_WriteByte(ADXL345_REG_DATA_FORMAT, + spiWire|intLevel|resolve|alignment|range); + ADXL345_WriteByte(ADXL345_REG_POWER_CTL, 0x08); // BIT3=0/1:(测量模式/待机模式);BIT2=0/1:(工作/休眠); + return HAL_OK; + } + else + { + return HAL_ERROR; + } +} + +void ADXL345_SetInterrupts(uint8_t interrupts) +{ + ADXL345_WriteByte(ADXL345_REG_INT_ENABLE, interrupts); +} + +void ADXL345_RemapInterrupts(uint8_t interrupts) +{ + ADXL345_WriteByte(ADXL345_REG_INT_MAP, interrupts); +} + +uint8_t ADXL345_IsInterrupt(uint8_t interrupt) +{ + uint8_t int_src = ADXL345_ReadByte(ADXL345_REG_INT_SOURCE); + return (int_src & interrupt); +} + +void ADXL345_EnableTapDetectOnAxes(uint8_t axes) +{ + ADXL345_WriteByte(ADXL345_REG_TAP_AXES, axes); +} \ No newline at end of file diff --git a/demo/spi/adxl345/adxl345.h b/demo/spi/adxl345/adxl345.h new file mode 100644 index 0000000..5f43edd --- /dev/null +++ b/demo/spi/adxl345/adxl345.h @@ -0,0 +1,176 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __FW_ADXL345__ +#define __FW_ADXL345__ + +#include "fw_hal.h" + +#define ADXL345_CS P35 +#define ADXL345_MOSI P34 +#define ADXL345_MISO P33 +#define ADXL345_SCK P32 +#define ADXL345_INT1 P36 +#define ADXL345_INT2 P37 + +#define ADXL345_DEFAULT_ADDRESS (0x53) // Assumes ALT address pin low +#define ADXL345_DEVICE_ID (0xE5) + +#define ADXL345_REG_DEVID (0x00) // R, Device ID +#define ADXL345_REG_THRESH_TAP (0x1D) // R/W, Tap threshold +#define ADXL345_REG_OFSX (0x1E) // R/W, X-axis offset +#define ADXL345_REG_OFSY (0x1F) // R/W, Y-axis offset +#define ADXL345_REG_OFSZ (0x20) // R/W, Z-axis offset +#define ADXL345_REG_DUR (0x21) // R/W, Tap duration +#define ADXL345_REG_LATENT (0x22) // R/W, Tap latency +#define ADXL345_REG_WINDOW (0x23) // R/W, Tap window +#define ADXL345_REG_THRESH_ACT (0x24) // R/W, Activity threshold +#define ADXL345_REG_THRESH_INACT (0x25) // R/W, Inactivity threshold +#define ADXL345_REG_TIME_INACT (0x26) // R/W, Inactivity time +#define ADXL345_REG_ACT_INACT_CTL (0x27) // R/W, Axis enable control for activity and inactivity detection +#define ADXL345_REG_THRESH_FF (0x28) // R/W, Free-fall threshold +#define ADXL345_REG_TIME_FF (0x29) // R/W, Free-fall time +#define ADXL345_REG_TAP_AXES (0x2A) // R/W, Axis control for single/double tap +#define ADXL345_REG_ACT_TAP_STATUS (0x2B) // R, Source for single/double tap +#define ADXL345_REG_BW_RATE (0x2C) // R/W, Data rate and power mode control +#define ADXL345_REG_POWER_CTL (0x2D) // R/W, Power-saving features control +#define ADXL345_REG_INT_ENABLE (0x2E) // R/W, Interrupt enable control +#define ADXL345_REG_INT_MAP (0x2F) // R/W, Interrupt mapping control +#define ADXL345_REG_INT_SOURCE (0x30) // R, Source of interrupts +#define ADXL345_REG_DATA_FORMAT (0x31) // R/W, Data format control +#define ADXL345_REG_DATAX0 (0x32) // R, X-axis data 0 +#define ADXL345_REG_DATAX1 (0x33) // R, X-axis data 1 +#define ADXL345_REG_DATAY0 (0x34) // R, Y-axis data 0 +#define ADXL345_REG_DATAY1 (0x35) // R, Y-axis data 1 +#define ADXL345_REG_DATAZ0 (0x36) // R, Z-axis data 0 +#define ADXL345_REG_DATAZ1 (0x37) // R, Z-axis data 1 +#define ADXL345_REG_FIFO_CTL (0x38) // R/W, FIFO control +#define ADXL345_REG_FIFO_STATUS (0x39) // R, FIFO status + +#define ADXL345_MG2G_MULTIPLIER (0.004) // 4mg per lsb + +/** + * Interrupt bits +*/ +#define ADXL345_INT_DATA_READY (0x80) +#define ADXL345_INT_SINGLE_TAP (0x40) +#define ADXL345_INT_DOUBLE_TAP (0x20) +#define ADXL345_INT_ACTIVITY (0x10) +#define ADXL345_INT_INACTIVITY (0x08) +#define ADXL345_INT_FREE_FALL (0x04) +#define ADXL345_INT_WATERMARK (0x02) +#define ADXL345_INT_OVERRUN (0x01) + +#define ADXL345_TAP_DETECT_AXIS_Z (0x01) +#define ADXL345_TAP_DETECT_AXIS_Y (0x02) +#define ADXL345_TAP_DETECT_AXIS_X (0x04) + +/** + * @brief Used with register 0x2C (ADXL345_REG_BW_RATE) to set bandwidth +*/ +typedef enum { + ADXL345_DATARATE_3200_HZ = 0x0F, // 1600Hz Bandwidth + ADXL345_DATARATE_1600_HZ = 0x0E, // 800Hz Bandwidth + ADXL345_DATARATE_800_HZ = 0x0D, // 400Hz Bandwidth + ADXL345_DATARATE_400_HZ = 0x0C, // 200Hz Bandwidth + ADXL345_DATARATE_200_HZ = 0x0B, // 100Hz Bandwidth + ADXL345_DATARATE_100_HZ = 0x0A, // 50Hz Bandwidth (default) + ADXL345_DATARATE_50_HZ = 0x09, // 25Hz Bandwidth + ADXL345_DATARATE_25_HZ = 0x08, // 12.5Hz Bandwidth + ADXL345_DATARATE_12_5_HZ = 0x07, // 6.25Hz Bandwidth + ADXL345_DATARATE_6_25HZ = 0x06, // 3.13Hz Bandwidth + ADXL345_DATARATE_3_13_HZ = 0x05, // 1.56Hz Bandwidth + ADXL345_DATARATE_1_56_HZ = 0x04, // 0.78Hz Bandwidth + ADXL345_DATARATE_0_78_HZ = 0x03, // 0.39Hz Bandwidth + ADXL345_DATARATE_0_39_HZ = 0x02, // 0.20Hz Bandwidth + ADXL345_DATARATE_0_20_HZ = 0x01, // 0.10Hz Bandwidth + ADXL345_DATARATE_0_10_HZ = 0x00, // 0.05Hz Bandwidth +} ADXL345_DataRate_t; + + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set SPI wires + */ +typedef enum { + ADXL345_SELF_TEST_OFF = 0x00, + ADXL345_SELF_TEST_ON = 0x80, +} ADXL345_SelfTest_t; + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set SPI wires + */ +typedef enum { + ADXL345_SPI_WIRE_4 = 0x00, + ADXL345_SPI_WIRE_3 = 0x40, +} ADXL345_SPI_Wire_t; + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set interrupt active level + */ +typedef enum { + ADXL345_INT_ACTIVE_HIGH = 0x00, + ADXL345_INT_ACTIVE_LOW = 0x20, +} ADXL345_IntActive_t; + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set resolution mode + */ +typedef enum { + ADXL345_DATA_RESOLVE_10BIT = 0x00, + ADXL345_DATA_RESOLVE_FULL = 0x08, +} ADXL345_DataResolve_t; + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set data alignment + */ +typedef enum { + ADXL345_DATA_ALIGNMENT_RIGHT = 0x00, + ADXL345_DATA_ALIGNMENT_LEFT = 0x04, +} ADXL345_DataAlignment_t; + +/** + * @brief Used with register ADXL345_REG_DATA_FORMAT to set g range + */ +typedef enum { + ADXL345_G_RANGE_2G = 0x00, // +/- 2g (default) + ADXL345_G_RANGE_4G = 0x01, // +/- 4g + ADXL345_G_RANGE_8G = 0x02, // +/- 8g + ADXL345_G_RANGE_16G = 0x03, // +/- 16g +} ADXL345_G_Range_t; + +uint8_t ADXL345_ReadByte(uint8_t addr); + +void ADXL345_WriteByte(uint8_t addr, uint8_t dat); + +HAL_StatusTypeDef ADXL345_Init( + ADXL345_DataRate_t dataRate, + ADXL345_SPI_Wire_t spiWire, + ADXL345_IntActive_t intLevel, + ADXL345_DataResolve_t resolve, + ADXL345_DataAlignment_t alignment, + ADXL345_G_Range_t range); +/** + * Enable interrupts +*/ +void ADXL345_SetInterrupts(uint8_t interrupts); +/** + * Remap interrupts to INT2 (default is INT1) +*/ +void ADXL345_RemapInterrupts(uint8_t interrupts); + +uint8_t ADXL345_IsInterrupt(uint8_t interrupt); + +void ADXL345_EnableTapDetectOnAxes(uint8_t axes); + +#endif // __FW_ADXL345__ diff --git a/demo/spi/adxl345/main.c b/demo/spi/adxl345/main.c new file mode 100644 index 0000000..97c56ce --- /dev/null +++ b/demo/spi/adxl345/main.c @@ -0,0 +1,129 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*** + * Demo: ADXL345 + * Board: STC8H8K64U + * 8H8K64U + * GND -> GND G + * VDD(Vcc) -> VCC V + * CS -> GPIO OUT P35 34 + * INT1 -> GPIO IN P36 INT2 35 + * INT2 -> GPIO IN P37 INT3 36 + * SDO -> MISO P33 30 + * SDI/SDA -> MOSI P34 31 + * SCL -> SCLK P32 29 + */ + +#include "fw_hal.h" +#include "adxl345.h" +#include + +uint8_t buf[6], count_int2 = 0, count_int3 = 0, count_double_tap = 0; + +void SPI_Init(void) +{ + // ADXL345, SPI CLK max frequency is 5MHz + SPI_SetClockPrescaler(SPI_ClockPreScaler_16); + // Clock is high when idle + SPI_SetClockPolarity(HAL_State_ON); + // Data transfer is driven by lower SS pin + SPI_SetClockPhase(SPI_ClockPhase_TrailingEdge); + // MSB first + SPI_SetDataOrder(SPI_DataOrder_MSB); + // Define the output pins + SPI_SetPort(SPI_AlterPort_P35_P34_P33_P32); + // Ignore SS pin, use MSTR to swith between master/slave mode + SPI_IgnoreSlaveSelect(HAL_State_ON); + // Master mode + SPI_SetMasterMode(HAL_State_ON); + // Start SPI + SPI_SetEnabled(HAL_State_ON); +} + +void GPIO_Init(void) +{ + // Configure GPIO pins before SPI and device + // MISO(P33), MOSI(P34) + GPIO_P3_SetMode(GPIO_Pin_3|GPIO_Pin_4, GPIO_Mode_InOut_QBD); + // SCLK(P32), CS(P35), + GPIO_P3_SetMode(GPIO_Pin_2|GPIO_Pin_5, GPIO_Mode_Output_PP); + // INT2(P36), INT3(P37) + GPIO_P3_SetMode(GPIO_Pin_6|GPIO_Pin_7, GPIO_Mode_Input_HIP); +} + +void INT_Init() +{ + EXTI_Int2_SetIntState(HAL_State_ON); + EXTI_Int3_SetIntState(HAL_State_ON); + EXTI_Global_SetIntState(HAL_State_ON); +} + +INTERRUPT(Int2_Routine, EXTI_VectInt2) +{ + count_int2++; + if (ADXL345_IsInterrupt(ADXL345_INT_DOUBLE_TAP) > 0) + { + count_double_tap++; + } +} + +INTERRUPT(Int3_Routine, EXTI_VectInt3) +{ + count_int3++; +} + +int main(void) +{ + uint8_t intsrc; + int16_t x, y, z; + SYS_SetClock(); + GPIO_Init(); + UART1_Config8bitUart(UART1_BaudSource_Timer1, HAL_State_ON, 115200); + SPI_Init(); + INT_Init(); + ADXL345_Init( + ADXL345_DATARATE_100_HZ, + ADXL345_SPI_WIRE_4, + ADXL345_INT_ACTIVE_LOW, + ADXL345_DATA_RESOLVE_FULL, + ADXL345_DATA_ALIGNMENT_RIGHT, + ADXL345_G_RANGE_8G + ); + ADXL345_WriteByte(ADXL345_REG_THRESH_TAP, 0x2F); + ADXL345_WriteByte(ADXL345_REG_DUR, 0x1F); + ADXL345_WriteByte(ADXL345_REG_LATENT, 0x1F); + ADXL345_WriteByte(ADXL345_REG_WINDOW, 0x7F); + ADXL345_EnableTapDetectOnAxes( + ADXL345_TAP_DETECT_AXIS_X|ADXL345_TAP_DETECT_AXIS_Y|ADXL345_TAP_DETECT_AXIS_Z); + ADXL345_SetInterrupts( + ADXL345_INT_DATA_READY|ADXL345_INT_SINGLE_TAP|ADXL345_INT_DOUBLE_TAP); + ADXL345_RemapInterrupts(ADXL345_INT_DATA_READY); + + while(1) + { + buf[0] = ADXL345_ReadByte(ADXL345_REG_DATAX0); + buf[1] = ADXL345_ReadByte(ADXL345_REG_DATAX1); + buf[2] = ADXL345_ReadByte(ADXL345_REG_DATAY0); + buf[3] = ADXL345_ReadByte(ADXL345_REG_DATAY1); + buf[4] = ADXL345_ReadByte(ADXL345_REG_DATAZ0); + buf[5] = ADXL345_ReadByte(ADXL345_REG_DATAZ1); + x = *((int16_t *)&buf[0]); + y = *((int16_t *)&buf[2]); + z = *((int16_t *)&buf[4]); + printf("X:%6d, Y:%6d, Z:%6d, DAT:%3d, TAP:%3d, 2-TAP:%3d\r\n", + x, y, z, count_int2, count_int3, count_double_tap); + SYS_Delay(100); + } +} diff --git a/src/fw_uart.c b/src/fw_uart.c index 360ecd9..98e8595 100644 --- a/src/fw_uart.c +++ b/src/fw_uart.c @@ -127,6 +127,13 @@ void UART1_TxString(uint8_t *str) while (*str) UART1_TxChar(*str++); } +int putchar(int dat) { + UART1_WriteBuffer(dat); + while(!TI); + UART1_ClearTxInterrupt(); + return dat; +} + /**************************************************************************** / * UART2