ISM RF transmitter library for MAX4146X family devices

Library for MAX41460, MAX41461, MAX41462, MAX41463, MAX41464 RF Transmitter ICs.

Revision:
0:4040347d719c
Child:
1:ccf0e1d28860
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Max4146x.cpp	Thu May 02 12:51:33 2019 +0300
@@ -0,0 +1,1185 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *******************************************************************************
+ */
+
+#include "Max4146x.h"
+#include <iostream>
+
+using namespace std;
+
+const uint8_t default_register_value_0[17] = {0x90, 0x81, 0x03, 0x00, 0x00, 0x04, 0x80, 0x80, 0x60, 0x00,
+                                              0x00, 0xC4, 0xDE, 0x98, 0x28, 0x04, 0x02};
+const uint8_t default_register_value_1[20] = {0x90, 0x81, 0x03, 0x00, 0x00, 0x04, 0x80, 0x80, 0x60, 0x00,
+                                              0x00, 0xC4, 0xDE, 0x98, 0x28, 0x04, 0x04, 0x00, 0xFF, 0x00};
+
+template <class REG>
+MAX4146X<REG>::MAX4146X(REG *reg, SPI *spi, DigitalOut *cs)
+{
+    operation_mode = UNINITIALIZED;
+
+    if (reg == NULL) {
+        return;
+    }
+
+    if (cs == NULL) {
+        return;
+    }
+
+    this->reg = reg;
+    ssel = cs;
+
+    if (spi == NULL) {
+        return;
+    }
+
+    spi_handler = spi;
+    i2c_handler = NULL;
+    preset_mode = 0;
+
+    if (initial_programming() < 0) {
+        return;
+    }
+
+    this->crystal_frequency = 16.0;
+    this->center_frequency = 315.0;
+    this->baud_rate = 5000.0;  //5 kHz
+
+    operation_mode = INITIALIZED;
+}
+
+template <class REG>
+MAX4146X<REG>::MAX4146X(REG *reg, SPI *spi)
+{
+    operation_mode = UNINITIALIZED;
+
+    if (reg == NULL) {
+        return;
+    }
+
+    this->reg = reg;
+
+    if (spi == NULL) {
+        return;
+    }
+
+    spi_handler = spi;
+    i2c_handler = NULL;
+    ssel = NULL;
+    preset_mode = 0;
+
+    if (initial_programming() < 0) {
+        return;
+    }
+
+    this->crystal_frequency = 16.0;
+    this->center_frequency = 315.0;
+    this->baud_rate = 5000.0; //5 kHz
+
+    operation_mode = INITIALIZED;
+}
+
+template <class REG>
+MAX4146X<REG>::MAX4146X(REG *reg, I2C *i2c)
+{
+    operation_mode = UNINITIALIZED;
+
+    if (reg == NULL) {
+        return;
+    }
+
+    this->reg = reg;
+
+    if (i2c == NULL) {
+        return;
+    }
+
+    i2c_handler = i2c;
+    spi_handler = NULL;
+    ssel = NULL;
+    preset_mode = 0;
+
+    if (initial_programming() < 0) {
+        return;
+    }
+
+    this->crystal_frequency = 16.0;
+    this->center_frequency = 315.0;
+    this->baud_rate = 5000.0;  //5 kHz
+
+    operation_mode = INITIALIZED;
+}
+
+template <class REG>
+MAX4146X<REG>::MAX4146X(DigitalOut *cs)
+{
+    operation_mode = UNINITIALIZED;
+
+    if (cs == NULL) {
+        return;
+    }
+
+    data_sent = cs;
+
+    data_rate = 5;
+
+    this->reg = NULL;
+    this->ssel = NULL;
+    spi_handler = NULL;
+    i2c_handler = NULL;
+    preset_mode = 1;
+
+    operation_mode = INITIALIZED;
+}
+
+template <>
+int MAX4146X<max41460_reg_map_t>::read_register(uint8_t reg, uint8_t *value, uint8_t len)
+{
+    int rtn_val = -1;
+
+    if (value == NULL) {
+        return -1;
+    }
+
+    if (this->reg == NULL) {
+        return -1;
+    }
+
+    if (ssel != NULL) {
+        *ssel = 0;
+    }
+    spi_handler->write((uint8_t)0x80 | reg);
+    for (uint8_t i = 0; i < len; i++) {
+        *(value++) = spi_handler->write(0x00);     // read back  data bytes
+    }
+    if (ssel != NULL) {
+        *ssel = 1;
+    }
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::read_register(uint8_t reg, uint8_t *value, uint8_t len)
+{
+    int rtn_val = -1;
+
+    if (value == NULL) {
+        return -1;
+    }
+
+    if (this->reg == NULL) {
+        return -1;
+    }
+
+    rtn_val = i2c_handler->write(I2C_ADDRESS, (const char *)&reg, 1, true);
+    if (rtn_val != 0) {
+        return -1;
+    }
+
+    rtn_val = i2c_handler->read(I2C_ADDRESS, (char *) value, len, false);
+    if (rtn_val < 0) {
+        return rtn_val;
+    }
+
+    return 0;
+}
+
+template <>
+int MAX4146X<max41460_reg_map_t>::write_register(uint8_t reg, const uint8_t *value, uint8_t len)
+{
+    int rtn_val = -1;
+    uint8_t local_data[1 + len];
+
+    if (value == NULL) {
+        return -1;
+    }
+
+    memcpy(&local_data[0], value, len);
+
+    rtn_val = spi_handler->write(0x7F & reg); // write mode and adress send
+    for (int i = 0; i < len; i++) {
+        rtn_val = spi_handler->write(local_data[i]); // write adress
+    }
+    if (rtn_val != 0) {
+        return rtn_val;
+    }
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::write_register(uint8_t reg, const uint8_t *value, uint8_t len)
+{
+    int rtn_val = -1;
+    uint8_t local_data[1 + len];
+
+    if (value == NULL) {
+        return -1;
+    }
+
+    local_data[0] = reg;
+
+    memcpy(&local_data[1], value, len);
+
+    rtn_val = i2c_handler->write(I2C_ADDRESS, (const char *)local_data,
+            sizeof(local_data));
+    if (rtn_val != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+#define SET_BIT_FIELD(address, reg_name, bit_field_name, value)                             \
+                int ret;                                                                    \
+                ret = read_register(address, (uint8_t *)&(reg_name), 1);                    \
+                if (ret) {                                                                  \
+                    return ret;                                                             \
+                }                                                                           \
+                bit_field_name = value;                                                     \
+                ret = write_register(address, (uint8_t *)&(reg_name), 1);                   \
+                if (ret) {                                                                  \
+                    return ret;                                                             \
+                }
+
+template <class REG>
+int MAX4146X<REG>::set_crystal_frequency(float freq)
+{
+    if (freq < 250 || freq > 950) {
+        return -1;
+    }
+    this->crystal_frequency = freq;
+
+    return 0;
+}
+
+template <class REG>
+float MAX4146X<REG>::get_crystal_frequency()
+{
+    return this->crystal_frequency;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_center_frequency(float freq)
+{
+    if (freq < 250 || freq > 950) {
+        return -1;
+    }
+
+    this->center_frequency = freq;
+
+    uint32_t value = (uint32_t)((65536 * freq) / this->crystal_frequency); //65536 is constant defined in the datasheet
+
+    return this->set_frequency(value);
+}
+
+template <class REG>
+float MAX4146X<REG>::get_center_frequency()
+{
+    return this->center_frequency;
+}
+
+template <class REG>
+int MAX4146X<REG>::adjust_baudrate(float rate)
+{
+    if (rate < 195.3 || rate > 200000.0) {
+        return -1;
+    }
+
+    if (this->preset_mode == 1) {
+        this->baud_rate = rate;
+    }
+
+    int error = 0;
+    uint8_t prediv = 3;
+
+    if (rate < 12500.0) {
+        error = this->set_bclk_postdiv(this->BCLK_POSTDIV_BY_5);
+        prediv = (uint8_t)((50000.0 / rate) - 1);
+    } else if (rate < 25000.0) {
+        error = this->set_bclk_postdiv(this->BCLK_POSTDIV_BY_4);
+        prediv = (uint8_t)((100000.0 / rate) - 1);
+    } else if (rate < 50000.0) {
+        error = this->set_bclk_postdiv(this->BCLK_POSTDIV_BY_3);
+        prediv = (uint8_t)((200000.0 / rate) - 1);
+    } else if (rate < 100000.0) {
+        error = this->set_bclk_postdiv(this->BCLK_POSTDIV_BY_2);
+        prediv = (uint8_t)((400000.0 / rate) - 1);
+    } else {
+        error = this->set_bclk_postdiv(this->BCLK_POSTDIV_BY_1);
+        prediv = (uint8_t)((800000.0 / rate) - 1);
+    }
+
+    if (error < 0) {
+        return -1;
+    }
+
+    return this->set_bclk_prediv(prediv);
+}
+
+template <class REG>
+float MAX4146X<REG>::get_baudrate()
+{
+    return this->baud_rate;
+}
+
+template <class REG>
+int MAX4146X<REG>::adjust_frequency_deviation(float deviation)
+{
+    uint8_t dev = 0;
+
+    if (this->read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1) < 0) {
+        return -1;
+    }
+
+    if (this->reg->reg_cfg1.bits.fskshape == 0) {
+        dev = (uint8_t)(deviation * 8.192 / crystal_frequency);
+        if (dev < 127) {
+            return this->set_deltaf(dev);
+        }
+    } else {
+        dev = (uint8_t)(deviation * 81.92 / crystal_frequency); // crystal_frequency in MHz form
+        if (dev < 15) {
+            return this->set_deltaf_shape(dev);
+        }
+    }
+
+    return -1;
+}
+
+template <class REG>
+int MAX4146X<REG>::adjust_manchester_bitrate(char rate)
+{
+    this->data_rate = rate;
+
+    return 0;
+}
+
+template <class REG>
+char MAX4146X<REG>::get_manchester_bitrate()
+{
+    return this->data_rate;
+}
+
+template <>
+int MAX4146X<max41460_reg_map_t>::send_data(uint8_t *data, uint32_t length)
+{
+    if (this->preset_mode == 0) {
+
+        if (ssel != NULL) {
+            *ssel = 0;
+        }
+
+        spi_handler->write(0x7F & 0x0A); /*write mode and adress send*/
+
+        spi_handler->write(0x01); /*write data SPI_EN1 clear*/
+
+
+        if (ssel != NULL) {
+            *ssel = 1;
+        }
+
+        wait_us(300); /* for waiting another SPI operation*/
+
+        if (ssel != NULL) {
+            *ssel = 0;
+        }
+
+        spi_handler->write(0x7F & 0x10); /*write mode and adress send*/
+
+        spi_handler->write(0x03); /*write data SPI_EN2 set*/
+
+        if (ssel != NULL) {
+            *ssel = 0;
+        }
+
+        wait_us(300); /* for waiting another SPI operation*/
+
+    }
+
+    return this->io_write(data, length);
+}
+
+template <class REG>
+int MAX4146X<REG>::send_data(uint8_t *data, uint32_t length)
+{
+    if (this->preset_mode == 0) {
+        if (length > 32767) {
+            return -100;
+        }
+
+        this->adjust_baudrate(this->baud_rate);
+
+//        this->set_i2c_txen1(I2C_TXEN1_DISABLE);
+
+        char * value = (char *)malloc(17 * sizeof(char));
+
+        if (value == NULL) {
+        	return -99;
+        }
+
+        int rtn_val = i2c_handler->write(I2C_ADDRESS, (char *) 0x00, 1, true);
+        rtn_val = i2c_handler->read(I2C_ADDRESS, value, length, true);
+		if (rtn_val != 0) {
+			return rtn_val;
+		}
+
+		free(value);
+
+        uint8_t local_data[4+length];
+
+        local_data[0] = CFG7_ADDR;
+        local_data[1] = 0x04;
+        local_data[2] = (uint8_t)((length >> 8) | 0x80);
+        local_data[3] = (uint8_t)((length) & 0x0FF);
+
+        memcpy(&local_data[4], data, length);
+
+        i2c_handler->write(I2C_ADDRESS, (const char *)local_data, sizeof(local_data), false);
+
+    } else {
+        this->io_write(data, length);
+    }
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::io_write(uint8_t *data, uint32_t length)
+{
+    //manchester array
+    manchester_bit_array = new  unsigned char[length * 2 * 8];
+
+    //bit array
+    bits_array = new unsigned char[length * 8];
+
+    //byte to bit conversion
+    for (int i = 0; i < length; i++) {
+        for (int j = 0; j < 8; j++) {
+            // Mask each bit in the byte and store it
+            if (data[i] & (mask << j)) {
+                bits_array[i * 8 + j] = 1;
+            } else {
+                bits_array[i * 8 + j] = 0;
+            }
+        }
+    }
+
+    //manchester encode
+    for (int i = 0; i < length * 8; i++) {
+        if (bits_array[i] == 0) {
+            //falling edge
+            manchester_bit_array[2 * i] = 1;
+            manchester_bit_array[2 * i + 1] = 0;
+        } else {
+            //rising edge
+            manchester_bit_array[2 * i] = 0;
+            manchester_bit_array[2 * i + 1] = 1;
+        }
+    }
+
+    delete[] bits_array;  //delete bit array anymore not used
+
+    float result = (500.0 / data_rate);
+
+    bool rxFinished = false;
+    Timer t;
+    core_util_critical_section_enter();
+    *this->data_sent = 0;
+    wait_us(100);
+    *this->data_sent = 1;
+    wait_us(350);
+    *this->data_sent = 0;
+    wait_us(10);
+    t.start();
+    int manch_bit_counter = 0;
+    do {
+        if (t.read_us() >= (result * manch_bit_counter)) {
+            if (manchester_bit_array[manch_bit_counter] == 0) {
+                *this->data_sent = 0;
+            } else {
+                *this->data_sent = 1;
+            }
+
+            manch_bit_counter++;
+
+            if (manch_bit_counter >= (length * 2 * 8)) {
+                rxFinished = true;
+                t.stop();
+                if (this->ssel != NULL) {
+                    *this->ssel = 1;
+                }
+            }
+
+        }
+    } while (!rxFinished);
+    *this->data_sent = 0;
+    core_util_critical_section_exit();
+
+    delete[]  manchester_bit_array;  //manchester array clean
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_softreset(softreset_t softreset)
+{
+    SET_BIT_FIELD(CFG8_ADDR, this->reg->reg_cfg8, this->reg->reg_cfg8.bits.softreset, softreset);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_xoclkdelay(xoclkdelay_t delay)
+{
+    SET_BIT_FIELD(CFG1_ADDR, this->reg->reg_cfg1, this->reg->reg_cfg1.bits.xoclkdelay, delay);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_xoclkdelay(xoclkdelay_t *delay)
+{
+    int ret;
+
+    ret = read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *delay = (xoclkdelay_t)this->reg->reg_cfg1.bits.xoclkdelay;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_fifo_flags(uint8_t *fifo_flags)
+{
+    return read_register(I2C6_ADDR, fifo_flags, 1);
+}
+
+template <class REG>
+int MAX4146X<REG>::get_pktcomplete(uint8_t *pktcomplete)
+{
+    int ret;
+
+    ret = read_register(I2C4_ADDR, (uint8_t *) & (this->reg->reg_i2c4), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pktcomplete = (uint8_t)this->reg->reg_i2c4.bits.pktcomplete;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_tx_pktlen(uint16_t *pktlen)
+{
+    int ret;
+
+    ret = read_register(I2C4_ADDR, (uint8_t *) & (this->reg->reg_i2c4), 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pktlen = (uint16_t)(((this->reg->reg_i2c4.bits.tx_pktlen_14_to_8) << 8) + (this->reg->reg_i2c5.raw)) ;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_xoclkdiv(xoclkdiv_t div)
+{
+    SET_BIT_FIELD(CFG1_ADDR, this->reg->reg_cfg1, this->reg->reg_cfg1.bits.xoclkdiv, div);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_xoclkdiv(xoclkdiv_t* div)
+{
+    int ret;
+
+    ret = read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *div = (xoclkdiv_t)this->reg->reg_cfg1.bits.xoclkdiv;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_fskshape(fskshape_t shape)
+{
+    SET_BIT_FIELD(CFG1_ADDR, this->reg->reg_cfg1, this->reg->reg_cfg1.bits.fskshape, shape);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_fskshape(fskshape_t* shape)
+{
+    int ret;
+
+    ret = read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *shape = (fskshape_t)this->reg->reg_cfg1.bits.fskshape;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_sync(sync_t state)
+{
+    SET_BIT_FIELD(CFG1_ADDR, this->reg->reg_cfg1, this->reg->reg_cfg1.bits.sync, state);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_sync(sync_t* state)
+{
+    int ret;
+
+    ret = read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *state = (sync_t)this->reg->reg_cfg1.bits.sync;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_modmode(modmode_t mode)
+{
+    SET_BIT_FIELD(CFG1_ADDR, this->reg->reg_cfg1, this->reg->reg_cfg1.bits.modmode, mode);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_modmode(modmode_t* mode)
+{
+    int ret;
+
+    ret = read_register(CFG1_ADDR, (uint8_t *) & (this->reg->reg_cfg1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *mode = (modmode_t)this->reg->reg_cfg1.bits.modmode;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_clkout_delay(clkout_delay_t delay)
+{
+    SET_BIT_FIELD(CFG2_ADDR, this->reg->reg_cfg2, this->reg->reg_cfg2.bits.clkout_delay, delay);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_clkout_delay(clkout_delay_t* delay)
+{
+    int ret;
+
+    ret = read_register(CFG2_ADDR, (uint8_t *) & (this->reg->reg_cfg2), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *delay = (clkout_delay_t)this->reg->reg_cfg2.bits.clkout_delay;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_bclk_postdiv(bclk_postdiv_t div)
+{
+    SET_BIT_FIELD(CFG2_ADDR, this->reg->reg_cfg2, this->reg->reg_cfg2.bits.bclk_postdiv, div);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_bclk_postdiv(bclk_postdiv_t* div)
+{
+    int ret;
+
+    ret = read_register(CFG2_ADDR, (uint8_t *) & (this->reg->reg_cfg2), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *div = (bclk_postdiv_t)this->reg->reg_cfg2.bits.bclk_postdiv;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_bclk_prediv(uint8_t prediv)
+{
+    if (prediv < 3) {
+        return -1;
+    }
+
+    SET_BIT_FIELD(CFG3_ADDR, this->reg->reg_cfg3, this->reg->reg_cfg3.bits.bclk_prediv, prediv);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_bclk_prediv(uint8_t* prediv)
+{
+    int ret;
+
+    ret = read_register(CFG3_ADDR, (uint8_t *) & (this->reg->reg_cfg3), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *prediv = (uint8_t)this->reg->reg_cfg3.bits.bclk_prediv;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_pwdn_mode(pwdn_mode_t pwdn_mode)
+{
+    SET_BIT_FIELD(CFG4_ADDR, this->reg->reg_cfg4, this->reg->reg_cfg4.bits.pwdn_mode, pwdn_mode);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_pwdn_mode(pwdn_mode_t* pwdn_mode)
+{
+    int ret;
+
+    ret = read_register(CFG4_ADDR, (uint8_t *) & (this->reg->reg_cfg4), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pwdn_mode = (pwdn_mode_t)this->reg->reg_cfg4.bits.pwdn_mode;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_tstep(uint8_t tstep)
+{
+    SET_BIT_FIELD(CFG5_ADDR, this->reg->reg_cfg5, this->reg->reg_cfg5.bits.tstep, tstep);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_tstep(uint8_t* tstep)
+{
+    int ret;
+
+    ret = read_register(CFG5_ADDR, (uint8_t *) & (this->reg->reg_cfg5), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *tstep = (uint8_t)this->reg->reg_cfg5.bits.tstep;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_pa_boost(pa_boost_t pa_boost)
+{
+    SET_BIT_FIELD(SHDN_ADDR, this->reg->reg_shdn, this->reg->reg_shdn.bits.pa_boost, pa_boost);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_pa_boost(pa_boost_t* pa_boost)
+{
+    int ret;
+
+    ret = read_register(CFG5_ADDR, (uint8_t *) & (this->reg->reg_shdn), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pa_boost = (pa_boost_t)this->reg->reg_shdn.bits.pa_boost;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_papwr(papwr_t papwr)
+{
+    SET_BIT_FIELD(PA1_ADDR, this->reg->reg_pa1, this->reg->reg_pa1.bits.papwr, papwr);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_papwr(papwr_t* papwr)
+{
+    int ret;
+
+    ret = read_register(PA1_ADDR, (uint8_t *) & (this->reg->reg_pa1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *papwr = (papwr_t)this->reg->reg_pa1.bits.papwr;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_pacap(pacap_t pacap)
+{
+    SET_BIT_FIELD(PA2_ADDR, this->reg->reg_pa2, this->reg->reg_pa2.bits.pacap, pacap);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_pacap(pacap_t* pacap)
+{
+    int ret;
+
+    ret = read_register(CFG5_ADDR, (uint8_t *) & (this->reg->reg_pa2), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pacap = (pacap_t)this->reg->reg_pa2.bits.pacap;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_cplin(cplin_t cplin)
+{
+    SET_BIT_FIELD(PLL1_ADDR, this->reg->reg_pll1, this->reg->reg_pll1.bits.cplin, cplin);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_cplin(cplin_t* cplin)
+{
+    int ret;
+
+    ret = read_register(PLL1_ADDR, (uint8_t *) & (this->reg->reg_pll1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *cplin = (cplin_t)this->reg->reg_pll1.bits.cplin;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_fracmode(fracmode_t fracmode)
+{
+    SET_BIT_FIELD(PLL1_ADDR, this->reg->reg_pll1, this->reg->reg_pll1.bits.fracmode, fracmode);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_fracmode(fracmode_t* fracmode)
+{
+    int ret;
+
+    ret = read_register(PLL1_ADDR, (uint8_t *) & (this->reg->reg_pll1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *fracmode = (fracmode_t)this->reg->reg_pll1.bits.fracmode;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_lodiv(lodiv_t lodiv)
+{
+    SET_BIT_FIELD(PLL1_ADDR, this->reg->reg_pll1, this->reg->reg_pll1.bits.lodiv, lodiv);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_lodiv(lodiv_t* lodiv)
+{
+    int ret;
+
+    ret = read_register(PLL1_ADDR, (uint8_t *) & (this->reg->reg_pll1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *lodiv = (lodiv_t)this->reg->reg_pll1.bits.lodiv;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_lomode(lomode_t lomode)
+{
+    SET_BIT_FIELD(PLL1_ADDR, this->reg->reg_pll1, this->reg->reg_pll1.bits.lomode, lomode);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_lomode(lomode_t* lomode)
+{
+    int ret;
+
+    ret = read_register(PLL1_ADDR, (uint8_t *) & (this->reg->reg_pll1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *lomode = (lomode_t)this->reg->reg_pll1.bits.lomode;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_cpval(cpval_t cpval)
+{
+
+    SET_BIT_FIELD(PLL2_ADDR, this->reg->reg_pll2, this->reg->reg_pll2.bits.cpval, cpval);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_cpval(cpval_t* cpval)
+{
+    int ret;
+
+    ret = read_register(PLL2_ADDR, (uint8_t *) & (this->reg->reg_pll2), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *cpval = (cpval_t)this->reg->reg_pll2.bits.cpval;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_frequency(uint32_t freq)
+{
+    uint8_t value[3] = {(uint8_t)(freq >> 16), (uint8_t)(freq >> 8), (uint8_t)freq};
+
+    return write_register(PLL3_ADDR, (uint8_t *)&value, 3);
+
+}
+
+template <class REG>
+int MAX4146X<REG>::get_frequency(uint32_t* freq)
+{
+    int ret;
+
+    uint8_t value[3];
+
+    ret =  read_register(PLL3_ADDR, (uint8_t *)&value, 3);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *freq = (uint32_t)((value[0] << 16) + (value[1] << 8) + value[2]);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_deltaf(uint8_t deltaf)
+{
+    if (deltaf > 127) {
+        return -1;
+    }
+
+    SET_BIT_FIELD(PLL6_ADDR, this->reg->reg_pll6, this->reg->reg_pll6.bits.deltaf, deltaf);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_deltaf(uint8_t* deltaf)
+{
+    int ret;
+
+    ret = read_register(PLL6_ADDR, (uint8_t *) & (this->reg->reg_pll6), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *deltaf = (uint8_t)this->reg->reg_pll6.bits.deltaf;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_deltaf_shape(uint8_t deltaf_shape)
+{
+    if (deltaf_shape > 15) {
+        return -1;
+    }
+
+    SET_BIT_FIELD(PLL7_ADDR, this->reg->reg_pll7, this->reg->reg_pll7.bits.deltaf_shape, deltaf_shape);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_deltaf_shape(uint8_t* deltaf_shape)
+{
+    int ret;
+
+    ret = read_register(PLL7_ADDR, (uint8_t *) & (this->reg->reg_pll7), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *deltaf_shape = (uint8_t)this->reg->reg_pll7.bits.deltaf_shape;
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::set_pktlen_mode(pktlen_mode_t pktlen_mode)
+{
+    SET_BIT_FIELD(I2C1_ADDR, this->reg->reg_i2c1, this->reg->reg_i2c1.bits.pktlen_mode, pktlen_mode);
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::get_pktlen_mode(pktlen_mode_t* pktlen_mode)
+{
+    int ret;
+
+    ret = read_register(I2C1_ADDR, (uint8_t *) & (this->reg->reg_i2c1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pktlen_mode = (pktlen_mode_t)this->reg->reg_i2c1.bits.pktlen_mode;
+
+    return 0;
+}
+
+
+template <class REG>
+int MAX4146X<REG>::set_i2c_pktlen(uint16_t pktlen)
+{
+    if (pktlen > 0x7FF) {
+        return -1;
+    }
+
+    SET_BIT_FIELD(I2C1_ADDR, this->reg->reg_i2c1, this->reg->reg_i2c1.bits.pktlen_14_to_8, (uint8_t)((pktlen >> 8) & 0x07));
+
+    uint8_t value = (uint8_t)(pktlen & 0xFF);
+
+    return write_register(I2C2_ADDR, (uint8_t *)&value, 1);
+}
+
+template <class REG>
+int MAX4146X<REG>::get_i2c_pktlen(uint16_t* pktlen)
+{
+    int ret;
+
+    ret = read_register(I2C1_ADDR, (uint8_t *) & (this->reg->reg_i2c1), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = read_register(I2C2_ADDR, (uint8_t *) & (this->reg->reg_i2c2), 1);
+    if (ret < 0) {
+        return ret;
+    }
+
+    *pktlen = (uint16_t)(((this->reg->reg_i2c1.raw & 0x7F)<<8) + (this->reg->reg_i2c2.raw &0x7F));
+
+    return 0;
+}
+
+template <class REG>
+int MAX4146X<REG>::initial_programming(void)
+{
+    uint8_t value = 0x80;
+    write_register(ADDL2_ADDR, (uint8_t *)&value, 1);
+
+    return write_register(CFG1_ADDR, default_register_value_1, 20);
+}
+
+template <>
+int MAX4146X<max41460_reg_map_t>::initial_programming(void)
+{
+    if (this->ssel != NULL){
+        *this->ssel = 0;
+        wait_us(100);
+    }
+
+    int rtn = write_register(CFG1_ADDR, default_register_value_0, 17);
+
+    if (this->ssel != NULL){
+        wait_us(90);
+        *this->ssel = 1;
+    }
+
+    return rtn;
+}
+
+
+template class MAX4146X<max41460_reg_map_t>;
+template class MAX4146X<max41461_2_reg_map_t>;
+template class MAX4146X<max41463_4_reg_map_t>;
+
+