Skip to content

Commit 9f565d2

Browse files
Dheeraj SinghDheeraj Singh
authored andcommitted
drivers/sensors: Add AS5047D magnetic encoder driver
This adds support for the AMS AS5047D SPI magnetic encoder. Features: - 14-bit angle read - SPI interface - basic error handling Tested on STM32F4 with SPI3. Signed-off-by: Dheeraj Singh <Dheerajsingh1107@gmail.com>
1 parent 3759cc7 commit 9f565d2

12 files changed

Lines changed: 716 additions & 8 deletions

File tree

Documentation/components/drivers/character/quadrature.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,36 @@ This ioctl sets the index position of the encoder. An argument is an
7878
This ioctl gets the index position of the encoder. An argument is a
7979
pointer to ``qe_index_s`` structure.
8080

81+
AS5047D Specific Interface
82+
~~~~~~~~~~~~~~~~~~~~~~~~~~
83+
84+
The AS5047D magnetic rotary encoder is supported through the quadrature
85+
encoder upper-half driver by ``drivers/sensors/as5047d.c``.
86+
87+
Include the AS5047D header for device-specific ioctls and bit definitions:
88+
89+
.. code-block:: c
90+
91+
#include <nuttx/sensors/as5047d.h>
92+
93+
The AS5047D implements additional ``ioctl`` commands:
94+
95+
* :c:macro:`QEIOC_AS5047D_DIAGNOSTICS`
96+
* :c:macro:`QEIOC_AS5047D_MAGNITUDE`
97+
98+
.. c:macro:: QEIOC_AS5047D_DIAGNOSTICS
99+
100+
Reads the AS5047D ``DIAAGC`` register. The argument is a pointer to
101+
``uint16_t`` where the register value is returned.
102+
103+
.. c:macro:: QEIOC_AS5047D_MAGNITUDE
104+
105+
Reads the AS5047D ``MAG`` register. The argument is a pointer to
106+
``uint16_t`` where the register value is returned.
107+
108+
The position value returned by :c:macro:`QEIOC_POSITION` is a 14-bit
109+
angle sample in the range ``0`` to ``16383``.
110+
81111
.. c:struct:: qe_index_s
82112
.. code-block:: c
83113
@@ -124,3 +154,8 @@ reader should refer to target documentation for target specific configuration.
124154
The ``CONFIG_SENSORS`` option has to be enabled in order to use the qencoder
125155
peripheral. The peripheral itself is enabled by ``CONFIG_SENSORS_QENCODER``
126156
option.
157+
158+
For AS5047D, enable these options:
159+
160+
- ``CONFIG_SPI``
161+
- ``CONFIG_SENSORS_AS5047D``

Documentation/platforms/arm/stm32f4/boards/nucleo-f446re/index.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,36 @@ testing purposes::
408408
PB_6 - GPIO_OUTPUT
409409
PC_7 - GPIO_INPUT_INTERRUPT
410410

411+
as5047d
412+
-------
413+
414+
This is basically an ``nsh`` configuration (see above) with added support
415+
for the AMS AS5047D magnetic rotary encoder using the quadrature encoder
416+
framework.
417+
418+
Board bring-up initializes AS5047D on SPI3 and registers it as
419+
``/dev/qe0``.
420+
421+
AS5047D connection (SPI3)::
422+
423+
AS5047D Signal Nucleo-F446RE Pin
424+
-------------- -----------------
425+
SCK PC10
426+
MISO PC11
427+
MOSI PC12
428+
CS PA15 (D8, GPIO_SPI3_CS_USER)
429+
430+
Relevant configuration options::
431+
432+
CONFIG_SPI=y
433+
CONFIG_STM32_SPI3=y
434+
CONFIG_SENSORS=y
435+
CONFIG_SENSORS_QENCODER=y
436+
CONFIG_SENSORS_AS5047D=y
437+
438+
You can verify encoder operation from NuttShell with the qencoder example
439+
application (``qe``), which reads position data from ``/dev/qe0``.
440+
411441
ihm08m1_f32 and ihm08m1_b16
412442
---------------------------
413443

boards/arm/stm32/nucleo-f446re/configs/qenco/defconfig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ CONFIG_BOARD_LOOPSPERMSEC=8499
1919
CONFIG_BUILTIN=y
2020
CONFIG_DEBUG_SYMBOLS=y
2121
CONFIG_EXAMPLES_QENCODER=y
22-
CONFIG_EXAMPLES_QENCODER_HAVE_MAXPOS=y
23-
CONFIG_EXAMPLES_QENCODER_MAXPOS=8192
22+
CONFIG_EXAMPLES_QENCODER_NSAMPLES=10
2423
CONFIG_INIT_ENTRYPOINT="nsh_main"
2524
CONFIG_INTELHEX_BINARY=y
2625
CONFIG_MQ_MAXMSGSIZE=5
@@ -35,13 +34,14 @@ CONFIG_RAW_BINARY=y
3534
CONFIG_RR_INTERVAL=200
3635
CONFIG_SCHED_WAITPID=y
3736
CONFIG_SENSORS=y
38-
CONFIG_SENSORS_QENCODER=y
37+
CONFIG_SENSORS_AS5047D=y
3938
CONFIG_START_DAY=14
4039
CONFIG_START_MONTH=10
4140
CONFIG_START_YEAR=2014
4241
CONFIG_STM32_JTAG_SW_ENABLE=y
4342
CONFIG_STM32_QENCODER_DISABLE_EXTEND16BTIMERS=y
4443
CONFIG_STM32_QENCODER_SAMPLE_FDTS_2=y
44+
CONFIG_STM32_SPI3=y
4545
CONFIG_STM32_TIM2=y
4646
CONFIG_STM32_TIM2_QE=y
4747
CONFIG_STM32_TIM2_QEPSC=0

boards/arm/stm32/nucleo-f446re/include/board.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,35 @@
304304
#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1
305305
#define GPIO_SPI2_SCK GPIO_SPI2_SCK_2
306306

307-
#define GPIO_SPI3_MISO GPIO_SPI3_MISO_1
308-
#define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_1
309-
#define GPIO_SPI3_SCK GPIO_SPI3_SCK_1
307+
/* SPI3 has two alternate pin mappings on this board:
308+
*
309+
* - LCD path uses PB3/PB4/PB5
310+
* - AS5047D path uses PC10/PC11/PC12
311+
*
312+
* Select pinmux by feature so both use-cases are supported in-tree.
313+
*/
314+
315+
#if defined(CONFIG_LCD_ILI9225) && defined(CONFIG_SENSORS_AS5047D)
316+
# error "LCD (ILI9225) and AS5047D require different SPI3 pin mappings"
317+
#elif defined(CONFIG_SENSORS_AS5047D)
318+
# define GPIO_SPI3_MISO GPIO_SPI3_MISO_2
319+
# define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_2
320+
# define GPIO_SPI3_SCK GPIO_SPI3_SCK_2
321+
#else
322+
# define GPIO_SPI3_MISO GPIO_SPI3_MISO_1
323+
# define GPIO_SPI3_MOSI GPIO_SPI3_MOSI_1
324+
# define GPIO_SPI3_SCK GPIO_SPI3_SCK_1
325+
#endif
326+
327+
/* Encoder SPI CS from your reference:
328+
* #define ENC_CS GPIOA, GPIO_PIN_15
329+
*/
330+
331+
#define ENC_CS_PORT GPIO_PORTA
332+
#define ENC_CS_PIN GPIO_PIN15
333+
#define GPIO_SPI3_CS_USER \
334+
(GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | GPIO_OUTPUT_SET \
335+
| ENC_CS_PORT | ENC_CS_PIN)
310336

311337
/* CAN */
312338

boards/arm/stm32/nucleo-f446re/src/stm32_bringup.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
# include <nuttx/leds/userled.h>
6161
#endif
6262

63+
#ifdef CONFIG_SENSORS_AS5047D
64+
#include <nuttx/sensors/as5047d.h>
65+
#endif
66+
6367
#include "stm32_romfs.h"
6468
#include "nucleo-f446re.h"
6569

@@ -84,6 +88,10 @@
8488
int stm32_bringup(void)
8589
{
8690
int ret = OK;
91+
#if defined(CONFIG_SENSORS_QENCODER) && defined(CONFIG_SENSORS_AS5047D)
92+
FAR struct spi_dev_s *spi;
93+
FAR struct qe_lowerhalf_s *lower;
94+
#endif
8795

8896
#ifdef CONFIG_FS_PROCFS
8997
/* Mount the procfs file system */
@@ -197,16 +205,45 @@ int stm32_bringup(void)
197205
#endif
198206

199207
#ifdef CONFIG_SENSORS_QENCODER
200-
/* Initialize and register the qencoder driver */
208+
#ifdef CONFIG_SENSORS_AS5047D
209+
/* Initialize and register the AS5047D qencoder driver */
210+
211+
spi = stm32_spibus_initialize(3);
212+
if (spi == NULL)
213+
{
214+
syslog(LOG_ERR, "ERROR: Failed to initialize SPI3 for AS5047D\n");
215+
return -ENODEV;
216+
}
217+
218+
#ifdef GPIO_SPI3_CS_USER
219+
stm32_configgpio(GPIO_SPI3_CS_USER);
220+
#endif
221+
222+
lower = as5047d_initialize(spi, SPIDEV_USER(0));
223+
if (lower == NULL)
224+
{
225+
syslog(LOG_ERR, "ERROR: as5047d_initialize() failed\n");
226+
return -ENODEV;
227+
}
228+
229+
ret = qe_register("/dev/qe0", lower);
230+
if (ret < 0)
231+
{
232+
syslog(LOG_ERR, "ERROR: qe_register(/dev/qe0) failed: %d\n", ret);
233+
return ret;
234+
}
235+
#else
236+
/* Initialize and register the STM32 timer qencoder driver */
201237

202238
ret = board_qencoder_initialize(0, CONFIG_NUCLEO_F446RE_QETIMER);
203239
if (ret != OK)
204240
{
205241
syslog(LOG_ERR,
206-
"ERROR: Failed to register the qencoder: %d\n",
242+
"ERROR: Failed to register timer qencoder: %d\n",
207243
ret);
208244
return ret;
209245
}
246+
# endif
210247
#endif
211248

212249
#ifdef CONFIG_SENSORS_HALL3PHASE

boards/arm/stm32/nucleo-f446re/src/stm32_spi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ void stm32_spi3select(struct spi_dev_s *dev, uint32_t devid,
175175
spiinfo("devid: %d CS: %s\n",
176176
(int)devid, selected ? "assert" : "de-assert");
177177

178+
#ifdef GPIO_SPI3_CS_USER
179+
stm32_gpiowrite(GPIO_SPI3_CS_USER, !selected);
180+
#endif
181+
178182
#ifdef HAVE_LCD
179183
stm32_gpiowrite(GPIO_LCD_CS, !selected);
180184
#endif

drivers/sensors/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ if(CONFIG_SENSORS)
412412
list(APPEND SRCS adt7320.c)
413413
endif()
414414

415+
if(CONFIG_SENSORS_AS5047D)
416+
list(APPEND SRCS as5047d.c)
417+
endif()
418+
415419
if(CONFIG_SENSORS_AS5048A)
416420
list(APPEND SRCS as5048a.c)
417421
endif()

drivers/sensors/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ config SENSORS_AS5048A
159159
---help---
160160
Enable driver support for the AMS AS5048A magnetic rotary encoder.
161161

162+
config SENSORS_AS5047D
163+
bool "AMS AS5047D Magnetic Rotary Encoder support"
164+
default n
165+
select SPI
166+
select SENSORS_QENCODER
167+
---help---
168+
Enable driver support for the AMS AS5047D magnetic rotary encoder.
169+
162170
config SENSORS_AS726X
163171
bool "AMS AS726X Spetral sensor support"
164172
default n

drivers/sensors/Make.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,10 @@ ifeq ($(CONFIG_SENSORS_AS5048A),y)
408408
CSRCS += as5048a.c
409409
endif
410410

411+
ifeq ($(CONFIG_SENSORS_AS5047D),y)
412+
CSRCS += as5047d.c
413+
endif
414+
411415
endif # CONFIG_SPI
412416

413417
# These drivers depend on 1WIRE support

0 commit comments

Comments
 (0)