commit
7e30f48650
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