diff --git a/conf/modules/encoder_amt22.xml b/conf/modules/encoder_amt22.xml
new file mode 100644
index 0000000000..83811448be
--- /dev/null
+++ b/conf/modules/encoder_amt22.xml
@@ -0,0 +1,33 @@
+
+
+
+ Driver for AMT22 encoder from CUI devices.
+
+
+ spi_master
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/modules/humid_sht_i2c.xml b/conf/modules/humid_sht_i2c.xml
index a956442058..c2b1c9ff7e 100644
--- a/conf/modules/humid_sht_i2c.xml
+++ b/conf/modules/humid_sht_i2c.xml
@@ -3,18 +3,14 @@
Sensirion SHT25 humidity sensor (I2C)
-
+
-
-
-
-
diff --git a/sw/airborne/arch/chibios/mcu_periph/i2c_arch.c b/sw/airborne/arch/chibios/mcu_periph/i2c_arch.c
index 23eb7d6fdb..7bba45ecd5 100644
--- a/sw/airborne/arch/chibios/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/chibios/mcu_periph/i2c_arch.c
@@ -235,6 +235,7 @@ static void handle_i2c_thd(struct i2c_periph *p)
}
i2cReleaseBus((I2CDriver *)p->reg_addr);
+ pprz_bsem_signal(&t->bsem);
}
/**
@@ -440,6 +441,7 @@ static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
p->trans_insert_idx = temp;
chSysUnlock();
+ pprz_bsem_init(&t->bsem, true);
chSemSignal(&((struct i2c_init *)p->init_struct)->sem);
// transaction submitted
return TRUE;
diff --git a/sw/airborne/arch/chibios/mcu_periph/spi_arch.c b/sw/airborne/arch/chibios/mcu_periph/spi_arch.c
index 1c75dd53d2..c6e26d5676 100644
--- a/sw/airborne/arch/chibios/mcu_periph/spi_arch.c
+++ b/sw/airborne/arch/chibios/mcu_periph/spi_arch.c
@@ -389,6 +389,7 @@ static void handle_spi_thd(struct spi_periph *p)
t->after_cb(t);
}
+ pprz_bsem_signal(&t->bsem);
}
/**
@@ -552,6 +553,7 @@ bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
p->trans_insert_idx = idx;
chSysUnlock();
+ pprz_bsem_init(&t->bsem, true);
chSemSignal(&((struct spi_init *)p->init_struct)->sem);
// transaction submitted
return TRUE;
diff --git a/sw/airborne/arch/chibios/modules/core/threads_arch.c b/sw/airborne/arch/chibios/modules/core/threads_arch.c
index ddd093e674..57811c5cf0 100644
--- a/sw/airborne/arch/chibios/modules/core/threads_arch.c
+++ b/sw/airborne/arch/chibios/modules/core/threads_arch.c
@@ -44,6 +44,16 @@ void pprz_bsem_wait(pprz_bsem_t* bsem) {
chBSemWait(&bsem->bsem);
}
+int pprz_bsem_wait_timeout(pprz_bsem_t* bsem, float timeout) {
+ sysinterval_t chtimeout;
+ if(timeout < 0.002) {
+ chtimeout = chTimeUS2I(timeout*1e6);
+ } else {
+ chtimeout = chTimeMS2I(timeout*1e3);
+ }
+ return chBSemWaitTimeout(&bsem->bsem, chtimeout);
+}
+
void pprz_bsem_signal(pprz_bsem_t* bsem) {
chBSemSignal(&bsem->bsem);
}
diff --git a/sw/airborne/arch/linux/mcu_periph/i2c_arch.c b/sw/airborne/arch/linux/mcu_periph/i2c_arch.c
index 706a05ace3..41774e7735 100644
--- a/sw/airborne/arch/linux/mcu_periph/i2c_arch.c
+++ b/sw/airborne/arch/linux/mcu_periph/i2c_arch.c
@@ -104,6 +104,7 @@ static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t)
p->trans[p->trans_insert_idx] = t;
p->trans_insert_idx = next_idx;
+ pprz_bsem_init(&t->bsem, true);
/* wake handler thread */
pthread_cond_signal(condition);
pthread_mutex_unlock(mutex);
@@ -199,6 +200,7 @@ static void *i2c_thread(void *data)
pthread_mutex_lock(mutex);
p->trans_extract_idx = (p->trans_extract_idx + 1) % I2C_TRANSACTION_QUEUE_LEN;
pthread_mutex_unlock(mutex);
+ pprz_bsem_signal(&t->bsem);
}
return NULL;
}
diff --git a/sw/airborne/arch/linux/modules/core/threads_arch.c b/sw/airborne/arch/linux/modules/core/threads_arch.c
index a4c1e22de7..e5d14975f3 100644
--- a/sw/airborne/arch/linux/modules/core/threads_arch.c
+++ b/sw/airborne/arch/linux/modules/core/threads_arch.c
@@ -15,6 +15,7 @@
#include "stdbool.h"
#include
#include
+#include
int pprz_mtx_init(pprz_mutex_t* mtx) {
@@ -44,6 +45,16 @@ void pprz_bsem_wait(pprz_bsem_t* bsem) {
sem_wait(&bsem->sem);
}
+int pprz_bsem_wait_timeout(pprz_bsem_t* bsem, float timeout) {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ time_t timeout_secs = (time_t)timeout;
+ long timeout_nsecs = (timeout - timeout_secs) * 1e9;
+ ts.tv_sec += timeout_secs;
+ ts.tv_nsec += timeout_nsecs;
+ return sem_timedwait(&bsem->sem, &ts);
+}
+
void pprz_bsem_signal(pprz_bsem_t* bsem) {
int val;
pthread_mutex_lock(&bsem->mtx);
diff --git a/sw/airborne/arch/stm32/modules/core/threads_arch.c b/sw/airborne/arch/stm32/modules/core/threads_arch.c
index fab9ba91a8..ba9a02cc66 100644
--- a/sw/airborne/arch/stm32/modules/core/threads_arch.c
+++ b/sw/airborne/arch/stm32/modules/core/threads_arch.c
@@ -51,6 +51,18 @@ void pprz_bsem_wait(pprz_bsem_t* bsem) {
bsem->value = 0;
}
+int pprz_bsem_wait_timeout(pprz_bsem_t* bsem, float timeout) {
+ float time_end = get_sys_time_float() + timeout;
+ while(get_sys_time_float() - time_end > 0) {
+ // active wait
+ if(bsem->value) {
+ bsem->value = 0;
+ return 0;
+ }
+ }
+ return -1;
+}
+
void pprz_bsem_signal(pprz_bsem_t* bsem) {
bsem->value = 1;
}
diff --git a/sw/airborne/boards/bebop/actuators.c b/sw/airborne/boards/bebop/actuators.c
index d1eae6e314..08c2422232 100644
--- a/sw/airborne/boards/bebop/actuators.c
+++ b/sw/airborne/boards/bebop/actuators.c
@@ -74,7 +74,7 @@ void actuators_bebop_commit(void)
{
// Receive the status
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_GET_OBS_DATA;
- i2c_blocking_transceive(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1, 13);
+ i2c_blocking_transceive(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1, 13, 0.5);
// Update status
electrical.vsupply = (float)(actuators_bebop.i2c_trans.buf[9] + (actuators_bebop.i2c_trans.buf[8] << 8)) / 1000.f;
@@ -94,7 +94,7 @@ void actuators_bebop_commit(void)
if (actuators_bebop.i2c_trans.buf[10] != 4 && actuators_bebop.i2c_trans.buf[10] != 2 && autopilot_get_motors_on()) {
// Reset the error
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_CLEAR_ERROR;
- i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1);
+ i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1, 0.5);
// Start the motors
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_START_PROP;
@@ -104,12 +104,12 @@ void actuators_bebop_commit(void)
#else
actuators_bebop.i2c_trans.buf[1] = 0b00000101;
#endif
- i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 2);
+ i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 2, 0.5);
}
// Stop the motors
else if (actuators_bebop.i2c_trans.buf[10] == 4 && !autopilot_get_motors_on()) {
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_STOP_PROP;
- i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1);
+ i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 1, 0.5);
} else if (actuators_bebop.i2c_trans.buf[10] == 4 && autopilot_get_motors_on()) {
// Send the commands
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_SET_REF_SPEED;
@@ -126,14 +126,14 @@ void actuators_bebop_commit(void)
#pragma GCC diagnostic ignored "-Wcast-qual"
actuators_bebop.i2c_trans.buf[10] = actuators_bebop_checksum((uint8_t *)actuators_bebop.i2c_trans.buf, 9);
#pragma GCC diagnostic pop
- i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 11);
+ i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 11, 0.5);
}
// Update the LEDs
if (actuators_bebop.led != (led_hw_values & 0x3)) {
actuators_bebop.i2c_trans.buf[0] = ACTUATORS_BEBOP_TOGGLE_GPIO;
actuators_bebop.i2c_trans.buf[1] = (led_hw_values & 0x3);
- i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 2);
+ i2c_blocking_transmit(&i2c1, &actuators_bebop.i2c_trans, actuators_bebop.i2c_trans.slave_addr, 2, 0.5);
actuators_bebop.led = led_hw_values & 0x3;
}
diff --git a/sw/airborne/boards/bebop/mt9f002.c b/sw/airborne/boards/bebop/mt9f002.c
index a0744a3409..9f2a6f469c 100644
--- a/sw/airborne/boards/bebop/mt9f002.c
+++ b/sw/airborne/boards/bebop/mt9f002.c
@@ -194,7 +194,7 @@ static void write_reg(struct mt9f002_t *mt, uint16_t addr, uint32_t val, uint8_t
}
// Transmit the buffer
- i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, MT9F002_ADDRESS, len + 2);
+ i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, MT9F002_ADDRESS, len + 2, 0.5);
}
/**
@@ -207,7 +207,7 @@ static uint32_t read_reg(struct mt9f002_t *mt, uint16_t addr, uint8_t len)
mt->i2c_trans.buf[1] = addr & 0xFF;
// Transmit the buffer and receive back
- i2c_blocking_transceive(mt->i2c_periph, &mt->i2c_trans, MT9F002_ADDRESS, 2, len);
+ i2c_blocking_transceive(mt->i2c_periph, &mt->i2c_trans, MT9F002_ADDRESS, 2, len, 0.5);
/* Fix signdness */
for (uint8_t i = 0; i < len; i++) {
diff --git a/sw/airborne/boards/bebop/mt9v117.c b/sw/airborne/boards/bebop/mt9v117.c
index 0d2d8a5a3a..46ab8804d5 100644
--- a/sw/airborne/boards/bebop/mt9v117.c
+++ b/sw/airborne/boards/bebop/mt9v117.c
@@ -231,7 +231,7 @@ static void write_reg(struct mt9v117_t *mt, uint16_t addr, uint32_t val, uint16_
}
// Transmit the buffer
- i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, MT9V117_ADDRESS, len + 2);
+ i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, MT9V117_ADDRESS, len + 2, 0.5);
}
/**
@@ -244,7 +244,7 @@ static uint32_t read_reg(struct mt9v117_t *mt, uint16_t addr, uint16_t len)
mt->i2c_trans.buf[1] = addr & 0xFF;
// Transmit the buffer and receive back
- i2c_blocking_transceive(mt->i2c_periph, &mt->i2c_trans, MT9V117_ADDRESS, 2, len);
+ i2c_blocking_transceive(mt->i2c_periph, &mt->i2c_trans, MT9V117_ADDRESS, 2, len, 0.5);
/* Fix sigdness */
for (uint8_t i = 0; i < len; i++) {
@@ -302,7 +302,7 @@ static inline void mt9v117_write_patch(struct mt9v117_t *mt)
}
// Transmit the buffer
- i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, mt->i2c_trans.slave_addr, mt9v117_patch_lines[i].len);
+ i2c_blocking_transmit(mt->i2c_periph, &mt->i2c_trans, mt->i2c_trans.slave_addr, mt9v117_patch_lines[i].len, 0.5);
}
write_reg(mt, MT9V117_LOGICAL_ADDRESS_ACCESS, 0x0000, 2);
diff --git a/sw/airborne/boards/disco/actuators.c b/sw/airborne/boards/disco/actuators.c
index 47db6d574a..45b4cc850a 100644
--- a/sw/airborne/boards/disco/actuators.c
+++ b/sw/airborne/boards/disco/actuators.c
@@ -119,7 +119,7 @@ void actuators_disco_commit(void)
// Receive the status
actuators_disco.i2c_trans.buf[0] = ACTUATORS_DISCO_GET_OBS_DATA;
- i2c_blocking_transceive(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1, sizeof(obs_data));
+ i2c_blocking_transceive(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1, sizeof(obs_data), 0.5);
// copy data from buffer
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
@@ -149,17 +149,17 @@ void actuators_disco_commit(void)
actuators_disco.motor_rpm > DISCO_BLDC_START_MOTOR_THRESHOLD) {
// Reset the error
actuators_disco.i2c_trans.buf[0] = ACTUATORS_DISCO_CLEAR_ERROR;
- i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1);
+ i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1, 0.5);
// Start the motors
actuators_disco.i2c_trans.buf[0] = ACTUATORS_DISCO_START_PROP;
- i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1);
+ i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1, 0.5);
}
// Stop the motors
else if ((bldc_status == DISCO_BLDC_STATUS_RUNNING || bldc_status == DISCO_BLDC_STATUS_RAMPUP) &&
actuators_disco.motor_rpm < DISCO_BLDC_START_MOTOR_THRESHOLD) {
actuators_disco.i2c_trans.buf[0] = ACTUATORS_DISCO_STOP_PROP;
- i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1);
+ i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 1, 0.5);
} else if (bldc_status == DISCO_BLDC_STATUS_RUNNING) {
// Send the commands
actuators_disco.i2c_trans.buf[0] = ACTUATORS_DISCO_SET_REF_SPEED;
@@ -170,7 +170,7 @@ void actuators_disco_commit(void)
#pragma GCC diagnostic ignored "-Wcast-qual"
actuators_disco.i2c_trans.buf[4] = actuators_disco_checksum((uint8_t *)actuators_disco.i2c_trans.buf, 3);
#pragma GCC diagnostic pop
- i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 11);
+ i2c_blocking_transmit(&i2c1, &actuators_disco.i2c_trans, actuators_disco.i2c_trans.slave_addr, 11, 0.5);
}
// Send ABI message
diff --git a/sw/airborne/mcu_periph/i2c.c b/sw/airborne/mcu_periph/i2c.c
index 3bffe9017b..31961e430f 100644
--- a/sw/airborne/mcu_periph/i2c.c
+++ b/sw/airborne/mcu_periph/i2c.c
@@ -229,73 +229,45 @@ bool i2c_transceive(struct i2c_periph *p, struct i2c_transaction *t,
return i2c_submit(p, t);
}
-/** Default timeout for blocking I2C transactions */
-#ifndef I2C_BLOCKING_TIMEOUT
-#define I2C_BLOCKING_TIMEOUT 1.f
-#endif
+static enum I2CTransactionStatus i2c_blocking_submit(struct i2c_periph *p, struct i2c_transaction *t, float timeout) {
+ if (!i2c_submit(p, t)) {
+ return I2CTransFailed;
+ }
-bool i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint8_t len)
+ // Wait for transaction to complete
+ if(pprz_bsem_wait_timeout(&t->bsem, timeout) == 0) {
+ return t->status;
+ } else {
+ return I2CTransFailed;
+ }
+}
+
+enum I2CTransactionStatus i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint8_t len, float timeout)
{
t->type = I2CTransTx;
t->slave_addr = s_addr;
t->len_w = len;
t->len_r = 0;
- if (!i2c_submit(p, t)) {
- return false;
- }
-
- // Wait for transaction to complete
- float start_t = get_sys_time_float();
- while (t->status == I2CTransPending || t->status == I2CTransRunning) {
- if (p->spin) p->spin(p);
- if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
- break; // timeout after 1 second
- }
- }
- return true;
+ return i2c_blocking_submit(p, t, timeout);
}
-bool i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint16_t len)
+enum I2CTransactionStatus i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint16_t len, float timeout)
{
t->type = I2CTransRx;
t->slave_addr = s_addr;
t->len_w = 0;
t->len_r = len;
- if (!i2c_submit(p, t)) {
- return false;
- }
-
- // Wait for transaction to complete
- float start_t = get_sys_time_float();
- while (t->status == I2CTransPending || t->status == I2CTransRunning) {
- if (p->spin) p->spin(p);
- if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
- break; // timeout after 1 second
- }
- }
- return true;
+ return i2c_blocking_submit(p, t, timeout);
}
-bool i2c_blocking_transceive(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint8_t len_w, uint16_t len_r)
+enum I2CTransactionStatus i2c_blocking_transceive(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint8_t len_w, uint16_t len_r, float timeout)
{
t->type = I2CTransTxRx;
t->slave_addr = s_addr;
t->len_w = len_w;
t->len_r = len_r;
- if (!i2c_submit(p, t)) {
- return false;
- }
-
- // Wait for transaction to complete
- float start_t = get_sys_time_float();
- while (t->status == I2CTransPending || t->status == I2CTransRunning) {
- if (p->spin) p->spin(p);
- if (get_sys_time_float() - start_t > I2C_BLOCKING_TIMEOUT) {
- break; // timeout after 1 second
- }
- }
- return true;
+ return i2c_blocking_submit(p, t, timeout);
}
diff --git a/sw/airborne/mcu_periph/i2c.h b/sw/airborne/mcu_periph/i2c.h
index 27ef685cde..ae7af74175 100644
--- a/sw/airborne/mcu_periph/i2c.h
+++ b/sw/airborne/mcu_periph/i2c.h
@@ -33,6 +33,7 @@
#include "std.h"
#include "mcu_periph/i2c_arch.h"
+#include "modules/core/threads.h"
/**
* @addtogroup mcu_periph
@@ -124,6 +125,10 @@ struct i2c_transaction {
/** Transaction status.
*/
volatile enum I2CTransactionStatus status;
+
+ /** binary semaphore for blocking functions
+ */
+ pprz_bsem_t bsem;
};
/** I2C transaction queue length.
@@ -328,10 +333,11 @@ extern bool i2c_transceive(struct i2c_periph *p, struct i2c_transaction *t,
* @param t i2c transaction
* @param s_addr slave address
* @param len number of bytes to transmit
- * @return TRUE if insertion to the transaction queue succeeded
+ * @param timeout timeout in seconds after which the transaction is considered failed
+ * @return the status of the transaction, or I2CTransFailed if insertion to the transaction queue failed
*/
-bool i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint8_t len);
+enum I2CTransactionStatus i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint8_t len, float timeout);
/** Submit a read only transaction and wait for it to complete.
* Convenience function which is usually preferred over i2c_submit,
@@ -340,10 +346,11 @@ bool i2c_blocking_transmit(struct i2c_periph *p, struct i2c_transaction *t,
* @param t i2c transaction
* @param s_addr slave address
* @param len number of bytes to receive
- * @return TRUE if insertion to the transaction queue succeeded
+ * @param timeout timeout in seconds after which the transaction is considered failed
+ * @return the status of the transaction, or I2CTransFailed if insertion to the transaction queue failed
*/
-bool i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint16_t len);
+enum I2CTransactionStatus i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint16_t len, float timeout);
/** Submit a write/read transaction and wait for it to complete.
* Convenience function which is usually preferred over i2c_submit,
@@ -353,10 +360,11 @@ bool i2c_blocking_receive(struct i2c_periph *p, struct i2c_transaction *t,
* @param s_addr slave address
* @param len_w number of bytes to transmit
* @param len_r number of bytes to receive
- * @return TRUE if insertion to the transaction queue succeeded
+ * @param timeout timeout in seconds after which the transaction is considered failed
+ * @return the status of the transaction, or I2CTransFailed if insertion to the transaction queue failed
*/
-bool i2c_blocking_transceive(struct i2c_periph *p, struct i2c_transaction *t,
- uint8_t s_addr, uint8_t len_w, uint16_t len_r);
+enum I2CTransactionStatus i2c_blocking_transceive(struct i2c_periph *p, struct i2c_transaction *t,
+ uint8_t s_addr, uint8_t len_w, uint16_t len_r, float timeout);
/** @}*/
/** @}*/
diff --git a/sw/airborne/mcu_periph/spi.c b/sw/airborne/mcu_periph/spi.c
index ef5327d89b..d46ca6ed90 100644
--- a/sw/airborne/mcu_periph/spi.c
+++ b/sw/airborne/mcu_periph/spi.c
@@ -164,3 +164,17 @@ extern void spi_slave_init(struct spi_periph *p)
#endif /* SPI_SLAVE */
+
+
+enum SPITransactionStatus spi_blocking_transceive(struct spi_periph *p, struct spi_transaction *t, float timeout) {
+ if (!spi_submit(p, t)) {
+ return SPITransFailed;
+ }
+
+ // Wait for transaction to complete
+ if(pprz_bsem_wait_timeout(&t->bsem, timeout) == 0) {
+ return t->status;
+ } else {
+ return SPITransFailed;
+ }
+}
\ No newline at end of file
diff --git a/sw/airborne/mcu_periph/spi.h b/sw/airborne/mcu_periph/spi.h
index f6f8ed06ec..e8f6b4e4de 100644
--- a/sw/airborne/mcu_periph/spi.h
+++ b/sw/airborne/mcu_periph/spi.h
@@ -35,11 +35,7 @@
#include "mcu_periph/spi_arch.h"
#include "mcu_periph/sys_time.h"
-
-#ifndef SPI_BLOCKING_TIMEOUT
-#define SPI_BLOCKING_TIMEOUT 1.f
-#endif
-
+#include "modules/core/threads.h"
/**
* @addtogroup mcu_periph
@@ -160,6 +156,7 @@ struct spi_transaction {
SPICallback before_cb; ///< NULL or function called before the transaction
SPICallback after_cb; ///< NULL or function called after the transaction
volatile enum SPITransactionStatus status;
+ pprz_bsem_t bsem;
};
/** SPI transaction queue length.
@@ -294,21 +291,10 @@ extern bool spi_submit(struct spi_periph *p, struct spi_transaction *t);
/** Perform a spi transaction (blocking).
* @param p spi peripheral to be used
* @param t spi transaction
- * @return TRUE if transaction completed (success or failure)
+ * @param timeout timeout in seconds after which the transaction is considered failed
+ * @return the status of the transaction, or SPITransFailed if insertion to the transaction queue failed
*/
-static inline bool spi_blocking_transceive(struct spi_periph *p, struct spi_transaction *t) {
- if (!spi_submit(p, t)) {
- return false;
- }
- // Wait for transaction to complete
- float start_t = get_sys_time_float();
- while (t->status == SPITransPending || t->status == SPITransRunning) {
- if (get_sys_time_float() - start_t > SPI_BLOCKING_TIMEOUT) {
- break;
- }
- }
- return true;
-}
+enum SPITransactionStatus spi_blocking_transceive(struct spi_periph *p, struct spi_transaction *t, float timeout);
/** Select a slave.
* @param slave slave id
diff --git a/sw/airborne/modules/core/threads.h b/sw/airborne/modules/core/threads.h
index 1feee7db7a..b8c32e5c07 100644
--- a/sw/airborne/modules/core/threads.h
+++ b/sw/airborne/modules/core/threads.h
@@ -34,6 +34,14 @@ int pprz_mtx_unlock(pprz_mutex_t* mtx);
void pprz_bsem_init(pprz_bsem_t* bsem, bool taken);
void pprz_bsem_wait(pprz_bsem_t* bsem);
+
+/**
+ * @brief Wait on semaphore no more than timeout.
+ * @param timeout in seconds
+ * @returns 0 on success
+ */
+int pprz_bsem_wait_timeout(pprz_bsem_t* bsem, float timeout);
+
void pprz_bsem_signal(pprz_bsem_t* bsem);
/**
diff --git a/sw/airborne/modules/meteo/humid_sht_i2c.c b/sw/airborne/modules/meteo/humid_sht_i2c.c
index 85e8a312db..b4ec87b5b0 100644
--- a/sw/airborne/modules/meteo/humid_sht_i2c.c
+++ b/sw/airborne/modules/meteo/humid_sht_i2c.c
@@ -27,9 +27,6 @@
#include "modules/meteo/humid_sht_i2c.h"
-
-#include "mcu_periph/i2c.h"
-#include "mcu_periph/uart.h"
#include "pprzlink/messages.h"
#include "modules/datalink/downlink.h"
@@ -40,14 +37,146 @@
#define SHT_SLAVE_ADDR 0x80
-struct i2c_transaction sht_trans;
-uint8_t sht_status;
-uint8_t sht_serial[8] = {0};
-uint32_t sht_serial1 = 0, sht_serial2 = 0;
-uint16_t humidsht_i2c, tempsht_i2c;
-float fhumidsht_i2c, ftempsht_i2c;
+#define SHT2_WRITE_USER 0xE6
+#define SHT2_READ_USER 0xE7
+#define SHT2_TRIGGER_TEMP 0xF3
+#define SHT2_TRIGGER_HUMID 0xF5
+#define SHT2_SOFT_RESET 0xFE
-int8_t humid_sht_crc(volatile uint8_t *data)
+static void humid_sht_thd(void* arg);
+static void sht_read_serial(struct sht_humid_t* sht);
+static int sht_read_temp(struct sht_humid_t* sht);
+static int sht_read_humid(struct sht_humid_t* sht);
+static int8_t humid_sht_crc(volatile uint8_t *data);
+
+
+
+static struct sht_humid_t sht;
+
+
+void humid_sht_init_i2c(void)
+{
+ sht.sht_status = SHT2_UNINIT;
+ pprz_bsem_init(&sht.bsem_sht_status, true);
+ pprz_thread_create(&sht.thd_handle, 512, "humid_sht25", PPRZ_NORMAL_PRIO+1, humid_sht_thd, &sht);
+}
+
+void humid_sht_periodic_i2c(void)
+{
+ if(sht.sht_status == SHT2_READING) {
+ /* send serial number every 30 seconds */
+ RunOnceEvery((4 * 30), DOWNLINK_SEND_SHT_I2C_SERIAL(DefaultChannel, DefaultDevice, &sht.sht_serial1, &sht.sht_serial2));
+ }
+
+ if(pprz_bsem_wait_timeout(&sht.bsem_sht_status, 0) == 0) {
+ DOWNLINK_SEND_SHT_I2C_STATUS(DefaultChannel, DefaultDevice, &sht.humidsht_i2c, &sht.tempsht_i2c, &sht.fhumidsht_i2c, &sht.ftempsht_i2c);
+ }
+}
+
+
+static void humid_sht_thd(void* arg) {
+ sys_time_usleep(100000);
+ struct sht_humid_t* sht = (struct sht_humid_t*)arg;
+
+ /* soft reset sensor */
+ sht->sht_trans.buf[0] = SHT2_SOFT_RESET;
+ while(i2c_blocking_transmit(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 1, 0.5) != I2CTransSuccess) {
+ sys_time_usleep(100000);
+ }
+
+ /* read serial number */
+ sht_read_serial(sht);
+
+ sht->sht_status = SHT2_READING;
+
+ while(true) {
+ /* read temperature */
+ if(sht_read_temp(sht)) {continue;}
+ /* read humidity */
+ if(sht_read_humid(sht)) {continue;}
+ /* signal semaphore to handle data */
+ pprz_bsem_signal(&sht->bsem_sht_status);
+
+ sys_time_usleep(500000);
+ }
+}
+
+
+static void sht_read_serial(struct sht_humid_t* sht) {
+ uint8_t sht_serial[8] = {0};
+
+ /* request serial number part 1 */
+ sht->sht_trans.buf[0] = 0xFA;
+ sht->sht_trans.buf[1] = 0x0F;
+ while(i2c_blocking_transceive(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 2, 8, 0.5) != I2CTransSuccess) {
+ sys_time_usleep(10000);
+ }
+ /* read serial number part 1 */
+ sht_serial[5] = sht->sht_trans.buf[0];
+ sht_serial[4] = sht->sht_trans.buf[2];
+ sht_serial[3] = sht->sht_trans.buf[4];
+ sht_serial[2] = sht->sht_trans.buf[6];
+
+ /* request serial number part 2 */
+ sht->sht_trans.buf[0] = 0xFC;
+ sht->sht_trans.buf[1] = 0xC9;
+ while(i2c_blocking_transceive(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 2, 6, 0.5) != I2CTransSuccess) {
+ sys_time_usleep(10000);
+ }
+ /* read serial number part 2 */
+ sht_serial[1] = sht->sht_trans.buf[0];
+ sht_serial[0] = sht->sht_trans.buf[1];
+ sht_serial[7] = sht->sht_trans.buf[3];
+ sht_serial[6] = sht->sht_trans.buf[4];
+
+ sht->sht_serial1 = sht_serial[7] << 24 | sht_serial[6] << 16 | sht_serial[5] << 8 | sht_serial[4];
+ sht->sht_serial2 = sht_serial[3] << 24 | sht_serial[2] << 16 | sht_serial[1] << 8 | sht_serial[0];
+}
+
+static int sht_read_temp(struct sht_humid_t* sht) {
+ /* trigger temp measurement, no master hold */
+ sht->sht_trans.buf[0] = SHT2_TRIGGER_TEMP;
+ if(i2c_blocking_transmit(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 1, 0.5) != I2CTransSuccess ) {
+ return -1;
+ }
+ /* needs 85ms delay from temp trigger measurement */
+ sys_time_usleep(85000);
+ /* read temperature */
+ if(i2c_blocking_receive(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 3, 0.5) != I2CTransSuccess) {
+ return -1;
+ }
+ if (humid_sht_crc(sht->sht_trans.buf) != 0) {
+ /* checksum error*/
+ return -1;
+ }
+
+ sht->tempsht_i2c = ((sht->sht_trans.buf[0] << 8) | sht->sht_trans.buf[1]) & 0xFFFC;
+ sht->ftempsht_i2c = -46.85 + 175.72 / 65536. * sht->tempsht_i2c;
+ return 0;
+}
+
+static int sht_read_humid(struct sht_humid_t* sht) {
+ /* trigger humid measurement, no master hold */
+ sht->sht_trans.buf[0] = SHT2_TRIGGER_HUMID;
+ if(i2c_blocking_transmit(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 1, 0.5) != I2CTransSuccess) {
+ return -1;
+ }
+ /* needs 29ms delay from humid trigger measurement */
+ sys_time_usleep(29000);
+ /* read humidity */
+ if(i2c_blocking_receive(&SHT_I2C_DEV, &sht->sht_trans, SHT_SLAVE_ADDR, 3, 0.5) != I2CTransSuccess) {
+ return -1;
+ }
+ if (humid_sht_crc(sht->sht_trans.buf) != 0) {
+ /* checksum error */
+ return -1;
+ }
+ sht->humidsht_i2c = ((sht->sht_trans.buf[0] << 8) | sht->sht_trans.buf[1]) & 0xFFFC;
+ sht->fhumidsht_i2c = -6. + 125. / 65536. * sht->humidsht_i2c;
+ return 0;
+}
+
+static int8_t humid_sht_crc(volatile uint8_t *data)
{
uint8_t i, bit, crc = 0;
@@ -67,147 +196,3 @@ int8_t humid_sht_crc(volatile uint8_t *data)
return 0;
}
}
-
-void humid_sht_init_i2c(void)
-{
- sht_status = SHT2_UNINIT;
-}
-
-void humid_sht_periodic_i2c(void)
-{
- switch (sht_status) {
-
- case SHT2_UNINIT:
- /* do soft reset, then wait at least 15ms */
- sht_status = SHT2_RESET;
- sht_trans.buf[0] = SHT2_SOFT_RESET;
- i2c_transmit(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 1);
- break;
-
- case SHT2_SERIAL:
- /* get serial number part 1 */
- sht_status = SHT2_SERIAL1;
- sht_trans.buf[0] = 0xFA;
- sht_trans.buf[1] = 0x0F;
- i2c_transceive(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 2, 8);
- break;
-
- case SHT2_SERIAL1:
- case SHT2_SERIAL2:
- break;
-
- default:
- /* trigger temp measurement, no master hold */
- sht_trans.buf[0] = SHT2_TRIGGER_TEMP;
- sht_status = SHT2_TRIG_TEMP;
- i2c_transmit(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 1);
- /* send serial number every 30 seconds */
- RunOnceEvery((4 * 30), DOWNLINK_SEND_SHT_I2C_SERIAL(DefaultChannel, DefaultDevice, &sht_serial1, &sht_serial2));
- break;
- }
-}
-
-/* needs 85ms delay from temp trigger measurement */
-void humid_sht_p_temp(void)
-{
- if (sht_status == SHT2_GET_TEMP) {
- /* get temp */
- sht_status = SHT2_READ_TEMP;
- i2c_receive(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 3);
- }
-}
-
-/* needs 29ms delay from humid trigger measurement */
-void humid_sht_p_humid(void)
-{
- if (sht_status == SHT2_GET_HUMID) {
- /* read humid */
- sht_status = SHT2_READ_HUMID;
- i2c_receive(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 3);
- }
-}
-
-void humid_sht_event_i2c(void)
-{
- if (sht_trans.status == I2CTransSuccess) {
- switch (sht_status) {
-
- case SHT2_TRIG_TEMP:
- sht_status = SHT2_GET_TEMP;
- sht_trans.status = I2CTransDone;
- break;
-
- case SHT2_READ_TEMP:
- /* read temperature */
- tempsht_i2c = (sht_trans.buf[0] << 8) | sht_trans.buf[1];
- tempsht_i2c &= 0xFFFC;
- if (humid_sht_crc(sht_trans.buf) == 0) {
- /* trigger humid measurement, no master hold */
- sht_trans.buf[0] = SHT2_TRIGGER_HUMID;
- sht_status = SHT2_TRIG_HUMID;
- i2c_transmit(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 1);
- } else {
- /* checksum error, restart */
- sht_status = SHT2_IDLE;
- sht_trans.status = I2CTransDone;
- }
- break;
-
- case SHT2_TRIG_HUMID:
- sht_status = SHT2_GET_HUMID;
- sht_trans.status = I2CTransDone;
- break;
-
- case SHT2_READ_HUMID:
- /* read humidity */
- humidsht_i2c = (sht_trans.buf[0] << 8) | sht_trans.buf[1];
- humidsht_i2c &= 0xFFFC;
- fhumidsht_i2c = -6. + 125. / 65536. * humidsht_i2c;
- ftempsht_i2c = -46.85 + 175.72 / 65536. * tempsht_i2c;
-
- sht_status = SHT2_IDLE;
- sht_trans.status = I2CTransDone;
-
- if (humid_sht_crc(sht_trans.buf) == 0) {
- DOWNLINK_SEND_SHT_I2C_STATUS(DefaultChannel, DefaultDevice, &humidsht_i2c, &tempsht_i2c, &fhumidsht_i2c, &ftempsht_i2c);
- }
- break;
-
- case SHT2_RESET:
- sht_status = SHT2_SERIAL;
- sht_trans.status = I2CTransDone;
- break;
-
- case SHT2_SERIAL1:
- /* read serial number part 1 */
- sht_serial[5] = sht_trans.buf[0];
- sht_serial[4] = sht_trans.buf[2];
- sht_serial[3] = sht_trans.buf[4];
- sht_serial[2] = sht_trans.buf[6];
- /* get serial number part 2 */
- sht_status = SHT2_SERIAL2;
- sht_trans.buf[0] = 0xFC;
- sht_trans.buf[1] = 0xC9;
- i2c_transceive(&SHT_I2C_DEV, &sht_trans, SHT_SLAVE_ADDR, 2, 6);
- break;
-
- case SHT2_SERIAL2:
- /* read serial number part 2 */
- sht_serial[1] = sht_trans.buf[0];
- sht_serial[0] = sht_trans.buf[1];
- sht_serial[7] = sht_trans.buf[3];
- sht_serial[6] = sht_trans.buf[4];
- sht_serial1 = sht_serial[7] << 24 | sht_serial[6] << 16 | sht_serial[5] << 8 | sht_serial[4];
- sht_serial2 = sht_serial[3] << 24 | sht_serial[2] << 16 | sht_serial[1] << 8 | sht_serial[0];
- DOWNLINK_SEND_SHT_I2C_SERIAL(DefaultChannel, DefaultDevice, &sht_serial1, &sht_serial2);
- sht_status = SHT2_IDLE;
- sht_trans.status = I2CTransDone;
- break;
-
- default:
- sht_trans.status = I2CTransDone;
- break;
- }
- }
-}
-
diff --git a/sw/airborne/modules/meteo/humid_sht_i2c.h b/sw/airborne/modules/meteo/humid_sht_i2c.h
index 0669bb2948..fc3b398ef5 100644
--- a/sw/airborne/modules/meteo/humid_sht_i2c.h
+++ b/sw/airborne/modules/meteo/humid_sht_i2c.h
@@ -1,39 +1,32 @@
#ifndef HUMID_SHT_I2C_H
#define HUMID_SHT_I2C_H
+#include "mcu_periph/i2c.h"
+#include "modules/core/threads.h"
#include "std.h"
-#define SHT2_WRITE_USER 0xE6
-#define SHT2_READ_USER 0xE7
-#define SHT2_TRIGGER_TEMP 0xF3
-#define SHT2_TRIGGER_HUMID 0xF5
-#define SHT2_SOFT_RESET 0xFE
-
enum sht_stat_i2c {
SHT2_UNINIT,
- SHT2_IDLE,
- SHT2_RESET,
- SHT2_SERIAL,
- SHT2_SERIAL1,
- SHT2_SERIAL2,
- SHT2_SET_CONFIG,
- SHT2_READ_SERIAL,
- SHT2_TRIG_TEMP,
- SHT2_GET_TEMP,
- SHT2_READ_TEMP,
- SHT2_TRIG_HUMID,
- SHT2_GET_HUMID,
- SHT2_READ_HUMID
+ SHT2_READING,
};
-int8_t humid_sht_crc(volatile uint8_t *data);
+
+struct sht_humid_t {
+ struct i2c_transaction sht_trans;
+ enum sht_stat_i2c sht_status;
+ uint32_t sht_serial1;
+ uint32_t sht_serial2;
+ uint16_t humidsht_i2c;
+ uint16_t tempsht_i2c;
+ float fhumidsht_i2c;
+ float ftempsht_i2c;
+
+ pprz_thread_t thd_handle;
+ pprz_bsem_t bsem_sht_status;
+};
+
+
void humid_sht_init_i2c(void);
void humid_sht_periodic_i2c(void);
-void humid_sht_p_temp(void);
-void humid_sht_p_humid(void);
-void humid_sht_event_i2c(void);
-
-extern uint16_t humidsht_i2c, tempsht_i2c;
-extern float fhumidsht_i2c, ftempsht_i2c;
#endif
diff --git a/sw/airborne/modules/sensors/encoder_amt22.c b/sw/airborne/modules/sensors/encoder_amt22.c
new file mode 100644
index 0000000000..01491ee402
--- /dev/null
+++ b/sw/airborne/modules/sensors/encoder_amt22.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 Flo&Fab
+ *
+ * This file is part of paparazzi
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, see
+ * .
+ */
+
+/** @file "modules/sensors/encoder_amt22.c"
+ * @author Flo&Fab
+ * Driver for AMT22 encoder from CUI devices.
+ */
+
+#include "modules/sensors/encoder_amt22.h"
+#include "peripherals/amt22.h"
+#include "modules/datalink/downlink.h"
+
+static amt22_t amt22;
+static amt22_config_t amt22_conf = {
+ .p = &AMT22_SPI_DEV,
+ .slave_idx = AMT22_SPI_SLAVE_IDX,
+ .type = AMT22_12_SINGLE,
+};
+
+void encoder_amt22_init(void)
+{
+ amt22_init(&amt22, &amt22_conf);
+}
+
+void encoder_amt22_periodic(void)
+{
+ amt22_periodic(&amt22);
+ float f[2] = {amt22_get_position(&amt22), amt22_get_turns(&amt22)};
+ DOWNLINK_SEND_PAYLOAD_FLOAT(DefaultChannel, DefaultDevice, 2, f);
+}
diff --git a/sw/airborne/modules/sensors/encoder_amt22.h b/sw/airborne/modules/sensors/encoder_amt22.h
new file mode 100644
index 0000000000..5448ba3256
--- /dev/null
+++ b/sw/airborne/modules/sensors/encoder_amt22.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2025 Flo&Fab
+ *
+ * This file is part of paparazzi
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with paparazzi; see the file COPYING. If not, see
+ * .
+ */
+
+/** @file "modules/sensors/encoder_amt22.h"
+ * @author Flo&Fab
+ * Driver for AMT22 encoder from CUI devices.
+ */
+
+#ifndef ENCODER_AMT22_H
+#define ENCODER_AMT22_H
+
+extern void encoder_amt22_init(void);
+extern void encoder_amt22_periodic(void);
+
+#endif // ENCODER_AMT22_H
diff --git a/sw/airborne/peripherals/amt22.c b/sw/airborne/peripherals/amt22.c
new file mode 100644
index 0000000000..e6f899071f
--- /dev/null
+++ b/sw/airborne/peripherals/amt22.c
@@ -0,0 +1,133 @@
+#include "amt22.h"
+
+
+#ifndef AMT22_SPI_CDIV
+#define AMT22_SPI_CDIV SPIDiv256
+#endif
+
+static bool amt22_checkbit(uint8_t p0, uint8_t p1);
+
+static void amt22_thd(void* arg);
+
+void amt22_init(amt22_t* amt, amt22_config_t* conf) {
+ amt->config = conf;
+ // Set up SPI peripheral and transaction
+ amt->trans.slave_idx = amt->config->slave_idx;
+ amt->trans.input_buf = amt->spi_input_buf;
+ amt->trans.output_buf = amt->spi_output_buf;
+ amt->trans.select = SPISelectUnselect;
+ amt->trans.cpol = SPICpolIdleLow;
+ amt->trans.cpha = SPICphaEdge1;
+ amt->trans.dss = SPIDss8bit;
+ amt->trans.bitorder = SPIMSBFirst;
+ amt->trans.cdiv = AMT22_SPI_CDIV;
+ amt->trans.before_cb = NULL;
+ amt->trans.after_cb = NULL;
+ amt->trans.status = SPITransDone;
+ amt->position = 0;
+ amt->turns = 0;
+
+
+ if(amt->config->type == AMT22_12_SINGLE || amt->config->type == AMT22_14_SINGLE) {
+ //single turn
+ amt->trans.output_buf[0] = 0x00;
+ amt->trans.output_buf[1] = 0x00;
+ amt->trans.output_length = 2;
+ amt->trans.input_length = 2;
+ } else {
+ //multi_turn
+ amt->trans.output_buf[0] = 0x00;
+ amt->trans.output_buf[1] = 0xA0;
+ amt->trans.output_buf[2] = 0x00;
+ amt->trans.output_buf[3] = 0x00;
+ amt->trans.output_length = 4;
+ amt->trans.input_length = 4;
+ }
+
+ pprz_bsem_init(&amt->bsem_amt22_read, true);
+ pprz_mtx_init(&amt->mtx);
+ pprz_thread_create(&amt->thd_handle, 512, "amt22", PPRZ_NORMAL_PRIO+1, amt22_thd, amt);
+}
+
+void amt22_periodic(amt22_t* amt) {
+ // trigger read
+ pprz_bsem_signal(&amt->bsem_amt22_read);
+}
+
+
+bool amt22_read(amt22_t* amt) {
+ if(spi_blocking_transceive(amt->config->p, &amt->trans, 0.5) != SPITransSuccess) {
+ return false;
+ }
+
+ uint8_t p0 = amt->trans.input_buf[0];
+ uint8_t p1 = amt->trans.input_buf[1];
+
+ if(!amt22_checkbit(p0,p1)) {
+ return false;
+ }
+
+ uint16_t position = (p0 << 8 | p1) & 0x3fff;
+ int16_t turns = 0;
+
+ // 12 bits so shift 2
+ if(amt->config->type == AMT22_12_SINGLE || amt->config->type == AMT22_12_MULTI) {
+ position >>= 2;
+ }
+
+ if(amt->config->type == AMT22_12_MULTI || amt->config->type == AMT22_14_MULTI) {
+ uint8_t t0 = amt->trans.input_buf[2];
+ uint8_t t1 = amt->trans.input_buf[3];
+ turns = (t0 << 8 | t1);
+ }
+
+ pprz_mtx_lock(&amt->mtx);
+ amt->position = position;
+ amt->turns = turns;
+ pprz_mtx_unlock(&amt->mtx);
+ return true;
+}
+
+static bool amt22_checkbit(uint8_t p0, uint8_t p1) {
+ uint16_t data = ((p0 << 8 | p1) & 0x3fff) >> 2;
+ uint8_t odd = 0;
+ uint8_t even = 0;
+ while (data)
+ {
+ even ^= data & 1;
+ data >>= 1;
+ odd ^= data & 1;
+ data >>= 1;
+ }
+ even = !even;
+ odd = !odd;
+ if((even == ((p0 & 0x40) >> 6)) && (odd == ((p0 & 0x80) >> 7))) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+uint16_t amt22_get_position(amt22_t* amt) {
+ pprz_mtx_lock(&amt->mtx);
+ uint16_t pos = amt->position;
+ pprz_mtx_unlock(&amt->mtx);
+ return pos;
+}
+
+int16_t amt22_get_turns(amt22_t* amt) {
+ pprz_mtx_lock(&amt->mtx);
+ int16_t turns = amt->turns;
+ pprz_mtx_unlock(&amt->mtx);
+ return turns;
+}
+
+
+static void amt22_thd(void* arg) {
+ amt22_t* amt = (amt22_t*)arg;
+
+ while(true) {
+ pprz_bsem_wait(&amt->bsem_amt22_read);
+ amt22_read(amt);
+ }
+}
\ No newline at end of file
diff --git a/sw/airborne/peripherals/amt22.h b/sw/airborne/peripherals/amt22.h
new file mode 100644
index 0000000000..a5087e1e3f
--- /dev/null
+++ b/sw/airborne/peripherals/amt22.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "mcu_periph/spi.h"
+#include "modules/core/threads.h"
+
+enum amt22_type {
+ AMT22_12_SINGLE, ///< 12-bits, single-turn
+ AMT22_14_SINGLE, ///< 14-bits, single-turn
+ AMT22_12_MULTI, ///< 12-bits, multi-turn
+ AMT22_14_MULTI, ///< 14-bits, multi-turn
+};
+
+typedef struct {
+ struct spi_periph *p;
+ uint8_t slave_idx;
+ enum amt22_type type;
+} amt22_config_t;
+
+typedef struct {
+ amt22_config_t *config;
+
+ // private
+ struct spi_transaction trans;
+ volatile uint8_t spi_input_buf[4];
+ volatile uint8_t spi_output_buf[4];
+
+ uint16_t position;
+ int16_t turns;
+
+ pprz_thread_t thd_handle;
+ pprz_bsem_t bsem_amt22_read;
+ pprz_mutex_t mtx;
+} amt22_t;
+
+void amt22_init(amt22_t* amt22, amt22_config_t* conf);
+void amt22_periodic(amt22_t* amt22);
+uint16_t amt22_get_position(amt22_t* amt22);
+int16_t amt22_get_turns(amt22_t* amt22);
diff --git a/sw/airborne/peripherals/pca95xx.c b/sw/airborne/peripherals/pca95xx.c
index 337351f4c0..2e3159d72b 100644
--- a/sw/airborne/peripherals/pca95xx.c
+++ b/sw/airborne/peripherals/pca95xx.c
@@ -50,7 +50,7 @@ bool pca95xx_configure(struct pca95xx *dev, uint8_t val, bool blocking)
dev->i2c_trans.buf[0] = PCA95XX_CONFIG_REG;
dev->i2c_trans.buf[1] = val;
if (blocking) {
- return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
+ return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2, 0.5) == I2CTransSuccess;
} else {
return i2c_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
}
@@ -68,7 +68,7 @@ bool pca95xx_set_output(struct pca95xx *dev, uint8_t mask, bool blocking)
dev->i2c_trans.buf[0] = PCA95XX_OUTPUT_REG;
dev->i2c_trans.buf[1] = mask;
if (blocking) {
- return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
+ return i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2, 0.5) == I2CTransSuccess;
} else {
return i2c_transmit(dev->i2c_p, &dev->i2c_trans, dev->i2c_trans.slave_addr, 2);
}
diff --git a/sw/airborne/peripherals/vl53l1_platform.c b/sw/airborne/peripherals/vl53l1_platform.c
index 1e062635c3..845a57b6a1 100644
--- a/sw/airborne/peripherals/vl53l1_platform.c
+++ b/sw/airborne/peripherals/vl53l1_platform.c
@@ -47,7 +47,7 @@ int8_t VL53L1_WriteMulti(VL53L1_DEV dev, uint16_t index, uint8_t *pdata, uint32_
dev->i2c_trans.buf[1] = (index & 0x00FF);
memcpy((uint8_t *) dev->i2c_trans.buf + 2, pdata, count);
return !i2c_blocking_transmit(dev->i2c_p, &dev->i2c_trans,
- dev->i2c_trans.slave_addr, 2 + count);
+ dev->i2c_trans.slave_addr, 2 + count, 1.f);
}
int8_t VL53L1_ReadMulti(VL53L1_DEV dev, uint16_t index, uint8_t *pdata, uint32_t count)