mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
drivers/timers: Add common include files, definitions and upper-half for DSHOT
DShot is a packet based serial protocol, used for controlling motor controllers (ESCs), typically for drones. This adds an upper-half driver for dshot protocol, along with common configuration options and definitions definitions. Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
parent
c3e7c94d2f
commit
b810cbe4d3
6 changed files with 986 additions and 0 deletions
|
|
@ -86,6 +86,10 @@ if(CONFIG_PWM)
|
|||
list(APPEND SRCS pwm.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_DSHOT)
|
||||
list(APPEND SRCS dshot.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_CAPTURE)
|
||||
list(APPEND SRCS capture.c)
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,24 @@ config FAKE_CAPTURE
|
|||
|
||||
endif # CAPTURE
|
||||
|
||||
config DSHOT
|
||||
bool "DShot Driver Support"
|
||||
default n
|
||||
---help---
|
||||
This selection enables the DShot driver for ESC control.
|
||||
|
||||
if DSHOT
|
||||
|
||||
config DSHOT_NCHANNELS
|
||||
int "Maximum DShot channels in API structs"
|
||||
default 8
|
||||
range 1 16
|
||||
---help---
|
||||
Specifies the number of output channels per timer. Each timer
|
||||
may support fewer output channels than this value.
|
||||
|
||||
endif # DSHOT
|
||||
|
||||
config TIMER
|
||||
bool "Timer Support"
|
||||
default n
|
||||
|
|
|
|||
|
|
@ -118,6 +118,12 @@ ifeq ($(CONFIG_PWM),y)
|
|||
TMRVPATH = :timers
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DSHOT),y)
|
||||
CSRCS += dshot.c
|
||||
TMRDEPPATH = --dep-path timers
|
||||
TMRVPATH = :timers
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CAPTURE),y)
|
||||
CSRCS += capture.c
|
||||
|
||||
|
|
|
|||
638
drivers/timers/dshot.c
Normal file
638
drivers/timers/dshot.c
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
/****************************************************************************
|
||||
* drivers/timers/dshot.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/timers/dshot.h>
|
||||
|
||||
#ifdef CONFIG_DSHOT
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define DSHOT_GCR_MASK 0x000fffffu
|
||||
#define DSHOT_ERPMSCALE_NUM 600000u
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct dshot_upperhalf_s
|
||||
{
|
||||
uint8_t crefs;
|
||||
mutex_t lock;
|
||||
FAR struct dshot_lowerhalf_s *dev;
|
||||
struct dshot_ch_telemetry_s telemetry[DSHOT_NCHANNELS];
|
||||
bool bidir;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_open(FAR struct file *filep);
|
||||
static int dshot_close(FAR struct file *filep);
|
||||
static ssize_t dshot_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen);
|
||||
static ssize_t dshot_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen);
|
||||
static int dshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct file_operations g_dshotops =
|
||||
{
|
||||
dshot_open, /* open */
|
||||
dshot_close, /* close */
|
||||
dshot_read, /* read */
|
||||
dshot_write, /* write */
|
||||
NULL, /* seek */
|
||||
dshot_ioctl, /* ioctl */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_crc
|
||||
*
|
||||
* Description:
|
||||
* Calculate the 4-bit CRC for a DShot packet.
|
||||
*
|
||||
* Input Parameters:
|
||||
* packet - The DShot packet to calculate CRC for.
|
||||
* bidir - Boolean indicating if bidirectional DShot is enabled.
|
||||
*
|
||||
* Returned Value:
|
||||
* The calculated 4-bit CRC value.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t dshot_crc(uint16_t packet, bool bidir)
|
||||
{
|
||||
uint16_t crc;
|
||||
|
||||
crc = packet >> 4;
|
||||
crc = crc ^ (crc >> 4) ^ (crc >> 8);
|
||||
|
||||
if (bidir)
|
||||
{
|
||||
crc = ~crc;
|
||||
}
|
||||
|
||||
return crc & 0xf;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_build_packet
|
||||
*
|
||||
* Description:
|
||||
* Build a complete DShot packet from throttle, telemetry, and bidir
|
||||
* values.
|
||||
*
|
||||
* Input Parameters:
|
||||
* throttle - Throttle value (0-2047).
|
||||
* telemetry - Boolean indicating if telemetry request is enabled.
|
||||
* bidir - Boolean indicating if bidirectional DShot is enabled.
|
||||
*
|
||||
* Returned Value:
|
||||
* The constructed 16-bit DShot packet.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t dshot_build_packet(uint16_t throttle, bool telemetry,
|
||||
bool bidir)
|
||||
{
|
||||
uint16_t packet = 0;
|
||||
packet |= throttle << 5;
|
||||
packet |= (telemetry ? 1 << 4 : 0);
|
||||
packet |= dshot_crc(packet, bidir);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_parse_raw_packet
|
||||
*
|
||||
* Description:
|
||||
* Parse raw pattern from the line into a 16-bit packet and verify CRC.
|
||||
* Steps:
|
||||
* 1. Extract GCR20 value from the raw value
|
||||
* 2. Extract the 16-bit packet from the GCR20
|
||||
* 3. Check the packet CRC
|
||||
*
|
||||
* Input Parameters:
|
||||
* raw - The raw encoded packet value to parse.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, returns the 12-bit payload as a positive integer.
|
||||
* On error, returns a negative error code.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_parse_raw_packet(uint32_t raw)
|
||||
{
|
||||
static const int8_t gcr_decode[32] =
|
||||
{
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 9, 10, 11, -1, 13, 14, 15,
|
||||
-1, -1, 2, 3, -1, 5, 6, 7,
|
||||
-1, 0, 8, 1, -1, 4, 12, -1
|
||||
};
|
||||
|
||||
uint32_t gcr20 = (raw ^ (raw >> 1)) & DSHOT_GCR_MASK;
|
||||
uint16_t packet = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
int16_t nibble = gcr_decode[gcr20 & 0x1f];
|
||||
|
||||
if (nibble < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
packet |= nibble << (4 * i);
|
||||
gcr20 >>= 5;
|
||||
}
|
||||
|
||||
if (dshot_crc(packet, true) != (packet & 0xf))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return packet >> 4;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_copy_telemetry
|
||||
*
|
||||
* Description:
|
||||
* Copy telemetry data for selected channels from upper-half to output.
|
||||
*
|
||||
* Input Parameters:
|
||||
* upper - Pointer to the upper-half driver state.
|
||||
* out - Pointer to output telemetry array.
|
||||
* ch_mask - Bitmask indicating which channels to copy.
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void dshot_copy_telemetry(FAR struct dshot_upperhalf_s *upper,
|
||||
FAR struct dshot_ch_telemetry_s *out,
|
||||
uint16_t ch_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DSHOT_NCHANNELS; i++)
|
||||
{
|
||||
if ((ch_mask & (1u << i)) != 0)
|
||||
{
|
||||
out[i] = upper->telemetry[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_update_telemetry
|
||||
*
|
||||
* Description:
|
||||
* Update telemetry data from lower-half driver for selected channels.
|
||||
* Parses raw telemetry data and extracts EDT or eRPM information.
|
||||
*
|
||||
* Input Parameters:
|
||||
* upper - Pointer to the upper-half driver state.
|
||||
* ch_mask - Bitmask indicating which channels to update.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_update_telemetry(FAR struct dshot_upperhalf_s *upper,
|
||||
uint16_t ch_mask)
|
||||
{
|
||||
FAR struct dshot_lowerhalf_s *lower = upper->dev;
|
||||
struct dshot_raw_telemetry_s raw[DSHOT_NCHANNELS];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
memset(raw, 0, sizeof(raw));
|
||||
|
||||
DEBUGASSERT(lower->ops->get_raw_telemetry != NULL);
|
||||
ret = lower->ops->get_raw_telemetry(lower, raw, ch_mask);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < DSHOT_NCHANNELS; i++)
|
||||
{
|
||||
if ((ch_mask & (1u << i)) != 0)
|
||||
{
|
||||
int value = dshot_parse_raw_packet(raw[i].raw);
|
||||
|
||||
if (value > 0)
|
||||
{
|
||||
uint16_t telem = (uint16_t)value & 0x0fff;
|
||||
uint8_t exponent = telem >> 9;
|
||||
|
||||
if ((exponent & 1) == 0)
|
||||
{
|
||||
upper->telemetry[i].edt_type = (uint8_t)(telem >> 8);
|
||||
upper->telemetry[i].edt_value = (uint8_t)(telem & 0xff);
|
||||
upper->telemetry[i].timestamp = raw[i].timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t mantissa = telem & 0x1ff;
|
||||
uint32_t period = mantissa << exponent;
|
||||
if (period != 0)
|
||||
{
|
||||
uint32_t rpm = DSHOT_ERPMSCALE_NUM / period;
|
||||
upper->telemetry[i].erpm =
|
||||
(uint16_t)((rpm > 0xffff) ? 0xffff : rpm);
|
||||
upper->telemetry[i].timestamp = raw[i].timestamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_open
|
||||
*
|
||||
* Description:
|
||||
* This function is called whenever the DShot device is opened.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - A pointer to the file structure instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_open(FAR struct file *filep)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct dshot_upperhalf_s *upper = inode->i_private;
|
||||
uint8_t tmp;
|
||||
int ret;
|
||||
|
||||
ret = nxmutex_lock(&upper->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
tmp = upper->crefs + 1;
|
||||
if (tmp == 0)
|
||||
{
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return -EMFILE;
|
||||
}
|
||||
|
||||
if (tmp == 1)
|
||||
{
|
||||
DEBUGASSERT(upper->dev->ops->setup != NULL);
|
||||
ret = upper->dev->ops->setup(upper->dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
upper->crefs = tmp;
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_close
|
||||
*
|
||||
* Description:
|
||||
* This function is called when the DShot device is closed.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - A pointer to the file structure instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_close(FAR struct file *filep)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct dshot_upperhalf_s *upper = inode->i_private;
|
||||
int ret;
|
||||
|
||||
ret = nxmutex_lock(&upper->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (upper->crefs > 1)
|
||||
{
|
||||
upper->crefs--;
|
||||
}
|
||||
else
|
||||
{
|
||||
upper->crefs = 0;
|
||||
DEBUGASSERT(upper->dev->ops->shutdown != NULL);
|
||||
upper->dev->ops->shutdown(upper->dev);
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_read
|
||||
*
|
||||
* Description:
|
||||
* A dummy read method. This is provided only to satisfy the VFS layer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - A pointer to the file structure instance.
|
||||
* buffer - The user-provided buffer into which data will be returned.
|
||||
* buflen - The size of the buffer in bytes.
|
||||
*
|
||||
* Returned Value:
|
||||
* Always returns 0 (end-of-file).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t dshot_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_write
|
||||
*
|
||||
* Description:
|
||||
* A dummy write method. This is provided only to satisfy the VFS layer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - A pointer to the file structure instance.
|
||||
* buffer - The user-provided buffer from which data will be written.
|
||||
* buflen - The number of bytes to be written.
|
||||
*
|
||||
* Returned Value:
|
||||
* Always returns -EPERM (operation not permitted).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t dshot_write(FAR struct file *filep, FAR const char *buffer,
|
||||
size_t buflen)
|
||||
{
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_ioctl
|
||||
*
|
||||
* Description:
|
||||
* The standard ioctl method. This is used to perform DShot-specific
|
||||
* operations including setting throttle, configuring channels, and
|
||||
* retrieving telemetry data.
|
||||
*
|
||||
* Input Parameters:
|
||||
* filep - A pointer to the file structure instance.
|
||||
* cmd - The ioctl command code.
|
||||
* arg - The argument provided with the ioctl command.
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int dshot_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
FAR struct inode *inode = filep->f_inode;
|
||||
FAR struct dshot_upperhalf_s *upper = inode->i_private;
|
||||
FAR struct dshot_lowerhalf_s *lower = upper->dev;
|
||||
int ret;
|
||||
|
||||
ret = nxmutex_lock(&upper->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case DSHOTIOC_CONFIGURE:
|
||||
{
|
||||
FAR struct dshot_config_s *cfg =
|
||||
(FAR struct dshot_config_s *)((uintptr_t)arg);
|
||||
|
||||
if (cfg == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUGASSERT(lower->ops->configure);
|
||||
ret = lower->ops->configure(lower, cfg);
|
||||
upper->bidir = cfg->bidir;
|
||||
}
|
||||
break;
|
||||
|
||||
case DSHOTIOC_SET_THROTTLE:
|
||||
{
|
||||
FAR struct dshot_throttle_s *req =
|
||||
(FAR struct dshot_throttle_s *)((uintptr_t)arg);
|
||||
uint16_t packets[DSHOT_NCHANNELS];
|
||||
int i;
|
||||
|
||||
if (req == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Retrieve the latest telemetry */
|
||||
|
||||
if (req->telemetry_req != 0)
|
||||
{
|
||||
ret = dshot_update_telemetry(upper, req->telemetry_req);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
dshot_copy_telemetry(upper, req->ch_telemetry,
|
||||
req->telemetry_req);
|
||||
}
|
||||
|
||||
/* Build DShot packets for each channel */
|
||||
|
||||
for (i = 0; i < DSHOT_NCHANNELS; i++)
|
||||
{
|
||||
if ((req->ch_mask & (1u << i)) != 0)
|
||||
{
|
||||
bool telemetry = (req->telemetry_req & (1u << i)) != 0;
|
||||
packets[i] =
|
||||
dshot_build_packet(req->throttle[i], telemetry,
|
||||
upper->bidir);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the packets */
|
||||
|
||||
DEBUGASSERT(lower->ops->send_command);
|
||||
ret = lower->ops->send_command(lower, packets, req->ch_mask);
|
||||
}
|
||||
break;
|
||||
|
||||
case DSHOTIOC_GET_TELEMETRY:
|
||||
{
|
||||
FAR struct dshot_telemetry_s *tlm =
|
||||
(FAR struct dshot_telemetry_s *)((uintptr_t)arg);
|
||||
|
||||
if (tlm == NULL)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = dshot_update_telemetry(upper, tlm->ch_mask);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
dshot_copy_telemetry(upper, tlm->ch_telemetry, tlm->ch_mask);
|
||||
ret = OK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if (lower->ops->ioctl != NULL)
|
||||
{
|
||||
ret = lower->ops->ioctl(lower, cmd, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&upper->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_register
|
||||
*
|
||||
* Description:
|
||||
* This function binds an instance of a "lower half" DShot driver with the
|
||||
* "upper half" DShot device and registers that device so that it can be
|
||||
* used by application code.
|
||||
*
|
||||
* When this function is called, the "lower half" driver should be in the
|
||||
* reset state (as if the shutdown() method had already been called).
|
||||
*
|
||||
* Input Parameters:
|
||||
* path - The full path to the driver to be registered in the NuttX pseudo-
|
||||
* filesystem. The recommended convention is to name all DShot drivers
|
||||
* as "/dev/dshot0", "/dev/dshot1", etc., where the driver path differs
|
||||
* only in the "minor" number at the end of the device name.
|
||||
* dev - A pointer to an instance of lower half DShot driver. This
|
||||
* instance is bound to the DShot driver and must persist as long as the
|
||||
* driver persists.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int dshot_register(FAR const char *path, FAR struct dshot_lowerhalf_s *dev)
|
||||
{
|
||||
FAR struct dshot_upperhalf_s *upper;
|
||||
int ret;
|
||||
|
||||
if (dev == NULL || dev->ops == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
upper = kmm_zalloc(sizeof(struct dshot_upperhalf_s));
|
||||
if (upper == NULL)
|
||||
{
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nxmutex_init(&upper->lock);
|
||||
upper->dev = dev;
|
||||
|
||||
ret = register_driver(path, &g_dshotops, 0666, upper);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_destroy(&upper->lock);
|
||||
kmm_free(upper);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DSHOT */
|
||||
|
|
@ -113,6 +113,7 @@
|
|||
#define _1WIREBASE (0x4500) /* 1WIRE ioctl commands */
|
||||
#define _EEPIOCBASE (0x4600) /* EEPROM driver ioctl commands */
|
||||
#define _PTPBASE (0x4700) /* PTP ioctl commands */
|
||||
#define _DSHOTIOCBASE (0x4800) /* Dshot device ioctl commands */
|
||||
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
|
||||
|
||||
/* boardctl() commands share the same number space */
|
||||
|
|
@ -807,6 +808,13 @@
|
|||
#define _PTPIOCVALID(c) (_IOC_TYPE(c)==_PTPBASE)
|
||||
#define _PTPIOC(nr) _IOC(_PTPBASE,nr)
|
||||
|
||||
/* DSHOT ioctl definitions (see nuttx/timers/dshot.h) ***********************/
|
||||
|
||||
/* see nuttx/include/timers/dshot.h */
|
||||
|
||||
#define _DSHOTIOCVALID(c) (_IOC_TYPE(c)==_DSHOTIOCBASE)
|
||||
#define _DSHOTIOC(nr) _IOC(_DSHOTIOCBASE,nr)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
|
|
|||
312
include/nuttx/timers/dshot.h
Normal file
312
include/nuttx/timers/dshot.h
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/timers/dshot.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_TIMERS_DSHOT_H
|
||||
#define __INCLUDE_NUTTX_TIMERS_DSHOT_H
|
||||
|
||||
/* Common definitions for DShot drivers */
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DSHOT_NCHANNELS
|
||||
# if CONFIG_DSHOT_NCHANNELS > 16
|
||||
# error "max 16 channels supported"
|
||||
# endif
|
||||
# define DSHOT_NCHANNELS CONFIG_DSHOT_NCHANNELS
|
||||
#else
|
||||
# define DSHOT_NCHANNELS 1
|
||||
#endif
|
||||
|
||||
/* IOCTL Commands ***********************************************************/
|
||||
|
||||
/* Configure the DShot instance; speed, bidirectional mode, active channels */
|
||||
|
||||
#define DSHOTIOC_CONFIGURE _DSHOTIOC(0x01)
|
||||
|
||||
/* Write throttle data or special command for one or more channels */
|
||||
|
||||
#define DSHOTIOC_SET_THROTTLE _DSHOTIOC(0x02)
|
||||
|
||||
/* Retrieve telemetry from the last successful bidirectional RX */
|
||||
|
||||
#define DSHOTIOC_GET_TELEMETRY _DSHOTIOC(0x03)
|
||||
|
||||
/* DSHOT Speeds *************************************************************/
|
||||
|
||||
#define DSHOT_SPEED_150 150000u
|
||||
#define DSHOT_SPEED_300 300000u
|
||||
#define DSHOT_SPEED_600 600000u
|
||||
#define DSHOT_SPEED_1200 1200000u
|
||||
#define DSHOT_SPEED_2400 2400000u
|
||||
#define DSHOT_SPEED_3600 3600000u
|
||||
|
||||
/* DSHOT special commands (throttle values 0-47)*****************************/
|
||||
|
||||
#define DSHOT_CMD_MOTOR_STOP 0
|
||||
#define DSHOT_CMD_BEEP1 1
|
||||
#define DSHOT_CMD_BEEP2 2
|
||||
#define DSHOT_CMD_BEEP3 3
|
||||
#define DSHOT_CMD_BEEP4 4
|
||||
#define DSHOT_CMD_BEEP5 5
|
||||
#define DSHOT_CMD_ESC_INFO 6
|
||||
#define DSHOT_CMD_SPIN_DIRECTION_1 7
|
||||
#define DSHOT_CMD_SPIN_DIRECTION_2 8
|
||||
#define DSHOT_CMD_3D_MODE_OFF 9
|
||||
#define DSHOT_CMD_3D_MODE_ON 10
|
||||
#define DSHOT_CMD_SETTINGS_REQUEST 11
|
||||
#define DSHOT_CMD_SAVE_SETTINGS 12
|
||||
#define DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE 13
|
||||
#define DSHOT_CMD_EXTENDED_TELEMETRY_DISABLE 14
|
||||
|
||||
/* 15 - 19 Unassigned */
|
||||
|
||||
#define DSHOT_CMD_SPIN_DIRECTION_NORMAL 20
|
||||
#define DSHOT_CMD_SPIN_DIRECTION_REVERSED 21
|
||||
#define DSHOT_CMD_LED0_ON 22
|
||||
#define DSHOT_CMD_LED1_ON 23
|
||||
#define DSHOT_CMD_LED2_ON 24
|
||||
#define DSHOT_CMD_LED3_ON 25
|
||||
#define DSHOT_CMD_LED0_OFF 26
|
||||
#define DSHOT_CMD_LED1_OFF 27
|
||||
#define DSHOT_CMD_LED2_OFF 28
|
||||
#define DSHOT_CMD_LED3_OFF 29
|
||||
|
||||
#define DSHOT_CMD_AUDIO_STREAM_MODE 30
|
||||
#define DSHOT_CMD_SILENT_MODE 31
|
||||
|
||||
#define DSHOT_CMD_SIGNAL_LINE_TELEMETRY_DISABLE 32
|
||||
#define DSHOT_CMD_SIGNAL_LINE_TELEMETRY_ENABLE 33
|
||||
#define DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_TELEMETRY 34
|
||||
#define DSHOT_CMD_SIGNAL_LINE_CONTINUOUS_ERPM_PERIOD_TELEMETRY 35
|
||||
|
||||
/* 36 - 41 Unassigned */
|
||||
|
||||
#define DSHOT_CMD_SIGNAL_LINE_TEMPERATURE_TELEMETRY 42
|
||||
#define DSHOT_CMD_SIGNAL_LINE_VOLTAGE_TELEMETRY 43
|
||||
#define DSHOT_CMD_SIGNAL_LINE_CURRENT_TELEMETRY 44
|
||||
#define DSHOT_CMD_SIGNAL_LINE_CONSUMPTION_TELEMETRY 45
|
||||
#define DSHOT_CMD_SIGNAL_LINE_ERPM_TELEMETRY 46
|
||||
#define DSHOT_CMD_SIGNAL_LINE_ERPM_PERIOD_TELEMETRY 47
|
||||
|
||||
/* Extended telemetry types *************************************************/
|
||||
|
||||
#define DSHOT_EDT_TYPE_TEMP 0x02 /* Temperature in C */
|
||||
#define DSHOT_EDT_TYPE_V 0x04 /* Voltage: 0.25V per step */
|
||||
#define DSHOT_EDT_TYPE_A 0x06 /* Current in Amp */
|
||||
#define DSHOT_EDT_TYPE_DBG1 0x08 /* Debug value 1 */
|
||||
#define DSHOT_EDT_TYPE_DBG2 0x0A /* Debug value 2 */
|
||||
#define DSHOT_EDT_TYPE_DBG3 0x0C /* Debug value 3 */
|
||||
#define DSHOT_EDT_TYPE_STATE 0x0E /* State/Event */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Configuration argument for DSHOTIOC_CONFIGURE
|
||||
*
|
||||
* freq - Bit rate in Hz: DSHOT_SPEED_150/300/600/1200/2400/3600
|
||||
* telem_freq - Telemetry frequency. Use 1.25 * freq for standard speed
|
||||
* (e.g., 750kHz for DShot600). Some ESCs may require
|
||||
* different values (e.g., 1.15 * freq for T-motor F55A).
|
||||
* active_mask - Bitmask of active channels (bit0=ch0, bit1=ch1, etc.)
|
||||
* bidir - Enable bidirectional DShot (inverted command data,
|
||||
* response on same line).
|
||||
*/
|
||||
|
||||
struct dshot_config_s
|
||||
{
|
||||
uint32_t freq;
|
||||
uint32_t telem_freq;
|
||||
uint16_t active_mask;
|
||||
bool bidir;
|
||||
};
|
||||
|
||||
/* Telemetry data for a single DShot channel. Contains eRPM, extended
|
||||
* telemetry type/value, and timestamp of the last valid response.
|
||||
*
|
||||
* erpm - eRPM value from telemetry response.
|
||||
* edt_type - Extended telemetry type (if supported).
|
||||
* edt_value - Extended telemetry value (if supported).
|
||||
* timestamp - Timestamp of the last valid response.
|
||||
*/
|
||||
|
||||
struct dshot_ch_telemetry_s
|
||||
{
|
||||
uint16_t erpm;
|
||||
uint8_t edt_type;
|
||||
uint8_t edt_value;
|
||||
struct timespec timestamp;
|
||||
};
|
||||
|
||||
/* Telemetry result for DSHOTIOC_GET_TELEMETRY ioctl command.
|
||||
* Contains bitmask of channels to read and telemetry data for each.
|
||||
*
|
||||
* ch_mask - Bitmask of logical channels to read telemetry from.
|
||||
* ch_telemetry - Telemetry data array for each channel.
|
||||
*/
|
||||
|
||||
struct dshot_telemetry_s
|
||||
{
|
||||
uint16_t ch_mask;
|
||||
struct dshot_ch_telemetry_s ch_telemetry[DSHOT_NCHANNELS];
|
||||
};
|
||||
|
||||
/* Per-channel throttle value for DSHOTIOC_SET_THROTTLE ioctl command.
|
||||
* Specifies throttle values, channel mask, and optional telemetry
|
||||
* request for efficient batching of operations.
|
||||
*
|
||||
* throttle - Throttle value array (0 = disarm, 48-2047 = armed range,
|
||||
* or special command values).
|
||||
* ch_mask - Bitmask of logical channels to set.
|
||||
* telemetry_req - Bitmask: bit N requests telemetry from channel N.
|
||||
* ch_telemetry - Telemetry data from previous request. Allows reading
|
||||
* previous telemetry response without separate ioctl.
|
||||
*/
|
||||
|
||||
struct dshot_throttle_s
|
||||
{
|
||||
uint16_t throttle[DSHOT_NCHANNELS];
|
||||
uint16_t ch_mask;
|
||||
uint16_t telemetry_req;
|
||||
struct dshot_ch_telemetry_s ch_telemetry[DSHOT_NCHANNELS];
|
||||
};
|
||||
|
||||
/* Raw telemetry frame captured from the DShot signal line.
|
||||
* Contains the raw GCR-encoded packet and capture timestamp.
|
||||
*
|
||||
* raw - Raw 20-bit GCR encoded packet data.
|
||||
* timestamp - Capture timestamp of the raw packet.
|
||||
*/
|
||||
|
||||
struct dshot_raw_telemetry_s
|
||||
{
|
||||
uint32_t raw;
|
||||
struct timespec timestamp;
|
||||
};
|
||||
|
||||
/* Lower-half driver operations table. Provides callback functions for
|
||||
* the upper-half driver to control DShot hardware. All methods except
|
||||
* ioctl are mandatory.
|
||||
*
|
||||
* setup - Called when driver is opened. Configure and initialize
|
||||
* device for use.
|
||||
* shutdown - Called when driver is closed. Stop output and free
|
||||
* hardware resources.
|
||||
* configure - Configure speed, active channels, and bidirectional
|
||||
* mode according to dshot_config_s.
|
||||
* send_command - Send DShot command packets to specified channels.
|
||||
* get_raw_telemetry - Fetch raw telemetry packets from specified channels.
|
||||
* ioctl - Optional platform-specific ioctl handler.
|
||||
*/
|
||||
|
||||
struct dshot_lowerhalf_s;
|
||||
struct dshot_ops_s
|
||||
{
|
||||
CODE int (*setup)(FAR struct dshot_lowerhalf_s *dev);
|
||||
|
||||
CODE int (*shutdown)(FAR struct dshot_lowerhalf_s *dev);
|
||||
|
||||
CODE int (*configure)(FAR struct dshot_lowerhalf_s *dev,
|
||||
FAR const struct dshot_config_s *cfg);
|
||||
|
||||
CODE int (*send_command)(FAR struct dshot_lowerhalf_s *dev,
|
||||
FAR const uint16_t *packets,
|
||||
uint16_t ch_mask);
|
||||
|
||||
CODE int (*get_raw_telemetry)(FAR struct dshot_lowerhalf_s *dev,
|
||||
FAR struct dshot_raw_telemetry_s *raw,
|
||||
uint16_t ch_mask);
|
||||
|
||||
CODE int (*ioctl)(FAR struct dshot_lowerhalf_s *dev,
|
||||
int cmd, unsigned long arg);
|
||||
};
|
||||
|
||||
/* Public representation of lower-half state. */
|
||||
|
||||
struct dshot_lowerhalf_s
|
||||
{
|
||||
FAR const struct dshot_ops_s *ops;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* "Upper-Half" DShot Driver Interfaces
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dshot_register
|
||||
*
|
||||
* Description:
|
||||
* This function binds an instance of a "lower half" timer driver with the
|
||||
* "upper half" DSHOT device and registers that device so that can be used
|
||||
* by application code.
|
||||
*
|
||||
* When this function is called, the "lower half" driver should be in the
|
||||
* reset state (as if the shutdown() method had already been called).
|
||||
*
|
||||
* Input Parameters:
|
||||
* path - The full path to the driver to be registered in the NuttX pseudo-
|
||||
* filesystem.
|
||||
* dev - A pointer to an instance of lower half DShot driver. This instance
|
||||
* is bound to the DShot driver and must persist as long as the driver
|
||||
* persists.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int dshot_register(FAR const char *path, FAR struct dshot_lowerhalf_s *dev);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_TIMERS_DSHOT_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue