Skip to content

Commit 03dc405

Browse files
committed
sensors: as5048: add initial support for AS5048 angle sensor
Which is a contactless angle sensor that communicates over SPI. Signed-off-by: Felipe Neves <[email protected]>
1 parent f45b554 commit 03dc405

File tree

8 files changed

+201
-1
lines changed

8 files changed

+201
-1
lines changed

drivers/sensor/ams/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# zephyr-keep-sorted-start
5+
add_subdirectory_ifdef(CONFIG_AMS_AS5048 ams_as5048)
56
add_subdirectory_ifdef(CONFIG_AMS_AS5600 ams_as5600)
67
add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore)
78
add_subdirectory_ifdef(CONFIG_CCS811 ccs811)

drivers/sensor/ams/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# zephyr-keep-sorted-start
5+
source "drivers/sensor/ams/ams_as5048/Kconfig"
56
source "drivers/sensor/ams/ams_as5600/Kconfig"
67
source "drivers/sensor/ams/ams_iAQcore/Kconfig"
78
source "drivers/sensor/ams/ccs811/Kconfig"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
zephyr_library_sources(ams_as5048.c)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# AS5048 Angular position sensor configuration option
2+
3+
# Copyright (c) 2025, Felipe Neves.
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config AMS_AS5048
7+
bool "AMS AS5048 magnetic angle sensor"
8+
depends on DT_HAS_AMS_AS5048_ENABLED
9+
select SPI
10+
help
11+
Enable driver for the AMS AS5048 magnetic rotary encoder. The driver
12+
supports reading the absolute angle via the SPI interface.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (c) 2025, Felipe Neves
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ams_as5048
8+
9+
#include <errno.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/drivers/sensor.h>
12+
#include <zephyr/drivers/spi.h>
13+
#include <zephyr/init.h>
14+
#include <zephyr/logging/log.h>
15+
#include <zephyr/sys/byteorder.h>
16+
17+
LOG_MODULE_REGISTER(ams_as5048, CONFIG_SENSOR_LOG_LEVEL);
18+
19+
#define AS5048_REG_ANGLE 0x3FFF
20+
#define AS5048_READ_BIT BIT(14)
21+
#define AS5048_PARITY_BIT BIT(15)
22+
#define AS5048_DATA_MASK GENMASK(13, 0)
23+
#define AS5048_ERROR_BIT BIT(14)
24+
#define AS5048_MAX_STEPS 16384
25+
#define AS5048_FULL_ANGLE_DEG 360
26+
#define AS5048_MICRO_DEGREE 1000000
27+
28+
struct as5048_config {
29+
struct spi_dt_spec spi;
30+
};
31+
32+
struct as5048_data {
33+
uint16_t angle_raw;
34+
};
35+
36+
static uint16_t as5048_build_read_command(uint16_t reg)
37+
{
38+
uint16_t cmd = reg & AS5048_DATA_MASK;
39+
40+
cmd |= AS5048_READ_BIT;
41+
42+
/* Even parity across bits 0..14 (read bit + address). */
43+
if (__builtin_parity(cmd)) {
44+
cmd |= AS5048_PARITY_BIT;
45+
}
46+
47+
return cmd;
48+
}
49+
50+
static int as5048_sample_fetch(const struct device *dev, enum sensor_channel chan)
51+
{
52+
struct as5048_data *data = dev->data;
53+
const struct as5048_config *cfg = dev->config;
54+
uint16_t tx_buf[2];
55+
uint16_t rx_buf[2];
56+
const struct spi_buf tx[] = {
57+
{
58+
.buf = &tx_buf[0],
59+
.len = sizeof(tx_buf[0]),
60+
},
61+
{
62+
.buf = &tx_buf[1],
63+
.len = sizeof(tx_buf[1]),
64+
},
65+
};
66+
struct spi_buf rx[] = {
67+
{
68+
.buf = &rx_buf[0],
69+
.len = sizeof(rx_buf[0]),
70+
},
71+
{
72+
.buf = &rx_buf[1],
73+
.len = sizeof(rx_buf[1]),
74+
},
75+
};
76+
int ret;
77+
78+
if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_ROTATION)) {
79+
return -ENOTSUP;
80+
}
81+
82+
tx_buf[0] = sys_cpu_to_be16(as5048_build_read_command(AS5048_REG_ANGLE));
83+
tx_buf[1] = sys_cpu_to_be16(0x0000);
84+
85+
ret = spi_transceive_dt(&cfg->spi, tx, ARRAY_SIZE(tx), rx, ARRAY_SIZE(rx));
86+
if (ret < 0) {
87+
LOG_ERR("spi transceive failed (%d)", ret);
88+
return ret;
89+
}
90+
91+
uint16_t raw = sys_be16_to_cpu(rx_buf[1]);
92+
93+
if (raw & AS5048_ERROR_BIT) {
94+
LOG_ERR("AS5048 reported error (0x%04x)", raw);
95+
return -EIO;
96+
}
97+
98+
data->angle_raw = raw & AS5048_DATA_MASK;
99+
100+
return 0;
101+
}
102+
103+
static int as5048_channel_get(const struct device *dev,
104+
enum sensor_channel chan,
105+
struct sensor_value *val)
106+
{
107+
struct as5048_data *data = dev->data;
108+
109+
if (chan != SENSOR_CHAN_ROTATION) {
110+
return -ENOTSUP;
111+
}
112+
113+
int32_t scaled = (int32_t)data->angle_raw * AS5048_FULL_ANGLE_DEG;
114+
115+
val->val1 = scaled / AS5048_MAX_STEPS;
116+
val->val2 = ((scaled % AS5048_MAX_STEPS) * AS5048_MICRO_DEGREE) / AS5048_MAX_STEPS;
117+
118+
return 0;
119+
}
120+
121+
static int as5048_init(const struct device *dev)
122+
{
123+
const struct as5048_config *cfg = dev->config;
124+
125+
if (!spi_is_ready_dt(&cfg->spi)) {
126+
LOG_ERR("SPI device not ready");
127+
return -ENODEV;
128+
}
129+
130+
return 0;
131+
}
132+
133+
static SENSOR_DEVICE_API(as5048_api) = {
134+
.sample_fetch = as5048_sample_fetch,
135+
.channel_get = as5048_channel_get,
136+
};
137+
138+
#define AS5048_INIT(inst) \
139+
static struct as5048_data as5048_data_##inst; \
140+
static const struct as5048_config as5048_config_##inst = { \
141+
.spi = SPI_DT_SPEC_INST_GET(inst, \
142+
SPI_WORD_SET(16) | SPI_TRANSFER_MSB, 0U), \
143+
}; \
144+
SENSOR_DEVICE_DT_INST_DEFINE(inst, as5048_init, NULL, \
145+
&as5048_data_##inst, &as5048_config_##inst, \
146+
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
147+
&as5048_api);
148+
149+
DT_INST_FOREACH_STATUS_OKAY(AS5048_INIT)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
description: |
4+
AMS AS5048 magnetic rotary sensor
5+
6+
&spi3 {
7+
status = "okay";
8+
9+
as5048@0 {
10+
compatible = "ams,as5048";
11+
reg = <0>;
12+
spi-max-frequency = <4000000>;
13+
};
14+
};
15+
16+
17+
compatible: "ams,as5048"
18+
19+
include: [sensor-device.yaml, spi-device.yaml]
20+
21+
properties:
22+
reg:
23+
required: true
24+
25+
spi-max-frequency:
26+
required: true

tests/drivers/build_all/sensor/app.overlay

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@
156156
<&test_gpio 0 0>,
157157
<&test_gpio 0 0>,
158158
<&test_gpio 0 0>,
159-
<&test_gpio 0 0>; /* 0x39 */
159+
<&test_gpio 0 0>,
160+
<&test_gpio 0 0>; /* 0x3A */
160161
#include "spi.dtsi"
161162
};
162163

tests/drivers/build_all/sensor/spi.dtsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,3 +489,9 @@ test_spi_adxl345: adxl345@3a {
489489
int1-gpios = <&test_gpio 0 0>;
490490
fifo-watermark = <1>;
491491
};
492+
493+
test_spi_as5048: as5048@3b {
494+
compatible = "ams,as5048";
495+
reg = <0x3b>;
496+
spi-max-frequency = <0>;
497+
};

0 commit comments

Comments
 (0)