Rouge Bit Manipulated Registers...!!! HELP

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, everyone. I m making an IR transmission project which uses ATTINY84. For coding I m using Visual Code with PlatformIO using Arduino framework (I tried installing Atmel Studio but FAILED). I have successfully coded program to send 6 pulse of IR wave, 20 cycles each, at 38 k HZ frequency. Later in project I needed to use INPUT CAPTURE feature of 16 bit timer1 to time some events. Since I was using same timer1 for IR transmission , I changed code a bit. From directly writing hex values to registers to Bit Twiddling so I don't affect ICNC1 and ICES1 bit(related to INPUT CAPTURE feature) in TCCR1B register. Everything in IR transmission code is same, except I have used Bit Twiddling to manipulate the Registers. However, to my surprise when i hooked a logic analyzer to check the PWM, i was taken aback...!!! Instead of clear 6 signal which i was receiving prior, now turned to total nonsense(Images attached). I rechecked the code but didn't find any discrepancies. I have posted code. Please shower me with your Insights on why out of this whole world, this is happening to me...!!!!

EXTRA INFORMATION:

-chip running at 16MHz

-Input Capture will come from ANALOG COMPARATOR output ACO (haven't coded it yet because first i need to take care of ROUGE IR transmission)

-Replacing lines with ones that follows "//*** " makes code work fine. (WHY BIT TWIDDLING IS ROUGE?)

-Timing in SANE_PWM(WORKING) is perfect.

-I know i can shift IR transmission to other pin , but using PA6 pin is my sole option.

#define F_CPU 16000000UL
#include <avr/io.h>
#include <Arduino.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define ON_Signal  12
#define OFF_Signal 18
#define IR_pin PA6

volatile bool IR_Signal_Sent = false;
uint8_t IR_Counter = 0;

void Timer1_IR(uint8_t IR_Signal_Time);
void Timer1_IR(uint8_t IR_Signal_Time){   
  //INITIALIZING TIMER1  
  OCR1A = 207;   //TOP value for CTC(13 uS)
  TCCR1A = 0x40; //toggling OC1A(PA6) at TOP
  TIMSK1 |= (1<<OCIE1A);  //Output Compare A Interrupt enabled to count 38kHz cycles 
  sei();
    
  //FOR LOOP TO SEND 5 CONSECUTIVE DELAY SIGNAL
  for(uint8_t i=0; i<6; i++){
    //***TCCR1B = 0x09;    //CTC mode, No prescaler @16 MHz(Tick period=0.0625 uS), Start Timer1 
    TCCR1B |= ((1<<CS10)|(1<<WGM12)); //Should have same effect as line above. 
    while(IR_Signal_Sent == false){
      //Wait 20 cycles of signal to be sent
    }
    IR_Signal_Sent = false;

    if(IR_Signal_Time == ON_Signal){
      _delay_ms(ON_Signal);
    }
    else{
      _delay_ms(OFF_Signal);
    }
  }
  
  TIMSK1 &= ~(1<<OCIE1A);
}

ISR(TIM1_COMPA_vect){
  IR_Counter ++;  //Increment Count everytime reaching TOP
  if(IR_Counter >= 20){   //Sending 20 Cycles of IR wave
    //***TCCR1B = 0x00;   //Stop Timer1
    TCCR1B &= ~((1<<CS10)|(1<<WGM12)); //Should have Same effect as line above
    IR_Counter = 0;       //Reset Counter
    TCNT1 = 0;            //Reset Timer1 Counter
    IR_Signal_Sent = true;
  }
}

void setup() {
  DDRA  |=  (1<<IR_pin);   //OC1A as PWM OUTPUT
}

void loop() {
  Timer1_IR(ON_Signal);   //Sending ON Signal
  _delay_ms(500);
  Timer1_IR(OFF_Signal);  //Sending OFF Signal
  _delay_ms(500);
}

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    //***TCCR1B = 0x09;    //CTC mode, No prescaler @16 MHz(Tick period=0.0625 uS), Start Timer1
    TCCR1B |= ((1<<CS10)|(1<<WGM12)); //Should have same effect as line above. 

A few suggestions of things to check. I assume you have already double checked that (1<<CS10)|(1<<WGM12) = 0x09

 

Are all the other bits in TCCR1B  0 at this point?

If they aren't then the result isn't the same.

I guess 0 is the power on reset value for TCCR1B so the other bits should be 0, unless there is something in code you haven't shown that writes to TCCR1B before this code runs?

 

What happens if you add TCCR1B = 0 into your setup function, then use the bit twiddling?

What happnes if you use direct write TCCR1B = 0x09 when turning the bits on but use the bit twiddling in the ISR to turn them off ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

 

MrKendo wrote:
Are all the other bits in TCCR1B  0 at this point? If they aren't then the result isn't the same. I guess 0 is the power on reset value for TCCR1B so the other bits should be 0, unless there is something in code you haven't shown that writes to TCCR1B before this code runs?

YES. Because the code I have posted is the only code I m programming in the ATTINY84. SO there lies no chance that I accidentally set any non-relevant bit to 1.

 

MrKendo wrote:
What happnes if you use direct write TCCR1B = 0x09 when turning the bits on but use the bit twiddling in the ISR to turn them off ?

Reason behind using bit twiddling is that I might use INPUT CAPTURE function in future. To do that i m forced to code the above program to BIT TWIDDLE, so that bits like ICNS1 doesn't get affected, since they too are located in same register TCCR1B. Therefor BIT TWIDDLING is my only option since I want to make maintainable code that it wont affect other bits which might be used in future.

 

I am attaching screenshots of datasheet too. Thanks for reply btw.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Milind_G wrote:

YES. Because the code I have posted is the only code I m programming in the ATTINY84. SO there lies no chance that I accidentally set any non-relevant bit to 1.

It might be the only code you think you're programming in the ATTINY, but there must be some more code 'behind the scenes' because there's nothing in the code posted that shows what is calling your setup and loop functions. There's also no 'main' function. I suspect this 'behind the scenes' code comes from the Arduino environment.

I've no idea if any of ths 'behind the scenes' code touches TCCR1B or not, just seemed like the obvious thing to check first.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If the environment is actially arduino there is backend code that affects the timers as they are used for various delay functtions so the point of something else tickling the bits is a valid point.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:
If the environment is actially arduino there is backend code that affects the timers as they are used for various delay functtions so the point of something else tickling the bits is a valid point.

You are correct Jim. Using arduino framework does come with its shortcomings. When using Arduino framework, ISR(TIM0_OVF_vect) gives an error of multiple vector declaration, something like that. I found it out hard way in some of my older programs. However, using any of the ISR vectors related to Timer 1 was not a problem. only Overflow ISR of timer0 gives out that error.

 

By the way I have done some code correction and now I m happy to say IT WORKS LIKE A CHARM !!!

CORRECTIONS:

-Instead of setting WGM12 bit in the for loop, which sends IR signal, I have set it beforehand in starting of the function.

-Only, starting the timer1 without any prescaler, i.e., (1<<CS10) is done in the for loop.

-Therefore in the ISR now i have to just clear the CS10 bit to stop timer without need to clear WGM12 bit.

 

I m posting the code below, but still it dosen't makes sense, that why that happened..!!! Maybe Timing problem in bit twiddling? (that doesn't makes sense, since i m running @ 16 MHz). I encourage you readers to suggest the possible reasons, so as a community we can grow and throw out such time consuming and head scratching bugs in our future code. Thanks to all who replied.

_MILIND

 

#define F_CPU 16000000UL
#include <avr/io.h>
#include <Arduino.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define ON_SIGNAL  12
#define OFF_SIGNAL 18
#define IR_pin PA6

volatile bool IR_Signal_Sent = false;
uint8_t IR_Counter = 0;

void Timer1_IR(uint8_t IR_Signal_Time);
void Timer1_IR(uint8_t IR_Signal_Time){   
  //INITIALIZING TIMER1  
  OCR1A = 207;  //TOP value for CTC(13 uS)
  TCCR1A = 0x40; //TCCR1A = 0x10;  //toggling OC1A(PA6) at TOP
  TCCR1B |= (1<<WGM12);  //CTC MODE>>THIS IS ONE OF THE CHANGE
  TIMSK1 |= (1<<OCIE1A);  //Output Compare A Interrupt enabled to count 38kHz cycles 
  sei();
    
  //FOR LOOP TO SEND 5 CONSECUTIVE DELAY SIGNAL
  for(uint8_t i=0; i<6; i++){
    TCCR1B |= (1<<CS10); //Startig Timer>>THIS IS ONE OF THE CHANGE
    while(IR_Signal_Sent == false){
      //Wait signal to be sent
    }
    IR_Signal_Sent = false;
    if(IR_Signal_Time == ON_SIGNAL){
      _delay_ms(ON_SIGNAL);
    }
    else{
      _delay_ms(OFF_SIGNAL);
    }
  }
  //STOPING AND RESETING TIMER1
  TCCR1A = 0X00;
  TCCR1B = 0X00;  //TCCR1B &= ~((1<<WGM12) | (1<<CS10));
  TIMSK1 &= ~(1<<OCIE1A);
  PORTA  &= ~(1<<IR_pin);
}

void setup() {
  DDRA  |=  (1<<IR_pin);   //OC1A as PWM OUTPUT
}

void loop() {
  Timer1_IR(ON_SIGNAL);   //Sending ON Signal
  _delay_ms(500);
  Timer1_IR(OFF_SIGNAL);  //Sending OFF Signal
  _delay_ms(500);
}

ISR(TIM1_COMPA_vect){
  IR_Counter ++;  //Increment Count everytime reaching TOP
  
  //TO CHECK WHETHER 20 CYCLES OF IR WAVE HAS BEEN SENT
  if(IR_Counter >= 20){
    TCCR1B &= ~(1<<CS10);  //Stop Timer>>THIS IS ONE OF THE CHANGE
    IR_Counter = 0;  //Reset Counter
    TCNT1 = 0;  //Reset Timer1 Counter
    IR_Signal_Sent = true;
  }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
because there's nothing in the code posted that shows what is calling your setup and loop functions

Arduino.h library let me use setup and main loop function. Since i started learning embeded via Arduino and hence using its IDE. You kinda get stuck to it. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Milind_G wrote:

I m posting the code below, but still it dosen't makes sense, that why that happened..!!! Maybe Timing problem in bit twiddling? (that doesn't makes sense, since i m running @ 16 MHz). I encourage you readers to suggest the possible reasons, so as a community we can grow and throw out such time consuming and head scratching bugs in our future code

It makes sense to me.

You are using the arduino framework.

This adds a hidden main faunction. The first thing that hidden main function does, before it calls your setup function, is to call a hidden init function. Within that init function it configures the hardware timers. It primarily uses timer 0, including adding an ISR for timer 0 overflow, but it does also set the prescaler on timer 1 (it sets c10 and cs11 bits in TCCR1B).  At least this is the case for atmega328p, so I'm assuming it's similar with ATTINY84.

So by the time your code gets to run, a lot of the timer registers are no longer at their power on reset value.

 

Did you ever try, from #2, "What happens if you add TCCR1B = 0 into your setup function, then use the bit twiddling?".

I predict it ill work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
This adds a hidden main faunction. The first thing that hidden main function does, before it calls your setup function, is to call a hidden init function. Within that init function it configures the hardware timers. It primarily uses timer 0, including adding an ISR for timer 0 overflow, but it does also set the prescaler on timer 1 (it sets c10 and cs11 bits in TCCR1B).  At least this is the case for atmega328p, so I'm assuming it's similar with ATTINY84.

 

That explains a lot !!!  I guess its time for me to leave arduino framework. Thanks.

 

MrKendo wrote:
Did you ever try, from #2, "What happens if you add TCCR1B = 0 into your setup function, then use the bit twiddling?". I predict it ill work.

 

I have to try that yet. But if you look at the second code(WORKING) I have posted, in that I m using bit twiddling for WGM12 and CS10 bits. So any other bits in TCCR1B is not affected. If what you are suggesting might be happening , then it might also affect this working code. Which it doesn't.

P.S:- I am not running any other code other than posted, which might influence the ill behavior. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Milind_G wrote:

MrKendo wrote:
Did you ever try, from #2, "What happens if you add TCCR1B = 0 into your setup function, then use the bit twiddling?". I predict it ill work.

 

I have to try that yet. But if you look at the second code(WORKING) I have posted, in that I m using bit twiddling for WGM12 and CS10 bits. So any other bits in TCCR1B is not affected. If what you are suggesting might be happening , then it might also affect this working code. Which it doesn't.

P.S:- I am not running any other code other than posted, which might influence the ill behavior. 

In your second code, you have added

TCCR1B = 0X00;

at the end of your Timer1_IR function. So after it has run through that function once, you now have TCCR1B back to a known state with all bits 0.

I suspect it isn't actually working correctly for the very first time through that function.

It makes more sense to set TCCR1B (in fact, I would do this for all timer 1 registers) to a known state ie. 0 at the start, within your setup function. This essentially undoes whatever the arduino framework has done. Then you know exactly where you are starting from.

 

I don't have arduino installed, so I've been looking at the arduino avr core code on github.

 

The main function https://github.com/arduino/Ardui...

 

And you can see the init() function here https://github.com/arduino/Ardui...

In particuar lines 284 onwards for timer 1.

In fact, it also sets wgm10 bit in TCCR1A. So it would be safer to set all timer1 registers back to 0 in your setup.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
In your second code, you have added TCCR1B = 0X00; at the end of your Timer1_IR function. So after it has run through that function once, you now have TCCR1B back to a known state with all bits 0. I suspect it isn't actually working correctly for the very first time through that function.

YES this is a valid possibility.

 

MrKendo wrote:
It makes more sense to set TCCR1B (in fact, I would do this for all timer 1 registers) to a known state ie. 0 at the start, within your setup function. This essentially undoes whatever the arduino framework has done. Then you know exactly where you are starting from.

I guess that's a good programming practice. Thanks. I will implement this in all my future codes. As the saying goes prevention is better than cure ! 

 

MrKendo wrote:
In fact, it also sets wgm10 bit in TCCR1A. So it would be safer to set all timer1 registers back to 0 in your setup.

Yes, now it makes sense. This information was helpful !!! I should no longer be dependent on Arduino Framework. Time for a switch. I tried installing Atmel Studio but it wont install giving me an error of missing window update. I tried to install the required but failed. As I look up , this issue was experienced by many. I know its out of topic for me to ask for GOOD & FREE alternative toolchain and IDE for AVR. If you feel like , then please suggest one. Thanks. Namaste !