/* * Copyright (C) 2017 Neo Nenaco * Copyright (C) 2017 Koen Zandberg * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup drivers_mrf24j40 * @{ * * @file * @brief Implementation of driver internal functions * * @author Koen Zandberg * @author Neo Nenaco * * @} */ #include "periph/spi.h" #include "periph/gpio.h" #include "xtimer.h" #include "mrf24j40_internal.h" #include "mrf24j40_registers.h" #define ENABLE_DEBUG (0) #include "debug.h" #define SPIDEV (dev->params.spi) #define CSPIN (dev->params.cs_pin) static inline void getbus(mrf24j40_t *dev) { spi_acquire(SPIDEV, CSPIN, SPI_MODE_0, dev->params.spi_clk); } void mrf24j40_init(mrf24j40_t *dev) { mrf24j40_hardware_reset(dev); #if ENABLE_DEBUG /* Check if MRF24J40 is available */ uint8_t txmcr = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); if ((txmcr == 0xFF) || (txmcr == 0x00)) { /* Write default value to TXMCR register */ mrf24j40_reg_write_short(dev, MRF24J40_REG_TXMCR, MRF24J40_TXMCR_MACMINBE1 | MRF24J40_TXMCR_MACMINBE0 | MRF24J40_TXMCR_CSMABF2); txmcr = mrf24j40_reg_read_short(dev, MRF24J40_REG_TXMCR); if (txmcr != (MRF24J40_TXMCR_MACMINBE1 | MRF24J40_TXMCR_MACMINBE0 | MRF24J40_TXMCR_CSMABF2)) { DEBUG("[mrf24j40] Initialization failure, SPI interface communication failed\n"); /* Return to prevents hangup later in the initialization */ return; } } #endif /* do a soft reset */ mrf24j40_reg_write_short(dev, MRF24J40_REG_SOFTRST, MRF24J40_SOFTRST_RSTPWR | MRF24J40_SOFTRST_RSTBB | MRF24J40_SOFTRST_RSTMAC ); /* flush RX FIFO */ mrf24j40_reg_write_short(dev, MRF24J40_REG_RXFLUSH, MRF24J40_RXFLUSH_RXFLUSH); /* Here starts init-process as described on MRF24J40 Manual Chap. 3.2 */ mrf24j40_reg_write_short(dev, MRF24J40_REG_PACON2, (MRF24J40_PACON2_TXONTS2 | MRF24J40_PACON2_TXONTS1 | MRF24J40_PACON2_FIFOEN)); mrf24j40_reg_write_short(dev, MRF24J40_REG_TXSTBL, (MRF24J40_TXSTBL_RFSTBL3 | MRF24J40_TXSTBL_RFSTBL0 | MRF24J40_TXSTBL_MSIFS2 | MRF24J40_TXSTBL_MSIFS0)); mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON1, MRF24J40_RFCON1_VCOOPT1); mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON2, MRF24J40_RFCON2_PLLEN); mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON6, (MRF24J40_RFCON6_TXFIL | MRF24J40_RFCON6_20MRECVR)); mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON7, MRF24J40_RFCON7_SLPCLKSEL1 ); mrf24j40_reg_write_long(dev, MRF24J40_REG_RFCON8, MRF24J40_RFCON8_RFVCO ); mrf24j40_reg_write_long(dev, MRF24J40_REG_SLPCON1, (MRF24J40_SLPCON1_CLKOUTEN | MRF24J40_SLPCON1_SLPCLKDIV0)); mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG2, MRF25J40_BBREG2_CCAMODE1 ); mrf24j40_reg_write_short(dev, MRF24J40_REG_CCAEDTH, 0x60); mrf24j40_reg_write_short(dev, MRF24J40_REG_BBREG6, MRF24J40_BBREG6_RSSIMODE2 ); /* Enable immediate sleep mode */ mrf24j40_reg_write_short(dev, MRF24J40_REG_WAKECON, MRF24J40_WAKECON_IMMWAKE); /* set interrupt pin polarity, rising edge */ mrf24j40_reg_write_long(dev, MRF24J40_REG_SLPCON0, MRF24J40_SLPCON0_INTEDGE ); /* reset RF state machine */ mrf24j40_reset_state_machine(dev); /* clear interrupts */ mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); /* mrf24j40_set_interrupts */ mrf24j40_reg_write_short(dev, MRF24J40_REG_INTCON, ~(MRF24J40_INTCON_RXIE | MRF24J40_INTCON_TXNIE)); } uint8_t mrf24j40_reg_read_short(mrf24j40_t *dev, const uint8_t addr) { char value; getbus(dev); value = spi_transfer_reg(SPIDEV, CSPIN, MRF24J40_SHORT_ADDR_TRANS | (addr << MRF24J40_ADDR_OFFSET) | MRF24J40_ACCESS_READ, 0); spi_release(SPIDEV); return (uint8_t)value; } void mrf24j40_reg_write_short(mrf24j40_t *dev, const uint8_t addr, const uint8_t value) { getbus(dev); spi_transfer_reg(SPIDEV, CSPIN , MRF24J40_SHORT_ADDR_TRANS | (addr << MRF24J40_ADDR_OFFSET) | MRF24J40_ACCESS_WRITE, value); spi_release(SPIDEV); } uint8_t mrf24j40_reg_read_long(mrf24j40_t *dev, const uint16_t addr) { uint8_t reg1, reg2; reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); reg2 = (addr << 5) | MRF24J40_ACCESS_READ; char value; getbus(dev); spi_transfer_byte(SPIDEV, CSPIN, true, reg1); spi_transfer_byte(SPIDEV, CSPIN, true, reg2); value = spi_transfer_byte(SPIDEV, CSPIN, false, 0); spi_release(SPIDEV); return (uint8_t)value; } void mrf24j40_reg_write_long(mrf24j40_t *dev, const uint16_t addr, const uint8_t value) { uint8_t reg1, reg2; reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); reg2 = (addr << 5) | MRF24J40_ACCESS_WRITE_LNG; getbus(dev); spi_transfer_byte(SPIDEV, CSPIN, true, reg1); spi_transfer_byte(SPIDEV, CSPIN, true, reg2); spi_transfer_byte(SPIDEV, CSPIN, false, value); spi_release(SPIDEV); } void mrf24j40_tx_normal_fifo_write(mrf24j40_t *dev, const uint16_t offset, const uint8_t *data, const size_t len) { uint16_t addr; uint8_t reg1; uint8_t reg2; addr = offset; reg1 = MRF24J40_LONG_ADDR_TRANS | (addr >> 3); reg2 = (addr << 5) | MRF24J40_ACCESS_WRITE_LNG; getbus(dev); spi_transfer_byte(SPIDEV, CSPIN, true, reg1); spi_transfer_byte(SPIDEV, CSPIN, true, reg2); spi_transfer_bytes(SPIDEV, CSPIN, false, (char *)data, NULL, len); spi_release(SPIDEV); } void mrf24j40_rx_fifo_read(mrf24j40_t *dev, const uint16_t offset, uint8_t *data, const size_t len) { uint16_t rx_addr; rx_addr = MRF24J40_RX_FIFO + offset; uint8_t reg1, reg2; reg1 = MRF24J40_LONG_ADDR_TRANS | (rx_addr >> 3); reg2 = (rx_addr << 5) | MRF24J40_ACCESS_READ; getbus(dev); spi_transfer_byte(SPIDEV, CSPIN, true, reg1); spi_transfer_byte(SPIDEV, CSPIN, true, reg2); spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, (char *)data, len); spi_release(SPIDEV); } void mrf24j40_reset_tasks(mrf24j40_t *dev) { dev->pending = MRF24J40_TASK_TX_DONE; } void mrf24j40_update_tasks(mrf24j40_t *dev) { if (dev->irq_flag) { uint8_t newpending = 0; uint8_t instat = 0; dev->irq_flag = 0; instat = mrf24j40_reg_read_short(dev, MRF24J40_REG_INTSTAT); /* check if TX done */ if (instat & MRF24J40_INTSTAT_TXNIF) { newpending |= MRF24J40_TASK_TX_DONE | MRF24J40_TASK_TX_READY; /* transmit done, returning to configured idle state */ mrf24j40_assert_sleep(dev); } if (instat & MRF24J40_INTSTAT_RXIF) { newpending |= MRF24J40_TASK_RX_READY; } /* check if RX pending */ dev->pending |= newpending; } } void mrf24j40_hardware_reset(mrf24j40_t *dev) { /* wake up from sleep in case radio is sleeping */ mrf24j40_assert_awake(dev); /* trigger hardware reset */ gpio_clear(dev->params.reset_pin); /* Datasheet - Not specified */ xtimer_usleep(MRF24J40_RESET_PULSE_WIDTH); gpio_set(dev->params.reset_pin); /* Datasheet - MRF24J40 ~2ms */ xtimer_usleep(MRF24J40_RESET_DELAY); }