559 lines
20 KiB
C
559 lines
20 KiB
C
/** library to communication with ams AS3935 Franklin lightning sensor IC using SPI
|
|
* @file
|
|
* @author King Kévin <kingkevin@cuvoodoo.info>
|
|
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
|
|
* @date 2019
|
|
* @note peripherals used: SPI @ref sensor_as3935_spi, GPIO @ref sensor_as3935_gpio
|
|
*/
|
|
/* standard libraries */
|
|
#include <stdint.h> // standard integer types
|
|
#include <stdlib.h> // general utilities
|
|
#include <stdbool.h> // boolean utilities
|
|
#include <math.h> // math utilities
|
|
#include <strings.h> // fff utilities
|
|
|
|
/* STM32 (including CM3) libraries */
|
|
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
|
#include <libopencm3/stm32/rcc.h> // real-time control clock library
|
|
#include <libopencm3/stm32/gpio.h> // general purpose input output library
|
|
#include <libopencm3/stm32/spi.h> // SPI library
|
|
#include <libopencm3/stm32/exti.h> // external interrupt defines
|
|
#include <libopencm3/cm3/nvic.h> // interrupt handler
|
|
|
|
/* own libraries */
|
|
#include "global.h" // common methods
|
|
#include "sensor_as3935.h" // own definitions
|
|
|
|
/** @defgroup sensor_as3935_spi SPI peripheral used to communicate with the AS3935
|
|
* @{
|
|
*/
|
|
#define SENSOR_AS3935_SPI 1 /**< SPI peripheral */
|
|
/** @} */
|
|
|
|
/** @defgroup sensor_as3935_gpio GPIO used to control the AS3935
|
|
* @{
|
|
*/
|
|
#define SENSOR_AS3935_GPIO_SI PA3 /**< AS3935 Select Interface pin (high = SPI, low = I2C) */
|
|
#define SENSOR_AS3935_GPIO_IRQ PA2 /**< AS3935 Interrupt pin (active high) */
|
|
#define SENSOR_AS3935_GPIO_EN_VREG PA0 /**< AS3935 Voltage Regulator Enable pin (active high) */
|
|
/** @} */
|
|
|
|
/** register details */
|
|
struct sensor_as3935_register_info_t {
|
|
uint8_t address; /**< register address */
|
|
uint8_t mask; /**< mask of relevant register bits */
|
|
bool writable; /**< if register is writable */
|
|
};
|
|
|
|
/** AS3935 registers description */
|
|
static const struct sensor_as3935_register_info_t sensor_as3935_register_infos[] = {
|
|
[SENSOR_AS3935_REGISTER_AFE_GB] = {
|
|
.address = 0x00,
|
|
.mask = 0x3e,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_PWD] = {
|
|
.address = 0x00,
|
|
.mask = 0x01,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_NF_LEV] = {
|
|
.address = 0x01,
|
|
.mask = 0x70,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_WDTH] = {
|
|
.address = 0x01,
|
|
.mask = 0x0f,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_CL_STAT] = {
|
|
.address = 0x02,
|
|
.mask = 0x40,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_MIN_NUM_LIGH] = {
|
|
.address = 0x02,
|
|
.mask = 0x30,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_SREJ] = {
|
|
.address = 0x02,
|
|
.mask = 0x0f,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LCO_FDIV] = {
|
|
.address = 0x03,
|
|
.mask = 0xc0,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_MASK_DIST] = {
|
|
.address = 0x03,
|
|
.mask = 0x20,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_INT] = {
|
|
.address = 0x03,
|
|
.mask = 0x0f,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_S_LIG_L] = {
|
|
.address = 0x04,
|
|
.mask = 0xff,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_S_LIG_M] = {
|
|
.address = 0x05,
|
|
.mask = 0xff,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_S_LIG_MM] = {
|
|
.address = 0x06,
|
|
.mask = 0x1f,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_DISTANCE] = {
|
|
.address = 0x07,
|
|
.mask = 0x3f,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_DISP_LCO] = {
|
|
.address = 0x08,
|
|
.mask = 0x80,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_DISP_SRCO] = {
|
|
.address = 0x08,
|
|
.mask = 0x40,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_DISP_TRCO] = {
|
|
.address = 0x08,
|
|
.mask = 0x20,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_TUN_CAP] = {
|
|
.address = 0x08,
|
|
.mask = 0x0f,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT1] = {
|
|
.address = 0x09,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT2] = {
|
|
.address = 0x0a,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT3] = {
|
|
.address = 0x0b,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT4] = {
|
|
.address = 0x0c,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT5] = {
|
|
.address = 0x0d,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT6] = {
|
|
.address = 0x0e,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT7] = {
|
|
.address = 0x0f,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT8] = {
|
|
.address = 0x10,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT9] = {
|
|
.address = 0x11,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT10] = {
|
|
.address = 0x12,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT11] = {
|
|
.address = 0x13,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT12] = {
|
|
.address = 0x14,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT13] = {
|
|
.address = 0x15,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT14] = {
|
|
.address = 0x16,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT15] = {
|
|
.address = 0x17,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT16] = {
|
|
.address = 0x18,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT17] = {
|
|
.address = 0x19,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT18] = {
|
|
.address = 0x1a,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT19] = {
|
|
.address = 0x1b,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT20] = {
|
|
.address = 0x1c,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT21] = {
|
|
.address = 0x1d,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT22] = {
|
|
.address = 0x1e,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT23] = {
|
|
.address = 0x1f,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT24] = {
|
|
.address = 0x20,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT25] = {
|
|
.address = 0x21,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT26] = {
|
|
.address = 0x22,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT27] = {
|
|
.address = 0x23,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT28] = {
|
|
.address = 0x24,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT29] = {
|
|
.address = 0x25,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT30] = {
|
|
.address = 0x26,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT31] = {
|
|
.address = 0x27,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT32] = {
|
|
.address = 0x28,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT33] = {
|
|
.address = 0x29,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT34] = {
|
|
.address = 0x2a,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT35] = {
|
|
.address = 0x2b,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT36] = {
|
|
.address = 0x2c,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT37] = {
|
|
.address = 0x2d,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT38] = {
|
|
.address = 0x2e,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT39] = {
|
|
.address = 0x2f,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT40] = {
|
|
.address = 0x30,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT41] = {
|
|
.address = 0x31,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_LDLUT42] = {
|
|
.address = 0x32,
|
|
.mask = 0xff,
|
|
.writable = true,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_TRCO_CALIB_DONE] = {
|
|
.address = 0x3a,
|
|
.mask = 0x80,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_TRCO_CALIB_NOK] = {
|
|
.address = 0x3a,
|
|
.mask = 0x40,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_SRCO_CALIB_DONE] = {
|
|
.address = 0x3b,
|
|
.mask = 0x80,
|
|
.writable = false,
|
|
},
|
|
[SENSOR_AS3935_REGISTER_SRCO_CALIB_NOK] = {
|
|
.address = 0x3b,
|
|
.mask = 0x40,
|
|
.writable = false,
|
|
},
|
|
};
|
|
|
|
/** flag set if an interrupt has been received */
|
|
volatile bool sensor_as3935_interrupt = false;
|
|
/** if we are currently calibrating the sensor */
|
|
static bool sensor_as3935_calibrating = false;
|
|
/** number of interrupts received */
|
|
static volatile uint16_t sensor_as3935_interrupt_count = 0;
|
|
|
|
bool sensor_as3935_setup(void)
|
|
{
|
|
// disable internal voltage regulator since we already provide 3.3V (plus VREG is tied to VCC using a 0R resistor)
|
|
rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_EN_VREG)); // enable clock for GPIO port
|
|
gpio_clear(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG)); // set low to disable voltage regulator
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG)); // set GPIO as output
|
|
// select SPI interface
|
|
rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_SI)); // enable clock for GPIO port
|
|
gpio_clear(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_PIN(SENSOR_AS3935_GPIO_SI)); // pull low since it's active high
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(SENSOR_AS3935_GPIO_SI)); // set GPIO as output
|
|
// configure interrupt
|
|
rcc_periph_clock_enable(GPIO_RCC(SENSOR_AS3935_GPIO_IRQ)); // enable clock for GPIO port
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_IRQ)); // set interrupt as input
|
|
// setup SPI
|
|
rcc_periph_clock_enable(RCC_SPI_SCK_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for clock signal
|
|
gpio_set_mode(SPI_SCK_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(SENSOR_AS3935_SPI)); // set SCK as output (clock speed will be negotiated later)
|
|
rcc_periph_clock_enable(RCC_SPI_MOSI_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for MOSI signal
|
|
gpio_set_mode(SPI_MOSI_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_MOSI_PIN(SENSOR_AS3935_SPI)); // set MOSI as output
|
|
rcc_periph_clock_enable(RCC_SPI_MISO_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for MISO signal
|
|
gpio_set_mode(SPI_MISO_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(SENSOR_AS3935_SPI)); // set MISO as input
|
|
rcc_periph_clock_enable(RCC_SPI_NSS_PORT(SENSOR_AS3935_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
|
|
gpio_set_mode(SPI_NSS_PORT(SENSOR_AS3935_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set NSS (CS) as output
|
|
rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
|
|
rcc_periph_clock_enable(RCC_SPI(SENSOR_AS3935_SPI)); // enable clock for SPI peripheral
|
|
spi_reset(SPI(SENSOR_AS3935_SPI)); // clear SPI values to default
|
|
spi_init_master(SPI(SENSOR_AS3935_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_64, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 64 (72E6/64=1125 kHz, max AS3935 SCK is 2 MHz, maximum SPI PCLK clock is 72 Mhz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (polarity depends on clock phase), use 16 bits frames , use MSb first
|
|
spi_set_full_duplex_mode(SPI(SENSOR_AS3935_SPI)); // ensure we are in full duplex mode
|
|
spi_enable_software_slave_management(SPI(SENSOR_AS3935_SPI)); // control NSS (CS) manually
|
|
spi_set_nss_high(SPI(SENSOR_AS3935_SPI)); // set NSS high (internally) so we can output
|
|
spi_disable_ss_output(SPI(SENSOR_AS3935_SPI)); // disable NSS output since we control CS manually
|
|
gpio_set(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS high to unselect device
|
|
// sadly we can't use the interrupts as events to sleep (WFE) since sleep disables also communication (e.g. going to sleep until Rx buffer is not empty prevents transmission)
|
|
spi_enable(SPI(SENSOR_AS3935_SPI)); // enable SPI
|
|
sleep_ms(2); // be sure TCO has enough time to start
|
|
// configure device
|
|
sensor_as3935_command(SENSOR_AS3935_OPERATION_DIRECT_COMMAND, SENSOR_AS3935_DIRECT_COMMAND_PRESET_DEFAULT, SENSOR_AS3935_DIRECT_COMMAND_VALUE); // reset all values to default
|
|
if (0x24 != sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, 0, 0)) { // check if communication works by checking default register value
|
|
return false;
|
|
}
|
|
sensor_as3935_power_down(); // power down to save power
|
|
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
|
|
// configure IRQ interrupt
|
|
exti_select_source(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ), GPIO_PORT(SENSOR_AS3935_GPIO_IRQ)); // mask external interrupt of the IRQ pin only for this port
|
|
exti_set_trigger(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ), EXTI_TRIGGER_RISING); // IRQ goes high in interrupt
|
|
exti_enable_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ)); // enable external interrupt
|
|
nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // enable interrupt
|
|
sensor_as3935_interrupt = (0 != gpio_get(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_PIN(SENSOR_AS3935_GPIO_IRQ))); // update interrupt status
|
|
return true;
|
|
}
|
|
|
|
void sensor_as3935_release(void)
|
|
{
|
|
nvic_disable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ));
|
|
exti_disable_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ));
|
|
spi_reset(SPI(SENSOR_AS3935_SPI));
|
|
spi_disable(SPI(SENSOR_AS3935_SPI));
|
|
rcc_periph_clock_disable(RCC_SPI(SENSOR_AS3935_SPI));
|
|
gpio_set_mode(SPI_NSS_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_NSS_PIN(SENSOR_AS3935_SPI));
|
|
gpio_set_mode(SPI_MISO_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MISO_PIN(SENSOR_AS3935_SPI));
|
|
gpio_set_mode(SPI_MOSI_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MOSI_PIN(SENSOR_AS3935_SPI));
|
|
gpio_set_mode(SPI_SCK_PORT(SENSOR_AS3935_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_SCK_PIN(SENSOR_AS3935_SPI));
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_IRQ));
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_SI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_SI));
|
|
gpio_set_mode(GPIO_PORT(SENSOR_AS3935_GPIO_EN_VREG), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_PIN(SENSOR_AS3935_GPIO_EN_VREG));
|
|
}
|
|
|
|
uint8_t sensor_as3935_command(enum sensor_as3935_operation_t operation, uint8_t address_command, uint8_t data)
|
|
{
|
|
gpio_clear(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS low to select device
|
|
spi_send(SPI(SENSOR_AS3935_SPI), ((operation & 0x3) << 14) | ((address_command & 0x3f) << 8) | data); // send command
|
|
(void)SPI_DR(SPI(SENSOR_AS3935_SPI)); // clear RXNE flag (by reading previously received data (not done by spi_read or spi_xref)
|
|
while (!(SPI_SR(SPI(SENSOR_AS3935_SPI)) & SPI_SR_TXE)); // wait until Tx buffer is empty before clearing the (previous) RXNE flag
|
|
while (!(SPI_SR(SPI(SENSOR_AS3935_SPI)) & SPI_SR_RXNE)); // wait for next data to be available
|
|
gpio_set(SPI_NSS_PORT(SENSOR_AS3935_SPI), SPI_NSS_PIN(SENSOR_AS3935_SPI)); // set CS high to unselect device
|
|
return SPI_DR(SPI(SENSOR_AS3935_SPI)); // return received data
|
|
}
|
|
|
|
uint8_t sensor_as3935_read_register(enum sensor_as3935_register_t name)
|
|
{
|
|
if (name >= LENGTH(sensor_as3935_register_infos)) { // check if register exists
|
|
return 0;
|
|
}
|
|
if (SENSOR_AS3935_REGISTER_INT == name) { // you need to wait 2 ms after an interrupt before reading the register
|
|
sleep_ms(2);
|
|
}
|
|
struct sensor_as3935_register_info_t register_info = sensor_as3935_register_infos[name]; // get register information
|
|
uint8_t value = sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, register_info.address, 0); // get register value
|
|
value &= register_info.mask; // only keep relevant bits
|
|
value >>= (ffs(register_info.mask) - 1); // shit value bits
|
|
return value;
|
|
}
|
|
|
|
bool sensor_as3935_write_register(enum sensor_as3935_register_t name, uint8_t value)
|
|
{
|
|
if (name >= LENGTH(sensor_as3935_register_infos)) { // check if register exists
|
|
return false;
|
|
}
|
|
struct sensor_as3935_register_info_t register_info = sensor_as3935_register_infos[name]; // get register information
|
|
if (!register_info.writable) {
|
|
return false;
|
|
}
|
|
uint8_t data = sensor_as3935_command(SENSOR_AS3935_OPERATION_READ, register_info.address, 0); // get register data
|
|
value <<= (ffs(register_info.mask) - 1); // shit value bits
|
|
value &= register_info.mask; // only keep relevant bits
|
|
data &= ~register_info.mask; // clear relevant bit is final data
|
|
data |= value; // put value in data
|
|
sensor_as3935_command(SENSOR_AS3935_OPERATION_WRITE, register_info.address, data); // write register data
|
|
return true;
|
|
}
|
|
|
|
void sensor_as3935_power_down(void)
|
|
{
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 1);
|
|
}
|
|
|
|
int8_t sensor_as3935_power_up(void)
|
|
{
|
|
nvic_disable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // no need to count the next clock calibration
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 0); // power up
|
|
sensor_as3935_command(SENSOR_AS3935_OPERATION_DIRECT_COMMAND, SENSOR_AS3935_DIRECT_COMMAND_CALIB_RCO, SENSOR_AS3935_DIRECT_COMMAND_VALUE); // start RCO calibration
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_SRCO, 1); // output SRCO to start calibration
|
|
sleep_ms(2); // as defined in the calibration procedure
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_SRCO, 0); // stop SRCO output
|
|
nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(SENSOR_AS3935_GPIO_IRQ)); // re-enable interrupt
|
|
sensor_as3935_interrupt = (0 != gpio_get(GPIO_PORT(SENSOR_AS3935_GPIO_IRQ), GPIO_PIN(SENSOR_AS3935_GPIO_IRQ))); // update interrupt status
|
|
// check if calibration succeeded
|
|
if (0 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_SRCO_CALIB_DONE)) {
|
|
return -1;
|
|
}
|
|
if (1 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_SRCO_CALIB_NOK)) {
|
|
return -2;
|
|
}
|
|
// the datasheet does not mention how to calibrate TRCO, but it is not equivalent to the SRCO mechanism and just happens if you try it often enough
|
|
if (0 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_TRCO_CALIB_DONE)) {
|
|
return -3;
|
|
}
|
|
if (1 == sensor_as3935_read_register(SENSOR_AS3935_REGISTER_TRCO_CALIB_NOK)) {
|
|
return -4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool sensor_as3935_tune(void)
|
|
{
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_PWD, 0); // power up (without calibration)
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_LCO_FDIV, 0); // divide LCO by 16 (500 kHz LCO becomes 31250 Hz output)
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_LCO, 1); // output LCO on INT to measure frequency
|
|
uint8_t best_tune = 0; // remember best internal tuning capacitor setting
|
|
uint16_t best_offset = UINT16_MAX; // remember best LCO frequency offset
|
|
sensor_as3935_calibrating = true; // count the pulses now
|
|
for (uint8_t tune_cap = 0; tune_cap < 16; tune_cap++) { // test all internal tuning capacitor settings
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_TUN_CAP, tune_cap); // set internal capacitor
|
|
sleep_ms(1); // wait a bit until the output stabilize
|
|
sensor_as3935_interrupt_count = 0; // start counting
|
|
sleep_ms(100); // wait to measure frequency precisely enough (3.5% corresponds to 109 pulses)
|
|
uint16_t offset = abs(sensor_as3935_interrupt_count - 3125); // calculate offset to ideal frequency (500 kHz / 16 during 100 ms)
|
|
if (offset < best_offset) { // check if the tune frequency is closed to the ideal
|
|
best_offset = offset; // remember new best offset
|
|
best_tune = tune_cap; // remember we found a new better tuning setting
|
|
}
|
|
}
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_DISP_LCO, 0); // switch back INT output for interrupts
|
|
sensor_as3935_calibrating = false; // stop counting the pulses
|
|
if (best_offset > 109 + 10) { // no setting has an error < 3.5% for 500 kHz (500 kHz / 16 * 3.5% during 100 ms, plus some measurement error margin)
|
|
return false;
|
|
}
|
|
sensor_as3935_write_register(SENSOR_AS3935_REGISTER_TUN_CAP, best_tune); // set best capacitor tuning setting
|
|
return true;
|
|
}
|
|
|
|
/** interrupt service routine called when IRQ does high to indicate interrupt (or clock outputs) */
|
|
void GPIO_EXTI_ISR(SENSOR_AS3935_GPIO_IRQ)(void)
|
|
{
|
|
if (sensor_as3935_calibrating) {
|
|
sensor_as3935_interrupt_count++; // increment pulse count to calculate to frequency
|
|
} else {
|
|
sensor_as3935_interrupt = true; // notify user
|
|
}
|
|
exti_reset_request(GPIO_EXTI(SENSOR_AS3935_GPIO_IRQ)); // reset interrupt
|
|
}
|