Skip to content

Commit 035156e

Browse files
uLipenashif
authored andcommitted
sensors: as5048: add initial support for AS5048 angle sensor
Which is a contactless angle sensor that communicates over SPI. Signed-off-by: Felipe Neves <ryukokki.felipe@gmail.com>
1 parent dedc526 commit 035156e

File tree

8 files changed

+214
-1
lines changed

8 files changed

+214
-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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
default y
9+
depends on DT_HAS_AMS_AS5048_ENABLED
10+
select SPI
11+
help
12+
Enable driver for the AMS AS5048 magnetic rotary encoder. The driver
13+
supports reading the absolute angle via the SPI interface.
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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+
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+
67+
const struct spi_buf_set tx_set = {
68+
.buffers = tx,
69+
.count = ARRAY_SIZE(tx),
70+
};
71+
72+
struct spi_buf rx[] = {
73+
{
74+
.buf = &rx_buf[0],
75+
.len = sizeof(rx_buf[0]),
76+
},
77+
{
78+
.buf = &rx_buf[1],
79+
.len = sizeof(rx_buf[1]),
80+
},
81+
};
82+
83+
const struct spi_buf_set rx_set = {
84+
.buffers = rx,
85+
.count = ARRAY_SIZE(rx),
86+
};
87+
88+
int ret;
89+
90+
if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_ROTATION)) {
91+
return -ENOTSUP;
92+
}
93+
94+
tx_buf[0] = sys_cpu_to_be16(as5048_build_read_command(AS5048_REG_ANGLE));
95+
tx_buf[1] = sys_cpu_to_be16(0x0000);
96+
97+
ret = spi_transceive_dt(&cfg->spi, &tx_set, &rx_set);
98+
if (ret < 0) {
99+
LOG_ERR("spi transceive failed (%d)", ret);
100+
return ret;
101+
}
102+
103+
uint16_t raw = sys_be16_to_cpu(rx_buf[1]);
104+
105+
if (raw & AS5048_ERROR_BIT) {
106+
LOG_ERR("AS5048 reported error (0x%04x)", raw);
107+
return -EIO;
108+
}
109+
110+
data->angle_raw = raw & AS5048_DATA_MASK;
111+
112+
return 0;
113+
}
114+
115+
static int as5048_channel_get(const struct device *dev,
116+
enum sensor_channel chan,
117+
struct sensor_value *val)
118+
{
119+
struct as5048_data *data = dev->data;
120+
121+
if (chan != SENSOR_CHAN_ROTATION) {
122+
return -ENOTSUP;
123+
}
124+
125+
int32_t scaled = (int32_t)data->angle_raw * AS5048_FULL_ANGLE_DEG;
126+
127+
val->val1 = scaled / AS5048_MAX_STEPS;
128+
val->val2 = ((scaled % AS5048_MAX_STEPS) * AS5048_MICRO_DEGREE) / AS5048_MAX_STEPS;
129+
130+
return 0;
131+
}
132+
133+
static int as5048_init(const struct device *dev)
134+
{
135+
const struct as5048_config *cfg = dev->config;
136+
137+
if (!spi_is_ready_dt(&cfg->spi)) {
138+
LOG_ERR("SPI device not ready");
139+
return -ENODEV;
140+
}
141+
142+
return 0;
143+
}
144+
145+
static DEVICE_API(sensor, as5048_api) = {
146+
.sample_fetch = as5048_sample_fetch,
147+
.channel_get = as5048_channel_get,
148+
};
149+
150+
#define AS5048_INIT(inst) \
151+
static struct as5048_data as5048_data_##inst; \
152+
static const struct as5048_config as5048_config_##inst = { \
153+
.spi = SPI_DT_SPEC_INST_GET(inst, \
154+
SPI_WORD_SET(16) | SPI_TRANSFER_MSB), \
155+
}; \
156+
SENSOR_DEVICE_DT_INST_DEFINE(inst, as5048_init, NULL, \
157+
&as5048_data_##inst, &as5048_config_##inst, \
158+
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
159+
&as5048_api);
160+
161+
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)