wayne roberts / SX1232

Dependents:   chat_sx1232

Revision:
0:06cc2cd9f340
Child:
1:67a841d57890
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sx1232.cpp	Wed May 01 23:40:33 2013 +0000
@@ -0,0 +1,439 @@
+#include "sx1232.h"
+
+SX1232::SX1232(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dio_0) : m_spi(mosi, miso, sclk), m_cs(cs), reset_pin(rst), dio0(dio_0)
+{
+    dio0.rise(this, &SX1232::dio0_callback);
+    reset_pin.input();
+    m_cs = 1;
+    m_spi.format(8, 0);
+    m_spi.frequency(1000000);
+    
+    init();
+    service_action = SERVICE_NONE;
+}
+
+SX1232::~SX1232()
+{
+    set_opmode(RF_OPMODE_SLEEP);
+}
+
+void SX1232::init()
+{
+    RegOpMode.octet = read_reg(REG_OPMODE);
+    RegPktConfig1.octet = read_reg(REG_PACKETCONFIG1);
+    RegPktConfig2.octet = read_reg(REG_PACKETCONFIG2);
+    RegDioMapping1.octet = read_reg(REG_DIOMAPPING1);
+    RegDioMapping2.octet = read_reg(REG_DIOMAPPING2);
+    RegPayloadLength = read_reg(REG_PAYLOADLENGTH);
+    RegPaConfig.octet = read_reg(REG_PACONFIG);
+    RegOokPeak.octet = read_reg(REG_OOKPEAK);
+    RegRxConfig.octet = read_reg(REG_RXCONFIG);
+    RegLna.octet = read_reg(REG_LNA);
+    RegTimerResol.octet = read_reg(REG_TIMERRESOL);
+    RegSeqConfig1.octet = read_reg(REG_SEQCONFIG1);
+    RegSeqConfig2.octet = read_reg(REG_SEQCONFIG2);
+    RegAfcFei.octet = read_reg(REG_AFCFEI);
+    
+    RegPreambleDetect.octet = read_reg(REG_PREAMBLEDETECT);
+    if (RegPreambleDetect.octet != 0xaa) {
+        RegPreambleDetect.octet = 0xaa;
+        write_reg(REG_PREAMBLEDETECT, RegPreambleDetect.octet);
+    }
+    
+    RegSyncConfig.octet = read_reg(REG_SYNCCONFIG);
+    RegSyncConfig.bits.SyncSize = 2;    // actual size is this+1
+    RegSyncConfig.bits.AutoRestartRxMode = 1;   // restart Rx after fifo emptied.  2 is for frequency hopping
+    write_reg(REG_SYNCCONFIG, RegSyncConfig.octet);
+    write_reg(REG_SYNCVALUE1, 0xaa);
+    write_reg(REG_SYNCVALUE1, 0x90); // 802.15.4g examples: 0x7bc9, 0x904e, 0xc9c2, 0x7a0e
+    write_reg(REG_SYNCVALUE2, 0x4e);
+    
+    RegFifoThreshold.octet = read_reg(REG_FIFOTHRESH);
+    if (!RegFifoThreshold.bits.TxStartCondition) { // is start condition at fifoThreshold?
+        RegFifoThreshold.bits.TxStartCondition = 1; // make it start tx on FifoNotEmpty
+        write_reg(REG_FIFOTHRESH, RegFifoThreshold.octet);
+    }
+}
+
+void SX1232::hw_reset()
+{
+    /* only a french-swiss design would have hi-Z deassert */
+    reset_pin.output();
+    reset_pin.write(1);
+    wait(0.05);
+    reset_pin.input();
+    wait(0.05);
+}
+
+// variable-length pkt is only 255byte max
+// fixed-length packet could be larger than 255 bytes
+int SX1232::read_fifo()
+{
+    /* no blocking code or printf in an ISR */
+    int i, len;
+    
+    if (RegPktConfig1.bits.PacketFormatVariable) {
+        m_cs = 0;
+        m_spi.write(REG_FIFO); // bit7 is low for reading from radio
+        len = m_spi.write(0);
+        m_cs = 1;
+    } else
+        len = get_PayloadLength();
+     
+    m_cs = 0;
+    m_spi.write(REG_FIFO); // bit7 is low for reading from radio
+    for (i = 0; i < len; i++) {
+        // todo: flow control for pkt bigger than fifo (need ISR on FifoTreshold)
+        rx_buf[i] = m_spi.write(0);
+    }
+    m_cs = 1;
+    //_callback_rx.call();
+    return len;
+}
+        
+void SX1232::dio0_callback()
+{
+    /* no printf allowed here in ISR */
+    switch (RegDioMapping1.bits.Dio0Mapping) {
+        case 0:
+            if (RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
+                service_action = SERVICE_READ_FIFO;
+            } else if (RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) {
+                set_opmode(RF_OPMODE_STANDBY); // this should be quick enough for ISR
+            }
+            break;
+        case 1:
+            service_action = SERVICE_READ_FIFO;
+            break;
+        default:
+            service_action = SERVICE_ERROR;
+            break;
+    }
+    
+}
+
+void SX1232::set_opmode(chip_mode_e mode)
+{
+    RegOpMode.bits.Mode = mode;
+    write_reg(REG_OPMODE, RegOpMode.octet);
+}
+
+float SX1232::get_frf_MHz(void)
+{
+    uint32_t frf;
+    uint8_t lsb, mid, msb;
+    msb = read_reg(REG_FRFMSB);
+    mid = read_reg(REG_FRFMID);
+    lsb = read_reg(REG_FRFLSB);
+    frf = msb;
+    frf <<= 8;
+    frf += mid;
+    frf <<= 8;
+    frf += lsb;
+    return frf * FREQ_STEP_MHZ;
+}
+
+void SX1232::set_bitrate(uint32_t bps)
+{
+    uint8_t lsb, msb;
+    uint16_t br = XTAL_FREQ / bps;
+    msb = br >> 8;
+    lsb = br & 0xff;
+    write_reg(REG_BITRATEMSB, msb);
+    write_reg(REG_BITRATELSB, lsb);
+}
+
+uint32_t SX1232::get_bitrate()
+{
+    uint16_t br;
+    
+    br = read_reg(REG_BITRATEMSB);
+    br <<= 8;
+    br += read_reg(REG_BITRATELSB);
+
+    return XTAL_FREQ / br;
+}
+
+void SX1232::set_tx_fdev_hz(uint32_t hz)
+{
+    uint16_t fdev = hz / FREQ_STEP_HZ;
+    uint8_t lsb, msb;
+    msb = fdev >> 8;
+    lsb = fdev & 0xff;
+    write_reg(REG_FDEVMSB, msb);
+    write_reg(REG_FDEVLSB, lsb);
+}
+
+uint32_t SX1232::get_tx_fdev_hz(void)
+{
+    uint16_t fdev;
+    
+    fdev = read_reg(REG_FDEVMSB);
+    fdev <<= 8;
+    fdev += read_reg(REG_FDEVLSB);
+
+    return fdev * FREQ_STEP_HZ;
+}
+
+void SX1232::set_frf_MHz( float MHz )
+{
+    uint32_t frf;
+    uint8_t lsb, mid, msb;
+    
+    frf = MHz / FREQ_STEP_MHZ;
+    msb = frf >> 16;
+    mid = (frf >> 8) & 0xff;
+    lsb = frf & 0xff;
+    write_reg(REG_FRFMSB, msb);
+    write_reg(REG_FRFMID, mid);
+    write_reg(REG_FRFLSB, lsb);
+}
+
+void SX1232::ComputeRxBwMantExp( uint32_t rxBwValue, uint8_t* mantisse, uint8_t* exponent )
+{
+    uint8_t tmpExp, tmpMant;
+    double tmpRxBw;
+    double rxBwMin = 10e6;
+
+    for( tmpExp = 0; tmpExp < 8; tmpExp++ ) {
+        for( tmpMant = 16; tmpMant <= 24; tmpMant += 4 ) {
+            tmpRxBw = ComputeRxBw(tmpMant, tmpExp);         
+            if( fabs( tmpRxBw - rxBwValue ) < rxBwMin ) {
+                rxBwMin = fabs( tmpRxBw - rxBwValue );
+                *mantisse = tmpMant;
+                *exponent = tmpExp;
+            }
+        }
+    }
+}
+
+uint32_t SX1232::ComputeRxBw( uint8_t mantisse, uint8_t exponent ) {
+    // rxBw
+    if (RegOpMode.bits.ModulationType == 0)
+        return XTAL_FREQ / (mantisse * (1 << exponent+2));
+    else
+        return XTAL_FREQ / (mantisse * (1 << exponent+3));
+}
+
+void SX1232::set_rx_dcc_bw_hz(uint32_t dccValue, uint32_t bw_hz )
+{
+    uint8_t mantisse = 0;
+    uint8_t exponent = 0;
+    uint8_t reg;
+    
+    reg = ( uint8_t )dccValue & 0x60;
+    ComputeRxBwMantExp( bw_hz, &mantisse, &exponent );
+    switch( mantisse ) {
+        case 16:
+            reg |= ( uint8_t )( 0x00 | ( exponent & 0x07 ) );
+            break;
+        case 20:
+            reg |= ( uint8_t )( 0x08 | ( exponent & 0x07 ) );
+            break;
+        case 24:
+            reg |= ( uint8_t )( 0x10 | ( exponent & 0x07 ) );
+            break;
+        default:
+            // Something went terribely wrong
+            printf("maintisse:%d\r\n", mantisse);
+            break;
+    }
+    
+    write_reg(REG_RXBW, reg);
+}
+
+uint32_t SX1232::get_rx_bw_hz(uint8_t addr)
+{
+    uint8_t mantisse = 0;
+    uint8_t reg = read_reg(REG_RXBW);
+    switch( ( reg & 0x18 ) >> 3 )
+    {
+        case 0:
+            mantisse = 16;
+            break;
+        case 1:
+            mantisse = 20;
+            break;
+        case 2:
+            mantisse = 24;
+            break;
+        default:
+            break;
+    }
+    return ComputeRxBw( mantisse, ( uint8_t )reg & 0x07 );
+}
+
+uint16_t SX1232::get_PayloadLength()
+{
+    uint16_t ret;
+
+    RegPktConfig2.octet = read_reg(REG_PACKETCONFIG2);
+    RegPayloadLength = read_reg(REG_PAYLOADLENGTH);
+
+    ret = RegPktConfig2.bits.PayloadLengthHi;
+    ret <<= 8;
+    ret += RegPayloadLength;
+
+    return ret;
+}
+
+void SX1232::set_RegPayloadLength(uint16_t len)
+{
+    RegPktConfig2.bits.PayloadLengthHi = len >> 8;
+    write_reg(REG_PACKETCONFIG2, RegPktConfig2.octet);
+    RegPayloadLength = len & 0xff;
+    write_reg(REG_PAYLOADLENGTH, RegPayloadLength);
+}
+
+void SX1232::enable_afc(char en)
+{
+    if (en) {
+        RegRxConfig.bits.AfcAutoOn = 1;
+        RegRxConfig.bits.RxTrigger = 6; // 6: trigger on preamble detect
+        
+        if (RegSyncConfig.bits.AutoRestartRxMode != 1) {
+            // 2 is for frequency hopping application
+            // if 0 then manual RestartRx in RxConfig required
+            RegSyncConfig.bits.AutoRestartRxMode = 1;
+        }
+        // preamble detector triggers AFC
+        if (!RegPreambleDetect.bits.PreambleDetectorOn) {
+            RegPreambleDetect.bits.PreambleDetectorOn = 1;
+            RegPreambleDetect.bits.PreambleDetectorTol = 10; // chips
+            RegPreambleDetect.bits.PreambleDetectorSize = 1; // bytes
+            write_reg(REG_PREAMBLEDETECT, RegPreambleDetect.octet);
+        }
+        // set DIO4 output.  not required, only for monitoring
+        if ((RegDioMapping2.bits.Dio4Mapping != 3) || !RegDioMapping2.bits.MapPreambleDetect) {
+            RegDioMapping2.bits.Dio4Mapping = 3;
+            RegDioMapping2.bits.MapPreambleDetect = 1;
+            write_reg(REG_DIOMAPPING2, RegDioMapping2.octet);
+        }
+    } else {
+        RegRxConfig.bits.AfcAutoOn = 0;
+        RegRxConfig.bits.RxTrigger = 0;
+    }
+    write_reg(REG_RXCONFIG, RegRxConfig.octet);
+}
+
+int16_t SX1232::read_reg_s16(uint8_t addr)
+{
+    int16_t ret;
+    // Select the device by seting chip select low
+    m_cs = 0;
+
+    m_spi.write(addr); // bit7 is low for reading from radio
+ 
+    // Send a dummy byte to receive the contents of the WHOAMI register
+    ret = m_spi.write(0x00);
+    ret <<= 8;
+    ret += m_spi.write(0x00);
+ 
+    // Deselect the device
+    m_cs = 1;
+    
+    return ret;
+}
+
+uint8_t SX1232::read_reg(uint8_t addr)
+{
+    uint8_t ret;
+    // Select the device by seting chip select low
+    m_cs = 0;
+
+    m_spi.write(addr); // bit7 is low for reading from radio
+ 
+    // Send a dummy byte to receive the contents of the WHOAMI register
+    ret = m_spi.write(0x00);
+ 
+    // Deselect the device
+    m_cs = 1;
+    
+    return ret;
+}
+
+void SX1232::write_reg(uint8_t addr, uint8_t data)
+{
+    m_cs = 0;   // Select the device by seting chip select low
+
+    m_spi.write(addr | 0x80); // bit7 is high for writing to radio
+ 
+    // Send a dummy byte to receive the contents of the WHOAMI register
+    m_spi.write(data);
+ 
+    m_cs = 1;   // Deselect the device
+}
+
+// variable-length pkt is only 255byte max
+void SX1232::write_fifo__varlen(uint8_t len)
+{
+    int i;
+    
+    m_cs = 0;
+    m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
+    m_spi.write(len);
+    for (i = 0; i < len; i++) {
+        // todo: flow control for pkt bigger than fifo
+        m_spi.write(tx_buf[i]);
+    }
+    m_cs = 1;
+}
+
+// fixed-length packet could be larger than 255 bytes
+void SX1232::write_fifo__fixedlen(void)
+{
+    int i, len = get_PayloadLength();
+    m_cs = 0;
+    m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
+    for (i = 0; i < len; i++) {
+        // todo: flow control for pkt bigger than fifo
+        m_spi.write(tx_buf[i]);
+    }
+    m_cs = 1;
+}
+
+// arg only for variable-length
+void SX1232::start_tx(uint8_t len)
+{
+    if (RegOpMode.bits.Mode > RF_OPMODE_STANDBY) {
+        RegIrqFlags1_t RegIrqFlags1;
+        set_opmode(RF_OPMODE_STANDBY); // unwise fill fifo in RX
+        wait(0.01);
+        RegIrqFlags1.octet = read_reg(REG_IRQFLAGS1);
+        while (!RegIrqFlags1.bits.ModeReady) {
+            //printf("to stby:%02x\r\n", RegIrqFlags1.octet);
+            wait(0.01);
+            RegIrqFlags1.octet = read_reg(REG_IRQFLAGS1);
+        }
+    }
+        
+    // DIO0 to PacketSent
+    if (RegDioMapping1.bits.Dio0Mapping != 0) {
+        RegDioMapping1.bits.Dio0Mapping = 0;
+        write_reg(REG_DIOMAPPING1, RegDioMapping1.octet);
+    }
+    
+    if (RegPktConfig1.bits.PacketFormatVariable)
+        write_fifo__varlen(len);
+    else
+        write_fifo__fixedlen();
+
+    set_opmode(RF_OPMODE_TRANSMITTER);
+}
+
+void SX1232::start_rx()
+{
+    if (RegPktConfig1.bits.CrcOn) {    // DIO0 to CrcOk
+        if (RegDioMapping1.bits.Dio0Mapping != 1) {
+            RegDioMapping1.bits.Dio0Mapping = 1;
+            write_reg(REG_DIOMAPPING1, RegDioMapping1.octet);
+        }
+    } else {    // DIO0 to PayloadReady
+        if (RegDioMapping1.bits.Dio0Mapping != 0) {
+            RegDioMapping1.bits.Dio0Mapping = 0;
+            write_reg(REG_DIOMAPPING1, RegDioMapping1.octet);
+        }    
+    }
+    
+    set_opmode(RF_OPMODE_RECEIVER);
+}