1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-26 06:53:52 +01:00

drivers/dose: enable standby pin

Some CAN transceivers have a standby pin that has to be pulled low
in order to use it.
If the interface is disabled we can set it to high again to save some
power.
This commit is contained in:
Benjamin Valentin 2021-08-17 18:59:38 +02:00 committed by Benjamin Valentin
parent 64aac3a2b2
commit 6c1481b6ee
3 changed files with 85 additions and 9 deletions

View File

@ -48,6 +48,7 @@ static int send_octet(dose_t *ctx, uint8_t c);
static int _send(netdev_t *dev, const iolist_t *iolist);
static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
static int _set(netdev_t *dev, netopt_t opt, const void *value, size_t len);
static int _set_state(dose_t *ctx, netopt_state_t state);
static int _init(netdev_t *dev);
static uint16_t crc16_update(uint16_t crc, uint8_t octet)
@ -60,6 +61,15 @@ static uint16_t crc16_update(uint16_t crc, uint8_t octet)
return crc;
}
static void _init_standby(dose_t *ctx, const dose_params_t *params)
{
ctx->standby_pin = params->standby_pin;
if (gpio_is_valid(ctx->standby_pin) &&
gpio_init(ctx->standby_pin, GPIO_OUT)) {
gpio_clear(ctx->standby_pin);
}
}
static void _init_sense(dose_t *ctx, const dose_params_t *params)
{
#ifdef MODULE_PERIPH_UART_RXSTART_IRQ
@ -389,8 +399,8 @@ static int send_octet(dose_t *ctx, uint8_t c)
uart_write(ctx->uart, (uint8_t *) &c, sizeof(c));
/* Wait for a state transition */
uint8_t state = wait_for_state(ctx, DOSE_STATE_ANY);
if (state != DOSE_STATE_SEND) {
uint8_t new_state = wait_for_state(ctx, DOSE_STATE_ANY);
if (new_state != DOSE_STATE_SEND) {
/* Timeout */
DEBUG("dose send_octet(): timeout\n");
return -2;
@ -429,6 +439,16 @@ static int _send(netdev_t *dev, const iolist_t *iolist)
size_t pktlen;
uint16_t crc;
/* discard data when interface is in SLEEP mode */
if (ctx->state == DOSE_STATE_SLEEP) {
return -ENETDOWN;
}
/* sending data wakes the interface from STANDBY */
if (ctx->state == DOSE_STATE_STANDBY) {
_set_state(ctx, NETOPT_STATE_IDLE);
}
send:
crc = 0xffff;
pktlen = 0;
@ -517,6 +537,45 @@ static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
return 0;
}
static void _gpio_try_set(gpio_t pin)
{
if (gpio_is_valid(pin)) {
gpio_set(pin);
}
}
static void _gpio_try_clear(gpio_t pin)
{
if (gpio_is_valid(pin)) {
gpio_clear(pin);
}
}
static int _set_state(dose_t *ctx, netopt_state_t state)
{
switch (state) {
case NETOPT_STATE_STANDBY:
_gpio_try_set(ctx->standby_pin);
uart_poweroff(ctx->uart);
ctx->state = DOSE_STATE_STANDBY;
return sizeof(netopt_state_t);
case NETOPT_STATE_SLEEP:
_gpio_try_set(ctx->standby_pin);
uart_poweroff(ctx->uart);
ctx->state = DOSE_STATE_SLEEP;
return sizeof(netopt_state_t);
case NETOPT_STATE_IDLE:
uart_poweron(ctx->uart);
_gpio_try_clear(ctx->standby_pin);
ctx->state = DOSE_STATE_IDLE;
return sizeof(netopt_state_t);
default:
break;
}
return -ENOTSUP;
}
static int _set(netdev_t *dev, netopt_t opt, const void *value, size_t len)
{
dose_t *ctx = container_of(dev, dose_t, netdev);
@ -539,6 +598,9 @@ static int _set(netdev_t *dev, netopt_t opt, const void *value, size_t len)
CLRBIT(ctx->opts, DOSE_OPT_PROMISCUOUS);
}
return sizeof(netopt_enable_t);
case NETOPT_STATE:
assert(len <= sizeof(netopt_state_t));
return _set_state(ctx, *((const netopt_state_t *)value));
default:
return netdev_eth_set(dev, opt, value, len);
}
@ -585,6 +647,7 @@ void dose_setup(dose_t *ctx, const dose_params_t *params, uint8_t index)
uart_init(ctx->uart, params->baudrate, _isr_uart, (void *) ctx);
_init_sense(ctx, params);
_init_standby(ctx, params);
netdev_register(&ctx->netdev, NETDEV_DOSE, index);

View File

@ -38,16 +38,25 @@ extern "C" {
#ifndef DOSE_PARAM_SENSE_PIN
#define DOSE_PARAM_SENSE_PIN (GPIO_UNDEF)
#endif
#ifndef DOSE_PARAM_STANDBY_PIN
#define DOSE_PARAM_STANDBY_PIN (GPIO_UNDEF) /**< Standby/Silent mode */
#endif
#ifndef DOSE_PARAMS
#ifdef MODULE_PERIPH_UART_RXSTART_IRQ
#define DOSE_PARAMS { .uart = DOSE_PARAM_UART, \
.baudrate = DOSE_PARAM_BAUDRATE }
#else
#define DOSE_PARAMS { .uart = DOSE_PARAM_UART, \
.baudrate = DOSE_PARAM_BAUDRATE, \
.sense_pin = DOSE_PARAM_SENSE_PIN }
#endif
#define DOSE_PARAMS { \
.uart = DOSE_PARAM_UART, \
.baudrate = DOSE_PARAM_BAUDRATE, \
.standby_pin = DOSE_PARAM_STANDBY_PIN, \
}
#else /* MODULE_PERIPH_UART_RXSTART_IRQ */
#define DOSE_PARAMS { \
.uart = DOSE_PARAM_UART, \
.baudrate = DOSE_PARAM_BAUDRATE, \
.standby_pin = DOSE_PARAM_STANDBY_PIN, \
.sense_pin = DOSE_PARAM_SENSE_PIN, \
}
#endif /* !MODULE_PERIPH_UART_RXSTART_IRQ */
#endif
/**@}*/

View File

@ -87,6 +87,8 @@ typedef enum {
DOSE_STATE_IDLE = 0x02, /**< Frames will be received or sent */
DOSE_STATE_RECV = 0x03, /**< Currently receiving a frame */
DOSE_STATE_SEND = 0x04, /**< Currently sending a frame */
DOSE_STATE_STANDBY = 0x05, /**< Receiver is turned off, but send will wake it up */
DOSE_STATE_SLEEP = 0x06, /**< Receiver is turned off and send will be discarded */
DOSE_STATE_ANY = 0x0F /**< Special state filter used internally to observe any state transition */
} dose_state_t;
@ -158,6 +160,7 @@ typedef struct {
#if !defined(MODULE_PERIPH_UART_RXSTART_IRQ) || DOXYGEN
gpio_t sense_pin; /**< GPIO to sense for start bits on the UART's rx line */
#endif
gpio_t standby_pin; /**< GPIO to put the CAN transceiver in standby mode */
xtimer_t timeout; /**< Timeout timer ensuring always to get back to IDLE state */
uint32_t timeout_base; /**< Base timeout in us */
} dose_t;
@ -170,6 +173,7 @@ typedef struct {
#if !defined(MODULE_PERIPH_UART_RXSTART_IRQ) || DOXYGEN
gpio_t sense_pin; /**< GPIO to sense for start bits on the UART's rx line */
#endif
gpio_t standby_pin; /**< GPIO to put the CAN transceiver in standby mode */
uint32_t baudrate; /**< Baudrate to UART device */
} dose_params_t;