semaphore for SPI bus access removed from the driver, the user has to deal with concurrency

This commit is contained in:
Gunar Schorcht 2018-01-06 15:41:03 +01:00
parent 29735aa7c4
commit 1dbe9e46c4
4 changed files with 80 additions and 74 deletions

View file

@ -13,7 +13,7 @@
* | GPIO 14 (SCL) ----> SCL | * | GPIO 14 (SCL) ----> SCL |
* | GPIO 13 (SDA) <---> SDA | * | GPIO 13 (SDA) <---> SDA |
* | GPIO 5 <---- INT1 | * | GPIO 5 <---- INT1 |
* | GPIO 4 <---- INT2 | * | GPIO 4 <---- INT2 |
* +-----------------+ +----------+ * +-----------------+ +----------+
* *
* SPI * SPI
@ -289,17 +289,12 @@ void user_init(void)
if (sensor) if (sensor)
{ {
// --- SYSTEM CONFIGURATION PART ---- #ifdef INT_USED
#if !defined (INT_USED) /** --- INTERRUPT CONFIGURATION PART ---- */
// create a user task that fetches data from sensor periodically // Interrupt configuration has to be done before the sensor is set
xTaskCreate(user_task_periodic, "user_task_periodic", TASK_STACK_DEPTH, NULL, 2, NULL); // into measurement mode to avoid losing interrupts
#else // INT_USED
// create a task that is triggered only in case of interrupts to fetch the data
xTaskCreate(user_task_interrupt, "user_task_interrupt", TASK_STACK_DEPTH, NULL, 2, NULL);
// create an event queue to send interrupt events from interrupt // create an event queue to send interrupt events from interrupt
// handler to the interrupt task // handler to the interrupt task
@ -311,12 +306,9 @@ void user_init(void)
gpio_set_interrupt(INT1_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler); gpio_set_interrupt(INT1_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler);
gpio_set_interrupt(INT2_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler); gpio_set_interrupt(INT2_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler);
#endif // !defined(INT_USED) #endif // INT_USED
// -- SENSOR CONFIGURATION PART --- /** -- SENSOR CONFIGURATION PART --- */
// Interrupt configuration has to be done before the sensor is set
// into measurement mode
// set the type of INTx signals if necessary // set the type of INTx signals if necessary
// lsm303d_config_int_signals (sensor, lsm303d_push_pull); // lsm303d_config_int_signals (sensor, lsm303d_push_pull);
@ -417,7 +409,24 @@ void user_init(void)
lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true); lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true);
lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous); lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous);
// -- SENSOR CONFIGURATION PART --- /** -- TASK CREATION PART --- */
// must be done last to avoid concurrency situations with the sensor
// configuration part
#ifdef INT_USED
// create a task that is triggered only in case of interrupts to fetch the data
xTaskCreate(user_task_interrupt, "user_task_interrupt", TASK_STACK_DEPTH, NULL, 2, NULL);
#else // INT_USED
// create a user task that fetches data from sensor periodically
xTaskCreate(user_task_periodic, "user_task_periodic", TASK_STACK_DEPTH, NULL, 2, NULL);
#endif
} }
else
printf("Could not initialize LSM303D sensor\n");
} }

View file

@ -596,7 +596,7 @@ If SPI interface is used, configuration for ESP8266 and ESP32 could look like fo
| GPIO 12 (MISO)<------ SDO | | GPIO 18 (MISO)<------ SDO | | GPIO 12 (MISO)<------ SDO | | GPIO 18 (MISO)<------ SDO |
| GPIO 2 (CS) ------> CS | | GPIO 19 (CS) ------> CS | | GPIO 2 (CS) ------> CS | | GPIO 19 (CS) ------> CS |
| GPIO 5 <------ INT1 | | GPIO 5 <------ INT1 | | GPIO 5 <------ INT1 | | GPIO 5 <------ INT1 |
| GPIO 4 <------ INT2 | | GPIO 5 <------ INT2 | | GPIO 4 <------ INT2 | | GPIO 4 <------ INT2 |
+-----------------+ +----------+ +-----------------+ +----------+ +-----------------+ +----------+ +-----------------+ +----------+
``` ```
@ -682,9 +682,29 @@ sensor = lsm303d_init_sensor (SPI_BUS, 0, SPI_CS_GPIO);
The remaining of the program is independent on the communication interface. The remaining of the program is independent on the communication interface.
#### Configuring the sensor
Optionally, you could wish to set some measurement parameters. For details see the sections above, the header file of the driver ```lsm303d.h```, and of course the data sheet of the sensor.
#### Starting measurements
As last step, the sensor mode has be set to start periodic measurement. The sensor mode can be changed anytime later.
```
...
// start periodic measurement with output data rate of 12.5 Hz
lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true);
lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous);
...
```
#### Periodic user task #### Periodic user task
If initialization of the sensor was successful, the user task that uses the sensor has to be created. The user task can use different approaches to fetch new data. Either new data are fetched periodically or interrupt signals are used when new data are available or a configured event happens. Finally, a user task that uses the sensor has to be created.
**Please note:** To avoid concurrency situations when driver functions are used to access the sensor, for example to read data, the user task must not be created until the sensor configuration is completed.
The user task can use different approaches to fetch new data. Either new data are fetched periodically or interrupt signals are used when new data are available or a configured event happens.
If new data are fetched **periodically** the implementation of the user task is quite simple and could look like following. If new data are fetched **periodically** the implementation of the user task is quite simple and could look like following.
@ -790,22 +810,6 @@ gpio_set_interrupt(INT2_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler);
Furthermore, the interrupts have to be enabled and configured in the LSM303D sensor, see section **Interrupts** above. Furthermore, the interrupts have to be enabled and configured in the LSM303D sensor, see section **Interrupts** above.
#### Configuring the sensor
Optionally, you could wish to set some measurement parameters. For details see the sections above, the header file of the driver ```lsm303d.h```, and of course the data sheet of the sensor.
#### Starting measurements
As last step, the sensor mode has be set to start periodic measurement. The sensor mode can be changed anytime later.
```
...
// start periodic measurement with output data rate of 12.5 Hz
lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true);
lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous);
...
```
## Full Example ## Full Example
``` ```
@ -917,8 +921,6 @@ void read_data ()
(double)sdk_system_get_time()*1e-3, (double)sdk_system_get_time()*1e-3,
m_data.mx, m_data.my, m_data.mz); m_data.mx, m_data.my, m_data.mz);
lsm303d_raw_m_data_t m_data;
#ifdef TEMP_USED #ifdef TEMP_USED
float temp = lsm303d_get_temperature (sensor); float temp = lsm303d_get_temperature (sensor);
@ -958,11 +960,14 @@ void user_task_interrupt (void *pvParameters)
// get the source of the interrupt that reset *INTx* signals // get the source of the interrupt that reset *INTx* signals
#ifdef INT_DATA #ifdef INT_DATA
lsm303d_get_int_data_source (sensor, &data_src); lsm303d_get_int_data_source (sensor, &data_src);
#elif INT_THRESH #endif
#ifdef INT_THRESH
lsm303d_get_int_m_thresh_source(sensor, &thresh_src); lsm303d_get_int_m_thresh_source(sensor, &thresh_src);
#elif INT_EVENT #endif
#ifdef INT_EVENT
lsm303d_get_int_event_source (sensor, &event_src, lsm303d_int_event1_gen); lsm303d_get_int_event_source (sensor, &event_src, lsm303d_int_event1_gen);
#elif INT_CLICK #endif
#ifdef INT_CLICK
lsm303d_get_int_click_source (sensor, &click_src); lsm303d_get_int_click_source (sensor, &click_src);
#endif #endif
@ -1067,17 +1072,12 @@ void user_init(void)
if (sensor) if (sensor)
{ {
// --- SYSTEM CONFIGURATION PART ---- #ifdef INT_USED
#if !defined (INT_USED) /** --- INTERRUPT CONFIGURATION PART ---- */
// create a user task that fetches data from sensor periodically // Interrupt configuration has to be done before the sensor is set
xTaskCreate(user_task_periodic, "user_task_periodic", TASK_STACK_DEPTH, NULL, 2, NULL); // into measurement mode to avoid losing interrupts
#else // INT_USED
// create a task that is triggered only in case of interrupts to fetch the data
xTaskCreate(user_task_interrupt, "user_task_interrupt", TASK_STACK_DEPTH, NULL, 2, NULL);
// create an event queue to send interrupt events from interrupt // create an event queue to send interrupt events from interrupt
// handler to the interrupt task // handler to the interrupt task
@ -1089,12 +1089,9 @@ void user_init(void)
gpio_set_interrupt(INT1_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler); gpio_set_interrupt(INT1_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler);
gpio_set_interrupt(INT2_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler); gpio_set_interrupt(INT2_PIN, GPIO_INTTYPE_EDGE_POS, int_signal_handler);
#endif // !defined(INT_USED) #endif // INT_USED
// -- SENSOR CONFIGURATION PART --- /** -- SENSOR CONFIGURATION PART --- */
// Interrupt configuration has to be done before the sensor is set
// into measurement mode
// set the type of INTx signals if necessary // set the type of INTx signals if necessary
// lsm303d_config_int_signals (sensor, lsm303d_push_pull); // lsm303d_config_int_signals (sensor, lsm303d_push_pull);
@ -1195,7 +1192,25 @@ void user_init(void)
lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true); lsm303d_set_a_mode (sensor, lsm303d_a_odr_12_5, lsm303d_a_aaf_bw_773, true, true, true);
lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous); lsm303d_set_m_mode (sensor, lsm303d_m_odr_12_5, lsm303d_m_low_res, lsm303d_m_continuous);
// -- SENSOR CONFIGURATION PART --- /** -- TASK CREATION PART --- */
// must be done last to avoid concurrency situations with the sensor
// configuration part
#ifdef INT_USED
// create a task that is triggered only in case of interrupts to fetch the data
xTaskCreate(user_task_interrupt, "user_task_interrupt", TASK_STACK_DEPTH, NULL, 2, NULL);
#else // INT_USED
// create a user task that fetches data from sensor periodically
xTaskCreate(user_task_periodic, "user_task_periodic", TASK_STACK_DEPTH, NULL, 2, NULL);
#endif
} }
else
printf("Could not initialize LSM303D sensor\n");
} }
``` ```

View file

@ -397,8 +397,6 @@ lsm303d_sensor_t* lsm303d_init_sensor (uint8_t bus, uint8_t addr, uint8_t cs)
free (dev); free (dev);
return NULL; return NULL;
} }
if (!addr)
spi_semaphore_init(dev);
// check availability of the sensor // check availability of the sensor
if (!lsm303d_is_available (dev)) if (!lsm303d_is_available (dev))
@ -1556,8 +1554,6 @@ static bool lsm303d_spi_read(lsm303d_sensor_t* dev, uint8_t reg, uint8_t *data,
uint8_t addr = (reg & 0x3f) | LSM303D_SPI_READ_FLAG | LSM303D_SPI_AUTO_INC_FLAG; uint8_t addr = (reg & 0x3f) | LSM303D_SPI_READ_FLAG | LSM303D_SPI_AUTO_INC_FLAG;
spi_semaphore_take (dev);
static uint8_t mosi[LSM303D_SPI_BUF_SIZE]; static uint8_t mosi[LSM303D_SPI_BUF_SIZE];
static uint8_t miso[LSM303D_SPI_BUF_SIZE]; static uint8_t miso[LSM303D_SPI_BUF_SIZE];
@ -1568,7 +1564,6 @@ static bool lsm303d_spi_read(lsm303d_sensor_t* dev, uint8_t reg, uint8_t *data,
if (!spi_transfer_pf (dev->bus, dev->cs, mosi, miso, len+1)) if (!spi_transfer_pf (dev->bus, dev->cs, mosi, miso, len+1))
{ {
spi_semaphore_give (dev);
error_dev ("Could not read data from SPI", __FUNCTION__, dev); error_dev ("Could not read data from SPI", __FUNCTION__, dev);
dev->error_code |= LSM303D_SPI_READ_FAILED; dev->error_code |= LSM303D_SPI_READ_FAILED;
return false; return false;
@ -1578,8 +1573,6 @@ static bool lsm303d_spi_read(lsm303d_sensor_t* dev, uint8_t reg, uint8_t *data,
for (int i=0; i < len; i++) for (int i=0; i < len; i++)
data[i] = miso[i+1]; data[i] = miso[i+1];
spi_semaphore_give (dev);
#ifdef LSM303D_DEBUG_LEVEL_2 #ifdef LSM303D_DEBUG_LEVEL_2
printf("LSM303D %s: read the following bytes from reg %02x: ", __FUNCTION__, reg); printf("LSM303D %s: read the following bytes from reg %02x: ", __FUNCTION__, reg);
for (int i=0; i < len; i++) for (int i=0; i < len; i++)
@ -1609,8 +1602,6 @@ static bool lsm303d_spi_write(lsm303d_sensor_t* dev, uint8_t reg, uint8_t *data,
return false; return false;
} }
spi_semaphore_take (dev);
reg &= 0x7f; reg &= 0x7f;
// first byte in output is the register address // first byte in output is the register address
@ -1629,14 +1620,11 @@ static bool lsm303d_spi_write(lsm303d_sensor_t* dev, uint8_t reg, uint8_t *data,
if (!spi_transfer_pf (dev->bus, dev->cs, mosi, NULL, len+1)) if (!spi_transfer_pf (dev->bus, dev->cs, mosi, NULL, len+1))
{ {
spi_semaphore_give (dev);
error_dev ("Could not write data to SPI.", __FUNCTION__, dev); error_dev ("Could not write data to SPI.", __FUNCTION__, dev);
dev->error_code |= LSM303D_SPI_WRITE_FAILED; dev->error_code |= LSM303D_SPI_WRITE_FAILED;
return false; return false;
} }
spi_semaphore_give (dev);
return true; return true;
} }

View file

@ -67,12 +67,6 @@
#include "esp/spi.h" #include "esp/spi.h"
#include "i2c/i2c.h" #include "i2c/i2c.h"
// platform specific definitions
#define spi_semaphore_init(d)
#define spi_semaphore_take(d)
#define spi_semaphore_give(d)
// platform specific SPI functions // platform specific SPI functions
#define spi_bus_init(bus,sck,miso,mosi) // not needed on ESP8266 #define spi_bus_init(bus,sck,miso,mosi) // not needed on ESP8266