You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
5.8 KiB
295 lines
5.8 KiB
/* ieee802154_rf2xx_iface.c - ATMEL RF2XX IEEE 802.15.4 Interface */ |
|
|
|
/* |
|
* Copyright (c) 2019-2020 Gerson Fernando Budke |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define LOG_MODULE_NAME ieee802154_rf2xx_iface |
|
#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME); |
|
|
|
#include <errno.h> |
|
|
|
#include <zephyr/device.h> |
|
#include <zephyr/drivers/spi.h> |
|
#include <zephyr/drivers/gpio.h> |
|
|
|
#include <zephyr/net/ieee802154_radio.h> |
|
|
|
#include "ieee802154_rf2xx.h" |
|
#include "ieee802154_rf2xx_regs.h" |
|
#include "ieee802154_rf2xx_iface.h" |
|
|
|
void rf2xx_iface_phy_rst(const struct device *dev) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
|
|
/* Ensure control lines have correct levels. */ |
|
gpio_pin_set_dt(&conf->reset_gpio, 0); |
|
gpio_pin_set_dt(&conf->slptr_gpio, 0); |
|
|
|
/* Wait typical time of timer TR1. */ |
|
k_busy_wait(330); |
|
|
|
gpio_pin_set_dt(&conf->reset_gpio, 1); |
|
k_busy_wait(10); |
|
gpio_pin_set_dt(&conf->reset_gpio, 0); |
|
} |
|
void rf2xx_iface_phy_tx_start(const struct device *dev) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
|
|
/* Start TX transmission at rise edge */ |
|
gpio_pin_set_dt(&conf->slptr_gpio, 1); |
|
/* 16.125[μs] delay to detect signal */ |
|
k_busy_wait(20); |
|
/* restore initial pin state */ |
|
gpio_pin_set_dt(&conf->slptr_gpio, 0); |
|
} |
|
|
|
uint8_t rf2xx_iface_reg_read(const struct device *dev, |
|
uint8_t addr) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
uint8_t status; |
|
uint8_t regval = 0; |
|
|
|
addr |= RF2XX_RF_CMD_REG_R; |
|
|
|
const struct spi_buf tx_buf = { |
|
.buf = &addr, |
|
.len = 1 |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = &tx_buf, |
|
.count = 1 |
|
}; |
|
const struct spi_buf rx_buf[2] = { |
|
{ |
|
.buf = &status, |
|
.len = 1 |
|
}, |
|
{ |
|
.buf = ®val, |
|
.len = 1 |
|
}, |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = rx_buf, |
|
.count = 2 |
|
}; |
|
|
|
if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { |
|
LOG_ERR("Failed to exec rf2xx_reg_read CMD at address %d", |
|
addr); |
|
} |
|
|
|
LOG_DBG("Read Address: %02X, PhyStatus: %02X, RegVal: %02X", |
|
(addr & ~(RF2XX_RF_CMD_REG_R)), status, regval); |
|
|
|
return regval; |
|
} |
|
|
|
void rf2xx_iface_reg_write(const struct device *dev, |
|
uint8_t addr, |
|
uint8_t data) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
uint8_t status; |
|
|
|
addr |= RF2XX_RF_CMD_REG_W; |
|
|
|
const struct spi_buf tx_buf[2] = { |
|
{ |
|
.buf = &addr, |
|
.len = 1 |
|
}, |
|
{ |
|
.buf = &data, |
|
.len = 1 |
|
} |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = tx_buf, |
|
.count = 2 |
|
}; |
|
const struct spi_buf rx_buf = { |
|
.buf = &status, |
|
.len = 1 |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = &rx_buf, |
|
.count = 1 |
|
}; |
|
|
|
if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { |
|
LOG_ERR("Failed to exec rf2xx_reg_write at address %d", |
|
addr); |
|
} |
|
|
|
LOG_DBG("Write Address: %02X, PhyStatus: %02X, RegVal: %02X", |
|
(addr & ~(RF2XX_RF_CMD_REG_W)), status, data); |
|
} |
|
|
|
uint8_t rf2xx_iface_bit_read(const struct device *dev, |
|
uint8_t addr, |
|
uint8_t mask, |
|
uint8_t pos) |
|
{ |
|
uint8_t ret; |
|
|
|
ret = rf2xx_iface_reg_read(dev, addr); |
|
ret &= mask; |
|
ret >>= pos; |
|
|
|
return ret; |
|
} |
|
|
|
void rf2xx_iface_bit_write(const struct device *dev, |
|
uint8_t reg_addr, |
|
uint8_t mask, |
|
uint8_t pos, |
|
uint8_t new_value) |
|
{ |
|
uint8_t current_reg_value; |
|
|
|
current_reg_value = rf2xx_iface_reg_read(dev, reg_addr); |
|
current_reg_value &= ~mask; |
|
new_value <<= pos; |
|
new_value &= mask; |
|
new_value |= current_reg_value; |
|
rf2xx_iface_reg_write(dev, reg_addr, new_value); |
|
} |
|
|
|
void rf2xx_iface_frame_read(const struct device *dev, |
|
uint8_t *data, |
|
uint8_t length) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
uint8_t cmd = RF2XX_RF_CMD_FRAME_R; |
|
|
|
const struct spi_buf tx_buf = { |
|
.buf = &cmd, |
|
.len = 1 |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = &tx_buf, |
|
.count = 1 |
|
}; |
|
const struct spi_buf rx_buf = { |
|
.buf = data, |
|
.len = length |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = &rx_buf, |
|
.count = 1 |
|
}; |
|
|
|
if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { |
|
LOG_ERR("Failed to exec rf2xx_frame_read PHR"); |
|
} |
|
|
|
LOG_DBG("Frame R: PhyStatus: %02X. length: %02X", data[0], length); |
|
LOG_HEXDUMP_DBG(data + RX2XX_FRAME_HEADER_SIZE, length, "payload"); |
|
} |
|
|
|
void rf2xx_iface_frame_write(const struct device *dev, |
|
uint8_t *data, |
|
uint8_t length) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
uint8_t cmd = RF2XX_RF_CMD_FRAME_W; |
|
uint8_t status; |
|
uint8_t phr; |
|
|
|
/* Sanity check */ |
|
if (length > 125) { |
|
length = 125; |
|
} |
|
|
|
phr = length + RX2XX_FRAME_FCS_LENGTH; |
|
|
|
const struct spi_buf tx_buf[3] = { |
|
{ |
|
.buf = &cmd, |
|
.len = 1 |
|
}, |
|
{ |
|
.buf = &phr, /* PHR */ |
|
.len = 1 |
|
}, |
|
{ |
|
.buf = data, /* PSDU */ |
|
.len = length |
|
}, |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = tx_buf, |
|
.count = 3 |
|
}; |
|
const struct spi_buf rx_buf = { |
|
.buf = &status, |
|
.len = 1 |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = &rx_buf, |
|
.count = 1 |
|
}; |
|
|
|
if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { |
|
LOG_ERR("Failed to exec rf2xx_frame_write"); |
|
} |
|
|
|
LOG_DBG("Frame W: PhyStatus: %02X. length: %02X", status, length); |
|
LOG_HEXDUMP_DBG(data, length, "payload"); |
|
} |
|
|
|
void rf2xx_iface_sram_read(const struct device *dev, |
|
uint8_t address, |
|
uint8_t *data, |
|
uint8_t length) |
|
{ |
|
const struct rf2xx_config *conf = dev->config; |
|
uint8_t cmd = RF2XX_RF_CMD_SRAM_R; |
|
uint8_t status[2]; |
|
|
|
const struct spi_buf tx_buf[2] = { |
|
{ |
|
.buf = &cmd, |
|
.len = 1 |
|
}, |
|
{ |
|
.buf = &address, |
|
.len = 1 |
|
}, |
|
}; |
|
const struct spi_buf_set tx = { |
|
.buffers = tx_buf, |
|
.count = 2 |
|
}; |
|
const struct spi_buf rx_buf[2] = { |
|
{ |
|
.buf = status, |
|
.len = 2 |
|
}, |
|
{ |
|
.buf = data, |
|
.len = length |
|
}, |
|
}; |
|
const struct spi_buf_set rx = { |
|
.buffers = rx_buf, |
|
.count = 2 |
|
}; |
|
|
|
if (spi_transceive_dt(&conf->spi, &tx, &rx) != 0) { |
|
LOG_ERR("Failed to exec rf2xx_sram_read"); |
|
} |
|
|
|
LOG_DBG("SRAM R: length: %02X, status: %02X", length, status[0]); |
|
LOG_HEXDUMP_DBG(data, length, "content"); |
|
}
|
|
|