Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: sx1232.cpp
- 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);
+}