Attempting to take over TCD0 on a AT412. Why do I fail? #494
-
Together with my new friends the datasheet and the header file I am attempting to take control of the timer D on a Attiny412 My sketch turns on TCD0, reads the 12 bit timer value and prints it, when higher than the last printed value. I expect it to reach the maximum 12 bit value of 4095. Now when I compile with millis()/micros() disabled I capture the value 0. So I am forgetting something, but what ?? Please find below my small sketch:
note1) capturing the low byte / high byte separately or in one go did not make a difference |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
What value do you see for TCD0.CMPBCLR? I don't see you writing that to set TOP anywhere. I think its reset value is 0x000, so it's overflowing every timer tick and never getting higher than 0. If that's not it, print out the values of all the registers of TCD0, writing the results to Serial. also - Serial.println(value,BIN)? you'll probably be happier with Serial.printHex() - prints most types directly as hexadecimal....without pulling in quite as much bloat as the normal print methods at some point I'm planning to release a microscopic serial librariy. Also, this sort of construction is evil (mayber "evil" is too dramatic - "bad" may be more correct) - only do this when it's actually what you need the chip to do.
Don't do consecutive bit-writes to registers (which are volatile - the compiler can't optimize that into a single write) unless you require them to be separate writes. You know that TCD0.CTRLA = 0 to start with (or it godda ed well should be after calling the takeover function), So why not just do That is 3 words of flash and 3 clock cycles (ldi - load immediate - to load the 8-bit constant to a working register, and sts - store direct - to write it, the latter is a 2 word, 2 clock instruction. What you have is would turn into something like lds (load direct, 2 words 3 clocks, load the existing value to working register), ori (or it with that bitfield - 1 word 1 clock) , sts (2 words 2 clocks) to store it **got eraj Hence 5 words (10 bytes) per line. And it can't combine them because the peripheral registers are volatile - it has to do a read-modify-write cycle for each one. Overuse of |= on separate lines to write registers is a common idiom that I see in ArduinoLand - I think it comes from the classic AVR days... where common control registers for peripherals were in the low IO space, where that's not as painful. But the advice to use it gets told to people without enough information for them to know when it's valid, so it was used in cases where it was much worse than the alternatives. In the case of your example - if that were in the low I/O space, it would compile down to 4 words, 4 clocks. Still worse than simple assignment, but nowhere near the 20 words thaty the There are 32 registers at most on a given AVR part for which |= can be super efficient: If the register being written to resides in the mythical Low I/O space - that is it is located at an address between 0 and 31, then sbi and cbi instructions can be used on it. These work ONLY on those registers, when the value being OR'ed has only a single bit set, or being AND'ed has all but one bit set., and is compile time known). On the classic AVRs, there was some variation and mystery to which registers were in the low I/O space on a given part. On modern ones, there's no mystery: 0x00 through 0x1B are the VPORT registers for the ports A through G, followed by the GPIOR0-GPIOIR3 (which are general purpose i/o space registers that you can use as you wish - GPIOR0 may be written by the bootloader and/or core during startup as documented - the bootloader uses it to pass the reset cause to the application, because it has to clear the reset flags so that it can honor the specified entry conditions and only those), but nothing after startup reads or writes them unless you write code to do that yourself). Those are the only registers that you can do magic interrupt safe bitsets/clears. There's also an corresponding test instruction (skip-if-bit-in-io-register-is-set/cleared, sbis/sbic - so if I actually had tons of cide like that in ATTinyCore (the legacy core). Wehn I was looking over it last summer, having finally learned what not to do. at the drop of a hat i was anler to drop the size of init() on most parts by on ther order of a hundred bytes |
Beta Was this translation helpful? Give feedback.
-
That is promising, as it will make debugging easier on the low memory parts, where I have to discard Serial as debugging option, when I need the memory space that it eats. |
Beta Was this translation helpful? Give feedback.
What value do you see for TCD0.CMPBCLR? I don't see you writing that to set TOP anywhere. I think its reset value is 0x000, so it's overflowing every timer tick and never getting higher than 0.
If that's not it, print out the values of all the registers of TCD0, writing the results to Serial.
also - Serial.println(value,BIN)? you'll probably be happier with Serial.printHex() - prints most types directly as hexadecimal....without pulling in quite as much bloat as the normal print methods at some point I'm planning to release a microscopic serial librariy.
Also, this sort of construction is evil (mayber "evil" is too dramatic - "bad" may be more correct) - only do this when it's actually wh…