Learning SPI - IC AS3932

I’m currently working on building my own PKE key. the ic I’m using is AS3932 interfaced with an arduino pro mini and RFM69 900mhz radio.

spec sheet: https://www.sciosense.com/wp-content/uploads/documents/AS3932_DS000340_1-00.pdf

The AS3932 chip doesn’t have arduino library and I’ve never done SPI from scratch before. I’ve been trying to find tutorials and compare other libraries to try and understand how to do what I want. for the most part, I only need to write to the IC.

  • set the RTC internal
  • set data correlation off (the IC should trigger an interrupt upon the 125khz signal, I’m doing this to test my current antenna setup and from there I’ll make a programmable trigger
  • clear wake command
  • and eventually putting it to sleep as majority of the time it’ll be on battery and built into a key fob

I’ve noticed the CS pin is reversed for this chip. 2mhz max frequency, MSBFirst, and spimode1 (reads on the falling edge)

Where I’m getting stuck is how to transfer the data correctly to the chip.
I was using AS3935 lightning chip as a reference to try and understand the SPI setup along with the spi introduction page on the arduino website, spi.transfer() and spi.transaction()

here’s the code I have so far;

#include "Arduino.h"
#include <SPI.h>

#define cs 6 // Chip slect pin for AS3932 -- operates inverted to normal SPI - HIGH is selected

//void registerWrite(byte reg, byte mask, byte data);

/*
// register access macros - register address, bitmask
#define AS3935_AFE_GB    0x00, 0x3E
#define AS3935_PWD    0x00, 0x01
#define AS3935_NF_LEV   0x01, 0x70
#define AS3935_WDTH   0x01, 0x0F
#define AS3935_CL_STAT    0x02, 0x40
#define AS3935_MIN_NUM_LIGH 0x02, 0x30
#define AS3935_SREJ   0x02, 0x0F
#define AS3935_LCO_FDIV 0x03, 0xC0
#define AS3935_MASK_DIST  0x03, 0x20
#define AS3935_INT    0x03, 0x0F
#define AS3935_DISTANCE 0x07, 0x3F
#define AS3935_DISP_LCO 0x08, 0x80
#define AS3935_DISP_SRCO  0x08, 0x40
#define AS3935_DISP_TRCO  0x08, 0x20
#define AS3935_TUN_CAP    0x08, 0x0F
*/

#define AS3932_ON_OFF    0x00, 0x00
#define AS3932_MUX123    0x00, 0x00
#define AS3932_EN_A2     0x00, 0x00 // this one needs to be turned off in 2 channel mode
#define AS3932_EN_A3     0x00, 0x00
#define AS3932_EN_A1     0x00, 0x00
#define AS3932_ON_OFF    0x00, 0x00

#define AS3935_ABS_HY    0x01, 0x00
#define AS3935_AGC_TLIM  0x01, 0x00
#define AS3935_AGC_UD    0x01, 0x00
#define AS3935_ATT_ON    0x01, 0x00
#define AS3935_EN_PAT2   0x01, 0x00
#define AS3935_EN_WPAT   0x01, 0x00
#define AS3935_EN_RTC    0x01, 0x00 // needs to be changed for internal RTC (0)

#define AS3935_S_ABSH    0x02, 0x00
#define AS3935_W_PAT_T   0x02, 0x00
#define AS3935_S_WU1     0x02, 0x00

#define AS3935_HY_20m    0x03, 0x00
#define AS3935_HY_POS    0x03, 0x00
#define AS3935_FS_SLC    0x03, 0x00
#define AS3935_FS_ENV    0x03, 0x00

#define AS3935_T_OFF     0x04, 0x00
#define AS3935_R_VAL     0x04, 0x00
#define AS3935_GR        0x04, 0x00

#define AS3935_TS2       0x05, 0x00 // 01101001 2nd Byte of wake-up pattern

#define AS3935_TS1       0x06, 0x00 // 10010110 1st Byte of wake-up pattern

#define AS3935_T_OUT     0x07, 0x00 // 000 automatic timeout 000 = 0 sec 001 = 50msec 111 = 350msec [other variations available]
#define AS3935_T_HBIT    0x07, 0x00

#define AS3935_T_AUTO    0x08, 0x00

#define AS3935_RSSI1     0x0A, 0x00 

#define AS3935_RSSI3     0x0B, 0x00 

#define AS3935_RSSI2     0x0C, 0x00

#define AS3935_F_WAKE    0x0D, 0x00 

/*
B15 B14 || B13 B12 B11 B10 B9 B8 || B7 B6 B5 B4 B3 B2 B1 B0
 0   0                                                      read
 0   1                                                      write
 1   1                                                      command mode
                Register             Register Data
 0   0     0   0   0   0   0   1     0  0  1  0  0  0  1  0  // should set RTC internal (0)
 0   0     0   0   0   0   0   1     0  0  1  0  0  0  0  0  // sets data correlation off (0) - should activate upon detection of 125khz signal
 0   0     0   0   0   1   1   1     1  1  1  0  1  0  1  1  // register 7 timeout 350ms (111)
 1   1     0   0   0   0   0   0                             // clear wake - direct command

 (R1<1>=0
*/


//registerWrite(AS3935_AFE_GB,AS3935_AFE_OUTDOOR);
//return registerRead(AS3935_NF_LEV);


void setup() {
  // put your setup code here, to run once:
  pinMode(cs, OUTPUT);
  digitalWrite(cs, LOW);
  
SPI.begin();
//SPI.setDataMode(SPI_MODE1); // data sampled on falling edge
//SPI.setClockDivider(SPI_CLOCK_DIV16);
//SPI.setBitOrder(MSBFIRST);

delay (1000);

SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE1)); // start spi interface - 2mhz max clock, 
digitalWrite(cs, HIGH); // cs pin HIGH

byte myData[17] = {0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0}; // set rtc to internal

byte myData[17] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00}; // set rtc to internal

SPI.transfer(myData, sizeof(myData));
//SPI.transfer(); // transfer data
digitalWrite(cs, LOW); // cs pin LOW
SPI.endTransaction(); // end spi interface

}

void loop() {
  // put your main code here, to run repeatedly:

}

and more specifically I’m trying to understand the correct way to transfer the data:

byte myData[17] = {0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0}; // set rtc to internal

byte myData[17] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00}; // set rtc to internal

SPI.transfer(myData, sizeof(myData));

which array would be correct? is there a better way to do it? I really feel like I’m missing something.

any guidance would be approached.

When I'm learning to communicate with a new device, I work on reading one register with known contents first (like a device ID register) then reading and writing some other modifiable register.

Don't worry about sending arrays in one write command at this point. It may not even be possible to do so with this device (SPI is not standardized in that way), and you can always get a task done sending data to it one register at a time.

from my understanding of the data sheet that one array is communicating with just one register.

the first two zero's are write mode. (0,1 is read, and 1,1 is command mode)
the next 6 numbers set the register address, in this case register one, which controls 7 different things. I'm trying to control the last items which is the RTC. it's normally set to 1 by default and that's external rtc. all the other 0/1 are the default for that position.

I've seen code for the lightning ic for example that addresses with the bit mask but i was having trouble understanding it, and wanted to break the code down to the bare minimum, maybe I'll try with reading first tehn. I just didn't want to break the chip hence posting before trying anything. the chip is a little pricey and its listed as not for new designs.

You may be confusing an array of bits with bytes. SPI transfers are usually one byte at a time, and that is how the Arduino SPI library is used. The AS3932 registers are each 8 bits wide.

The AS3932 appears to expect contiguous 16 bit transfers, one command/address byte and one 8 bit register data byte at a time, so the straightforward approach would be to use software bit banging, following the timing diagram in Figure 26 as a guide. Bit banging is required with some devices, which transfer an unusual number of bits (like 20).

That is how I would proceed, and there are many examples on the web, but you should be able to use the Arduino SPI library to send the command/address and data byte as two successive operations. This guide shows you how: https://www.allaboutcircuits.com/projects/arduino-spi-library-ltc1286-dac714/.

Note: To read a register, you specify a read operation in the command/address byte, but still need to send dummy values for the data byte, which are ignored by the sensor. The register data appear in the Arduino SPI input register when the operation is completed.

Consult the AS3932 data sheet Figure 19, register table, to figure out which register you want to modify and what each bit means.

I'll definitely take a look at the tutorial you linked. thanks.

from some more reading i've been doing i realized the arduino wouldn't do it all at once.

my next thought was to try:

SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE1)); // start spi interface - 2mhz max clock, 
digitalWrite(cs, HIGH); // cs pin HIGH

SPI.transfer(0x00) // write mode?
SPI.transfer(0x01) // register 1?
// data structure?

//SPI.transfer(); // transfer data
digitalWrite(cs, LOW); // cs pin LOW
SPI.endTransaction(); // end spi interface

now even if that works i still don't understand how i would convert / send the register data.

I have been able to understand all the different bits of data in each register and know the ones i need to change. I've put comment next to them at the top of my original code, so tah ti remember which ones I want to access.

thanks for the help so far.

SPI.transfer(0x00) // write mode?
SPI.transfer(0x01) // register 1?

No. You need to read the data sheet more carefully.

In the first byte sent, the upper two bits specify the mode and lower six bits to specify the register address.

The second byte sent will be the new register contents (if write mode) or are ignored (if read mode).

Thanks for bearing with me
I think i was misunderstanding conversions of bits / binary / hex.

would this be more correct?

SPI.transfer(0b00000001) // write mode -- select register 1? || is this right?
SPI.transfer(0b00100011) // default data for register 1

now those I believe would be binary numbers, now they are written from the MSB to LSB do i need to reverse them? I'm wondering if the SPI library will reverse those numbers for the setting of MSB in which case it wouldn't work as I'd be sending the wrong data.

eg: MSB 00100011 LSB or LSB 11000100 MSB
is the spi library going to flip the binary number?

now they are written from the MSB to LSB do i need to reverse them?

No.

is the spi library going to flip the binary number?

No.

This is correct.

SPI.transfer(0b00000001) // write mode -- select register 1? || is this right?
SPI.transfer(0b00100011) // default data for register 1

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.