Skip to content

Commit

Permalink
cc2538: implement radio hal
Browse files Browse the repository at this point in the history
  • Loading branch information
jia200x committed Jul 30, 2020
1 parent 8ab7a28 commit ebeb695
Show file tree
Hide file tree
Showing 3 changed files with 380 additions and 0 deletions.
10 changes: 10 additions & 0 deletions cpu/cc2538/include/cc2538_rf.h
Expand Up @@ -68,6 +68,16 @@ extern "C" {

#define CC2538_CRC_BIT_MASK (0x80)

#define CC2538_CCA_THR_MASK (0x000000FF)

#define CC2538_CSP_SKIP_INST_MASK (0x70)
#define CC2538_CSP_SKIP_INST_POS (4U)

#define CC2538_CSP_SKIP_N_MASK (0x08)

#define CC2538_CSP_SKIP_COND_RSSI (0x07)
#define CC2538_CSP_SKIP_COND_CCA (0x00)

#define CC2538_RSSI_OFFSET (-73) /**< Signal strength offset value */
#define CC2538_RF_SENSITIVITY (-97) /**< dBm typical, normal conditions */

Expand Down
3 changes: 3 additions & 0 deletions cpu/cc2538/radio/cc2538_rf.c
Expand Up @@ -58,6 +58,9 @@ static const init_pair_t init_table[] = {
{&RFCORE_XREG_SRCMATCH, 0x00 },
{&RFCORE_XREG_FIFOPCTRL, CC2538_RF_MAX_DATA_LEN },
{&RFCORE_XREG_RFIRQM0, FIFOP | RXPKTDONE },
#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
{&RFCORE_XREG_RFIRQM1, TXDONE | CSP_STOP },
#endif
{&RFCORE_XREG_RFERRM, STROBE_ERR | TXUNDERF | TXOVERF | RXUNDERF | RXOVERF | NLOCK},
{NULL, 0},
};
Expand Down
367 changes: 367 additions & 0 deletions cpu/cc2538/radio/cc2538_rf_radio_ops.c
@@ -0,0 +1,367 @@
#include <errno.h>
#include <stdio.h>

#include "net/gnrc.h"

#include "cc2538_rf.h"
#include "cc2538_rf_internal.h"

#include "net/ieee802154/radio.h"

#if IS_USED(MODULE_IEEE802154_RADIO_HAL)
static const ieee802154_radio_ops_t cc2538_rf_ops;

ieee802154_dev_t cc2538_rf_dev = {
.driver = &cc2538_rf_ops,
};

static int _write(ieee802154_dev_t *dev, iolist_t *iolist)
{
(void) dev;
int pkt_len = 0;
RFCORE_SFR_RFST = ISFLUSHTX;
rfcore_write_byte(0);

for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) {
if (iol->iol_len) {
pkt_len += iol->iol_len;
rfcore_write_fifo(iol->iol_base, iol->iol_len);
}
}

/* Set first byte of TX FIFO to the packet length */
rfcore_poke_tx_fifo(0, pkt_len + CC2538_AUTOCRC_LEN);
return 0;
}

static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info)
{
(void) dev;
(void) info;
if (RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE != 0) {
return -EAGAIN;
}

return 0;
}

static int _request_transmit(ieee802154_dev_t *dev, uint8_t flags)
{
(void) dev;
if (flags & TX_MODE_AUTO) {
return -ENOTSUP;
}

if (flags & TX_MODE_TXRX) {
RFCORE_SFR_RFST = ISRXMASKBITSET;
}
else {
RFCORE_SFR_RFST = ISRXMASKBITCLR;
}

RFCORE_SFR_RFST = ISTXON;
return 0;
}

static int _len(ieee802154_dev_t *dev)
{
(void) dev;
return rfcore_peek_rx_fifo(0);
}

static int _indication_rx(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_info_t *info)
{
(void) dev;
int res;
size_t pkt_len = rfcore_read_byte();

pkt_len -= IEEE802154_FCS_LEN;

if (pkt_len > size) {
RFCORE_SFR_RFST = ISFLUSHRX;
return -ENOBUFS;
}

if (buf != NULL) {
rfcore_read_fifo(buf, pkt_len);
res = pkt_len;
if (info != NULL) {
uint8_t corr_val;
int8_t rssi_val;
rssi_val = rfcore_read_byte() + CC2538_RSSI_OFFSET;

RFCORE_ASSERT(rssi_val > CC2538_RF_SENSITIVITY);

/* The number of dB above maximum sensitivity detected for the
* received packet */
info->rssi = -CC2538_RF_SENSITIVITY + rssi_val;

corr_val = rfcore_read_byte() & CC2538_CORR_VAL_MASK;

if (corr_val < CC2538_CORR_VAL_MIN) {
corr_val = CC2538_CORR_VAL_MIN;
}
else if (corr_val > CC2538_CORR_VAL_MAX) {
corr_val = CC2538_CORR_VAL_MAX;
}

/* Interpolate the correlation value between 0 - 255
* to provide an LQI value */
info->lqi = 255 * (corr_val - CC2538_CORR_VAL_MIN) /
(CC2538_CORR_VAL_MAX - CC2538_CORR_VAL_MIN);
}
}
else {
res = 0;
}

RFCORE_SFR_RFST = ISFLUSHRX;

return res;
}

static int _confirm_cca(ieee802154_dev_t *dev)
{
(void) dev;
/* We use the register Z to indicate there's a pending CCA */
if (RFCORE_XREG_CSPZ) {
return -EAGAIN;
}

return RFCORE_XREG_CSPX;
}

static int _request_cca(ieee802154_dev_t *dev)
{
(void) dev;
/* Ignore baseband processing */
RFCORE_XREG_RFIRQM0 &= ~RXPKTDONE;

/* Clear last program */
RFCORE_SFR_RFST = ISCLEAR;

/* CCA requires RX-ON */
RFCORE_SFR_RFST = ISRXON;

/* If the RSSI is not yet valid, busy loop */
RFCORE_SFR_RFST = SKIP_S_C |
CC2538_CSP_SKIP_N_MASK |
CC2538_CSP_SKIP_COND_RSSI;

/* If CCA is not valid, skip the next instruction */
RFCORE_SFR_RFST = SKIP_S_C |
(1<<CC2538_CSP_SKIP_INST_POS) |
CC2538_CSP_SKIP_COND_CCA;

/* If the strobe processor execute this function,
* it means the CCA was valid. We use the
* register X to indicate so */
RFCORE_SFR_RFST = INCX;

/* Decrement the register Z (used to indicate
* there's a pending CCA request */
RFCORE_SFR_RFST = DECZ;

/* Stop the program */
RFCORE_SFR_RFST = STOP;

RFCORE_XREG_CSPX = 0;
RFCORE_XREG_CSPZ = 1;

/* Execute the last program */
RFCORE_SFR_RFST = ISSTART;
return 0;
}

static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold)
{
(void) dev;
(void) threshold;

if (threshold < CC2538_RF_SENSITIVITY) {
return -EINVAL;
}


RFCORE_XREG_CCACTRL0 &= ~CC2538_CCA_THR_MASK;
RFCORE_XREG_CCACTRL0 |= (threshold - CC2538_RSSI_OFFSET) & CC2538_CCA_THR_MASK;

return 0;
}

static int _config_phy(ieee802154_dev_t *dev, ieee802154_phy_conf_t *conf)
{
(void) dev;
cc2538_set_freq(IEEE802154_CHAN2FREQ(conf->channel));
cc2538_set_tx_power(conf->pow);

return 0;
}

static int _confirm_set_trx_state(ieee802154_dev_t *dev)
{
(void) dev;
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE == FSM_STATE_RX_CALIBRATION) {
return -EAGAIN;
}
return 0;
}

static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t state)
{

(void) dev;
bool wait_sfd = RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE > 0x2 && RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE < 0x7;
if ((RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE && !wait_sfd) ||
RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE) {
return -EBUSY;
}

switch(state) {
case IEEE802154_TRX_STATE_TRX_OFF:
case IEEE802154_TRX_STATE_TX_ON:
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE != FSM_STATE_IDLE) {
RFCORE_SFR_RFST = ISRFOFF;
}
break;
case IEEE802154_TRX_STATE_RX_ON:
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
RFCORE_SFR_RFST = ISRXON;
break;
}

return 0;
}

void _irq_handler(void)
{
uint_fast8_t flags_f0 = RFCORE_SFR_RFIRQF0;
uint_fast8_t flags_f1 = RFCORE_SFR_RFIRQF1;

RFCORE_SFR_RFIRQF0 = 0;
RFCORE_SFR_RFIRQF1 = 0;

if (flags_f1 & TXDONE) {
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_CONFIRM_TX_DONE);
}

if (flags_f0 & RXPKTDONE) {
/* CRC check */
uint8_t pkt_len = rfcore_peek_rx_fifo(0);
if (rfcore_peek_rx_fifo(pkt_len) & CC2538_CRC_BIT_MASK) {
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_INDICATION_RX_DONE);
}
else {
/* CRC failed; discard packet */
RFCORE_SFR_RFST = ISFLUSHRX;
}

}

if (flags_f1 & CSP_STOP) {
cc2538_rf_dev.cb(&cc2538_rf_dev, IEEE802154_RADIO_CONFIRM_CCA);
}
}

static int _off(ieee802154_dev_t *dev)
{
(void) dev;
return -ENOTSUP;
}

static bool _get_cap(ieee802154_dev_t *dev, ieee802154_rf_caps_t cap)
{
(void) dev;
switch(cap) {
case IEEE802154_CAP_AUTO_ACK:
case IEEE802154_CAP_24_GHZ:
case IEEE802154_CAP_TXRX:
case IEEE802154_CAP_IRQ_TX_DONE:
case IEEE802154_CAP_IRQ_CCA_DONE:
return true;
default:
return false;
}
}

static int _set_hw_addr_filter(ieee802154_dev_t *dev, uint8_t *short_addr, uint8_t *ext_addr, uint16_t pan_id)
{
(void) dev;
RFCORE_FFSM_SHORT_ADDR0 = short_addr[1];
RFCORE_FFSM_SHORT_ADDR1 = short_addr[0];

RFCORE_FFSM_EXT_ADDR0 = ext_addr[7];
RFCORE_FFSM_EXT_ADDR1 = ext_addr[6];
RFCORE_FFSM_EXT_ADDR2 = ext_addr[5];
RFCORE_FFSM_EXT_ADDR3 = ext_addr[4];
RFCORE_FFSM_EXT_ADDR4 = ext_addr[3];
RFCORE_FFSM_EXT_ADDR5 = ext_addr[2];
RFCORE_FFSM_EXT_ADDR6 = ext_addr[1];
RFCORE_FFSM_EXT_ADDR7 = ext_addr[0];

RFCORE_FFSM_PAN_ID0 = pan_id;
RFCORE_FFSM_PAN_ID1 = pan_id >> 8;
return 0;
}

static int _set_promiscuous(ieee802154_dev_t *dev, bool enable)
{
(void) dev;
cc2538_set_monitor(enable);
return 0;
}

static int _confirm_on(ieee802154_dev_t *dev)
{
(void) dev;
/* TODO */
return 0;
}

static int _request_on(ieee802154_dev_t *dev)
{
(void) dev;
/* TODO */
return 0;
}

static int _set_cca_mode(ieee802154_dev_t *dev, ieee802154_cca_mode_t mode)
{
(void) dev;
(void) mode;
/* TODO */
return 0;
}

static int _set_aack(ieee802154_dev_t *dev, ieee802154_aack_conf_t conf)
{
(void) dev;
(void) conf;
/* TODO */
return 0;
}

static const ieee802154_radio_ops_t cc2538_rf_ops = {
.write = _write,
.request_transmit = _request_transmit,
.confirm_transmit = _confirm_transmit,
.len = _len,
.indication_rx = _indication_rx,
.off = _off,
.request_on = _request_on,
.confirm_on = _confirm_on,
.request_set_trx_state = _request_set_trx_state,
.confirm_set_trx_state = _confirm_set_trx_state,
.request_cca = _request_cca,
.confirm_cca = _confirm_cca,
.get_cap = _get_cap,
.set_cca_threshold = _set_cca_threshold,
.set_cca_mode = _set_cca_mode,
.config_phy = _config_phy,
.set_promiscuous = _set_promiscuous,
.set_hw_addr_filter = _set_hw_addr_filter,
.set_aack = _set_aack
};
#else
int dont_be_pedantic;
#endif

0 comments on commit ebeb695

Please sign in to comment.