Merge pull request #17184 from benpicco/drivers/dose-standby_fix

drivers/dose: fix standby mode
This commit is contained in:
benpicco 2021-12-07 11:09:43 +01:00 committed by GitHub
commit 228ba83dc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 18 deletions

View File

@ -331,6 +331,7 @@ void uart_poweron(uart_t uart)
{ {
sercom_clk_en(dev(uart)); sercom_clk_en(dev(uart));
dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
_syncbusy(dev(uart));
} }
void uart_poweroff(uart_t uart) void uart_poweroff(uart_t uart)

View File

@ -48,8 +48,9 @@ static int send_octet(dose_t *ctx, uint8_t c);
static int _send(netdev_t *dev, const iolist_t *iolist); 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 _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(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 int _init(netdev_t *dev);
static void _poweron(dose_t *dev);
static void _poweroff(dose_t *dev, dose_state_t sleep_state);
static uint16_t crc16_update(uint16_t crc, uint8_t octet) static uint16_t crc16_update(uint16_t crc, uint8_t octet)
{ {
@ -446,7 +447,7 @@ static int _send(netdev_t *dev, const iolist_t *iolist)
/* sending data wakes the interface from STANDBY */ /* sending data wakes the interface from STANDBY */
if (ctx->state == DOSE_STATE_STANDBY) { if (ctx->state == DOSE_STATE_STANDBY) {
_set_state(ctx, NETOPT_STATE_IDLE); _poweron(ctx);
} }
send: send:
@ -537,37 +538,55 @@ static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
return 0; return 0;
} }
static void _gpio_try_set(gpio_t pin) static void _poweron(dose_t *ctx)
{ {
if (gpio_is_valid(pin)) { /* interface is already powered on - do nothing */
gpio_set(pin); if (ctx->state != DOSE_STATE_STANDBY &&
ctx->state != DOSE_STATE_SLEEP) {
return;
} }
if (gpio_is_valid(ctx->standby_pin)) {
gpio_clear(ctx->standby_pin);
}
uart_poweron(ctx->uart);
_enable_sense(ctx);
ctx->state = DOSE_STATE_IDLE;
} }
static void _gpio_try_clear(gpio_t pin) static void _poweroff(dose_t *ctx, dose_state_t sleep_state)
{ {
if (gpio_is_valid(pin)) { /* interface is already powered off - do nothing */
gpio_clear(pin); if (ctx->state == DOSE_STATE_STANDBY ||
ctx->state == DOSE_STATE_SLEEP) {
return;
} }
wait_for_state(ctx, DOSE_STATE_IDLE);
if (gpio_is_valid(ctx->standby_pin)) {
gpio_set(ctx->standby_pin);
}
_disable_sense(ctx);
uart_poweroff(ctx->uart);
ctx->state = sleep_state;
} }
static int _set_state(dose_t *ctx, netopt_state_t state) static int _set_state(dose_t *ctx, netopt_state_t state)
{ {
switch (state) { switch (state) {
case NETOPT_STATE_STANDBY: case NETOPT_STATE_STANDBY:
_gpio_try_set(ctx->standby_pin); _poweroff(ctx, DOSE_STATE_STANDBY);
uart_poweroff(ctx->uart);
ctx->state = DOSE_STATE_STANDBY;
return sizeof(netopt_state_t); return sizeof(netopt_state_t);
case NETOPT_STATE_SLEEP: case NETOPT_STATE_SLEEP:
_gpio_try_set(ctx->standby_pin); _poweroff(ctx, DOSE_STATE_SLEEP);
uart_poweroff(ctx->uart);
ctx->state = DOSE_STATE_SLEEP;
return sizeof(netopt_state_t); return sizeof(netopt_state_t);
case NETOPT_STATE_IDLE: case NETOPT_STATE_IDLE:
uart_poweron(ctx->uart); _poweron(ctx);
_gpio_try_clear(ctx->standby_pin);
ctx->state = DOSE_STATE_IDLE;
return sizeof(netopt_state_t); return sizeof(netopt_state_t);
default: default:
break; break;
@ -661,7 +680,10 @@ void dose_setup(dose_t *ctx, const dose_params_t *params, uint8_t index)
/* The timeout base is the minimal timeout base used for this driver. /* The timeout base is the minimal timeout base used for this driver.
* We have to ensure it is above the XTIMER_BACKOFF. Otherwise state * We have to ensure it is above the XTIMER_BACKOFF. Otherwise state
* transitions are triggered from another state transition setting up the * transitions are triggered from another state transition setting up the
* timeout. */ * timeout.
* To calculate how long it takes to transfer one byte we assume
* 8 data bits + 1 start bit + 1 stop bit per byte.
*/
ctx->timeout_base = CONFIG_DOSE_TIMEOUT_BYTES * 10UL * US_PER_SEC / params->baudrate; ctx->timeout_base = CONFIG_DOSE_TIMEOUT_BYTES * 10UL * US_PER_SEC / params->baudrate;
if (ctx->timeout_base < xtimer_usec_from_ticks(min_timeout)) { if (ctx->timeout_base < xtimer_usec_from_ticks(min_timeout)) {
ctx->timeout_base = xtimer_usec_from_ticks(min_timeout); ctx->timeout_base = xtimer_usec_from_ticks(min_timeout);