Author Topic: Arduuino-atmega8 timers differences- porting foreign code  (Read 1302 times)

0 Members and 1 Guest are viewing this topic.

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Arduuino-atmega8 timers differences- porting foreign code
« on: April 09, 2023, 08:17:13 pm »
Hello. i am here with rather newbie problem, probably my own creation. mostly related to downloading untested arduino code from the internet and trying to shoehorn it to a different microcontroller just because i have those not arduino :].
I never really worked with timers that much so i can't really decipher why it no work. if the oruginal code used 16 bit timer it would probably have no consequences which atmel chip it works on, because by datasheet both arduino (atmega 328) and atmega 8 have it configured in exact the same way. sadly project used timer 0 which in atmega 8 is vastly cut down. long story short i don't understand the code well enough to come up with the alternative solution.
Code: [Select]
#define TIMER_PRESCALER 64
#define DccBitTimerCount (F_CPU * 80L / TIMER_PRESCALER / 1000000L)
// 16000000 * 80 / 64 / 1000000 = 20; 20 x 4usecs = 80us

//========================

void beginBitDetection() {
  TCCR0A &= B11111100;
  attachInterrupt(0, startTimer, RISING);
}

//========================

void startTimer() {
  OCR0B = TCNT0 + DccBitTimerCount;
  TIMSK0 |= B00000100;
  TIFR0  |= B00000100;
}

//========================

ISR(TIMER0_COMPB_vect) {
  byte bitFound = ! ((PIND & B00000100) >> 2);
  TIMSK0 &= B11111011;
  byte nbs = nextBitSlot(bitBuffHead);
  if (nbs == bitBuffTail) return;
  else {
    bitBuffHead = nbs;
    bitBuffer[bitBuffHead] = bitFound;
  }
}

//========================

Those are parts of code of the program i have problems with. i was able to convert the rest with no issues, since it is a simple terminal talking program collecting informations from incoming model train controller taking up as a whole only half of atmega 8 flash. A bit of a waste of arduino really, which i don't have anyway :).

I am actually compiling and uploading this in arduino ide via usbasp after installing minicore boards. i am not sure if that is a good idea or would winavr be a bit faster after compiling, anyways, when i randomly change timers to ones existing on my ic without even understanding what they do code compiles, but also crashes right after sending the setup message.

if someone kindly explain to me how this code work i probably would be able to climb my way back studying atmega 8 datasheet. i am actually not interested in solution alone, because then i will kind of be out of the loop and still learn nothing.

If i understand it corectly porting it to timer1, the 16 bit one would make the code more universal, because both ic's use the same 16 bit counters but it would bee too slow if it have to work with full count and would have to be heavyly prescaled. but that just my ignorance talking.



 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12863
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #1 on: April 09, 2023, 08:50:46 pm »
Its attaching the function startTimer() to the digital pin 2 INT0 interrupt, rising edge triggered.  When that interrupt event occurs, it sets OCR0B to the current timer count + the #defined calculated constant DccBitTimerCount so that a different interrupt (TIMER0_COMPB, OCR0B compare match) will occur that many timer ticks later. When that ISR executes it polls digital pin 2 (as PD2) and if there's space, stuffs it into the next free location in a circular bit buffer bitBuffer[] (which seems to be organised on a one byte per bit basis as C pointers cant access individual bits).   Presumably, bitBuffer[] and its head and tail indexes bitBuffHead and bitBuffTail are globals or file scope variables, and volatile, so they can also be accessed from the main program outside of any ISR context.
« Last Edit: April 09, 2023, 08:52:34 pm by Ian.M »
 

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #2 on: April 09, 2023, 11:38:53 pm »
well i can sort of follow the program structure, so that only vaugly clear things up.

I am more concerned about that masked binary values for the registers and i feel like i need a drawing to understand what is going on with those, or a video toutorial :P syntax examples

anyway what i get from going over manuals a bit is that atmega8 timer 0 has only overflow trigger, timer 1 would have everything pretty much the same but it is 16 bit so bitmasking registers of what it should do would be wrong and timer 2 has only one compare register anda bit different prescaler options and topology but is again 8 bit.

sorry it is almost 2 am here so the question here might be a bit dumb
Was ocr0b register chosen for specyfic reason over ocr0a or was it a preference? Because if it is just a preference i should probably use timer 2 with one cor2 register because that should be enough if i am not mistaken, otherwise i need to somehow decode those binary masks to what they do and try that with 16 bit timer?

besides i am still unsure how it is getting the interupts to do anything on pin 2 if pin 2 is where i input the signal , which is continues stream in a loop
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12863
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #3 on: April 10, 2023, 12:40:32 am »
The ATmega328P full datasheet has what you need to decode those register manipulation bitmasks.  |= SETS any bit that's 1 in the mask and &= CLEARS any bit that's 0 in the mask.

e.g. TCCR0A &= B11111100; is clearing bits 0 and 1 of TCCR0A, and searching for that register in the datasheet eventually locates the register description, (Section 19.9.1. TC0 Control Register A, page 138), which tells be the bottom two bits are WGM00 and WGM01, and together with WGM02 (in TCCR0B) select the PWM mode from table 19-9.   I assume WGM02 is either set to 0 elsewhere in the code or has that state from reset, which would make the WGM bits 0b000, which disables Timer 0 PWM (the normal state).

Plow through the rest of them to figure out what's actually being set/cleared, then hit the datasheet for the timer 0 block diagrams to figure out the timer tick rate, and compare mode settings.  Then its simply a matter of matching them up with the capabilities of the ATmega8 timers.   There's no reason not to use a 16 bit timer - as the compare register is being set from the timer value in an ISR, and AVR 16 bit timers have a buffer register to capture the high byte to get a clean 'snapshot' read of the whole 16 bit timer, and hardware to update the whole of each 16 bit OCR register atomically, by deferring the high byte write till the low byte is written - as long as some care is taken with the byte order of the reads and writes, it will 'just work'.   The execution time of extra few instructions required for 16 bit vs 8 bit handling in startTimer() should be negligible unless its handling very high baud rate serial input.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #4 on: April 10, 2023, 08:00:21 am »
Quote
Code: [Select]
ISR(TIMER0_COMPB_vect)

IIRC, the main difference between the mega8 and the mega328 is that timer0 on the mega8 does NOT have the "output compare registers."  For Arduino, that means two less PWM outputs.
The program you're trying to run is clearly using the compare registers (and the interrupt) of TIMER0, so you'll probably have to modify it to use one of the other timers.
 

Online Ian.M

  • Super Contributor
  • ***
  • Posts: 12863
Re: Arduino-atmega8 timers differences - porting foreign code
« Reply #5 on: April 10, 2023, 09:27:41 am »
Yes.  The Arduino framework (on AVRs) makes heavy use of TIMER0 and its overflow interrupt, for the millis() time and delay() functions, and in the standard Arduino AVR core,  you cant intercept or add your own code to the TIMER0_OVF ISR.   

If you are coding 'bare metal' without the Arduino framework, to eliminate the need for output compare, in the startTimer() function you *could* preload Timer 0 with 256-DccBitTimerCount, so it overflows after the required no. of ticks, and start the timer.  Use TIMER0_OVF for the bit handling ISR.

However if you *are* using the Arduino framework, that isn't possible, so your only alternatives are to port the code to a timer that *has* output compare or switch to a different AVR MCU with Timer 0 output compare.
 

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #6 on: April 10, 2023, 10:19:31 am »
i could just go and buy knokof arduino on ebay and not learn anything usefull.

yes i am using arduino ide and yes milis function is used all over the code to gauge 0's and 1's from dcc signal stream because the have different length and i belive minicore uses them normally. but who knows i might be totaly wrong, that wouldn't be the first time.

the biggest question now is what arduino ide does with the other 2 timers, especially what mini core for atmega does with them?
is there a way to check all the board specyfic hidden code that programs all the functions for arduino ide?

edit********
i just feel like reading all the examples makes me even dumber than i was before because every code is different, doing things in completly different way and even if commented what that particular register mask does it dos not specyfi anything else, no other options no alternative syntax for doing the same and i feel like i am learning interupts and timers 3 times separately instead of just once as a whole. it is so frustrating to not know what you don't know. but i always hated examples that only showed you one way of doing things without even telling about other methods. it is like showing you the most convoluted way to get from point a to point b  without telling you the shortest route is blocked but instead informing tou this is "the way"
i will go back to reading manuals and perhaps find something that could replace timer0 implementation using arduino ide
« Last Edit: April 10, 2023, 10:35:36 am by kokodin »
 

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #7 on: April 10, 2023, 07:42:52 pm »
i am thinking out loud so please corect me if i am  wrong

i want to use timer 2  of atmega8 as a closest to functional equivalent
it has THE compare match register ocr2 , timsk is shared register between all interupts so i only need to set bits i want to compare match, and do the same for tifr so start timer would end up something like this
Code: [Select]
void startTimer() {
  OCR2 = TCNT2 + DccBitTimerCount;
  TIMSK |= B10000000;
  TIFR  |= B10000000;
}
but that was the easy part
Setting the interupt would now look something like this
Code: [Select]
ISR(TIMER2_COMP_vect) {
  byte bitFound = ! ((PIND & B00000100) >> 2);
  TIMSK &= B01111111;
  byte nbs = nextBitSlot(bitBuffHead);
  if (nbs == bitBuffTail) return;
  else {
    bitBuffHead = nbs;
    bitBuffer[bitBuffHead] = bitFound;
  }
}
but i am still not sure about tccr register
because in oryginal code author often mask non writable bits with 1's  and i am still not sure if timer 2 isn't used by arduino to something else plus the other register tccr0b isn't even mentioned in the code so i don't know what it was set to without checking it on arduino

anyway changing that register afect the text output the most, i must spam some debug prompts all over the code to track the branching execution but i don't think it is doing what ist suposed to just yet (but it no longer triping over itself in endless interupt and it almost work) it still hangs up after a few prompts so it may be stuck in some loop.

how it works now is with no dcc bus connected it hangs after displaying setup message and branching into bit detection functions but if i feed it with dcc bus it spit out some garbage i left in bit detection functions and then stops, it might be a timing problem or anything else really
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #8 on: April 11, 2023, 12:33:23 am »
Quote
what arduino ide does with the other 2 timers

The other timers are used only for PWM, but they are initialized for "phase correct" PWM, which means that they spend half their time counting down instead of up, making them unsuitable for what your code is doing UNLESS you re-initialize them for normal mode. That shouldn't be a problem if you're not using PWM on the pins it controls.
AFAIK, TIMER2 is about the same as TIMER0 except for its ability to run asynchronously and use the 32kHz oscillator.
 

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #9 on: April 11, 2023, 04:51:47 pm »
well i actually did make it almost work , more like a beaten dog than dcc decoder, but it does spit out some nonsense data now instead of being stuck in a bit read loop.
IT might sound like an excuse but i didn't code that much lately and i completly forget what logic operators do what and i didn't notice at first i am removing bits from registers instead puting them in. beside i didn't have 16mhz crystal so my board is runing from 12mhz one and probably all the timings are wrong (but there is a ballpark where it almost work around 46-49 prescaler on top of the code)

to be honest if i was to write this code from scratch i would probably want to use timer 1 in normal mode with no interupts set and trigger my interupts from every logic level change on the input pin then comparing timer value with a constant value and determining bit from that, then reseting timer to 0 and incrementing loop counter. and if i did that i could become almost clock independent. well any timer would do but i would need to prescale 8 bit ones
i could even fit phase correction into that based on that constant and 1 boolean bit because i don't see that in oryginal code

i was wrong about use of millis in the code though , it is only used to refresh the output every set number of millis

I will probably play around with this code a bit and ten try to build my own implementation from scratch to only gave things i want, for instance make it adressable dcc decoder that only spits commands adressed to it, only one step from driving a train
 

Offline kokodinTopic starter

  • Regular Contributor
  • *
  • Posts: 82
  • Country: pl
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #10 on: April 11, 2023, 09:00:26 pm »
I would like to thank everyone who tryed to help me. i learned a lot. But completly out of the blue, i found open source lubrary for arduino ide, that can perform every thing i wanted from this project, without using timers, on attiny84 and up, with any external clock. Plus it is very much a full fledged still maintained dcc protocol implementation project so i just build my device out of avalable lego blocks.
needless to say it works out of the box from any example.

so once more thanks for help but i think this thread is now closed, i will play with the timer in some other project now that i know how to use them(mostly)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Arduuino-atmega8 timers differences- porting foreign code
« Reply #11 on: April 12, 2023, 05:14:57 am »
Quote
i found open source library for arduino ide
This is the way!
It can be pretty demotivating WRT writing code when you can just "find" code that is pretty close to what you want that doesn't look too horrible.
(Occasionally it looks a lot BETTER than what I think I could do.  More Professional and stuff.  Sigh.)

 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf