Author Topic: Timing Help  (Read 9516 times)

Ringo42

  • Newbie
  • *
  • Posts: 11
Timing Help
« on: January 08, 2016, 11:21:15 am »
what speed is the digispark running at?
I'm trying to toggle an LED that is modulated at 38khz using the code from
http://forum.arduino.cc/index.php?topic=139729.0

but I get nothing out on pin b1.
ANy thoughts?

Ringo42

  • Newbie
  • *
  • Posts: 11
Re: Timing Help
« Reply #1 on: January 08, 2016, 12:28:11 pm »
thanks, I will be running this off of 5V not connected to USB, does that make F_CPU 8mhz or 16?. Can you help me get the attached code working? I'm not up to speed on how to set the divisors and get this pin going at 38khz.
I tried using Tone(1,38000), but looking at the output on an Oscope it is not very clean. sometimes the pin starts up at 38khz nicely, but other times it goes high, stays there for a few cycles before oscillating.
The original code uses the setFrequency function and the commented lines in IR_pulse_on and off.
Any help will be greatly appreciated.
« Last Edit: January 08, 2016, 12:47:06 pm by Ringo42 »

Ringo42

  • Newbie
  • *
  • Posts: 11
Re: Timing Help
« Reply #2 on: January 08, 2016, 12:48:03 pm »
oops, here is the code

Ringo42

  • Newbie
  • *
  • Posts: 11
Re: Timing Help
« Reply #3 on: January 08, 2016, 01:11:35 pm »
Its the setting of the timer registers that is killing me. I don't understand what is going on there.
When I run setFrequency it seems like everything locks up. I put a simple led toggle in loop and it doesnt work, nothing flashes. But comment out setFrequency and it does.
I tried using the IR libs and they don't compile so I figured I might as well stay with what I have.
Thanks

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #4 on: January 09, 2016, 01:46:54 am »
if you want to turn led on, use digitalWrite(1, HIGH);

Pin numbers are 0 to 6. No letters. Do not use AVR port names, unless you are using inline assembly language, or avr studio. This is Arduino IDE...

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #5 on: January 09, 2016, 03:38:01 am »
Yes, timing is a mess and libraries fill memory up.
This is how I send IR, 4 bits, IR LED positive on pin 0, negative on pin 1, no resistors, works up to about one meter distance with le LED I had at home.

const byte irPin = 0; //IR LED connected to digital 0
const byte irground = 1;
const int freq = 38000;
const byte BIT_PER_BLOCK = 4; // my protocol uses 4 bits, 1 nibble.
const int start_bit = 2510; //start bit threshold (microseconds)
const int zero = 2990;
const int uno = 3900;
const int space = 1400;
byte result = 0;
 
void setup() {
  pinMode(irPin, OUTPUT);
  pinMode(1, OUTPUT); //(pin 1 to ground)
}

void ir_bitbang (byte pin, byte ground, int hz, int tempus)
{
  digitalWrite(ground,LOW); // (enables IR led)
  tone(pin, hz); // start bit
  delayMicroseconds(tempus);
  noTone();
  digitalWrite(ground,HIGH);
  delayMicroseconds(space);
}

void loop()
{
  ir_bitbang (irPin, irground, freq, start_bit);  // start bit
  ir_bitbang (irPin, irground, freq, zero);  // bit3
  ir_bitbang (irPin, irground, freq, uno);   // bit2
  ir_bitbang (irPin, irground, freq, zero);  // bit1
  ir_bitbang (irPin, irground, freq, uno);  // bit0
  delay(1500);
}

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #6 on: January 09, 2016, 03:41:38 am »
This is how I receive, on a second Digispark.

#include "DigiKeyboard.h"

const int irPin = 0; //IR detector connected to digital 0
const byte BIT_PER_BLOCK = 4; //my protocol uses 4 bits, 1 nibble
const int start_bit = 3100; //start bit threshold (microseconds)
const int threshold = 4000;
byte result = 0;
 
void setup() {
  pinMode(irPin, INPUT);
  digitalWrite(irPin,HIGH); // pull-up resistor
}
void loop() {
  int data[BIT_PER_BLOCK];
  int i;
  DigiKeyboard.sendKeyStroke(0);   
 
  while(pulseIn(irPin, LOW) < start_bit); //wait for a start bit
 
  for(i = 0 ; i < BIT_PER_BLOCK ; i++) {
    //Start measuring bits, I only want low pulses
    //you may want to use high pulse --> pulseIn(irPin, HIGH)
    data = pulseIn(irPin, LOW);   
  }
 
  for(i = 0 ; i < BIT_PER_BLOCK ; i++)
  {
    if ((data) < threshold) {bitWrite(result, (BIT_PER_BLOCK-i), 0);}
    if ((data) > threshold) {bitWrite(result, (BIT_PER_BLOCK-i), 1);}
  } 
  DigiKeyboard.print(result, DEC);
  DigiKeyboard.print(" - ");
  DigiKeyboard.println(result, BIN);
  result = 0;
}

probono

  • Newbie
  • *
  • Posts: 17
Re: Timing Help
« Reply #7 on: January 10, 2016, 10:43:10 am »
Pinus, very interesting. When trying to compile your receive code, I get:

Code: [Select]
In function 'void loop()':
sketch_jan10a:31: error: incompatible types in assignment of 'long unsigned int' to 'int [4]'
     data = pulseIn(irPin, LOW);   
          ^
sketch_jan10a:36: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
     if ((data) < threshold) {bitWrite(result, (BIT_PER_BLOCK-i), 0);}
                  ^
sketch_jan10a:37: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
     if ((data) > threshold) {bitWrite(result, (BIT_PER_BLOCK-i), 1);}
                  ^
exit status 1
incompatible types in assignment of 'long unsigned int' to 'int [4]'

I am using Arduino 1.6.7 with the latest board definitions from https://raw.githubusercontent.com/digistump/arduino-boards-index/master/package_digistump_index.json and a Digispark (Default).

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #8 on: January 11, 2016, 05:51:34 am »
Strange, I do not get such errors and mine actually works, although it wastes memory, since that "data" vector was meant for protocols with higher amount of bytes.

I have modified the receiving part using only one byte, no vectors. It compiles OK on the original Digistump IDE. I haven't tested it with IR, though, since I am currently using the Digispark to control a switching power supply's frequency and duty cycle for another project I am working on.

Code: [Select]
#include "DigiKeyboard.h"

const int irPin = 0; //IR detector connected to digital 0
const byte BIT_PER_BLOCK = 4; // my protocol uses 4 bits, 1 nibble
const int start_bit = 3100; //start bit threshold (microseconds)
const int threshold = 4000;
 
void setup() {
  pinMode(irPin, INPUT);
  digitalWrite(irPin,HIGH); // pull-up resistor
}
void loop()
{
  byte data=0;
  byte i;
  DigiKeyboard.sendKeyStroke(0);   
 
  while(pulseIn(irPin, LOW) < start_bit); //wait for a start bit
 
  for(i = 0 ; i < BIT_PER_BLOCK ; i++)
  {
    //Start measuring bits, I only want low pulses
    //you may want to use high pulse --> pulseIn(irPin, HIGH)
    if (pulseIn(irPin, LOW) < threshold) {bitWrite(data, (BIT_PER_BLOCK-i), 0);}
    if (pulseIn(irPin, LOW) > threshold) {bitWrite(data, (BIT_PER_BLOCK-i), 1);}   
  }
 
  DigiKeyboard.print(data, DEC);
  DigiKeyboard.print(" - ");
  DigiKeyboard.println(data, BIN);
}


Ringo42

  • Newbie
  • *
  • Posts: 11
Re: Timing Help
« Reply #9 on: January 11, 2016, 10:51:19 am »
Here is what I have found.
When I go through and set up timer1, the timer gets set up correctly, however then loop() never runs.
I'm getting my 38khz out of pin1, but then it just seems to be locked up.
This happens with the original code I found online, and with the code below where I just went through the datasheet and set everything accordingly. I must be missing something.
Note the simple loop() is just for testing, the real one is below it. neither works.
I have another version where I use timer0 instead of 1 and it works fine, but I want to use timer1 to keep with the original code.
any thoughts on what would cause this?

Code: [Select]
/**
 * EasyRaceLapTimer - Copyright 2015-2016 by airbirds.de, a project of polyvision UG (haftungsbeschränkt)
 *
 * Author: Alexander B. Bierbrauer
 *
 * This file is part of EasyRaceLapTimer.
 *
 * Vresion: 0.2
 *
 * EasyRaceLapTimer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * EasyRaceLapTimer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with Foobar. If not, see http://www.gnu.org/licenses/.
 **/
// use 8MHZ internal clock of the Attiny
// Timer code from http://forum.arduino.cc/index.php?topic=139729.0


#define BIT_SET(a,b) ((a) |= (1<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
#define BIT_CHECK(a,b) ((a) & (1<<(b)))

// CHANGE HERE THE ID OF TRANSPONDER
// possible values are 1 to 63
#define TRANSPONDER_ID 42




#define NUM_BITS  9
#define ZERO 250
#define ONE  650

unsigned int buffer[NUM_BITS];
unsigned int num_one_pulses = 0;

unsigned int get_pulse_width_for_buffer(int bit){
  if(BIT_CHECK(TRANSPONDER_ID,bit)){
    num_one_pulses += 1;
    return ONE;
  }

  return ZERO;
}

unsigned int control_bit(){
  if(num_one_pulses % 2 >= 1){
    return ONE; 
  }else{
    return ZERO;
  }
}

void setup()
{
  PORTB = 0;
  DDRB =  0b00000010;    // set PB1 (= OCR1A) to be an output
digitalWrite(1, LOW);
  setFrequency(38000); // 38 kHz

  buffer[0] = ZERO;   
  buffer[1] = ZERO;   
  buffer[2] = get_pulse_width_for_buffer(5);
  buffer[3] = get_pulse_width_for_buffer(4);
  buffer[4] = get_pulse_width_for_buffer(3);
  buffer[5] = get_pulse_width_for_buffer(2);
  buffer[6] = get_pulse_width_for_buffer(1);
  buffer[7] = get_pulse_width_for_buffer(0);
  buffer[8] = control_bit();
  setFrequency(38000); // 38 kHz
}

// Set the frequency that we will get on pin OCR1A but don't turn it on
void setFrequency(uint16_t freq)
{
  TCNT1=0;
  TCCR1=0;
  TCCR1 |=(1<<COM1A0); //Timer1 in toggle mode Table 12-4
  TCCR1 |=(1<<CTC1);//cler timer on match
  TCCR1 |=(1<<CS10);//divide by 1
  GTCCR = 0;
  GTCCR |=(1<<COM1B0);
  OCR1C=107;
  TIMSK |=(1<<OCIE1A);
  digitalWrite(1, HIGH);// just to see if it turns on
}

// Turn the frequency on
void ir_pulse_on()
{
 TCNT1 = 0;
 //TCCR1 |= (1 << COM1A0);
 TCCR1 |= (1 << CS10);
 //TIMSK |=(1<<OCIE1A);
}

// Turn the frequency off and turn off the IR LED.
// We let the counter continue running, we just turn off the OCR1A pin.
void ir_pulse_off()
{
// TCCR1 &= ~(1 << COM1A0);
 //TCCR1 &= (0<< CS10);
// TCCR1 &= ~(1<< CS10);
 TCCR1=0;
// TIMSK &= ~(1<<OCIE1A);
}

void loop() // just to see if it is running, real code is below
{
//ir_pulse_on();
 digitalWrite(1, HIGH);
  delay(1000);               // wait for a second
//ir_pulse_off();
 digitalWrite(1, LOW);
  delay(1000);               // wait for a second
}


/*
void loop(){
  for(int i = 0; i < 3; i++){
    for(int b = 0; b < NUM_BITS; b++){
      switch(b){
        case 0:
          ir_pulse_on();
          delayMicroseconds(buffer[b]);
          break;
        case 1:
          ir_pulse_off();
          delayMicroseconds(buffer[b]);
          break;
        case 2:
          ir_pulse_on();
          delayMicroseconds(buffer[b]);
          break;
        case 3:
          ir_pulse_off();
          delayMicroseconds(buffer[b]);
          break;
        case 4:
          ir_pulse_on();
          delayMicroseconds(buffer[b]);
          break;
        case 5:
          ir_pulse_off();
          delayMicroseconds(buffer[b]);
          break;
        case 6:
          ir_pulse_on();
          delayMicroseconds(buffer[b]);
          break;
        case 7:
          ir_pulse_off();
          delayMicroseconds(buffer[b]);
          break;
        case 8:
          ir_pulse_on();
          delayMicroseconds(buffer[b]);
          break;
      }
      ir_pulse_off();
    } // going through the buffer
   
    delay(20 + random(0, 5));
  } // 3 times
} // end of main loop

*/

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #10 on: January 11, 2016, 01:28:26 pm »
Ringo, why use timers, when you can use tone()?

Your code says it is for internal 8MHz clock, when ours is 16.5.

And then you do not disable interrupts and when you change timers, as soon as an interrupt happens (I assume there are system interrupts happening in background when we use Arduino), it is going to crash because you have interfered with system timers.

A finite state machine is not really complex.

Ringo42

  • Newbie
  • *
  • Posts: 11
Re: Timing Help
« Reply #11 on: January 11, 2016, 01:33:47 pm »
I tried tone, but turning tone on and off makes for some weird waveforms. Sometimes instead of the waveform starting up correctly, it goes high for a few cycles before oscillating. Maybe not a big deal for tones, but for sending data that makes it weird. Also, I'm telling arduino that it is the 8mhz board, that part is ok. I can get this to work with timer0, just not timer1.
I'll try disabling the interrupts, didn't think of that.
Thanks


Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #12 on: January 12, 2016, 04:30:52 am »
I tried tone, but turning tone on and off makes for some weird waveforms. Sometimes instead of the waveform starting up correctly, it goes high for a few cycles before oscillating. Maybe not a big deal for tones, but for sending data that makes it weird. Also, I'm telling arduino that it is the 8mhz board, that part is ok. I can get this to work with timer0, just not timer1.
I'll try disabling the interrupts, didn't think of that.
Thanks

I am writing this for everyone to better understand, even for future reference, not just for you, whom might, or might not need this explanation.

What people did before you and me, was to assume you can't have noise free and flat power/efficiency communications.
So they have implemented a system based on pulses length.

Zeroes last a certain amount of pulses.
Ones last a different amount of pulses.
The difference in duration between zero and one needs to be high enough to always be sure to be able to discern between the two.
Between each zero and one there is a delay to let the system get ready for next bit.
Before any packet begins you must have a start bit, or bytes, which is the signature of your protocol. In other words, it says you are receiving your own data, not someone else's.
Optional, a CRC, or parity check bit, at the end. This enables to verify data integrity and sometimes even rebuild your data.
This scheme works with just about anything, from IR, to RF, to laser.

It has been even explained on a site, with Microchip PIC code, by Roman Black.

Sorry for being pedantic, I used to teach and write technical articles, in another life.

Pinus

  • Newbie
  • *
  • Posts: 35
Re: Timing Help
« Reply #13 on: January 29, 2016, 02:15:54 pm »
BTW, I am doing a project at high speed and found out you were right, Arduino functions are just too slow. I have also used direct port read and write. Not only it is easy, it also just takes two cpu cycles, instead of tens of them.