Writing an 8 bit Configuration Register to an Analog IC using Serial interface?

Hello People,

I am new to Arduino. I have an analog front end transceiver (EM4097) whose operation is controlled by an 8 bit configuration register that needs to be written via serial interface. I have the bit setting data available( Highs, Lows) but I am not quite sure of how to implement the same using an ATMEGA328P-PU (Arduino UNO). The serial interface is controlled by the CLK. Between clock cycles 2 and 9, the device(EM4097) receives an 8 bit configuration register. In response to this, the MCU, receives diagnostic output information between clock cycles 10 and 12.

Any suggestions on how to do this would help

Best,

AA

Hi,

lrdazmmlk: I have an analog front end transceiver (EM4097)

What is one of those ?

Can you provide a datasheet ?

Have you any code that you are trying to get working ?

Yours, TonyWilk

Hi Tony,
Yes I can provide the datasheet. The code is very dumb as of now; But I will post anyway.

//To initialize EM4097 analog front end IC.
//the code can also generate 125kHz clock from pint 9.
//sends the command status 8-bit register with respect to 125kHz clock signal.
//timer setup for timer0, timer1, and timer2.
//For arduino uno or any board with ATMEL 328/168.. diecimila, duemilanove, lilypad, nano, mini...
//this code will enable all three arduino timer interrupts.
//timer0 will interrupt at 2kHz
//timer1 will interrupt at 1Hz
//timer2 will interrupt at 8kHz

#include "TimerOne.h"

//F_CPU == 16000000;
//storage variables
boolean toggle0 = 0;
boolean toggle1 = 0;
boolean toggle2 = 0;
const int bit_value = 3;
const int Diag_data = 4;
int n=1;
int inout

#define SREG_IBIT 0b10000000

 //8 bit STATUS_REGISTER
char s[6], f[8] = { 'S', 'P', 'D', 'C', 'A', 'G', 'G', 'T' };
 
void PrintSreg(uint8_t sreg) {
  for (uint8_t i=0; i<8; i++) {
    sprintf(s, " %c: %d", f[i], (sreg & (1 << i) ? 1 : 0));
    Serial.print(s);
  }
  Serial.println();
}
 
void setup() {
  Serial.begin(9600);
   
  //Sample Point
  asm (
    "out __SREG__, %0 \n"
    "sec              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Power Down
  asm (
    "out __SREG__, %0 \n"
    "sez              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Data Direction
  asm (
    "out __SREG__, %0 \n"
    "sen              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Clock Source
  asm (
    "out __SREG__, %0 \n"
    "sev              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Analog Source
  asm (
    "out __SREG__, %0 \n"
    "ses              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Gain Setting
  asm (
    "out __SREG__, %0 \n"
    "seh              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Gain Setting
  asm (
    "out __SREG__, %0 \n"
    "set              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  //Test Mode
  asm (
    "out __SREG__, %0 \n"
    "set              \n"
    : : "r" (SREG_IBIT) 
  );
  PrintSreg(SREG);
  
  //set pins as outputs
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(bit_value, OUTPUT);//timer 1Hz// sending the command status register
  Serial.begin(9600);
  //pinMode(3, OUTPUT); 
  pinMode(4, INPUT); //read the output data after the command register is sent
  //pinMode(data, INPUT);
  DDRB=(0<<PB0); // DDRB-direction register-R/W for port B and PB0 is digital pin 8(Maybe as input, for now!)
   
   //Timer1 functions from timerone library.(required for operation) to generate carrier wave. 
   
   Timer1.initialize(8); //Timer1 period of 8us, break analogWrite() for digital pins 9&10 on Arduino 
   Timer1.pwm(9, 512); //generate PWM waveform (on Pin 9 and 50% duty cycle ), output pins for Timer1 are PB pins 1&2
/****cli();//stop interrupts
//set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR2A register to 0
  TCCR0B = 0;// same for TCCR2B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);
//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
//set timer2 interrupt at 8kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
}//end setup
ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle0){
    digitalWrite(8,HIGH);
    toggle0 = 0;
  }
  else{
    digitalWrite(8,LOW);
    toggle0 = 1;
  }
}
ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(13,LOW);
    toggle1 = 1;
  }
}
  
ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9
//generates pulse wave of frequency 8kHz/2 = 4kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle2){
    digitalWrite(9,HIGH);
    toggle2 = 0;
  }
  else{
    digitalWrite(9,LOW);
    toggle2 = 1;
  }
}
***/
}
void loop()
{
  
  if (n=1)
  {

   //SYNCHRONIZATION BITS// _ input_ has to sync after the second clock pulse
  digitalWrite(bit_value, LOW);
  delayMicroseconds(7);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);  
  digitalWrite(bit_value, LOW); //bit#1 for serial interface to EM4097 //AM demodulation
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, HIGH); //bit#2 //Active
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, HIGH); //bit#3 //data direction #3-low=data as output, #3-high=clock as output
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, HIGH); //bit#4 //Internal PLL for #4-0 and external clock for #4-1
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, HIGH); //bit#5 //fast start-up
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, LOW); //bit#6 //default value for gain of 480 @ 00 for #bit6&7
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, LOW); //bit#7
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  digitalWrite(bit_value, LOW); //bit#8 //normal mode
  delayMicroseconds(8);
  input_data = digitalRead(bit_value);
  Serial.println(input_data);
  }
  n++;
  int data = digitalRead(Diag_data);
  Serial.println(data); //print the diagnotic output from clock 10 to 12 cycles
  delayMicroseconds(8);
  data = digitalRead(Diag_data);
  Serial.println(data);
  delayMicroseconds(8);
  data = digitalRead(Diag_data);
  Serial.println(data); //followed by data wrt to bit#3&4 configuration
  delayMicroseconds(8);
  data = digitalRead(Diag_data);
  Serial.println(data);
  
  
}

int SHD=4;
int n=2;
void setup() {
  Serial.begin(9600);
  pinMode(SHD, OUTPUT);
}
void loop() {
  SHD=1;
  delay(500);
  SHD=0;
  while(n=2)
  {
  int value = analogRead(A2);
  float voltage = value * (5.0 / 1023.0);
  Serial.println(voltage);
  delay(250);
  }
}

4097-ds.pdf (714 KB)

The serial interface to that EM4097 is a bit strange.

As you said, it needs an odd starting clock bit, then another 8 clocks to shift in data.
then it appears you can continue to clock and read bits out of the device

So, it is clear that the usual Arduino shiftOut() function is of no use to us here and we will have to toggle pins to get the job done - which it looks like you are attempting the main loop()

To tidy things up you could write something like this…

#define EM_IN   ?    // define here the pin which you connect to the EM4097 'IN' pin
#define EM_OUT  ?    // define here the pin which you connect to the EM4097 'OUT' pin
#define EM_CLK  ?    // define here the pin you connect to the EM4097 'CLK' pin

// Initialise serial pins for the EM4097 interface
//
void EM_setup()
{
  pinMode( EM_IN, OUTPUT );
  digitalWrite( EM_IN, LOW );
  pinMode( EM_OUT, INPUT_PULLUP );
  pinMode( EM_CLK, OUTPUT );
  digitalWrite( EM_CLK, LOW );
}

// Do a clock reset on the EM4097
//
void EM_reset()
{
  EM_setup();
  delayMicroseconds(10);
  digitalWrite( EM_CLK, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( EM_IN, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( EM_CLK, LOW );
  delayMicroseconds( 10 );
  digitalWrite( EM_IN, LOW );
}

// Write one bit to the EM4097
// 
void EM_writeBit( uint8_t bit0 )
{
  digitalWrite( EM_IN, bit0 & 1 );
  delayMicroseconds( 1 );
  digitalWrite( EM_CLK, HIGH );
  delayMicroseconds( 1 );
  digitalWrite( EM_CLK, LOW );
  delayMicroseconds( 1 );
}

// Write config register
// passed: 8-bit config value (bit0 == config Bit#1, bit7= config Bit #8)
//
void EM_writeConfig( uint8_t config )
{
  EM_writeBit( 0 );     // initial clk pulse

  for( int i=0; i < 8; i++ )
  {
    EM_writeBit( config );   // write out each bit
    config= config >> 1;   // and shift down the bits
  }
}

void loop()
{
   // in here you can now:
   uint8_t config= VALUE_FOR_THE_CONFIG REGISTER;
   EM_reset();
   EM_writeConfig( config );
}

Yours,
TonyWilk

Hello Tony,
Thank you for the quick input. The datasheet says the same. I have used a previous version of the IC under the name EM4095 which requires configuration bitwise; here an entire register needs to be sent to the IC.

I have made some remarks/doubts in the code below

#define EM_IN   ?    // define here the pin which you connect to the EM4097 'IN' pin
#define EM_OUT  ?    // define here the pin which you connect to the EM4097 'OUT' pin
#define EM_CLK  ?    // define here the pin you connect to the EM4097 'CLK' pin

// Initialise serial pins for the EM4097 interface
//
void EM_setup()
{
  pinMode( EM_IN, OUTPUT );
  digitalWrite( EM_IN, LOW );
  pinMode( EM_OUT, INPUT_PULLUP );// [color=red]why did you assign the pin with input_pullup?[/color] 
  pinMode( EM_CLK, OUTPUT );
  digitalWrite( EM_CLK, LOW );
}

// Do a clock reset on the EM4097
//
void EM_reset()
{
  EM_setup();
  delayMicroseconds(10);
  digitalWrite( EM_CLK, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( EM_IN, HIGH );
  delayMicroseconds( 10 );
  digitalWrite( EM_CLK, LOW );
  delayMicroseconds( 10 );
  digitalWrite( EM_IN, LOW );
}

// Write one bit to the EM4097 [color=red]Is this for synchronization?[/color]
// 
void EM_writeBit( uint8_t bit0 )
{
  digitalWrite( EM_IN, bit0 & 1 );
  delayMicroseconds( 1 );
  digitalWrite( EM_CLK, HIGH );
  delayMicroseconds( 1 );
  digitalWrite( EM_CLK, LOW );
  delayMicroseconds( 1 );
}

// Write config register
// passed: 8-bit config value (bit0 == config Bit#1, bit7= config Bit #8)
//
void EM_writeConfig( uint8_t config )
{
  EM_writeBit( 0 );     // initial clk pulse [color=red]The register is sent between the 2nd and 9th clock cycles, Shouldn't the loop start at 2?[/color]

  for( int i=0; i < 8; i++ )
  {
    EM_writeBit( config );   // write out each bit
    config= config >> 1;   // and shift down the bits
  }
}

void loop()
{
   // in here you can now:
   uint8_t config= VALUE_FOR_THE_CONFIG REGISTER;[color=red]Is this the bit value or register value?[/color]
   EM_reset();
   EM_writeConfig( config );
}

Regards,
AA

INPUT_PULLUP… don’t know what the EM4097 output is like, doesn’t hurt.

Write one bit… that function is intended to just write one bit, sets the data, wiggles the clk line

The register is sent between the 2nd and 9th clock cycles, Shouldn’t the loop start at 2?
The datasheet numbers the CLK pulses starting at 1.
The first CLK is supposed to set it into command state.
Then there are 8 data bits (the datasheet numbers them 2 to 9)

the for loop counts 0 to 7 and outputs 8 bits.
If you wanted, you could write that as: for( int i=2; i <=9; i++ ) and it will do exactly the same thing.

Is this the bit value or register value?
It should be the value you want to put in the config register

Yours,
TonyWilk

Thanks for the clarification Tony. I will try this out and let you know what the result is. Thanks again.

Hi Tony,

I have been working to on this lately. However, the clock and data signals are not in sync. The delay in the code is 10 ms but on checking with an oscilloscope it is 14 ms. Coming to the diagnostic output - it repeats itself after two attempts of synchronization; i.e., the diagnostic information is available in the third attempt to synchronization and repeats itself again after two attempts and so on. Would you know why this is happening?

I have attached a shot of the oscilloscope output. You will see in that the data bit starts at the falling edge of clock cycle 2 instead of rising edge.

Best,

AA

image1 (2).png

Hi,

lrdazmmlk: I have been working to on this lately. However, the clock and data signals are not in sync. The delay in the code is 10 ms but on checking with an oscilloscope it is 14 ms.

Clock will happen in the middle of data since the code does: output data, clk high, clk low, ... that is not a problem. Timing... I think you mean 10 uS - the real delay will be a few microseconds longer since it takes time to execute the other instructions.

From that oscilloscope picture it looks like there are only 8 clock pulses after the 'clock reset' sequence - I thought it was supposed to 9 clock pulses, where has the other one gone ?

I don't know what you are trying to do in your software now, so I don't understand your other questions.

Yours, TonyWilk

Hi Tony, So does that mean, the data and clock being out of sync does not matter? [citing your mention of delay of the order of few micrcoseconds] I am actually checking that now. The duty cycles are actually uneven if you noticed. Plus, the clk is supposed to be at a frequency of 125 kHz; which in this case is not.

All I am trying to do is to write an 8 bit register and later set the IC such it can demodulate an incoming AM signal using envelope detection.

Best, AA

lrdazmmlk:
Hi Tony,
So does that mean, the data and clock being out of sync does not matter? [citing your mention of delay of the order of few micrcoseconds]

The only thing that matters is that data is shifted on the rising edge of CLK, to shift data into the device the data pin has to be written first and be stable, then CLK is taken high. What happens after that does not really matter until the next bit. Read the Serial Interface section in the datasheet and see Fig.7 (both on page 6)

Yours,
TonyWilk

Hi Tony,

I was able to get the ninth clock pulse; made a change in the if condition. Yes, but as you can see, the data is being shifted at the falling clock edge and not rising clock edge.

Best,
AA

IMG_3988.png

lrdazmmlk:
but as you can see, the data is being shifted at the falling clock edge and not rising clock edge.

No it is not.
ScopePic.png
The data is shifted IN TO the device ON the rising edge of CLK... at the instants in time I've marked with the vertical red lines. The data from the Arduino has to change -between- the rising edges.

I've also marked (as per the diagram on page 6) the bit numbers which should correspond with the Configuration Register Definitions on page 7.

Yours,
TonyWilk

ScopePic.png

Hi Tony,

Oh yes! I missed that "shift' in bit values in the register on rising edge of clock. Makes sense now.

Thanks for the clarification Tony.

Best,

AA

Hi Tony,
I have been trying to leave the test mode of the IC. In the datasheet, it is mentioned that after the 13th clock, the IC is supposed to leave the test mode. But I get repetitions of it; the output is repeating itsef; PLL unlocked.

AA

repeatout.png

Hi,

lrdazmmlk: According to the datasheet, the 8 bit information is loaded into the resigter on the falling edge of clock pulse 9;

As far as I can see the description of changing state on the falling edge of the 9th clock is what you can see on the last 'scope picture... the green data line dips slightly after the falling edge of that last CLK pulse.

Really, I can't do any more here - I don't have a device to work on and it looks like the code you are now using does clock the device correctly. You'll just have to keep reading the datasheet and trying stuff to get it to work.

Yours, TonyWilk

Hi Tony,

That was an error on my side. I forgot the LSB bit 0, that starts at rising edge of clk2. Thanks again. It's the repetition that's the concern. A 125 kHz carrier signal should be seen at pin2 of the IC, but as of now I am only getting noise. As far as the test mode is concerned, I am not sure how to leave that.

I will look into. Thanks for your time.

Best, AA