Go Down

Topic: What PWM mode to select and how? (Read 2164 times) previous topic - next topic

6v6gt

No problem. Here it is:



Your hand drawn picture is certainly more of a conventional representation of a signal encoding than that in post #4.
So a 0 is represented by a phase transition within the bit frame and a 1 by no transition. Is that correct ?
The modulated signal frequency is 1/0.23845 kHz (4.19375 kHz) if the old diagram is correct.


lrdazmmlk

Yes it is. I was able to generate a 125 kHz signal using a reference from the forum itself. What should I do for the clock and be able to read the data in (I m guessing this has to do with PWM)? I assume what I generated now is a 125kHz clock signal :smiley-eek-blue: ?

Below is the code:

Code: [Select]
//#include <avr/io.h>
//#include <util/delay.h>
//#include "delay_x.h"
#define F_CPU 16000000
#define CLK 12

const int ocr1aPin = 9;

// Set the frequency that we will get on pin OCR1A
void setFrequency(uint32_t freq)
{
  uint32_t requiredDivisor = (F_CPU/2)/(uint32_t)freq;
  uint16_t prescalerVal;
  uint8_t prescalerBits;
  if (requiredDivisor < 65536UL)
  {
    prescalerVal = 1;
    prescalerBits = 1;
  }
  else if (requiredDivisor < 8 * 65536UL)
  {
    prescalerVal = 8;
    prescalerBits = 2;
  }
  else if (requiredDivisor < 64 * 65536UL)
  {
    prescalerVal = 64;
    prescalerBits = 3;
  }
  else if (requiredDivisor < 256 * 65536UL)
  {
    prescalerVal = 256;
    prescalerBits = 4;
  }
  else
  {
    prescalerVal = 1024;
    prescalerBits = 5;
  }

  uint16_t top = ((requiredDivisor + (prescalerVal/2))/prescalerVal) - 1;
  TCCR1A = 0;
  TCCR1B = (1 << WGM12) | prescalerBits;
  TCCR1C = 0;
  OCR1A = (top & 0xFF);
}

// Turn the frequency on
void on()
{
  TCNT1H = 0;
  TCNT1L = 0; 
  TCCR1A |= (1 << COM1A0);
}

// Turn the frequency off and turn of the IR LED
void off()
{
  TCCR1A &= ~(1 << COM1A0);
}

void setup()
{
  digitalWrite(ocr1aPin, LOW);
  pinMode(ocr1aPin, OUTPUT);
 
}

void clk_setup(){
 
  pinMode(CLK, OUTPUT);
  digitalWrite(CLK, LOW);
}

void clk_reset(){
  clk_setup();
  delayMicroseconds(7812500000);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(7812500000);
  digitalWrite(CLK, LOW);
  /*delayMicroseconds(7812500000);
  digitalWrite(CLK, HIGH);
  delayMicroseconds(7812500000);
  digitalWrite(CLK, LOW);*/
 
  }
 
void loop(){

  setFrequency(125000);
  on();
  delay(8);
  off();
 
  }

/*void floatDelay(float ms)
{
  unsigned long whole = ms;
  int part = (ms - t) * 1000;
  delay(whole);
  if (part > 4) delayMicroseconds(part);
}*/

6v6gt

My expertise is signal processing is limited. Where I had to process a specific AFSK signal, I found an algorithm written by an expert which was already adapted to 8 bit AVR architecture.
In general, what I can say is this that you can configure a timer to trigger the ADC at intervals to sample the carrier. Since you are already at a frequency of 125 kHz that is quite high. You may require multiple samples within the carrier period. In this specific case, you are (somehow) going to have to detect a phase shift. From what I understand from your description of the signal, you'd be able synchronise your clock from the transition points in the 0 bits.

lrdazmmlk

#18
Mar 07, 2018, 09:30 pm Last Edit: Mar 08, 2018, 08:00 pm by lrdazmmlk
I will try again. I am new to AVR, but it's fun to learn although a struggle. Plus, when you are a beginner and ask stupid questions it is both embarassing and you are shamed. But anyhow, how do you synchronize the clock?

From what I know, I think I have to first generate a 500kHz clock signal with the 16MHz and use that very clock signal to generate the 125kHz carrier? :smiley-confuse:

6v6gt

The clock synchronisation may be necessary if the frequency of the clock used to generate the signal may differ slightly from the clock you are using to analyse the signal. The window which you are using to view a bit might slip. Depending on the encoding scheme, this could be a problem especially if the same bit is repeated multiple times during which no transition occurs. Once a transition does occur, you can correct the slippage. Some encoding schemes force a transition every bit so then this is not a problem.

For analysing RFID related signalling, there is this tool if you haven't already seen it (RFIDler). It appears to do most of what you require.
All the code is there together with a comprehensive description. The design is for the Pic32 architecture, but I guess you can reverse engineer it for an Arduino variant although maybe not an AVR 8 bit one.


RFIDler Powerpoint:


github:
https://github.com/ApertureLabsLtd/RFIDler

source:

That is about the limit of what I can do here, but I'll be curious to see how you get on with it.




Smajdalf

Here is a guide how to include images: http://forum.arduino.cc/index.php?topic=519037.0

I am still confused. You say you are trying to decode data from DataIn signal but it seems you are trying to generate the CLK signal. Both makes sense because the chip you use has option to use external clock input instead of internal PLL and you claim the PLL is not working for some reason.

To decode the signal you cannot use the Timer alone, it needs a lot of help from software. To do so you will use the Timer "only" as a time reference but rest must be done in SW. There are more possibilities how to read the signal.
1) Use a Timer to generate an interrupt in regular intervals. In ISR you read the DataIn signal, store the value and when you get a sample long enough you analyze it somehow. I think it is poor method but if the signal is noisy you may implement some noise filtering this way easily.
2) Use a Pin Change interrupt on DataIn pin. When interrupt triggers read value in TCNTn and store it. By subtracting TCNTn value saved in last interrupt you can say how long it took for the signal to change level - if it was long time decoded value is 1, otherwise it is 0.
3) Use Input Capture feature of Timer1. It works as 2) but you read ICR1 instead of TNCT1. Advantage is you avoid jitter from interrupt latency but not all AVRs have timer with this feature.

Since I believe method 3) is superior I will show you how I would do it. You must use Timer1 for it and apply DataIn on ICP1 pin (PB0 of ATMega328, Digital 8 of Arduino Uno). You want to measure time between two edges of the DataIn signal, the time should be between 16 or 32 CLK pulses. If CLK is about 125kHz it means one CLK pulse is about 16MHz/125kHz=128 Arduino clock cycles. You have two options
a) Clock the Timer1 from main clock prescaled down to some reasonable value, prescaler 256 (CS=4) is a good choice, Timer1 frequency will be 16MHz/256=62.5 kHz (about half of frequency of CLK). One edge to edge interval will be about 8 or 16 Timer1 ticks.
b) Clock the Timer1 from CLK (CLK = 6 or 7, I don't think it does matter). In this case Timer1 frequency will be exactly CLK frequency and one edge to edge interval should take 16 or 32 Timer1 ticks. Downside is you need use pin T1 (PD5, Digital 5) as clock input for Timer1.
I think a) is better in many ways. In either case time between two events should be < 50 Timer1 ticks. Because of this it is better to use Timer1 as 8 bit timer - reducing associated values to single byte will make calculations faster. Fast PWM 8-bit mode (WGM1=5) can be used for this.
I think you need detect both rising and falling edge of DataIn. So you will enable Timer1 Capture Event interrupt and in the ISR you toggle Input Capture Edge Select bit. The code for this could be
Code: [Select]

ISR(TIMER1_CAPT_VECT) {
  TCCR1B^=1<<ICES1;
  static byte lastEdge;
  byte thisEdge=ICR1;
  byte difference=lastEdge - thisEdge;
  if (difference < someBoundary) TODO
  else TODO
  lastEdge=thisEdge;
}

setup () {
  TCCR1A=1<<WGM10;
  TCCR1B=(1<<ICNC1)|(1<<WGM12)|(1<<CS12);
  TIMSK1=1<<ICIE1;
}

lrdazmmlk

Thank you so much for the clarification. I will definitely try them out and keep you posted of the progress.

lrdazmmlk

Hey Smajdalf,
I was revisiting this post. What's the boundary condition in the ISR?

Also the lastEdge, thisEdge - what are these values? Timer count values?

Best,
A

lrdazmmlk

Hey Smajdalf,

I am reaching out to see if you could help me out. Should I define the ICR1 as top in setup?

Smajdalf

I don't remember what was going on in this topic but after a quick refresh:
thisEdge and lastEdge are "remembered" values of Timer1 at the time of captured edge.
lastEdge - thisEdge is time (in Timer1 ticks) of duration of the pulse. Depending on the time you want to do some action - it is up to you to decide what the action should be and what is the boundary.
TOP of the timer must NOT be ICR1. The TOP should be a fixed value: 0xff if using the timer only in 8 bit mode (to make the calculations faster). Maybe using it in 16 bit mode with 0xffff to would be better (less chance for some strange overflow bug). In this case thisEdge, lastEdge and all related variables should be unsigned int instead of byte.

Go Up