Added BMP180 and I2C driver and example
Fixed reference to unknown environment var Moved drivers into extras folder and added additional documentations. Changed LOCAL to static and renamed DEBUG to BMP180_DEBUG
This commit is contained in:
parent
76ad427dc2
commit
b251427643
14 changed files with 996 additions and 0 deletions
3
examples/bmp180_i2c/Makefile
Normal file
3
examples/bmp180_i2c/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
PROGRAM=BMP180_Reader
|
||||
EXTRA_COMPONENTS = extras/i2c extras/bmp180
|
||||
include ../../common.mk
|
7
examples/bmp180_i2c/README.md
Normal file
7
examples/bmp180_i2c/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# I2C / BMP180 Example
|
||||
|
||||
This example references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [bmp180](https://github.com/Angus71/esp-open-rtos-driver-bmp180), which are provided in the `../../extras` folder.
|
||||
|
||||
If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues.
|
||||
|
||||
To run this example connect the BMP085/BMP180 SCL to GPIO0 and SDA to GPIO2.
|
132
examples/bmp180_i2c/bmp180_i2c.c
Normal file
132
examples/bmp180_i2c/bmp180_i2c.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* Simple example for I2C / BMP180 / Timer & Event Handling
|
||||
*
|
||||
* This sample code is in the public domain.
|
||||
*/
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "queue.h"
|
||||
|
||||
// BMP180 driver
|
||||
#include "bmp180/bmp180.h"
|
||||
|
||||
#define MY_EVT_TIMER 0x01
|
||||
#define MY_EVT_BMP180 0x02
|
||||
|
||||
#define SCL_PIN GPIO_ID_PIN((0))
|
||||
#define SDA_PIN GPIO_ID_PIN((2))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t event_type;
|
||||
bmp180_result_t bmp180_data;
|
||||
} my_event_t;
|
||||
|
||||
// Communication Queue
|
||||
static xQueueHandle mainqueue;
|
||||
static xTimerHandle timerHandle;
|
||||
|
||||
// Own BMP180 User Inform Implementation
|
||||
bool bmp180_i2c_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
|
||||
{
|
||||
my_event_t ev;
|
||||
|
||||
ev.event_type = MY_EVT_BMP180;
|
||||
ev.bmp180_data.cmd = cmd;
|
||||
ev.bmp180_data.temperatue = temperatue;
|
||||
ev.bmp180_data.pressure = pressure;
|
||||
|
||||
return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
|
||||
}
|
||||
|
||||
// Timer call back
|
||||
static void bmp180_i2c_timer_cb(xTimerHandle xTimer)
|
||||
{
|
||||
my_event_t ev;
|
||||
ev.event_type = MY_EVT_TIMER;
|
||||
|
||||
xQueueSend(mainqueue, &ev, 0);
|
||||
}
|
||||
|
||||
// Check for communiction events
|
||||
void bmp180_task(void *pvParameters)
|
||||
{
|
||||
// Received pvParameters is communication queue
|
||||
xQueueHandle *com_queue = (xQueueHandle *)pvParameters;
|
||||
|
||||
printf("%s: Started user interface task\n", __FUNCTION__);
|
||||
|
||||
while(1)
|
||||
{
|
||||
my_event_t ev;
|
||||
|
||||
xQueueReceive(*com_queue, &ev, portMAX_DELAY);
|
||||
|
||||
switch(ev.event_type)
|
||||
{
|
||||
case MY_EVT_TIMER:
|
||||
printf("%s: Received Timer Event\n", __FUNCTION__);
|
||||
|
||||
bmp180_trigger_measurement(com_queue);
|
||||
break;
|
||||
case MY_EVT_BMP180:
|
||||
printf("%s: Received BMP180 Event temp:=%ld.%d°C press=%ld.%02ldhPa\n", __FUNCTION__, \
|
||||
(int32_t)ev.bmp180_data.temperatue, abs((int32_t)(ev.bmp180_data.temperatue*10)%10), \
|
||||
ev.bmp180_data.pressure/100, ev.bmp180_data.pressure%100 );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup HW
|
||||
void user_setup(void)
|
||||
{
|
||||
// Set UART Parameter
|
||||
sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
|
||||
|
||||
// Give the UART some time to settle
|
||||
sdk_os_delay_us(500);
|
||||
}
|
||||
|
||||
void user_init(void)
|
||||
{
|
||||
// Setup HW
|
||||
user_setup();
|
||||
|
||||
// Just some infomations
|
||||
printf("\n");
|
||||
printf("SDK version : %s\n", sdk_system_get_sdk_version());
|
||||
printf("GIT version : %s\n", GITSHORTREV);
|
||||
|
||||
// Use our user inform implementation
|
||||
bmp180_informUser = bmp180_i2c_informUser;
|
||||
|
||||
// Init BMP180 Interface
|
||||
bmp180_init(SCL_PIN, SDA_PIN);
|
||||
|
||||
// Create Main Communication Queue
|
||||
mainqueue = xQueueCreate(10, sizeof(my_event_t));
|
||||
|
||||
// Create user interface task
|
||||
xTaskCreate(bmp180_task, (signed char *)"bmp180_task", 256, &mainqueue, 2, NULL);
|
||||
|
||||
// Create Timer (Trigger a measurement every second)
|
||||
timerHandle = xTimerCreate((signed char *)"BMP180 Trigger", 1000/portTICK_RATE_MS, pdTRUE, NULL, bmp180_i2c_timer_cb);
|
||||
|
||||
if (timerHandle != NULL)
|
||||
{
|
||||
if (xTimerStart(timerHandle, 0) != pdPASS)
|
||||
{
|
||||
printf("%s: Unable to start Timer ...\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: Unable to create Timer ...\n", __FUNCTION__);
|
||||
}
|
||||
}
|
10
extras/README.md
Normal file
10
extras/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# extras
|
||||
|
||||
This folder contains supportive source code.
|
||||
|
||||
For current versions or reporting issues etc. please check the main development pages.
|
||||
|
||||
- [bmp180](https://github.com/Angus71/esp-open-rtos-driver-bmp180)
|
||||
- [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c)
|
||||
- [rboot-ota](http://richard.burtons.org/)
|
||||
|
22
extras/bmp180/LICENSE
Normal file
22
extras/bmp180/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Frank Bargstedt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
56
extras/bmp180/README.md
Normal file
56
extras/bmp180/README.md
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Driver for BMP085/BMP180 digital pressure sensor
|
||||
|
||||
This driver is written for usage with the ESP8266 and FreeRTOS ([esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos) and [esp-open-rtos-driver-i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c)).
|
||||
|
||||
### Usage
|
||||
|
||||
Before using the BMP180 module, the function `bmp180_init(SCL_PIN, SDA_PIN)` needs to be called to setup the I2C interface and do validation if the BMP180/BMP085 is accessible.
|
||||
|
||||
If the setup is sucessfully and a measurement is triggered, the result of the measurement is provided to the user as an event send via the `qQueue` provided with `bmp180_trigger_*measurement(pQueue);`
|
||||
|
||||
#### Example
|
||||
|
||||
```
|
||||
#define SCL_PIN GPIO_ID_PIN(0)
|
||||
#define SDA_PIN GPIO_ID_PIN(2)
|
||||
...
|
||||
|
||||
if (!bmp180_init(SCL_PIN, SDA_PIN)) {
|
||||
// An error occured, while dong the init (E.g device not found etc.)
|
||||
}
|
||||
|
||||
// Trigger a measurement
|
||||
bmp180_trigger_measurement(pQueue);
|
||||
|
||||
```
|
||||
|
||||
#### Change queue event
|
||||
|
||||
Per default the event send to the user via the provided queue is of the type `bmp180_result_t`. As this might not always be desired, a way is provided so that the user can provide a function, which creates and sends the event via the provided queue.
|
||||
|
||||
As all data aqquired from the BMP180/BMP085 is provided to the `bmp180_informUser` function, it is also possible to calculate new informations (E.g altitude etc.)
|
||||
|
||||
##### Example
|
||||
|
||||
```
|
||||
// Own BMP180 User Inform Implementation
|
||||
bool my_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) {
|
||||
my_event_t ev;
|
||||
|
||||
ev.event_type = MY_EVT_BMP180;
|
||||
ev.bmp180_data.cmd = cmd;
|
||||
ev.bmp180_data.temperatue = temperatue;
|
||||
ev.bmp180_data.pressure = pressure;
|
||||
|
||||
return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
// Use our user inform implementation
|
||||
// needs to be set before first measurement is triggered
|
||||
bmp180_informUser = my_informUser;
|
||||
|
||||
|
||||
```
|
||||
|
351
extras/bmp180/bmp180.c
Normal file
351
extras/bmp180/bmp180.c
Normal file
|
@ -0,0 +1,351 @@
|
|||
#include "bmp180.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "espressif/esp_common.h"
|
||||
#include "espressif/sdk_private.h"
|
||||
|
||||
#include "i2c/i2c.h"
|
||||
|
||||
#define BMP180_RX_QUEUE_SIZE 10
|
||||
#define BMP180_TASK_PRIORITY 9
|
||||
|
||||
#define BMP180_DEVICE_ADDRESS 0x77
|
||||
|
||||
#define BMP180_VERSION_REG 0xD0
|
||||
#define BMP180_CONTROL_REG 0xF4
|
||||
#define BMP180_RESET_REG 0xE0
|
||||
#define BMP180_OUT_MSB_REG 0xF6
|
||||
#define BMP180_OUT_LSB_REG 0xF7
|
||||
#define BMP180_OUT_XLSB_REG 0xF8
|
||||
|
||||
#define BMP180_CALIBRATION_REG 0xAA
|
||||
|
||||
//
|
||||
// Values for BMP180_CONTROL_REG
|
||||
//
|
||||
#define BMP180_MEASURE_TEMP 0x2E
|
||||
#define BMP180_MEASURE_PRESS_OSS0 0x34
|
||||
#define BMP180_MEASURE_PRESS_OSS1 0x74
|
||||
#define BMP180_MEASURE_PRESS_OSS2 0xB4
|
||||
#define BMP180_MEASURE_PRESS_OSS3 0xF4
|
||||
|
||||
#define BMP180_DEFAULT_CONV_TIME 5000
|
||||
|
||||
//
|
||||
// CHIP ID stored in BMP180_VERSION_REG
|
||||
//
|
||||
#define BMP180_CHIP_ID 0x55
|
||||
|
||||
//
|
||||
// Reset value for BMP180_RESET_REG
|
||||
//
|
||||
#define BMP180_RESET_VALUE 0xB6
|
||||
|
||||
|
||||
// BMP180_Event_Command
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
const xQueueHandle* resultQueue;
|
||||
} bmp180_command_t;
|
||||
|
||||
// Just works due to the fact that xQueueHandle is a "void *"
|
||||
static xQueueHandle bmp180_rx_queue = NULL;
|
||||
static xTaskHandle bmp180_task_handle = NULL;
|
||||
|
||||
// Calibration constants
|
||||
static int16_t AC1;
|
||||
static int16_t AC2;
|
||||
static int16_t AC3;
|
||||
static uint16_t AC4;
|
||||
static uint16_t AC5;
|
||||
static uint16_t AC6;
|
||||
|
||||
static int16_t B1;
|
||||
static int16_t B2;
|
||||
|
||||
static int16_t MB;
|
||||
static int16_t MC;
|
||||
static int16_t MD;
|
||||
|
||||
//
|
||||
// Forward declarations
|
||||
//
|
||||
static void bmp180_meassure(const bmp180_command_t* command);
|
||||
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
|
||||
|
||||
// Set default implementation .. User gets result as bmp180_result_t event
|
||||
bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) = bmp180_informUser_Impl;
|
||||
|
||||
// I2C Driver Task
|
||||
static void bmp180_driver_task(void *pvParameters)
|
||||
{
|
||||
// Data to be received from user
|
||||
bmp180_command_t current_command;
|
||||
|
||||
#ifdef BMP180_DEBUG
|
||||
// Wait for commands from the outside
|
||||
printf("%s: Started Task\n", __FUNCTION__);
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
// Wait for user to insert commands
|
||||
if (xQueueReceive(bmp180_rx_queue, ¤t_command, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
#ifdef BMP180_DEBUG
|
||||
printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue);
|
||||
#endif
|
||||
// use user provided queue
|
||||
if (current_command.resultQueue != NULL)
|
||||
{
|
||||
// Work on it ...
|
||||
bmp180_meassure(¤t_command);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t bmp180_readRegister8(uint8_t reg)
|
||||
{
|
||||
uint8_t r = 0;
|
||||
|
||||
if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, &r, 1))
|
||||
{
|
||||
r = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int16_t bmp180_readRegister16(uint8_t reg)
|
||||
{
|
||||
uint8_t d[] = { 0, 0 };
|
||||
int16_t r = 0;
|
||||
|
||||
if (i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2))
|
||||
{
|
||||
r = ((int16_t)d[0]<<8) | (d[1]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static void bmp180_start_Messurement(uint8_t cmd)
|
||||
{
|
||||
uint8_t d[] = { BMP180_CONTROL_REG, cmd };
|
||||
|
||||
i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2);
|
||||
}
|
||||
|
||||
static int16_t bmp180_getUncompensatedMessurement(uint8_t cmd)
|
||||
{
|
||||
// Write Start Code into reg 0xF4 (Currently without oversampling ...)
|
||||
bmp180_start_Messurement((cmd==BMP180_TEMPERATURE)?BMP180_MEASURE_TEMP:BMP180_MEASURE_PRESS_OSS0);
|
||||
|
||||
// Wait 5ms Datasheet states 4.5ms
|
||||
sdk_os_delay_us(BMP180_DEFAULT_CONV_TIME);
|
||||
|
||||
return (int16_t)bmp180_readRegister16(BMP180_OUT_MSB_REG);
|
||||
}
|
||||
|
||||
static void bmp180_fillInternalConstants(void)
|
||||
{
|
||||
AC1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+0);
|
||||
AC2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+2);
|
||||
AC3 = bmp180_readRegister16(BMP180_CALIBRATION_REG+4);
|
||||
AC4 = bmp180_readRegister16(BMP180_CALIBRATION_REG+6);
|
||||
AC5 = bmp180_readRegister16(BMP180_CALIBRATION_REG+8);
|
||||
AC6 = bmp180_readRegister16(BMP180_CALIBRATION_REG+10);
|
||||
|
||||
B1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+12);
|
||||
B2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+14);
|
||||
|
||||
MB = bmp180_readRegister16(BMP180_CALIBRATION_REG+16);
|
||||
MC = bmp180_readRegister16(BMP180_CALIBRATION_REG+18);
|
||||
MD = bmp180_readRegister16(BMP180_CALIBRATION_REG+20);
|
||||
|
||||
#ifdef BMP180_DEBUG
|
||||
printf("%s: AC1:=%d AC2:=%d AC3:=%d AC4:=%u AC5:=%u AC6:=%u \n", __FUNCTION__, AC1, AC2, AC3, AC4, AC5, AC6);
|
||||
printf("%s: B1:=%d B2:=%d\n", __FUNCTION__, B1, B2);
|
||||
printf("%s: MB:=%d MC:=%d MD:=%d\n", __FUNCTION__, MB, MC, MD);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool bmp180_create_communication_queues()
|
||||
{
|
||||
// Just create them once
|
||||
if (bmp180_rx_queue==NULL)
|
||||
{
|
||||
bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
|
||||
}
|
||||
|
||||
return (bmp180_rx_queue!=NULL);
|
||||
}
|
||||
|
||||
static bool bmp180_is_avaialble()
|
||||
{
|
||||
return (bmp180_readRegister8(BMP180_VERSION_REG)==BMP180_CHIP_ID);
|
||||
}
|
||||
|
||||
static bool bmp180_createTask()
|
||||
{
|
||||
// We already have a task
|
||||
portBASE_TYPE x = pdPASS;
|
||||
|
||||
if (bmp180_task_handle==NULL)
|
||||
{
|
||||
x = xTaskCreate(bmp180_driver_task, (signed char *)"bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle);
|
||||
}
|
||||
return (x==pdPASS);
|
||||
}
|
||||
|
||||
static void bmp180_meassure(const bmp180_command_t* command)
|
||||
{
|
||||
int32_t T, P;
|
||||
|
||||
// Init result to 0
|
||||
T = P = 0;
|
||||
|
||||
if (command->resultQueue != NULL)
|
||||
{
|
||||
int32_t UT, X1, X2, B5;
|
||||
|
||||
//
|
||||
// Temperature is always needed ... Also required for pressure only
|
||||
//
|
||||
// Calculation taken from BMP180 Datasheet
|
||||
UT = (int32_t)bmp180_getUncompensatedMessurement(BMP180_TEMPERATURE);
|
||||
|
||||
X1 = (UT - (int32_t)AC6) * ((int32_t)AC5) >> 15;
|
||||
X2 = ((int32_t)MC << 11) / (X1 + (int32_t)MD);
|
||||
B5 = X1 + X2;
|
||||
|
||||
T = (B5 + 8) >> 4;
|
||||
|
||||
#ifdef BMP180_DEBUG
|
||||
printf("%s: T:= %ld.%d\n", __FUNCTION__, T/10, abs(T%10));
|
||||
#endif
|
||||
|
||||
// Do we also need pressure?
|
||||
if (command->cmd & BMP180_PRESSURE)
|
||||
{
|
||||
int32_t X3, B3, B6;
|
||||
uint32_t B4, B7, UP;
|
||||
|
||||
UP = ((uint32_t)bmp180_getUncompensatedMessurement(BMP180_PRESSURE) & 0xFFFF);
|
||||
|
||||
// Calculation taken from BMP180 Datasheet
|
||||
B6 = B5 - 4000;
|
||||
X1 = ((int32_t)B2 * ((B6 * B6) >> 12)) >> 11;
|
||||
X2 = ((int32_t)AC2 * B6) >> 11;
|
||||
X3 = X1 + X2;
|
||||
|
||||
B3 = (((int32_t)AC1 * 4 + X3) + 2) >> 2;
|
||||
X1 = ((int32_t)AC3 * B6) >> 13;
|
||||
X2 = ((int32_t)B1 * ((B6 * B6) >> 12)) >> 16;
|
||||
X3 = ((X1 + X2) + 2) >> 2;
|
||||
B4 = ((uint32_t)AC4 * (uint32_t)(X3 + 32768)) >> 15;
|
||||
B7 = (UP - B3) * (uint32_t)(50000UL);
|
||||
|
||||
if (B7 < 0x80000000)
|
||||
{
|
||||
P = (B7 * 2) / B4;
|
||||
}
|
||||
else
|
||||
{
|
||||
P = (B7 / B4) * 2;
|
||||
}
|
||||
|
||||
X1 = (P >> 8) * (P >> 8);
|
||||
X1 = (X1 * 3038) >> 16;
|
||||
X2 = (-7357 * P) >> 16;
|
||||
P = P + ((X1 + X2 + (int32_t)3791) >> 4);
|
||||
|
||||
#ifdef BMP180_DEBUG
|
||||
printf("%s: P:= %ld\n", __FUNCTION__, P);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Inform the user ...
|
||||
if (!bmp180_informUser(command->resultQueue, command->cmd, ((bmp180_temp_t)T)/10.0, (bmp180_press_t)P))
|
||||
{
|
||||
// Failed to send info to user
|
||||
printf("%s: Unable to inform user bmp180_informUser returned \"false\"\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default user inform implementation
|
||||
static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
|
||||
{
|
||||
bmp180_result_t result;
|
||||
|
||||
result.cmd = cmd;
|
||||
result.temperatue = temperatue;
|
||||
result.pressure = pressure;
|
||||
|
||||
return (xQueueSend(*resultQueue, &result, 0) == pdTRUE);
|
||||
}
|
||||
|
||||
// Just init all needed queues
|
||||
bool bmp180_init(uint8_t scl, uint8_t sda)
|
||||
{
|
||||
// 1. Create required queues
|
||||
bool result = false;
|
||||
|
||||
if (bmp180_create_communication_queues())
|
||||
{
|
||||
// 2. Init i2c driver
|
||||
i2c_init(scl, sda);
|
||||
|
||||
// 3. Check for bmp180 ...
|
||||
if (bmp180_is_avaialble())
|
||||
{
|
||||
// 4. Init all internal constants ...
|
||||
bmp180_fillInternalConstants();
|
||||
|
||||
// 5. Start driver task
|
||||
if (bmp180_createTask())
|
||||
{
|
||||
// We are finished
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void bmp180_trigger_measurement(const xQueueHandle* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
}
|
||||
|
||||
|
||||
void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_PRESSURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
}
|
||||
|
||||
void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue)
|
||||
{
|
||||
bmp180_command_t c;
|
||||
|
||||
c.cmd = BMP180_TEMPERATURE;
|
||||
c.resultQueue = resultQueue;
|
||||
|
||||
xQueueSend(bmp180_rx_queue, &c, 0);
|
||||
}
|
55
extras/bmp180/bmp180.h
Normal file
55
extras/bmp180/bmp180.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* bmp180.h
|
||||
*
|
||||
* Created on: 23.08.2015
|
||||
* Author: fbargste
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_BMP180_H_
|
||||
#define DRIVER_BMP180_H_
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
|
||||
// Uncomment to enable debug output
|
||||
//#define BMP180_DEBUG
|
||||
|
||||
#define BMP180_TEMPERATURE (1<<0)
|
||||
#define BMP180_PRESSURE (1<<1)
|
||||
|
||||
//
|
||||
// Create bmp180_types
|
||||
//
|
||||
|
||||
// temperature in °C
|
||||
typedef float bmp180_temp_t;
|
||||
// pressure in mPa (To get hPa divide by 100)
|
||||
typedef uint32_t bmp180_press_t;
|
||||
|
||||
// BMP180_Event_Result
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cmd;
|
||||
bmp180_temp_t temperatue;
|
||||
bmp180_press_t pressure;
|
||||
} bmp180_result_t;
|
||||
|
||||
// Init bmp180 driver ...
|
||||
bool bmp180_init(uint8_t scl, uint8_t sda);
|
||||
|
||||
// Trigger a "complete" measurement (temperature and pressure will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_measurement(const xQueueHandle* resultQueue);
|
||||
|
||||
// Trigger a "temperature only" measurement (only temperature will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue);
|
||||
|
||||
// Trigger a "pressure only" measurement (only pressure will be valid when given to "bmp180_informUser)
|
||||
void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue);
|
||||
|
||||
// Give the user the chance to create it's own handler
|
||||
extern bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
|
||||
|
||||
#endif /* DRIVER_BMP180_H_ */
|
9
extras/bmp180/component.mk
Normal file
9
extras/bmp180/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/bmp180
|
||||
|
||||
INC_DIRS += $(ROOT)extras
|
||||
|
||||
# args for passing into compile rule generation
|
||||
extras/bmp180_INC_DIR = $(ROOT)extras
|
||||
extras/bmp180_SRC_DIR = $(ROOT)extras/bmp180
|
||||
|
||||
$(eval $(call component_compile_rules,extras/bmp180))
|
22
extras/i2c/LICENSE
Normal file
22
extras/i2c/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Johan Kanflo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
40
extras/i2c/README.md
Normal file
40
extras/i2c/README.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Yet another I2C driver for the ESP8266
|
||||
|
||||
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
|
||||
|
||||
### Adding to your project
|
||||
|
||||
Add the driver to your project as a submodule rather than cloning it:
|
||||
|
||||
````
|
||||
% git submodule add https://github.com/kanflo/esp-open-rtos-driver-i2c.git i2c
|
||||
````
|
||||
The esp-open-rtos makefile-fu will make sure the driver is built.
|
||||
|
||||
### Usage
|
||||
|
||||
|
||||
````
|
||||
#include <i2c.h>
|
||||
|
||||
#define SCL_PIN (0)
|
||||
#define SDA_PIN (2)
|
||||
|
||||
uint8_t slave_addr = 0x20;
|
||||
uint8_t reg_addr = 0x1f;
|
||||
uint8_t reg_data;
|
||||
uint8_t data[] = {reg_addr, 0xc8};
|
||||
|
||||
i2c_init(SCL_PIN, SDA_PIN);
|
||||
|
||||
// Write data to slave
|
||||
bool success = i2c_slave_write(slave_addr, data, sizeof(data));
|
||||
|
||||
// Issue write to slave, sending reg_addr, followed by reading 1 byte
|
||||
success = i2c_slave_read(slave_addr, ®_addr, reg_data, 1);
|
||||
|
||||
````
|
||||
|
||||
The driver is released under the MIT license.
|
||||
|
||||
[1] https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
9
extras/i2c/component.mk
Normal file
9
extras/i2c/component.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Component makefile for extras/i2c
|
||||
|
||||
INC_DIRS += $(ROOT)extras
|
||||
|
||||
# args for passing into compile rule generation
|
||||
extras/i2c_INC_DIR = $(ROOT)extras
|
||||
extras/i2c_SRC_DIR = $(ROOT)extras/i2c
|
||||
|
||||
$(eval $(call component_compile_rules,extras/i2c))
|
229
extras/i2c/i2c.c
Normal file
229
extras/i2c/i2c.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <esp8266.h>
|
||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||
#include "i2c.h"
|
||||
|
||||
|
||||
// I2C driver for ESP8266 written for use with esp-open-rtos
|
||||
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||
|
||||
// With calling overhead, we end up at ~100kbit/s
|
||||
#define CLK_HALF_PERIOD_US (1)
|
||||
|
||||
#define CLK_STRETCH (10)
|
||||
|
||||
static bool started;
|
||||
static uint8_t g_scl_pin;
|
||||
static uint8_t g_sda_pin;
|
||||
|
||||
void i2c_init(uint8_t scl_pin, uint8_t sda_pin)
|
||||
{
|
||||
started = false;
|
||||
g_scl_pin = scl_pin;
|
||||
g_sda_pin = sda_pin;
|
||||
}
|
||||
|
||||
static void i2c_delay(void)
|
||||
{
|
||||
sdk_os_delay_us(CLK_HALF_PERIOD_US);
|
||||
}
|
||||
|
||||
// Set SCL as input and return current level of line, 0 or 1
|
||||
static bool read_scl(void)
|
||||
{
|
||||
gpio_enable(g_scl_pin, GPIO_INPUT);
|
||||
return gpio_read(g_scl_pin); // Clock high, valid ACK
|
||||
}
|
||||
|
||||
// Set SDA as input and return current level of line, 0 or 1
|
||||
static bool read_sda(void)
|
||||
{
|
||||
gpio_enable(g_sda_pin, GPIO_INPUT);
|
||||
// TODO: Without this delay we get arbitration lost in i2c_stop
|
||||
i2c_delay();
|
||||
return gpio_read(g_sda_pin); // Clock high, valid ACK
|
||||
}
|
||||
|
||||
// Actively drive SCL signal low
|
||||
static void clear_scl(void)
|
||||
{
|
||||
gpio_enable(g_scl_pin, GPIO_OUTPUT);
|
||||
gpio_write(g_scl_pin, 0);
|
||||
}
|
||||
|
||||
// Actively drive SDA signal low
|
||||
static void clear_sda(void)
|
||||
{
|
||||
gpio_enable(g_sda_pin, GPIO_OUTPUT);
|
||||
gpio_write(g_sda_pin, 0);
|
||||
}
|
||||
|
||||
// Output start condition
|
||||
void i2c_start(void)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
if (started) { // if started, do a restart cond
|
||||
// Set SDA to 1
|
||||
(void) read_sda();
|
||||
i2c_delay();
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
// Repeated start setup time, minimum 4.7us
|
||||
i2c_delay();
|
||||
}
|
||||
if (read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_start\n");
|
||||
}
|
||||
// SCL is high, set SDA from 1 to 0.
|
||||
clear_sda();
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
started = true;
|
||||
}
|
||||
|
||||
// Output stop condition
|
||||
void i2c_stop(void)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
// Set SDA to 0
|
||||
clear_sda();
|
||||
i2c_delay();
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
// Stop bit setup time, minimum 4us
|
||||
i2c_delay();
|
||||
// SCL is high, set SDA from 0 to 1
|
||||
if (read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_stop\n");
|
||||
}
|
||||
i2c_delay();
|
||||
started = false;
|
||||
}
|
||||
|
||||
// Write a bit to I2C bus
|
||||
static void i2c_write_bit(bool bit)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
if (bit) {
|
||||
(void) read_sda();
|
||||
} else {
|
||||
clear_sda();
|
||||
}
|
||||
i2c_delay();
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
// SCL is high, now data is valid
|
||||
// If SDA is high, check that nobody else is driving SDA
|
||||
if (bit && read_sda() == 0) {
|
||||
printf("I2C: arbitration lost in i2c_write_bit\n");
|
||||
}
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
}
|
||||
|
||||
// Read a bit from I2C bus
|
||||
static bool i2c_read_bit(void)
|
||||
{
|
||||
uint32_t clk_stretch = CLK_STRETCH;
|
||||
bool bit;
|
||||
// Let the slave drive data
|
||||
(void) read_sda();
|
||||
i2c_delay();
|
||||
// Clock stretching
|
||||
while (read_scl() == 0 && clk_stretch--) ;
|
||||
// SCL is high, now data is valid
|
||||
bit = read_sda();
|
||||
i2c_delay();
|
||||
clear_scl();
|
||||
return bit;
|
||||
}
|
||||
|
||||
bool i2c_write(uint8_t byte)
|
||||
{
|
||||
bool nack;
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
i2c_write_bit((byte & 0x80) != 0);
|
||||
byte <<= 1;
|
||||
}
|
||||
nack = i2c_read_bit();
|
||||
return !nack;
|
||||
}
|
||||
|
||||
uint8_t i2c_read(bool ack)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
byte = (byte << 1) | i2c_read_bit();
|
||||
}
|
||||
i2c_write_bit(ack);
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool i2c_slave_write(uint8_t slave_addr, uint8_t *data, uint8_t len)
|
||||
{
|
||||
bool success = false;
|
||||
do {
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1))
|
||||
break;
|
||||
while (len--) {
|
||||
if (!i2c_write(*data++))
|
||||
break;
|
||||
}
|
||||
i2c_stop();
|
||||
success = true;
|
||||
} while(0);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
bool success = false;
|
||||
do {
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1)) {
|
||||
break;
|
||||
}
|
||||
i2c_write(data);
|
||||
i2c_stop();
|
||||
i2c_start();
|
||||
if (!i2c_write(slave_addr << 1 | 1)) { // Slave address + read
|
||||
break;
|
||||
}
|
||||
while(len) {
|
||||
*buf = i2c_read(len == 1);
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
success = true;
|
||||
} while(0);
|
||||
i2c_stop();
|
||||
if (!success) {
|
||||
printf("I2C: write error\n");
|
||||
}
|
||||
return success;
|
||||
}
|
51
extras/i2c/i2c.h
Normal file
51
extras/i2c/i2c.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Init bitbanging I2C driver on given pins
|
||||
void i2c_init(uint8_t scl_pin, uint8_t sda_pin);
|
||||
|
||||
// Write a byte to I2C bus. Return true if slave acked.
|
||||
bool i2c_write(uint8_t byte);
|
||||
|
||||
// Read a byte from I2C bus. Return true if slave acked.
|
||||
uint8_t i2c_read(bool ack);
|
||||
|
||||
// Write 'len' bytes from 'buf' to slave. Return true if slave acked.
|
||||
bool i2c_slave_write(uint8_t slave_addr, uint8_t *buf, uint8_t len);
|
||||
|
||||
// Issue a read operation and send 'data', followed by reading 'len' bytes
|
||||
// from slave into 'buf'. Return true if slave acked.
|
||||
bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len);
|
||||
|
||||
// Send start and stop conditions. Only needed when implementing protocols for
|
||||
// devices where the i2c_slave_[read|write] functions above are of no use.
|
||||
void i2c_start(void);
|
||||
void i2c_stop(void);
|
Loading…
Reference in a new issue