Merge pull request #237 from UncleRus/extras/hmc5883l
HMC5883L driver + example
This commit is contained in:
		
						commit
						b23dd64419
					
				
					 5 changed files with 461 additions and 0 deletions
				
			
		
							
								
								
									
										4
									
								
								examples/hmc5883l/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								examples/hmc5883l/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| PROGRAM = hmc5883l | ||||
| EXTRA_COMPONENTS = extras/i2c extras/hmc5883l | ||||
| #ESPBAUD = 460800
 | ||||
| include ../../common.mk | ||||
							
								
								
									
										41
									
								
								examples/hmc5883l/main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								examples/hmc5883l/main.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| /*
 | ||||
|  * Example of using HMC5883L driver | ||||
|  * | ||||
|  * Part of esp-open-rtos | ||||
|  * Copyright (C) 2016 Ruslan V. Uss <unclerus@gmail.com> | ||||
|  * BSD Licensed as described in the file LICENSE | ||||
|  */ | ||||
| #include <esp/uart.h> | ||||
| #include <espressif/esp_common.h> | ||||
| #include <stdio.h> | ||||
| #include <i2c/i2c.h> | ||||
| #include <hmc5883l/hmc5883l.h> | ||||
| 
 | ||||
| #define SCL_PIN 5 | ||||
| #define SDA_PIN 4 | ||||
| 
 | ||||
| void user_init(void) | ||||
| { | ||||
|     uart_set_baud(0, 115200); | ||||
|     printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); | ||||
| 
 | ||||
|     i2c_init(SCL_PIN, SDA_PIN); | ||||
| 
 | ||||
|     while (!hmc5883l_init()) | ||||
|         printf("Device not found\n"); | ||||
| 
 | ||||
|     hmc5883l_set_operating_mode(HMC5883L_MODE_CONTINUOUS); | ||||
|     hmc5883l_set_samples_averaged(HMC5883L_SAMPLES_8); | ||||
|     hmc5883l_set_data_rate(HMC5883L_DATA_RATE_07_50); | ||||
|     hmc5883l_set_gain(HMC5883L_GAIN_1090); | ||||
| 
 | ||||
|     while (true) | ||||
|     { | ||||
|         hmc5883l_data_t data; | ||||
|         hmc5883l_get_data(&data); | ||||
|         printf("Magnetic data: X:%.2f mG, Y:%.2f mG, Z:%.2f mG\n", data.x, data.y, data.z); | ||||
| 
 | ||||
|         for (uint32_t i = 0; i < 1000; i++) | ||||
|             sdk_os_delay_us(250); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								extras/hmc5883l/component.mk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								extras/hmc5883l/component.mk
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| # Component makefile for extras/hmc5883l
 | ||||
| 
 | ||||
| # expected anyone using this driver includes it as 'hmc5883l/hmc5883l.h'
 | ||||
| INC_DIRS += $(hmc5883l_ROOT).. | ||||
| 
 | ||||
| # args for passing into compile rule generation
 | ||||
| hmc5883l_SRC_DIR = $(hmc5883l_ROOT) | ||||
| 
 | ||||
| $(eval $(call component_compile_rules,hmc5883l)) | ||||
							
								
								
									
										189
									
								
								extras/hmc5883l/hmc5883l.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								extras/hmc5883l/hmc5883l.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,189 @@ | |||
| /*
 | ||||
|  * Driver for 3-axis digital compass HMC5883L | ||||
|  * | ||||
|  * Part of esp-open-rtos | ||||
|  * Copyright (C) 2016 Ruslan V. Uss <unclerus@gmail.com> | ||||
|  * BSD Licensed as described in the file LICENSE | ||||
|  */ | ||||
| #include "hmc5883l.h" | ||||
| #include <i2c/i2c.h> | ||||
| #include <espressif/esp_common.h> | ||||
| 
 | ||||
| #define ADDR 0x1e | ||||
| 
 | ||||
| #define REG_CR_A 0x00 | ||||
| #define REG_CR_B 0x01 | ||||
| #define REG_MODE 0x02 | ||||
| #define REG_DX_H 0x03 | ||||
| #define REG_DX_L 0x04 | ||||
| #define REG_DZ_H 0x05 | ||||
| #define REG_DZ_L 0x06 | ||||
| #define REG_DY_H 0x07 | ||||
| #define REG_DY_L 0x08 | ||||
| #define REG_STAT 0x09 | ||||
| #define REG_ID_A 0x0a | ||||
| #define REG_ID_B 0x0b | ||||
| #define REG_ID_C 0x0c | ||||
| 
 | ||||
| #define BIT_MA  5 | ||||
| #define BIT_DO  2 | ||||
| #define BIT_GN  5 | ||||
| 
 | ||||
| #define MASK_MD 0x03 | ||||
| #define MASK_MA 0x60 | ||||
| #define MASK_DO 0x1c | ||||
| #define MASK_MS 0x03 | ||||
| #define MASK_DR 0x01 | ||||
| #define MASK_DL 0x02 | ||||
| 
 | ||||
| #define MEASUREMENT_TIMEOUT 6000 | ||||
| 
 | ||||
| static const float gain_values [] = { | ||||
|     [HMC5883L_GAIN_1370] = 0.73, | ||||
|     [HMC5883L_GAIN_1090] = 0.92, | ||||
|     [HMC5883L_GAIN_820]  = 1.22, | ||||
|     [HMC5883L_GAIN_660]  = 1.52, | ||||
|     [HMC5883L_GAIN_440]  = 2.27, | ||||
|     [HMC5883L_GAIN_390]  = 2.56, | ||||
|     [HMC5883L_GAIN_330]  = 3.03, | ||||
|     [HMC5883L_GAIN_230]  = 4.35 | ||||
| }; | ||||
| 
 | ||||
| static float current_gain; | ||||
| static hmc5883l_operating_mode_t current_mode; | ||||
| 
 | ||||
| static inline void write_register(uint8_t reg, uint8_t val) | ||||
| { | ||||
|     uint8_t buf[2] = { reg, val }; | ||||
|     i2c_slave_write(ADDR, buf, 2); | ||||
| } | ||||
| 
 | ||||
| static inline uint8_t read_register(uint8_t reg) | ||||
| { | ||||
|     uint8_t res; | ||||
|     i2c_slave_read(ADDR, reg, &res, 1); | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| static inline void update_register(uint8_t reg, uint8_t mask, uint8_t val) | ||||
| { | ||||
|     write_register(reg, (read_register(reg) & mask) | val); | ||||
| } | ||||
| 
 | ||||
| bool hmc5883l_init() | ||||
| { | ||||
|     if (hmc5883l_get_id() != HMC5883L_ID) | ||||
|         return false; | ||||
|     current_gain = gain_values[hmc5883l_get_gain()]; | ||||
|     current_mode = hmc5883l_get_operating_mode(); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| uint32_t hmc5883l_get_id() | ||||
| { | ||||
|     uint32_t res = 0; | ||||
|     i2c_slave_read(ADDR, REG_ID_A, (uint8_t *)&res, 3); | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| hmc5883l_operating_mode_t hmc5883l_get_operating_mode() | ||||
| { | ||||
|     uint8_t res = read_register(REG_MODE) & MASK_MD; | ||||
|     return res == 0 ? HMC5883L_MODE_CONTINUOUS : HMC5883L_MODE_SINGLE; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode) | ||||
| { | ||||
|     write_register(REG_MODE, mode); | ||||
|     current_mode = mode; | ||||
| } | ||||
| 
 | ||||
| hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged() | ||||
| { | ||||
|     return (read_register(REG_CR_A) & MASK_MA) >> BIT_MA; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples) | ||||
| { | ||||
|     update_register(REG_CR_A, MASK_MA, samples << BIT_MA); | ||||
| } | ||||
| 
 | ||||
| hmc5883l_data_rate_t hmc5883l_get_data_rate() | ||||
| { | ||||
|     return (read_register(REG_CR_A) & MASK_DO) >> BIT_DO; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate) | ||||
| { | ||||
|     update_register(REG_CR_A, MASK_DO, rate << BIT_DO); | ||||
| } | ||||
| 
 | ||||
| hmc5883l_bias_t hmc5883l_get_bias() | ||||
| { | ||||
|     return read_register(REG_CR_A) & MASK_MS; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_set_bias(hmc5883l_bias_t bias) | ||||
| { | ||||
|     update_register(REG_CR_A, MASK_MS, bias); | ||||
| } | ||||
| 
 | ||||
| hmc5883l_gain_t hmc5883l_get_gain() | ||||
| { | ||||
|     return read_register(REG_CR_B) >> BIT_GN; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_set_gain(hmc5883l_gain_t gain) | ||||
| { | ||||
|     write_register(REG_CR_B, gain << BIT_GN); | ||||
|     current_gain = gain_values[gain]; | ||||
| } | ||||
| 
 | ||||
| bool hmc5883l_data_is_locked() | ||||
| { | ||||
|     return read_register(REG_STAT) & MASK_DL; | ||||
| } | ||||
| 
 | ||||
| bool hmc5883l_data_is_ready() | ||||
| { | ||||
|     return read_register(REG_STAT) & MASK_DR; | ||||
| } | ||||
| 
 | ||||
| bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data) | ||||
| { | ||||
|     if (current_mode == HMC5883L_MODE_SINGLE) | ||||
|     { | ||||
|         // overwrite mode register for measurement
 | ||||
|         hmc5883l_set_operating_mode(current_mode); | ||||
|         // wait for data
 | ||||
|         uint32_t timeout = sdk_system_get_time() + MEASUREMENT_TIMEOUT; | ||||
|         while (!hmc5883l_data_is_ready()) | ||||
|         { | ||||
|             if (sdk_system_get_time() >= timeout) | ||||
|                 return false; | ||||
|         } | ||||
|     } | ||||
|     uint8_t buf[6]; | ||||
|     i2c_slave_read(ADDR, REG_DX_H, buf, 6); | ||||
|     data->x = ((int16_t)buf[REG_DX_H - REG_DX_H] << 8) | buf[REG_DX_L - REG_DX_H]; | ||||
|     data->y = ((int16_t)buf[REG_DY_H - REG_DX_H] << 8) | buf[REG_DY_L - REG_DX_H]; | ||||
|     data->z = ((int16_t)buf[REG_DZ_H - REG_DX_H] << 8) | buf[REG_DZ_L - REG_DX_H]; | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg) | ||||
| { | ||||
|     mg->x = raw->x * current_gain; | ||||
|     mg->y = raw->y * current_gain; | ||||
|     mg->z = raw->z * current_gain; | ||||
| } | ||||
| 
 | ||||
| bool hmc5883l_get_data(hmc5883l_data_t *data) | ||||
| { | ||||
|     hmc5883l_raw_data_t raw; | ||||
| 
 | ||||
|     if (!hmc5883l_get_raw_data(&raw)) | ||||
|         return false; | ||||
|     hmc5883l_raw_to_mg(&raw, data); | ||||
|     return true; | ||||
| } | ||||
							
								
								
									
										218
									
								
								extras/hmc5883l/hmc5883l.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								extras/hmc5883l/hmc5883l.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,218 @@ | |||
| /*
 | ||||
|  * Driver for 3-axis digital compass HMC5883L | ||||
|  * | ||||
|  * Part of esp-open-rtos | ||||
|  * Copyright (C) 2016 Ruslan V. Uss <unclerus@gmail.com> | ||||
|  * BSD Licensed as described in the file LICENSE | ||||
|  */ | ||||
| #ifndef EXTRAS_HMC5883L_H_ | ||||
| #define EXTRAS_HMC5883L_H_ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" | ||||
| { | ||||
| #endif | ||||
| 
 | ||||
| #define HMC5883L_ID 0x00333448  // "H43"
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Device operating mode | ||||
|  */ | ||||
| typedef enum | ||||
| { | ||||
|     HMC5883L_MODE_CONTINUOUS = 0, //!< Continuous mode
 | ||||
|     HMC5883L_MODE_SINGLE          //!< Single measurement mode, default
 | ||||
| } hmc5883l_operating_mode_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Number of samples averaged per measurement | ||||
|  */ | ||||
| typedef enum | ||||
| { | ||||
|     HMC5883L_SAMPLES_1 = 0, //!< 1 sample, default
 | ||||
|     HMC5883L_SAMPLES_2,     //!< 2 samples
 | ||||
|     HMC5883L_SAMPLES_4,     //!< 4 samples
 | ||||
|     HMC5883L_SAMPLES_8      //!< 8 samples
 | ||||
| } hmc5883l_samples_averaged_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Data output rate in continuous measurement mode | ||||
|  */ | ||||
| typedef enum | ||||
| { | ||||
|     HMC5883L_DATA_RATE_00_75 = 0, //!< 0.75 Hz
 | ||||
|     HMC5883L_DATA_RATE_01_50,     //!< 1.5 Hz
 | ||||
|     HMC5883L_DATA_RATE_03_00,     //!< 3 Hz
 | ||||
|     HMC5883L_DATA_RATE_07_50,     //!< 7.5 Hz
 | ||||
|     HMC5883L_DATA_RATE_15_00,     //!< 15 Hz, default
 | ||||
|     HMC5883L_DATA_RATE_30_00,     //!< 30 Hz
 | ||||
|     HMC5883L_DATA_RATE_75_00      //!< 75 Hz
 | ||||
| } hmc5883l_data_rate_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Measurement mode of the device (bias) | ||||
|  */ | ||||
| typedef enum | ||||
| { | ||||
|     HMC5883L_BIAS_NORMAL = 0, //!< Default flow, no bias
 | ||||
|     HMC5883L_BIAS_POSITIVE,   //!< Positive bias configuration all axes, used for self test (see datasheet)
 | ||||
|     HMC5883L_BIAS_NEGATIVE    //!< Negative bias configuration all axes, used for self test (see datasheet)
 | ||||
| } hmc5883l_bias_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Device gain | ||||
|  */ | ||||
| typedef enum | ||||
| { | ||||
|     HMC5883L_GAIN_1370 = 0, //!< 0.73 mG/LSb, range -0.88..+0.88 G
 | ||||
|     HMC5883L_GAIN_1090,     //!< 0.92 mG/LSb, range -1.3..+1.3 G, default
 | ||||
|     HMC5883L_GAIN_820,      //!< 1.22 mG/LSb, range -1.9..+1.9 G
 | ||||
|     HMC5883L_GAIN_660,      //!< 1.52 mG/LSb, range -2.5..+2.5 G
 | ||||
|     HMC5883L_GAIN_440,      //!< 2.27 mG/LSb, range -4.0..+4.0 G
 | ||||
|     HMC5883L_GAIN_390,      //!< 2.56 mG/LSb, range -4.7..+4.7 G
 | ||||
|     HMC5883L_GAIN_330,      //!< 3.03 mG/LSb, range -5.6..+5.6 G
 | ||||
|     HMC5883L_GAIN_230       //!< 4.35 mG/LSb, range -8.1..+8.1 G
 | ||||
| } hmc5883l_gain_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Raw measurement result | ||||
|  */ | ||||
| typedef struct | ||||
| { | ||||
|     int16_t x; | ||||
|     int16_t y; | ||||
|     int16_t z; | ||||
| } hmc5883l_raw_data_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * Measurement result, milligauss | ||||
|  */ | ||||
| typedef struct | ||||
| { | ||||
|     float x; | ||||
|     float y; | ||||
|     float z; | ||||
| } hmc5883l_data_t; | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Init device | ||||
|  * \return false if error occured | ||||
|  */ | ||||
| bool hmc5883l_init(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get device ID | ||||
|  * Always returns 0x00333448 if IC functioning properly. | ||||
|  * \return Device ID | ||||
|  */ | ||||
| uint32_t hmc5883l_get_id(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get operating mode | ||||
|  * \return Measurement mode | ||||
|  */ | ||||
| hmc5883l_operating_mode_t hmc5883l_get_operating_mode(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Set operating mode | ||||
|  * \param mode Measurement mode | ||||
|  */ | ||||
| void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get number of samples averaged per measurement output | ||||
|  * \return Number of samples | ||||
|  */ | ||||
| hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Set number of samples averaged per measurement output | ||||
|  * \param samples Number of samples | ||||
|  */ | ||||
| void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get data output rate in continuous measurement mode | ||||
|  * \return Data output rate | ||||
|  */ | ||||
| hmc5883l_data_rate_t hmc5883l_get_data_rate(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Set data output rate in continuous measurement mode | ||||
|  * \param rate Data output rate | ||||
|  */ | ||||
| void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get measurement mode (bias of the axes) | ||||
|  * See datasheet for self test description | ||||
|  * \return Bias | ||||
|  */ | ||||
| hmc5883l_bias_t hmc5883l_get_bias(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Set measurement mode (bias of the axes) | ||||
|  * See datasheet for self test description | ||||
|  * \param bias Bias | ||||
|  */ | ||||
| void hmc5883l_set_bias(hmc5883l_bias_t bias); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get device gain | ||||
|  * \return Current gain | ||||
|  */ | ||||
| hmc5883l_gain_t hmc5883l_get_gain(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Set device gain | ||||
|  * \param gain Gain | ||||
|  */ | ||||
| void hmc5883l_set_gain(hmc5883l_gain_t gain); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get data state | ||||
|  * \return true when data is written to all six data registers | ||||
|  */ | ||||
| bool hmc5883l_data_is_ready(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get lock state. | ||||
|  * If data is locked, any new data will not be placed in data registers until | ||||
|  * one of these conditions are met: | ||||
|  * 1. data have been read, | ||||
|  * 2. operating mode is changed, | ||||
|  * 3. the measurement configuration (bias) is changed, | ||||
|  * 4. power is reset. | ||||
|  * \return true when data registers is locked | ||||
|  */ | ||||
| bool hmc5883l_data_is_locked(); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get raw magnetic data | ||||
|  * \param data Pointer to the struct to write raw data | ||||
|  * \return false if error occured in single measurement mode, always true in continuous mode | ||||
|  */ | ||||
| bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Convert raw magnetic data to milligausses | ||||
|  * \param raw Pointer to source raw data struct | ||||
|  * \param mg Pointer to target struct to write converted data | ||||
|  */ | ||||
| void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg); | ||||
| 
 | ||||
| /**
 | ||||
|  * \brief Get magnetic data in milligausses | ||||
|  * \param data Pointer to the struct to write data | ||||
|  * \return false if error occured in single measurement mode, always true in continuous mode | ||||
|  */ | ||||
| bool hmc5883l_get_data(hmc5883l_data_t *data); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #endif /* EXTRAS_HMC5883L_H_ */ | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue