From e2cb3d13ea62f16eda1625a9413726bbe87b7298 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 21 Feb 2023 17:34:00 +0100 Subject: [PATCH 1/6] sys/shell: don't include suit command by default --- sys/shell/Makefile.dep | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/shell/Makefile.dep b/sys/shell/Makefile.dep index 6cc8eaaff9ec6..eb2360479c1b5 100644 --- a/sys/shell/Makefile.dep +++ b/sys/shell/Makefile.dep @@ -129,9 +129,6 @@ ifneq (,$(filter shell_cmds_default,$(USEMODULE))) ifneq (,$(filter sht1x,$(USEMODULE))) USEMODULE += shell_cmd_sht1x endif - ifneq (,$(filter suit_transport_worker,$(USEMODULE))) - USEMODULE += shell_cmd_suit - endif ifneq (,$(filter vfs,$(USEMODULE))) USEMODULE += shell_cmd_vfs endif From f3aa2ac42ed46e4a2c2a600b533a509d0f8ed125 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 21 Feb 2023 17:34:29 +0100 Subject: [PATCH 2/6] examples/suit_update: enable suit command --- examples/suit_update/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/suit_update/Makefile b/examples/suit_update/Makefile index 8d61ced457f5b..b00db43999ae8 100644 --- a/examples/suit_update/Makefile +++ b/examples/suit_update/Makefile @@ -26,6 +26,7 @@ USEMODULE += gnrc_icmpv6_echo # include this for printing IP addresses USEMODULE += shell USEMODULE += shell_cmds_default +USEMODULE += shell_cmd_suit # Set this to 1 to enable code in RIOT that does safety checking # which is not needed in a production environment but helps in the From 5db24d4f511798e2512cf263d81ec02004d48fd1 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 21 Feb 2023 19:59:48 +0100 Subject: [PATCH 3/6] gcoap: Rename gcoap_get_resource_list_tl to gcoap_get_resource_list This is an API change in the latter, which would typically now take an extra argument GCOAP_SOCKET_TYPE_UNDEF. Follow-Up-For: https://github.com/RIOT-OS/RIOT/pull/16688 --- sys/include/net/gcoap.h | 28 +-------------------- sys/net/application_layer/cord/ep/cord_ep.c | 2 +- sys/net/application_layer/gcoap/gcoap.c | 4 +-- tests/unittests/tests-gcoap/tests-gcoap.c | 6 ++--- 4 files changed, 7 insertions(+), 33 deletions(-) diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index b9d4794d1b60e..be95145f216e3 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -1087,9 +1087,6 @@ uint8_t gcoap_op_state(void); * @brief Get the resource list, currently only `CoRE Link Format` * (COAP_FORMAT_LINK) supported * - * @deprecated Will be an alias for @ref gcoap_get_resource_list after the - * 2022.01 release. Will be removed after the 2022.04 release. - * * If @p buf := NULL, nothing will be written but the size of the resulting * resource list is computed and returned. * @@ -1109,32 +1106,9 @@ uint8_t gcoap_op_state(void); * @return the number of bytes written to @p buf * @return -1 on error */ -int gcoap_get_resource_list_tl(void *buf, size_t maxlen, uint8_t cf, +int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf, gcoap_socket_type_t tl_type); -/** - * @brief Get the resource list for all transports, - * currently only `CoRE Link Format` (COAP_FORMAT_LINK) supported - * - * If @p buf := NULL, nothing will be written but the size of the resulting - * resource list is computed and returned. - * - * @param[out] buf output buffer to write resource list into, my be NULL - * @param[in] maxlen length of @p buf, ignored if @p buf is NULL - * @param[in] cf content format to use for the resource list, currently - * only COAP_FORMAT_LINK supported - * - * @todo add support for `JSON CoRE Link Format` - * @todo add support for 'CBOR CoRE Link Format` - * - * @return the number of bytes written to @p buf - * @return -1 on error - */ -static inline int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf) -{ - return gcoap_get_resource_list_tl(buf, maxlen, cf, GCOAP_SOCKET_TYPE_UNDEF); -} - /** * @brief Writes a resource in CoRE Link Format to a provided buffer. * diff --git a/sys/net/application_layer/cord/ep/cord_ep.c b/sys/net/application_layer/cord/ep/cord_ep.c index 943938bf67aab..36b618c71492e 100644 --- a/sys/net/application_layer/cord/ep/cord_ep.c +++ b/sys/net/application_layer/cord/ep/cord_ep.c @@ -286,7 +286,7 @@ int cord_ep_register(const sock_udp_ep_t *remote, const char *regif) /* add the resource description as payload */ res = gcoap_get_resource_list(pkt.payload, pkt.payload_len, - COAP_FORMAT_LINK); + COAP_FORMAT_LINK, GCOAP_SOCKET_TYPE_UNDEF); if (res < 0) { retval = CORD_EP_ERR; goto end; diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c index f42c2b411fa2d..39d965734c64c 100644 --- a/sys/net/application_layer/gcoap/gcoap.c +++ b/sys/net/application_layer/gcoap/gcoap.c @@ -946,7 +946,7 @@ static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t le coap_opt_add_format(pdu, COAP_FORMAT_LINK); ssize_t plen = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD); - plen += gcoap_get_resource_list_tl(pdu->payload, (size_t)pdu->payload_len, + plen += gcoap_get_resource_list(pdu->payload, (size_t)pdu->payload_len, COAP_FORMAT_LINK, (gcoap_socket_type_t)coap_request_ctx_get_tl_type(ctx)); return plen; @@ -1706,7 +1706,7 @@ uint8_t gcoap_op_state(void) return count; } -int gcoap_get_resource_list_tl(void *buf, size_t maxlen, uint8_t cf, +int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf, gcoap_socket_type_t tl_type) { assert(cf == COAP_FORMAT_LINK); diff --git a/tests/unittests/tests-gcoap/tests-gcoap.c b/tests/unittests/tests-gcoap/tests-gcoap.c index d42b8e5824d15..4bb42affbd824 100644 --- a/tests/unittests/tests-gcoap/tests-gcoap.c +++ b/tests/unittests/tests-gcoap/tests-gcoap.c @@ -378,15 +378,15 @@ static void test_gcoap__server_get_resource_list(void) gcoap_register_listener(&listener); gcoap_register_listener(&listener_second); - size = gcoap_get_resource_list(NULL, 0, COAP_FORMAT_LINK); + size = gcoap_get_resource_list(NULL, 0, COAP_FORMAT_LINK, GCOAP_SOCKET_TYPE_UNDEF); TEST_ASSERT_EQUAL_INT(strlen(resource_list_str), size); res[0] = 'A'; - size = gcoap_get_resource_list(res, 0, COAP_FORMAT_LINK); + size = gcoap_get_resource_list(res, 0, COAP_FORMAT_LINK, GCOAP_SOCKET_TYPE_UNDEF); TEST_ASSERT_EQUAL_INT(0, size); TEST_ASSERT_EQUAL_INT((int)'A', (int)res[0]); - size = gcoap_get_resource_list(res, 127, COAP_FORMAT_LINK); + size = gcoap_get_resource_list(res, 127, COAP_FORMAT_LINK, GCOAP_SOCKET_TYPE_UNDEF); res[size] = '\0'; TEST_ASSERT_EQUAL_INT(strlen(resource_list_str), size); TEST_ASSERT_EQUAL_STRING(resource_list_str, (char *)res); From 86e6898fa539d6b57d621f448547daa0f8406501 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 21 Feb 2023 20:14:19 +0100 Subject: [PATCH 4/6] doc/gcoap: Update ToDo item referencing abandoned document --- sys/include/net/gcoap.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index be95145f216e3..8fd9ad356be91 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -1100,8 +1100,7 @@ uint8_t gcoap_op_state(void); * (i.e. usage of modules no `gcoap_dtls`, ...) this will * be ignored and @ref GCOAP_SOCKET_TYPE_UDP assumed. * - * @todo add support for `JSON CoRE Link Format` - * @todo add support for 'CBOR CoRE Link Format` + * @todo add support for CoRAL once it is done * * @return the number of bytes written to @p buf * @return -1 on error From 65a9fa2e2aab11b0865138b559df96a39fc29491 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 21 Feb 2023 12:19:50 +0100 Subject: [PATCH 5/6] sys/phydat: Fix unit confusion Previously, `UNIT_G` was used for g-force with the correct symbol `g`, `UNIT_GR` for gram (as in kilogram) with the incorrect symbol `G` (which would be correct for Gauss), and `UNIT_GS` for Gauss with symbol `Gs` (which is an uncommon but correct symbol). To avoid confusion between G-Force, Gauss, and Gram the units have been renamed to `UNIT_G_FORCE`, `UNIT_GRAM`, and `UNIT_GAUSS`. In addition, gram now uses the correct symbol `g` and Gauss uses `G`. --- drivers/adxl345/adxl345_saul.c | 2 +- drivers/bmx055/bmx055_saul.c | 4 +-- drivers/fxos8700/fxos8700_saul.c | 4 +-- drivers/hmc5883l/hmc5883l_saul.c | 2 +- drivers/lis2dh12/lis2dh12_saul.c | 2 +- drivers/lis3dh/lis3dh_saul.c | 2 +- drivers/lis3mdl/lis3mdl_saul.c | 2 +- drivers/lsm303dlhc/lsm303dlhc_saul.c | 4 +-- drivers/lsm6dsl/lsm6dsl_saul.c | 2 +- drivers/mag3110/mag3110_saul.c | 2 +- drivers/mma7660/mma7660_saul.c | 2 +- drivers/mma8x5x/mma8x5x_saul.c | 2 +- drivers/mpu9x50/mpu9x50_saul.c | 4 +-- drivers/qmc5883l/qmc5883l_saul.c | 2 +- sys/include/phydat.h | 27 ++++++++++++++++++--- sys/include/senml/phydat.h | 6 ++--- sys/phydat/phydat_str.c | 6 ++--- sys/senml/phydat.c | 12 ++++----- tests/phydat_dump/main.c | 6 ++--- tests/phydat_dump/tests/01-run.py | 4 +-- tests/senml_phydat/main.c | 4 +-- tests/unittests/tests-phydat/tests-phydat.c | 8 +++--- 22 files changed, 65 insertions(+), 44 deletions(-) diff --git a/drivers/adxl345/adxl345_saul.c b/drivers/adxl345/adxl345_saul.c index 432e249595c5c..594961e8d94a8 100644 --- a/drivers/adxl345/adxl345_saul.c +++ b/drivers/adxl345/adxl345_saul.c @@ -25,7 +25,7 @@ static int read_acc(const void *dev, phydat_t *res) { adxl345_read((const adxl345_t *)dev, (adxl345_data_t *)res->val); - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; } diff --git a/drivers/bmx055/bmx055_saul.c b/drivers/bmx055/bmx055_saul.c index a84cd8e15fff6..5d738b8e33428 100644 --- a/drivers/bmx055/bmx055_saul.c +++ b/drivers/bmx055/bmx055_saul.c @@ -29,7 +29,7 @@ static int read_mag(const void *dev, phydat_t *res) if (bmx055_mag_read(mydev, res->val) != BMX055_OK) { return 0; } - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = 0; return 3; } @@ -41,7 +41,7 @@ static int read_acc(const void *dev, phydat_t *res) if (bmx055_acc_read(mydev, res->val) != BMX055_OK) { return 0; } - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; } diff --git a/drivers/fxos8700/fxos8700_saul.c b/drivers/fxos8700/fxos8700_saul.c index e9954f9461b5f..7a46b5864c135 100644 --- a/drivers/fxos8700/fxos8700_saul.c +++ b/drivers/fxos8700/fxos8700_saul.c @@ -31,7 +31,7 @@ static int read_mag(const void *dev, phydat_t *res) /* Read failure */ return -ECANCELED; } - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = -3; return 3; } @@ -48,7 +48,7 @@ static int read_acc(const void *dev, phydat_t *res) res->scale = 0; } else { - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; if (((fxos8700_t *)dev)->p.acc_range == FXOS8700_REG_XYZ_DATA_CFG_FS__2G) { res->scale = -4; } diff --git a/drivers/hmc5883l/hmc5883l_saul.c b/drivers/hmc5883l/hmc5883l_saul.c index 63cf50de5fce1..ae1b5e2d82f94 100644 --- a/drivers/hmc5883l/hmc5883l_saul.c +++ b/drivers/hmc5883l/hmc5883l_saul.c @@ -28,7 +28,7 @@ static int read(const void *dev, phydat_t *res) res->val[0] = data.x; res->val[1] = data.y; res->val[2] = data.z; - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = -3; return 3; } diff --git a/drivers/lis2dh12/lis2dh12_saul.c b/drivers/lis2dh12/lis2dh12_saul.c index 5fe3d319c89f2..6f4f574af9276 100644 --- a/drivers/lis2dh12/lis2dh12_saul.c +++ b/drivers/lis2dh12/lis2dh12_saul.c @@ -26,7 +26,7 @@ static int read_accelerometer(const void *dev, phydat_t *res) if (lis2dh12_read(dev, (lis2dh12_fifo_data_t*)res->val) != LIS2DH12_OK) { return 0; } - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; } diff --git a/drivers/lis3dh/lis3dh_saul.c b/drivers/lis3dh/lis3dh_saul.c index 03cb933a098a4..bbf6bd94e4aca 100644 --- a/drivers/lis3dh/lis3dh_saul.c +++ b/drivers/lis3dh/lis3dh_saul.c @@ -39,7 +39,7 @@ static int read_acc(const void *dev, phydat_t *res) res->val[2] = xyz.acc_z; /* unit: milli-G */ res->scale = -3; - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; return 3; } diff --git a/drivers/lis3mdl/lis3mdl_saul.c b/drivers/lis3mdl/lis3mdl_saul.c index 93efec2ecbf32..92c95c6a079e4 100644 --- a/drivers/lis3mdl/lis3mdl_saul.c +++ b/drivers/lis3mdl/lis3mdl_saul.c @@ -29,7 +29,7 @@ static int read_mag(const void *dev, phydat_t *res) lis3mdl_read_mag(d, (lis3mdl_3d_data_t *)res); - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = -3; return 3; } diff --git a/drivers/lsm303dlhc/lsm303dlhc_saul.c b/drivers/lsm303dlhc/lsm303dlhc_saul.c index 461ad66f05d24..f89b31f7f85ba 100644 --- a/drivers/lsm303dlhc/lsm303dlhc_saul.c +++ b/drivers/lsm303dlhc/lsm303dlhc_saul.c @@ -34,7 +34,7 @@ static int read_acc(const void *dev, phydat_t *res) res->val[i] *= fac; } - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; } @@ -63,7 +63,7 @@ static int read_mag(const void *dev, phydat_t *res) res->val[i] = (int16_t)tmp; } - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = -3; return 3; } diff --git a/drivers/lsm6dsl/lsm6dsl_saul.c b/drivers/lsm6dsl/lsm6dsl_saul.c index 1a51f25fe209d..39ac219cc482d 100644 --- a/drivers/lsm6dsl/lsm6dsl_saul.c +++ b/drivers/lsm6dsl/lsm6dsl_saul.c @@ -31,7 +31,7 @@ static int read_acc(const void *dev, phydat_t *res) } res->scale = -3; - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; return 3; } diff --git a/drivers/mag3110/mag3110_saul.c b/drivers/mag3110/mag3110_saul.c index 0821ce4c204a4..f81ba62487b72 100644 --- a/drivers/mag3110/mag3110_saul.c +++ b/drivers/mag3110/mag3110_saul.c @@ -28,7 +28,7 @@ static int read_mag(const void *dev, phydat_t *res) { mag3110_read((const mag3110_t *)dev, (mag3110_data_t *)res->val); - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = 2; return 3; diff --git a/drivers/mma7660/mma7660_saul.c b/drivers/mma7660/mma7660_saul.c index 411e0d65e8631..39860ac548b0c 100644 --- a/drivers/mma7660/mma7660_saul.c +++ b/drivers/mma7660/mma7660_saul.c @@ -28,7 +28,7 @@ static int read_acc(const void *dev, phydat_t *res) { mma7660_read((const mma7660_t *)dev, (mma7660_data_t *)res->val); - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; diff --git a/drivers/mma8x5x/mma8x5x_saul.c b/drivers/mma8x5x/mma8x5x_saul.c index 8a925d740c252..5c4be8dea371b 100644 --- a/drivers/mma8x5x/mma8x5x_saul.c +++ b/drivers/mma8x5x/mma8x5x_saul.c @@ -29,7 +29,7 @@ static int read_acc(const void *dev, phydat_t *res) { mma8x5x_read((const mma8x5x_t *)dev, (mma8x5x_data_t *)res->val); - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; res->scale = -3; return 3; diff --git a/drivers/mpu9x50/mpu9x50_saul.c b/drivers/mpu9x50/mpu9x50_saul.c index 302cc4538ede9..f06b94e2ab6ea 100644 --- a/drivers/mpu9x50/mpu9x50_saul.c +++ b/drivers/mpu9x50/mpu9x50_saul.c @@ -33,7 +33,7 @@ static int read_acc(const void *dev, phydat_t *res) } res->scale = -3; - res->unit = UNIT_G; + res->unit = UNIT_G_FORCE; return 3; } @@ -59,7 +59,7 @@ static int read_mag(const void *dev, phydat_t *res) } res->scale = -2; - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; return 3; } diff --git a/drivers/qmc5883l/qmc5883l_saul.c b/drivers/qmc5883l/qmc5883l_saul.c index 266b46e155efa..ed68e4aaaf9f1 100644 --- a/drivers/qmc5883l/qmc5883l_saul.c +++ b/drivers/qmc5883l/qmc5883l_saul.c @@ -27,7 +27,7 @@ static int read(const void *dev, phydat_t *res) { int ret = qmc5883l_read((const qmc5883l_t *)dev, res->val); if ((ret == QMC5883L_OK) || (ret == QMC5883L_OVERFLOW)) { - res->unit = UNIT_GS; + res->unit = UNIT_GAUSS; res->scale = -3; return 3; } diff --git a/sys/include/phydat.h b/sys/include/phydat.h index d4083b2a25936..7322cd8970582 100644 --- a/sys/include/phydat.h +++ b/sys/include/phydat.h @@ -87,16 +87,16 @@ enum { UNIT_M2, /**< square meters */ UNIT_M3, /**< cubic meters */ /* kinetic */ - UNIT_G, /**< gravitational force */ + UNIT_G_FORCE, /**< gravitational force equivalent */ UNIT_DPS, /**< degree per second */ /* weight */ - UNIT_GR, /**< grams - not using the SI unit (kg) here to make scale + UNIT_GRAM, /**< grams - not using the SI unit (kg) here to make scale * handling simpler */ /* electricity */ UNIT_A, /**< Ampere */ UNIT_V, /**< Volts */ UNIT_W, /**< Watt */ - UNIT_GS, /**< gauss */ + UNIT_GAUSS, /**< gauss */ UNIT_T, /**< Tesla */ UNIT_DBM, /**< decibel-milliwatts */ UNIT_COULOMB, /**< coulomb */ @@ -126,6 +126,27 @@ enum { /* extend this list as needed */ }; +/** + * @brief Compatibility alias for @ref UNIT_G_FORCE + * + * @deprecated Use @ref UNIT_G_FORCE instead + */ +#define UNIT_G UNIT_G_FORCE + +/** + * @brief Compatibility alias for @ref UNIT_GRAM + * + * @deprecated Use @ref UNIT_GRAM instead + */ +#define UNIT_GR UNIT_GRAM + +/** + * @brief Compatibility alias for @ref UNIT_GAUSS + * + * @deprecated Use @ref UNIT_GAUSS instead + */ +#define UNIT_GS UNIT_GAUSS + /** * @brief Generic data structure for expressing physical values * diff --git a/sys/include/senml/phydat.h b/sys/include/senml/phydat.h index 1c645c5444b4a..8ebfb1a20065e 100644 --- a/sys/include/senml/phydat.h +++ b/sys/include/senml/phydat.h @@ -58,10 +58,10 @@ void phydat_to_senml_bool(senml_bool_value_t *senml, const phydat_t *phydat, con * * - @ref UNIT_TIME is converted to @ref SENML_UNIT_SECOND. * - @ref UNIT_F is converted to @ref SENML_UNIT_KELVIN. - * - @ref UNIT_G is converted to @ref SENML_UNIT_METER_PER_SQUARE_SECOND. + * - @ref UNIT_G_FORCE is converted to @ref SENML_UNIT_METER_PER_SQUARE_SECOND. * - @ref UNIT_BAR is converted to @ref SENML_UNIT_PASCAL. * - @ref UNIT_GPM3 is converted to @ref SENML_UNIT_KILOGRAM_PER_CUBIC_METER. - * - @ref UNIT_GS is converted to @ref SENML_UNIT_TESLA. + * - @ref UNIT_GAUSS is converted to @ref SENML_UNIT_TESLA. * - Compatible units are set to their SenML equivalent. * - Incompatible (or unknown) units are set to @ref SENML_UNIT_NONE. * @@ -80,7 +80,7 @@ void phydat_to_senml_float(senml_value_t *senml, const phydat_t *phydat, const u * - @ref UNIT_TIME is converted to @ref SENML_UNIT_SECOND. * - @ref UNIT_BAR is converted to @ref SENML_UNIT_PASCAL. * - @ref UNIT_GPM3 is converted to @ref SENML_UNIT_KILOGRAM_PER_CUBIC_METER. - * - @ref UNIT_GS is converted to @ref SENML_UNIT_TESLA. + * - @ref UNIT_GAUSS is converted to @ref SENML_UNIT_TESLA. * - Compatible units are set to their SenML equivalent. * - Incompatible (or unknown) units are set to @ref SENML_UNIT_NONE. * diff --git a/sys/phydat/phydat_str.c b/sys/phydat/phydat_str.c index bad60643f3423..c51d793327942 100644 --- a/sys/phydat/phydat_str.c +++ b/sys/phydat/phydat_str.c @@ -106,14 +106,14 @@ const char *phydat_unit_to_str(uint8_t unit) case UNIT_M: return "m"; case UNIT_M2: return "m^2"; case UNIT_M3: return "m^3"; - case UNIT_G: return "g"; + case UNIT_G_FORCE: return "g"; case UNIT_DPS: return "dps"; - case UNIT_GR: return "G"; + case UNIT_GRAM: return "g"; case UNIT_A: return "A"; case UNIT_V: return "V"; case UNIT_W: return "W"; case UNIT_DBM: return "dBm"; - case UNIT_GS: return "Gs"; + case UNIT_GAUSS: return "G"; case UNIT_T: return "T"; case UNIT_BAR: return "Bar"; case UNIT_PA: return "Pa"; diff --git a/sys/senml/phydat.c b/sys/senml/phydat.c index 31b3c2dd4831e..d08a93a96bb01 100644 --- a/sys/senml/phydat.c +++ b/sys/senml/phydat.c @@ -24,7 +24,7 @@ static uint8_t phydat_unit_to_senml_unit(uint8_t unit) case UNIT_M: return SENML_UNIT_METER; case UNIT_M2: return SENML_UNIT_SQUARE_METER; case UNIT_M3: return SENML_UNIT_CUBIC_METER; - case UNIT_GR: return SENML_UNIT_GRAM; + case UNIT_GRAM: return SENML_UNIT_GRAM; case UNIT_A: return SENML_UNIT_AMPERE; case UNIT_V: return SENML_UNIT_VOLT; case UNIT_W: return SENML_UNIT_WATT; @@ -45,8 +45,8 @@ static uint8_t phydat_unit_to_senml_unit(uint8_t unit) /* Incompatible units */ case UNIT_TEMP_F: return SENML_UNIT_NONE; /* use K or Cel instead */ - case UNIT_GS: return SENML_UNIT_NONE; /* use T instead */ - case UNIT_G: return SENML_UNIT_NONE; /* use m/s2 instead */ + case UNIT_GAUSS: return SENML_UNIT_NONE; /* use T instead */ + case UNIT_G_FORCE: return SENML_UNIT_NONE; /* use m/s2 instead */ case UNIT_BAR: return SENML_UNIT_NONE; /* use Pa or hPa instead */ case UNIT_TIME: return SENML_UNIT_NONE; /* split into second/minute/hour */ case UNIT_DATE: return SENML_UNIT_NONE; /* split into day/month/year */ @@ -87,7 +87,7 @@ void phydat_to_senml_float(senml_value_t *senml, const phydat_t *phydat, const u value = (value + 459.67) * (5. / 9.); senml->attr.unit = SENML_UNIT_KELVIN; break; - case UNIT_G: + case UNIT_G_FORCE: /* convert gravitational acceleration to acceleration */ value *= 9.80665; senml->attr.unit = SENML_UNIT_METER_PER_SQUARE_SECOND; @@ -100,7 +100,7 @@ void phydat_to_senml_float(senml_value_t *senml, const phydat_t *phydat, const u value *= 0.001; senml->attr.unit = SENML_UNIT_KILOGRAM_PER_CUBIC_METER; break; - case UNIT_GS: + case UNIT_GAUSS: value *= 0.0001; senml->attr.unit = SENML_UNIT_TESLA; break; @@ -138,7 +138,7 @@ void phydat_to_senml_decimal(senml_value_t *senml, const phydat_t *phydat, const e -= 3; senml->attr.unit = SENML_UNIT_KILOGRAM_PER_CUBIC_METER; break; - case UNIT_GS: + case UNIT_GAUSS: e -= 4; senml->attr.unit = SENML_UNIT_TESLA; break; diff --git a/tests/phydat_dump/main.c b/tests/phydat_dump/main.c index f4225b78c76a6..dc18897645f6d 100644 --- a/tests/phydat_dump/main.c +++ b/tests/phydat_dump/main.c @@ -39,13 +39,13 @@ _phydat_test_t _test_vector[] = { .dim = 3, .dat = { .val = { 1234, 13456, -14567 }, .unit = UNIT_M, .scale = -3 } }, { .dim = 1, .dat = { .val = { -12345 }, .unit = UNIT_M2, .scale = -5 } }, { .dim = 1, .dat = { .val = { -12345 }, .unit = UNIT_M3, .scale = -6 } }, - { .dim = 3, .dat = { .val = { 12, 34, 5678}, .unit = UNIT_G, .scale = -2 } }, + { .dim = 3, .dat = { .val = { 12, 34, 5678}, .unit = UNIT_G_FORCE, .scale = -2 } }, { .dim = 3, .dat = { .val = { 123, 345, 678 }, .unit = UNIT_DPS, .scale = -3 } }, - { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_GR, .scale = -1 } }, + { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_GRAM, .scale = -1 } }, { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_A, .scale = 3 } }, { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_V, .scale = 6 } }, { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_W, .scale = 7 } }, - { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_GS, .scale = -1 } }, + { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_GAUSS, .scale = -1 } }, { .dim = 3, .dat = { .val = { 123, 456, 789 }, .unit = UNIT_T, .scale = -9 } }, { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_DBM, .scale = -3 } }, { .dim = 1, .dat = { .val = { 12345 }, .unit = UNIT_COULOMB, .scale = 0 } }, diff --git a/tests/phydat_dump/tests/01-run.py b/tests/phydat_dump/tests/01-run.py index 670c589e06d1a..b909b60aac62e 100755 --- a/tests/phydat_dump/tests/01-run.py +++ b/tests/phydat_dump/tests/01-run.py @@ -39,11 +39,11 @@ def testfunc(child): child.expect(r'Data:\t\[0\] 123 mdps\r\n') child.expect(r'\t\[1\] 345 mdps\r\n') child.expect(r'\t\[2\] 678 mdps\r\n') - child.expect(r'Data:\t 1234.5 G\r\n') + child.expect(r'Data:\t 1234.5 g\r\n') child.expect(r'Data:\t 12345 kA\r\n') child.expect(r'Data:\t 12345 MV\r\n') child.expect(r'Data:\t 12345e7 W\r\n') - child.expect(r'Data:\t 1234.5 Gs\r\n') + child.expect(r'Data:\t 1234.5 G\r\n') child.expect(r'Data:\t\[0\] 123 nT\r\n') child.expect(r'\t\[1\] 456 nT\r\n') child.expect(r'\t\[2\] 789 nT\r\n') diff --git a/tests/senml_phydat/main.c b/tests/senml_phydat/main.c index 0781912f11dc2..2704bb168dc09 100644 --- a/tests/senml_phydat/main.c +++ b/tests/senml_phydat/main.c @@ -84,7 +84,7 @@ static value_test_t value_tests[] = { .senml2 = senml_df(0, 3, SENML_UNIT_NONE), }, { - .phydat = { { 314, 0, 0 }, UNIT_G, -2 }, + .phydat = { { 314, 0, 0 }, UNIT_G_FORCE, -2 }, .senml1 = senml_f(30.792881, SENML_UNIT_METER_PER_SQUARE_SECOND), .senml2 = senml_df(314, -2, SENML_UNIT_NONE), }, @@ -99,7 +99,7 @@ static value_test_t value_tests[] = { .senml2 = senml_df(193, 2, SENML_UNIT_KILOGRAM_PER_CUBIC_METER), }, { - .phydat = { { 220, 0, 0 }, UNIT_GS, 3 }, + .phydat = { { 220, 0, 0 }, UNIT_GAUSS, 3 }, .senml1 = senml_f(22, SENML_UNIT_TESLA), .senml2 = senml_df(220, -1, SENML_UNIT_TESLA), } diff --git a/tests/unittests/tests-phydat/tests-phydat.c b/tests/unittests/tests-phydat/tests-phydat.c index 504f029db5814..d7e08ba859528 100644 --- a/tests/unittests/tests-phydat/tests-phydat.c +++ b/tests/unittests/tests-phydat/tests-phydat.c @@ -58,7 +58,7 @@ static tdat_t data[] = { }, { .dim = 3, - .dat = { { 1032, 10, -509 }, UNIT_G, -3 }, + .dat = { { 1032, 10, -509 }, UNIT_G_FORCE, -3 }, .json = "{\"d\":[1.032,0.010,-0.509],\"u\":\"g\"}", }, { @@ -204,14 +204,14 @@ static void test_unitstr__success(void) TEST_ASSERT_EQUAL_STRING("m", phydat_unit_to_str_verbose(UNIT_M)); TEST_ASSERT_EQUAL_STRING("m^2", phydat_unit_to_str_verbose(UNIT_M2)); TEST_ASSERT_EQUAL_STRING("m^3", phydat_unit_to_str_verbose(UNIT_M3)); - TEST_ASSERT_EQUAL_STRING("g", phydat_unit_to_str_verbose(UNIT_G)); + TEST_ASSERT_EQUAL_STRING("g", phydat_unit_to_str_verbose(UNIT_G_FORCE)); TEST_ASSERT_EQUAL_STRING("dps", phydat_unit_to_str_verbose(UNIT_DPS)); - TEST_ASSERT_EQUAL_STRING("G", phydat_unit_to_str_verbose(UNIT_GR)); + TEST_ASSERT_EQUAL_STRING("g", phydat_unit_to_str_verbose(UNIT_GRAM)); TEST_ASSERT_EQUAL_STRING("A", phydat_unit_to_str_verbose(UNIT_A)); TEST_ASSERT_EQUAL_STRING("V", phydat_unit_to_str_verbose(UNIT_V)); TEST_ASSERT_EQUAL_STRING("W", phydat_unit_to_str_verbose(UNIT_W)); TEST_ASSERT_EQUAL_STRING("dBm", phydat_unit_to_str_verbose(UNIT_DBM)); - TEST_ASSERT_EQUAL_STRING("Gs", phydat_unit_to_str_verbose(UNIT_GS)); + TEST_ASSERT_EQUAL_STRING("G", phydat_unit_to_str_verbose(UNIT_GAUSS)); TEST_ASSERT_EQUAL_STRING("T", phydat_unit_to_str_verbose(UNIT_T)); TEST_ASSERT_EQUAL_STRING("Bar", phydat_unit_to_str_verbose(UNIT_BAR)); TEST_ASSERT_EQUAL_STRING("Pa", phydat_unit_to_str_verbose(UNIT_PA)); From 463e2e721ab3c5ab317ffe82c40fdebec6b14c22 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 2 Aug 2022 22:13:45 +0200 Subject: [PATCH 6/6] drivers/servo: reimplement with high level interface The previous servo driver didn't provide any benefit over using PWM directly, as users controlled the servo in terms of PWM duty cycles. This changes the interface to provide a high level interface that abstracts the gory PWM details. In addition, a SAUL layer and auto-initialization is provided. Co-authored-by: benpicco --- drivers/include/servo.h | 230 +++++++++++++++---- drivers/saul/init_devs/auto_init_servo.c | 58 +++++ drivers/saul/init_devs/init.c | 4 + drivers/servo/Kconfig | 32 ++- drivers/servo/Makefile | 2 +- drivers/servo/Makefile.dep | 23 +- drivers/servo/Makefile.include | 2 + drivers/servo/include/servo_params.h | 273 +++++++++++++++++++++++ drivers/servo/pwm.c | 100 +++++++++ drivers/servo/saul.c | 70 ++++++ drivers/servo/servo.c | 107 --------- drivers/servo/timer.c | 160 +++++++++++++ makefiles/pseudomodules.inc.mk | 15 ++ tests/driver_servo/Makefile | 19 +- tests/driver_servo/app.config.test | 5 +- tests/driver_servo/main.c | 59 +---- 16 files changed, 949 insertions(+), 210 deletions(-) create mode 100644 drivers/saul/init_devs/auto_init_servo.c create mode 100644 drivers/servo/Makefile.include create mode 100644 drivers/servo/include/servo_params.h create mode 100644 drivers/servo/pwm.c create mode 100644 drivers/servo/saul.c delete mode 100644 drivers/servo/servo.c create mode 100644 drivers/servo/timer.c diff --git a/drivers/include/servo.h b/drivers/include/servo.h index d74b89cb6b24d..26b84add825d4 100644 --- a/drivers/include/servo.h +++ b/drivers/include/servo.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2014 Freie Universität Berlin * Copyright (C) 2015 Eistec AB + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -11,6 +12,23 @@ * @defgroup drivers_servo Servo Motor Driver * @ingroup drivers_actuators * @brief High-level driver for servo motors + * + * Usage + * ===== + * + * Select a flavor of the driver, e.g. `USEMODULE += servo_pwm` for + * @ref drivers_servo_pwm or `USEMODULE += servo_timer` for + * @ref drivers_servo_timer to use. Typically, the PWM implementation is the + * preferred one, but some MCU (e.g. nRF52xxx) cannot configure the PWM + * peripheral to run anywhere close to the 50 Hz to 100 Hz required. + * + * In addition, you many need to extend or adapt @ref servo_params and, + * depending on the selected implementation, @ref servo_pwm_params or + * @ref servo_timer_params to match your hardware configuration. + * + * The test application in `tests/driver_servo` can serve as starting point for + * users. + * * @{ * * @file @@ -18,75 +36,197 @@ * * @author Hauke Petersen * @author Joakim Nohlgård + * @author Marian Buschsieweke */ #ifndef SERVO_H #define SERVO_H +#include +#include + #include "periph/pwm.h" +#include "periph/timer.h" +#include "saul.h" +#include "saul_reg.h" +#include "time_units.h" + +#ifndef SERVO_TIMER_MAX_CHAN +/** + * @brief In case the `servo_timer` backend is used to driver the servo, + * this is the highest channel number usable by the driver + * + * @note To drive *n* servos, *n* + 1 timer channels are required. Hence, + * this must be at least 2 + * + * Trimming this down safes a small bit of RAM: Storage for one pointer is + * wasted on every servo that could be controlled by a timer but is not + * actually used. + */ +#define SERVO_TIMER_MAX_CHAN 4 +#endif #ifdef __cplusplus extern "C" { #endif /** - * @brief Descriptor struct for a servo + * @brief The SAUL adaption driver for servos + */ +extern const saul_driver_t servo_saul_driver; + +/** + * @brief PWM configuration parameters for a servos + * + * Only used with */ typedef struct { - pwm_t device; /**< the PWM device driving the servo */ - int channel; /**< the channel the servo is connected to */ - unsigned int min; /**< minimum pulse width, in us */ - unsigned int max; /**< maximum pulse width, in us */ - unsigned int scale_nom; /**< timing scale factor, to adjust for an inexact PWM frequency, nominator */ - unsigned int scale_den; /**< timing scale factor, to adjust for an inexact PWM frequency, denominator */ -} servo_t; + uint16_t res; /**< PWM resolution to use */ + uint16_t freq; /**< PWM frequency to use */ + pwm_t pwm; /**< PWM dev the servo is connected to */ +} servo_pwm_params_t; /** - * @brief Initialize a servo motor by assigning it a PWM device and channel - * - * Digital servos are controlled by regular pulses sent to them. The width - * of a pulse determines the position of the servo. A pulse width of 1.5ms - * puts the servo in the center position, a pulse width of about 1.0ms and - * about 2.0ms put the servo to the maximum angles. These values can however - * differ slightly from servo to servo, so the min and max values are - * parameterized in the init function. - * - * The servo is initialized with default PWM values: - * - frequency: 100Hz (10ms interval) - * - resolution: 10000 (1000 steps per ms) - * - * These default values can be changed by setting SERVO_RESOLUTION and - * SERVO_FREQUENCY macros. - * Caution: When initializing a servo, the PWM device will be reconfigured to - * new frequency/resolution values. It is however fine to use multiple servos - * with the same PWM device, just on different channels. - * - * @param[out] dev struct describing the servo - * @param[in] pwm the PWM device the servo is connected to - * @param[in] pwm_channel the PWM channel the servo is connected to - * @param[in] min minimum pulse width (in the resolution range) - * @param[in] max maximum pulse width (in the resolution range) - * - * @return 0 on success - * @return <0 on error + * @brief Servo device state */ -int servo_init(servo_t *dev, pwm_t pwm, int pwm_channel, unsigned int min, unsigned int max); +typedef struct servo servo_t; /** - * @brief Set the servo motor to a specified position + * @brief Memory needed for book keeping when using @ref drivers_servo_timer + */ +typedef struct { + /** + * @brief Look up table to get from channel + * + * @note Since timer channel 0 is used to set all servo pins, we use + * `chan - 1` as idx rather than `chan` to not waste one entry. + */ + servo_t *servo_map[SERVO_TIMER_MAX_CHAN]; +} servo_timer_ctx_t; + +/** + * @brief Timer configuration parameters for a servos + */ +typedef struct { + tim_t timer; /**< Timer to use */ + uint32_t timer_freq; /**< Timer frequency to use */ + uint16_t servo_freq; /**< Servo frequency (typically 50 Hz or 100 Hz) */ + servo_timer_ctx_t *ctx; /**< Per-timer state needed for book keeping */ +} servo_timer_params_t; + +/** + * @brief Configuration parameters for a servo + */ +typedef struct { +#if defined(MODULE_SERVO_PWM) || defined(DOXYGEN) + /** + * @brief Specification of the PWM device the servo is connected to + * + * @note Only available when @ref drivers_servo_pwm is used + */ + const servo_pwm_params_t *pwm; +#endif +#if defined(MODULE_SERVO_TIMER) || defined(DOXYGEN) + /** + * @brief Specification of the timer to use + * + * @note Only available when @ref drivers_servo_timer is used + */ + const servo_timer_params_t *timer; + /** + * @brief GPIO pin the servo is connected to + * + * @note Only available when @ref drivers_servo_timer is used + */ + gpio_t servo_pin; +#endif + uint16_t min_us; /**< Duration of high phase (in µs) for min extension */ + uint16_t max_us; /**< Duration of high phase (in µs) for max extension */ +#ifdef MODULE_SERVO_PWM + /** + * @brief PWM channel to use + * + * @note Only available when @ref drivers_servo_pwm is used + */ + uint8_t pwm_chan; +#endif +#ifdef MODULE_SERVO_TIMER + /** + * @brief Timer channel to use + * + * @pre `(timer_chan > 0) && (timer_chan <= SERVO_TIMER_MAX_CHAN)` + * + * @note Only available when @ref drivers_servo_timer is used + * + * The timer channel 0 is used to set the GPIO pin of all servos + * driver by the timer, the other channels are used to clean the GPIO pin + * of the corresponding servo according to the current duty cycle. + */ + uint8_t timer_chan; +#endif +} servo_params_t; + +/** + * @brief Servo device state + */ +struct servo { + const servo_params_t *params; /**< Parameters of this servo */ + /** + * @brief Minimum PWM duty cycle / timer target matching + * @ref servo_params_t::min_us + * + * Note that the actual PWM frequency can be significantly different from + * the requested one, depending on what the hardware can generate using the + * clock source and clock dividers available. + */ + uint16_t min; + /** + * @brief Maximum PWM duty cycle / timer target matching + * @ref servo_params_t::min_us + * + * Note that the actual PWM frequency can be significantly different from + * the requested one, depending on what the hardware can generate using the + * clock source and clock dividers available. + */ + uint16_t max; +#ifdef MODULE_SERVO_TIMER + uint16_t current; /**< Current timer target */ +#endif +}; + +#if defined(MODULE_SERVO_TIMER) || DOXYGEN +/** + * @brief Default timer context + */ +extern servo_timer_ctx_t servo_timer_default_ctx; +#endif + +/** + * @brief Initialize servo * - * The position of the servo is specified in the pulse width that - * controls the servo. With default configurations, a value of 1500 - * means a pulse width of 1.5 ms, which is the center position on - * most servos. + * @param[out] dev Device handle to initialize + * @param[in] params Parameters defining the PWM configuration * - * In case pos is larger/smaller then the max/min values, pos will be set to - * these values. + * @retval 0 Success + * @retval <0 Failure (as negative errno code to indicate cause) + */ +int servo_init(servo_t *dev, const servo_params_t *params); + +/** + * @brief Set the servo motor to a specified position + * + * The position of the servo is specified in the fraction of maximum extension, + * with 0 being the lowest extension (e.g. on an 180° servo it would be at -90°) + * and `UINT8_MAX` being the highest extension (e.g. +90° on that 180° servo). * * @param[in] dev the servo to set - * @param[in] pos the position to set the servo (in the resolution range) + * @param[in] pos the extension to set + * + * Note: 8 bit of resolution may seem low, but is indeed more than high enough + * for any practical PWM based servo. For higher precision, stepper motors would + * be required. */ -void servo_set(const servo_t *dev, unsigned int pos); +void servo_set(servo_t *dev, uint8_t pos); #ifdef __cplusplus } diff --git a/drivers/saul/init_devs/auto_init_servo.c b/drivers/saul/init_devs/auto_init_servo.c new file mode 100644 index 0000000000000..a53a741bc0be8 --- /dev/null +++ b/drivers/saul/init_devs/auto_init_servo.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_saul + * @ingroup sys_auto_init_saul + * @{ + * + * @file + * @brief Auto initialization for servo motors + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#include "assert.h" +#include "kernel_defines.h" +#include "log.h" +#include "phydat.h" +#include "saul.h" +#include "saul/periph.h" +#include "saul_reg.h" +#include "servo.h" +#include "servo_params.h" + +#define SERVO_NUMOF ARRAY_SIZE(servo_params) + +static servo_t servos[SERVO_NUMOF]; +static saul_reg_t saul_entries[SERVO_NUMOF]; + +void auto_init_servo(void) +{ + for (unsigned i = 0; i < SERVO_NUMOF; i++) { + LOG_DEBUG("[servo] auto-init servo #%u\n", i); + int retval = servo_init(&servos[i], &servo_params[i]); + if (retval != 0) { + LOG_WARNING("[servo] auto-init of servo #%u failed: %d\n", + i, retval); + continue; + } + saul_reg_t *e = &saul_entries[i]; + + e->dev = &servos[i]; + e->name = servo_saul_info[i].name; + e->driver = &servo_saul_driver; + + saul_reg_add(e); + } +} diff --git a/drivers/saul/init_devs/init.c b/drivers/saul/init_devs/init.c index 55b26e96aded7..6853178912352 100644 --- a/drivers/saul/init_devs/init.c +++ b/drivers/saul/init_devs/init.c @@ -339,4 +339,8 @@ void saul_init_devs(void) extern void auto_init_vl6180x(void); auto_init_vl6180x(); } + if (IS_USED(MODULE_SERVO)) { + extern void auto_init_servo(void); + auto_init_servo(); + } } diff --git a/drivers/servo/Kconfig b/drivers/servo/Kconfig index 9cff354f93e58..744c7de1b5469 100644 --- a/drivers/servo/Kconfig +++ b/drivers/servo/Kconfig @@ -6,7 +6,35 @@ # config MODULE_SERVO - bool "Servo Motor driver" - depends on HAS_PERIPH_PWM + bool "Servo motor driver" + depends on TEST_KCONFIG + select MODULE_SERVO_SAUL if MODULE_SAUL_DEFAULT + +config MODULE_SERVO_SAUL + bool "SAUL integration of the servo motor driver" depends on TEST_KCONFIG + +choice SERVO_DRIVER_BACKEND + bool "Servo motor driver backend" + depends on MODULE_SERVO + default MODULE_SERVO_PWM if HAS_PERIPH_PWM + default MODULE_SERVO_TIMER if !HAS_PERIPH_PWM && HAS_PERIPH_TIMER_PERIODIC + +config MODULE_SERVO_PWM + bool "periph_pwm based Servo Motor driver backend (preferred)" + depends on HAS_PERIPH_PWM + # PWM prescaler on nRF5x MCUs cannot generate a 50 Hz signal + depends on !HAS_CPU_NRF51 + depends on !HAS_CPU_NRF52 + depends on !HAS_CPU_NRF9160 select MODULE_PERIPH_PWM + select SERVO_DRIVER_BACKEND + +config MODULE_SERVO_TIMER + bool "periph_timer based Servo Motor driver backend" + depends on HAS_PERIPH_TIMER + depends on HAS_PERIPH_TIMER_PERIODIC + select MODULE_PERIPH_TIMER + select MODULE_PERIPH_TIMER_PERIODIC + select SERVO_DRIVER_BACKEND +endchoice diff --git a/drivers/servo/Makefile b/drivers/servo/Makefile index 2ff3f9dcb1578..cd1af2456e055 100644 --- a/drivers/servo/Makefile +++ b/drivers/servo/Makefile @@ -1,3 +1,3 @@ -MODULE = servo +SUBMODULES := 1 include $(RIOTBASE)/Makefile.base diff --git a/drivers/servo/Makefile.dep b/drivers/servo/Makefile.dep index 3e3849e830548..318c71dde80b9 100644 --- a/drivers/servo/Makefile.dep +++ b/drivers/servo/Makefile.dep @@ -1 +1,22 @@ -FEATURES_REQUIRED += periph_pwm +ifneq (,$(filter saul,$(USEMODULE))) + DEFAULT_MODULE += servo_saul +endif + +# if no servo driver implementation is chosen, we pick one +ifeq (,$(filter servo_pwm servo_timer,$(USEMODULE))) + # choose servo_pwm except for MCUs known to be incompatible + ifneq (,$(filter nrf5%, $(CPU_FAM))) + USEMODULE += servo_timer + else + USEMODULE += servo_pwm + endif +endif + +ifneq (,$(filter servo_pwm,$(USEMODULE))) + FEATURES_REQUIRED += periph_pwm +endif + +ifneq (,$(filter servo_timer,$(USEMODULE))) + FEATURES_REQUIRED += periph_timer_periodic + FEATURES_REQUIRED += periph_gpio +endif diff --git a/drivers/servo/Makefile.include b/drivers/servo/Makefile.include new file mode 100644 index 0000000000000..a28c5c5ddf69b --- /dev/null +++ b/drivers/servo/Makefile.include @@ -0,0 +1,2 @@ +USEMODULE_INCLUDES_servo := $(LAST_MAKEFILEDIR)/include +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_servo) diff --git a/drivers/servo/include/servo_params.h b/drivers/servo/include/servo_params.h new file mode 100644 index 0000000000000..03a82aa5ddd4a --- /dev/null +++ b/drivers/servo/include/servo_params.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_servo + * + * @{ + * @file + * @brief Default configuration for servo devices + * + * @author Marian Buschsieweke + */ + +#ifndef SERVO_PARAMS_H +#define SERVO_PARAMS_H + +#include "board.h" +#include "macros/units.h" +#include "periph/gpio.h" +#include "periph/pwm.h" +#include "periph/timer.h" +#include "saul_reg.h" +#include "servo.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Default servo PWM configuration + * @{ + */ +#ifndef SERVO_PWM_PARAM_DEV +/** + * @brief PWM device to use to control the servo + * + * Defaults to `PWM_DEV(0)`. + */ +#define SERVO_PWM_PARAM_DEV PWM_DEV(0) +#endif + +#ifndef SERVO_PWM_PARAM_RES +/** + * @brief PWM resolution to use to control the servo + * + * Defaults to `UINT16_MAX`. + */ +#define SERVO_PWM_PARAM_RES UINT16_MAX +#endif + +#ifndef SERVO_PWM_PARAM_FREQ +/** + * @brief PWM frequency in Hertz to use to control the servo + * + * Defaults to `50UL` Hz. + */ +#define SERVO_PWM_PARAM_FREQ 50 +#endif + +#ifndef SERVO_PWM_PARAMS +/** + * @brief PWM parameters for controlling a servo + */ +#define SERVO_PWM_PARAMS {\ + .pwm = SERVO_PWM_PARAM_DEV, \ + .freq = SERVO_PWM_PARAM_FREQ, \ + .res = SERVO_PWM_PARAM_RES, \ + } +#endif +/** @} */ + +/** + * @brief Servo PWM parameters + */ +static const servo_pwm_params_t servo_pwm_params[] = +{ + SERVO_PWM_PARAMS +}; + +/** + * @name Default servo timer configuration + * @{ + */ +#ifndef SERVO_TIMER_PARAM_DEV +/** + * @brief Timer to use to control the servo + * + * Defaults to `TIMER_DEV(1)`. + */ +#define SERVO_TIMER_PARAM_DEV TIMER_DEV(1) +#endif + +#ifndef SERVO_TIMER_PARAM_TIMER_FREQ +/** + * @brief Timer frequency to use to control the servo in Hz + * + * Defaults to 1 MHz + */ +#define SERVO_TIMER_PARAM_TIMER_FREQ MHZ(1) +#endif + +#ifndef SERVO_TIMER_PARAM_SERVO_FREQ +/** + * @brief Servo frequency in Hertz + * + * Defaults to `50UL` Hz. + */ +#define SERVO_TIMER_PARAM_SERVO_FREQ 50 +#endif + +#ifndef SERVO_TIMER_PARAM_TIMER_CTX +/** + * @brief Default servo timer context + * + * Allocated in drivers/servo/timer.c + */ +extern servo_timer_ctx_t servo_timer_default_ctx; +/** + * @brief Memory needed for book keeping + * + * Defaults to `&servo_timer_default_ctx`. One context per timer used is needed. + * E.g. when 4 servos are connected but all are controlled with the same timer + * peripheral, only one context is needed. + */ +#define SERVO_TIMER_PARAM_TIMER_CTX (&servo_timer_default_ctx) +#endif + +#ifndef SERVO_TIMER_PARAMS +/** + * @brief TIMER parameters for controlling a servo + */ +#define SERVO_TIMER_PARAMS {\ + .timer = SERVO_TIMER_PARAM_DEV, \ + .timer_freq = SERVO_TIMER_PARAM_TIMER_FREQ, \ + .servo_freq = SERVO_TIMER_PARAM_SERVO_FREQ, \ + .ctx = SERVO_TIMER_PARAM_TIMER_CTX, \ + } +#endif +/** @} */ + +/** + * @brief Servo timer parameters + */ +static const servo_timer_params_t servo_timer_params[] = +{ + SERVO_TIMER_PARAMS +}; + +/** + * @name Default servo configuration + * @{ + */ +#ifndef SERVO_PARAM_PWM_PARAMS +/** + * @brief PWM parameters + * + * Defaults to `&servo_pwm_params[0]`. + */ +#define SERVO_PARAM_PWM_PARAMS (&servo_pwm_params[0]) +#endif + +#ifndef SERVO_PARAM_TIMER_PARAMS +/** + * @brief Timer parameters + * + * Defaults to `&servo_timer_params[0]`. + */ +#define SERVO_PARAM_TIMER_PARAMS (&servo_timer_params[0]) +#endif + +#ifndef SERVO_PARAM_PWM_CHAN +/** + * @brief PWM channel to use to control the servo + * + * Defaults to `0` + */ +#define SERVO_PARAM_PWM_CHAN 0 +#endif + +#ifndef SERVO_PARAM_TIMER_CHAN +/** + * @brief Timer channel used to clear the servo pin + * + * Defaults to `1` + */ +#define SERVO_PARAM_TIMER_CHAN 1 +#endif + +#ifndef SERVO_PARAM_PIN +/** + * @brief GPIO pin the servo input is connected to + * + * @note Only used with @ref drivers_servo_timer + */ +#define SERVO_PARAM_PIN GPIO_UNDEF +#endif + +#ifndef SERVO_PARAM_MIN_US +/** + * @brief Minimum time in µs of a pulse (corresponds to minimum extension) + * + * Defaults to `900UL`. + */ +#define SERVO_PARAM_MIN_US 900UL +#endif + +#ifndef SERVO_PARAM_MAX_US +/** + * @brief Maximum time in µs of a pulse (corresponds to maximum extension) + * + * Defaults to `2100UL`. + */ +#define SERVO_PARAM_MAX_US 2100UL +#endif + +#ifndef SERVO_PARAMS +/** + * @brief Parameters for controlling a servo + */ +#ifdef MODULE_SERVO_PWM +#define SERVO_PARAMS {\ + .pwm = SERVO_PARAM_PWM_PARAMS, \ + .min_us = SERVO_PARAM_MIN_US, \ + .max_us = SERVO_PARAM_MAX_US, \ + .pwm_chan = SERVO_PARAM_PWM_CHAN, \ + } +#endif +#ifdef MODULE_SERVO_TIMER +#define SERVO_PARAMS {\ + .timer = SERVO_PARAM_TIMER_PARAMS, \ + .servo_pin = SERVO_PARAM_PIN, \ + .min_us = SERVO_PARAM_MIN_US, \ + .max_us = SERVO_PARAM_MAX_US, \ + .timer_chan = SERVO_PARAM_TIMER_CHAN, \ + } +#endif +#endif +/**@}*/ + +/** + * @brief Servo configuration + */ +static const servo_params_t servo_params[] = +{ + SERVO_PARAMS +}; + +#ifndef SERVO_SAULINFO +/** + * @brief Servo SAUL info + */ +#define SERVO_SAULINFO { .name = "servo" } +#endif + +/** + * @brief Allocate and configure entries to the SAUL registry + */ +static const saul_reg_info_t servo_saul_info[] = +{ + SERVO_SAULINFO +}; + +#ifdef __cplusplus +} +#endif + +#endif /* SERVO_PARAMS_H */ +/** @} */ diff --git a/drivers/servo/pwm.c b/drivers/servo/pwm.c new file mode 100644 index 0000000000000..17e3210b4d501 --- /dev/null +++ b/drivers/servo/pwm.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2015 Eistec AB + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_servo_pwm + * @{ + * + * @file + * @brief Servo motor driver implementation using PWM + * + * @author Hauke Petersen + * @author Joakim Nohlgård + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include +#include + +#include "kernel_defines.h" +#include "periph/pwm.h" +#include "servo.h" +#include "test_utils/expect.h" +#include "macros/math.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +/** + * @brief Calculate the duty cycle corresponding to the given duration of the + * "on duration" + * @param pwm_freq frequency of the PWM peripheral + * @param pwm_res resolution of the PWM peripheral + * @param duration duration of the "on phase" in microseconds + * + * @note Scientific rounding is used + */ +static uint16_t duty_cycle(uint32_t freq, uint16_t res, uint16_t duration_us) +{ + return DIV_ROUND((uint64_t)duration_us * freq * res, US_PER_SEC); +} + +int servo_init(servo_t *dev, const servo_params_t *params) +{ + memset(dev, 0, sizeof(*dev)); + const servo_pwm_params_t *pwm_params = params->pwm; + DEBUG("[servo] trying to initialize PWM %u with frequency %u Hz " + "and resolution %u\n", + (unsigned)pwm_params->pwm, (unsigned)pwm_params->freq, + (unsigned)pwm_params->res); + + /* Note: This may initialize the PWM dev over and over again if multiple + * servos are connected to the same PWM. But other than wasting CPU + * cycles, this does no harm. And it greatly simplifies the API, so + * we willfully accept this inefficiency here. + */ + uint32_t freq = pwm_init(pwm_params->pwm, PWM_LEFT, pwm_params->freq, + pwm_params->res); + DEBUG("[servo] initialized PWM %u with frequency %" PRIu32 " Hz\n", + (unsigned)pwm_params->pwm, freq); + + /* assert successful initialization with frequency roughly matching + * requested frequency. A 50 Hz MG90S servo controlled by a 100 Hz PWM + * worked just fine for me, so we are really lax here and accept + * everything in the range of [0.5f; 2f] */ + assert((freq != 0) + && (freq >= pwm_params->freq - pwm_params->freq / 2U) + && (freq <= pwm_params->freq * 2)); + + if (!freq) { + return -EIO; + } + + dev->params = params; + dev->min = duty_cycle(freq, pwm_params->res, params->min_us); + dev->max = duty_cycle(freq, pwm_params->res, params->max_us); + + return 0; +} + +void servo_set(servo_t *dev, uint8_t pos) +{ + const servo_params_t *par = dev->params; + uint32_t duty = dev->max - dev->min; + duty *= pos; + duty >>= 8; + duty += dev->min; + DEBUG("[servo] setting %p to %u (%u / 255)\n", + (void *)dev, (unsigned)duty, (unsigned)pos); + pwm_set(par->pwm->pwm, par->pwm_chan, duty); +} diff --git a/drivers/servo/saul.c b/drivers/servo/saul.c new file mode 100644 index 0000000000000..8ab1d25fd3419 --- /dev/null +++ b/drivers/servo/saul.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_saul + * @{ + * + * @file + * @brief SAUL wrapper for servo motors + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#include "assert.h" +#include "phydat.h" +#include "saul.h" +#include "saul/periph.h" +#include "saul_reg.h" +#include "servo.h" + +static int write(const void *dev, const phydat_t *state) +{ + servo_t *s = (void *)dev; + int32_t num = state->val[0]; + switch (state->unit) { + case UNIT_PERCENT: + num *= 100; + num >>= 8; + break; + case UNIT_PERMILL: + num *= 1000; + num >>= 8; + break; + case UNIT_BOOL: + num = (num) ? 255 : 0; + break; + case UNIT_NONE: + case UNIT_UNDEF: + break; + default: + return -EINVAL; + } + + if (num > UINT8_MAX) { + num = UINT8_MAX; + } + + if (num < 0) { + num = 0; + } + + servo_set(s, num); + return 1; +} + +const saul_driver_t servo_saul_driver = { + .read = saul_read_notsup, + .write = write, + .type = SAUL_ACT_SERVO, +}; diff --git a/drivers/servo/servo.c b/drivers/servo/servo.c deleted file mode 100644 index eac4dcbdef7d4..0000000000000 --- a/drivers/servo/servo.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Eistec AB - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. - */ - -/** - * @ingroup drivers_servo - * @{ - * - * @file - * @brief Servo motor driver implementation - * - * @author Hauke Petersen - * @author Joakim Nohlgård - * - * @} - */ - -#include "servo.h" -#include "periph/pwm.h" -#include "timex.h" /* for US_PER_SEC */ - -#define ENABLE_DEBUG 0 -#include "debug.h" - -#ifndef SERVO_FREQUENCY -#define SERVO_FREQUENCY (100U) -#endif - -#ifndef SERVO_RESOLUTION -#define SERVO_RESOLUTION (US_PER_SEC / SERVO_FREQUENCY) -#endif - -int servo_init(servo_t *dev, pwm_t pwm, int pwm_channel, unsigned int min, unsigned int max) -{ - int actual_frequency; - - actual_frequency = pwm_init(pwm, PWM_LEFT, SERVO_FREQUENCY, SERVO_RESOLUTION); - - DEBUG("servo: requested %d hz, got %d hz\n", SERVO_FREQUENCY, actual_frequency); - - if (actual_frequency < 0) { - /* PWM error */ - return -1; - } - dev->device = pwm; - dev->channel = pwm_channel; - dev->min = min; - dev->max = max; - - /* Compute scaling fractional */ - /* - * The PWM pulse width can be written as: - * - * t = k / (f * r) - * - * where t is the pulse high time, k is the value set in the PWM peripheral, - * f is the frequency, and r is the resolution of the PWM module. - * - * define t0 as the desired pulse width: - * - * t0 = k0 / (f0 * r) - * - * where f0 is the requested frequency, k0 is the requested number of ticks. - * Introducing f1 as the closest achievable frequency and k1 as the set tick - * value yields: - * - * t1 = k1 / (f1 * r) - * - * setting t1 = t0 and substituting k1 = k0 * s yields: - * - * k0 / (f0 * r) = k0 * s / (f1 * r) - * - * solve for s: - * - * s = f1 / f0 - * - * where s is the optimal scale factor to translate from requested position - * to actual hardware ticks. - */ - dev->scale_nom = actual_frequency; - dev->scale_den = SERVO_FREQUENCY; - - return 0; -} - -void servo_set(const servo_t *dev, unsigned int pos) -{ - unsigned int raw_value; - if (pos > dev->max) { - pos = dev->max; - } - else if (pos < dev->min) { - pos = dev->min; - } - - /* rescale value to match PWM peripheral configuration */ - raw_value = (pos * dev->scale_nom) / dev->scale_den; - - DEBUG("servo_set: pos %d -> raw %d\n", pos, raw_value); - - pwm_set(dev->device, dev->channel, raw_value); -} diff --git a/drivers/servo/timer.c b/drivers/servo/timer.c new file mode 100644 index 0000000000000..c47f31396ee06 --- /dev/null +++ b/drivers/servo/timer.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_servo_timer + * @{ + * + * @file + * @brief Servo motor driver implementation using periph_timer_periodic + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include +#include + +#include "atomic_utils.h" +#include "irq.h" +#include "kernel_defines.h" +#include "macros/math.h" +#include "periph/gpio.h" +#include "periph/timer.h" +#include "servo.h" +#include "test_utils/expect.h" +#include "time_units.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +servo_timer_ctx_t servo_timer_default_ctx; + +static unsigned ticks_from_us(uint64_t duration, uint64_t freq) +{ + return DIV_ROUND(duration * freq, US_PER_SEC); +} + +/* + * Timer channel 0 is always used for the rising flank of all servos driven + * by the same timer. The channels 1 till n are used for the falling flanks of + * servos 0 till n-1. E.g. as shown in this diagram: + * + * Servo_0 ______/""""\___________ + * Servo_1 ______/""""""""\_______ + * ... + * Servo_n ______/""""""""""""\___ + * + * ^ ^ ^ ^ + * | | | | + * timer chan 0 -+ | | | + * timer chan 1 ------+ | | + * timer chan 2 ----------+ | + * ... | + * timer chan n+1 ------------+ + * + * Channel 0 is set to the period of one PWM control cycle and due to flag + * `TIM_FLAG_RESET_ON_MATCH` will end the period and stat the new period. As + * a result, n+1 channels are needed to control n servos. + */ +static void timer_cb(void *arg, int chan) +{ + servo_timer_ctx_t *ctx = arg; + if (chan == 0) { + /* end of period, set the control pin of all controlled servos */ + for (unsigned i = 0; i < ARRAY_SIZE(ctx->servo_map); i++) { + servo_t *servo = ctx->servo_map[i]; + if (servo) { + gpio_set(servo->params->servo_pin); + } + } + } + else { + /* end of duty cycle of a servo, clear the control pin of the servo + * for which the timer fired */ + assert((unsigned)chan <= ARRAY_SIZE(ctx->servo_map)); + servo_t *servo = ctx->servo_map[chan - 1]; + assert(servo); + gpio_clear(servo->params->servo_pin); + } +} + +int servo_init(servo_t *dev, const servo_params_t *params) +{ + memset(dev, 0, sizeof(*dev)); + assert(params->servo_pin != GPIO_UNDEF); + assert((params->timer_chan > 0) + && (params->timer_chan <= SERVO_TIMER_MAX_CHAN)); + DEBUG("[servo] init %p for GPIO pin %x\n", (void *)dev, + (unsigned)params->servo_pin); + + const servo_timer_params_t *timer_params = params->timer; + + gpio_init(params->servo_pin, GPIO_OUT); + + /* Note: This may initialize the timer dev over and over again if multiple + * servos are connected to the same timer . But other than wasting CPU + * cycles, this does no harm. And it greatly simplifies the API, so + * we willfully accept this inefficiency here. + */ + int retval = timer_init(timer_params->timer, timer_params->timer_freq, + timer_cb, timer_params->ctx); + DEBUG("[servo] timer_init(0x%x, %" PRIu32", timer_cb, ctx)) returned %i\n", + (unsigned)timer_params->timer, timer_params->timer_freq, retval); + + assert(retval == 0); + if (retval != 0) { + return -EINVAL; + } + + uint32_t servo_period_us = US_PER_SEC / timer_params->servo_freq; + unsigned ticks = ticks_from_us(servo_period_us, timer_params->timer_freq); + retval = timer_set_periodic(timer_params->timer, 0, ticks, + TIM_FLAG_RESET_ON_MATCH); + DEBUG("[servo] timer_set_periodic(0x%x, 0, %u) returned %i\n", + (unsigned)timer_params->timer, ticks, retval); + + assert(retval == 0); + if (retval != 0) { + return -ENOTSUP; + } + + dev->params = params; + dev->min = ticks_from_us(params->min_us, timer_params->timer_freq); + dev->max = ticks_from_us(params->max_us, timer_params->timer_freq); + + unsigned irq_state = irq_disable(); + timer_params->ctx->servo_map[params->timer_chan - 1] = dev; + irq_restore(irq_state); + + servo_set(dev, 127); + + return 0; +} + +void servo_set(servo_t *dev, uint8_t pos) +{ + uint32_t target = dev->max - dev->min; + target *= pos; + target >>= 8; + target += dev->min; + DEBUG("[servo] setting %p to %u (%u / 255)\n", + (void *)dev, (unsigned)target, (unsigned)pos); + + /* Update duty cycle */ + const servo_params_t *params = dev->params; + tim_t tim = params->timer->timer; + int retval = timer_set_periodic(tim, params->timer_chan, target, 0); + + assert(retval == 0); + DEBUG("[servo] timer_set_periodic(0x%x, %u, %u) returned %i\n", + (unsigned)tim, (unsigned)params->timer_chan, + (unsigned)dev->min, retval); +} diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 82b82b812538e..6854028bf24f3 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -384,6 +384,21 @@ PSEUDOMODULES += semtech_loramac_rx PSEUDOMODULES += senml_cbor PSEUDOMODULES += senml_phydat PSEUDOMODULES += senml_saul +## @defgroup drivers_servo_pwm PWM based servo driver +## @ingroup drivers_servo +## @{ +PSEUDOMODULES += servo_pwm +## @} +## @defgroup drivers_servo_timer periph_timer_periodic based servo driver +## @ingroup drivers_servo +## @{ +PSEUDOMODULES += servo_timer +## @} +## @defgroup drivers_servo_saul SAUL integration of the servo driver +## @ingroup drivers_servo +## @{ +PSEUDOMODULES += servo_saul +## @} ## @defgroup pseudomodule_sha1sum sha1sum ## @ingroup sys_shell_commands ## @{ diff --git a/tests/driver_servo/Makefile b/tests/driver_servo/Makefile index db4089c281983..928d1b12f524d 100644 --- a/tests/driver_servo/Makefile +++ b/tests/driver_servo/Makefile @@ -1,6 +1,23 @@ include ../Makefile.tests_common -USEMODULE += xtimer USEMODULE += servo +USEMODULE += shell +USEMODULE += shell_cmds_default +USEMODULE += saul_default include $(RIOTBASE)/Makefile.include + +SERVO_PIN ?= GPIO_PIN(0, 0) + +TIMER ?= TIMER_DEV(0) +TIMER_FREQ ?= CLOCK_CORECLOCK/8 + +ifneq (,$(filter atmega_common,$(USEMODULE))) + # The ATmega PWM driver has no support for 16 bit timers (as of now). Hence, + # limit the PWM resolution to what a 8 bit timer can handle. + CFLAGS += -DSERVO_PWM_PARAM_RES=256 +endif + +CFLAGS += '-DSERVO_PARAM_PIN=$(SERVO_PIN)' +CFLAGS += '-DSERVO_TIMER_PARAM_DEV=$(TIMER)' +CFLAGS += '-DSERVO_TIMER_PARAM_FREQ=$(TIMER_FREQ)' diff --git a/tests/driver_servo/app.config.test b/tests/driver_servo/app.config.test index 95e75094386d0..b2c4c23df32af 100644 --- a/tests/driver_servo/app.config.test +++ b/tests/driver_servo/app.config.test @@ -1,4 +1,7 @@ # this file enables modules defined in Kconfig. Do not use this file for # application configuration. This is only needed during migration. +CONFIG_MODULE_SAUL=y +CONFIG_MODULE_SAUL_DEFAULT=y CONFIG_MODULE_SERVO=y -CONFIG_MODULE_XTIMER=y +CONFIG_MODULE_SHELL=y +CONFIG_MODULE_SHELL_CMDS_DEFAULT=y diff --git a/tests/driver_servo/main.c b/tests/driver_servo/main.c index a93d9fab44b2b..588d45002ac3d 100644 --- a/tests/driver_servo/main.c +++ b/tests/driver_servo/main.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Eistec AB + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * * This file is subject to the terms and conditions of the GNU Lesser General * Public License v2.1. See the file LICENSE in the top level directory for more @@ -13,69 +14,23 @@ * @file * @brief Test for servo driver * - * This test initializes the given servo device and moves it between - * 1.000 -- 2.000 ms, roughly -/+ 90 degrees from the middle position if the - * connected servo is a standard RC servo. - * * @author Joakim Nohlgård + * @author Marian Buschsieweke * * @} */ +#include #include -#include "cpu.h" -#include "board.h" -#include "xtimer.h" -#include "periph/pwm.h" -#include "servo.h" - -#define DEV PWM_DEV(0) -#define CHANNEL 0 - -#define SERVO_MIN (1000U) -#define SERVO_MAX (2000U) - -/* these are defined outside the limits of the servo_init min/max parameters above */ -/* we will test the clamping functionality of the servo_set function. */ -#define STEP_LOWER_BOUND (900U) -#define STEP_UPPER_BOUND (2100U) - -/* Step size that we move per WAIT us */ -#define STEP (10U) - -/* Sleep time between updates, no need to update the servo position more than - * once per cycle */ -#define WAIT (10000U) - -static servo_t servo; +#include "shell.h" int main(void) { - int res; - unsigned int pos = (STEP_LOWER_BOUND + STEP_UPPER_BOUND) / 2; - int step = STEP; - - puts("\nRIOT RC servo test"); - puts("Connect an RC servo or scope to PWM_0 channel 0 to see anything"); - - res = servo_init(&servo, DEV, CHANNEL, SERVO_MIN, SERVO_MAX); - if (res < 0) { - puts("Errors while initializing servo"); - return -1; - } - puts("Servo initialized."); - - while (1) { - servo_set(&servo, pos); - - pos += step; - if (pos <= STEP_LOWER_BOUND || pos >= STEP_UPPER_BOUND) { - step = -step; - } + puts("RIOT RC servo test"); - xtimer_usleep(WAIT); - } + char buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(NULL, buf, sizeof(buf)); return 0; }