1

So far I have only worked with ATmega32 chips, programming them in C. Now I have to work with an ATTINY12, which can only be programmed in ASM.

As a proof of concept, I wrote a simple program that turns on a LED on PB0. I can compile the code and flash the microcontroller successfully, but the LED does not turn on.

I verified that the circuit works as intended and I tried 2 different microcontroller to rule out a hardware issue. It looks like I am misunderstanding something in the source code I have assembled based on a couple of tutorials I've found.

#include <avr/io.h>
.org 0x00 
.global main

main:
    ldi R16,0b00000001
    out DDRB,R16           // Set PB0 as output pin

    ldi R16,0b00000001
    out PORTB,R16          // Set PB0 to high

loop:
    rjmp loop              // loop forever
.end

I compiled the source with Microchip Studio and flashed the chip with AVRDUDE. I also added LEDs to PB1-PB5 for debugging, but none of them showed any sign of life.

The program seems so simple and straightforward. What am I missing?

Edit: After a couple of very helpful comments, I found another weird behavior. When I try to set a single bit on PORTB using sbi PORTB, 1, which should set PB0 to high, the compiler throws an error operand out of range: 56. This does not make sense, because PORTB is supposed to have 6 bits (0-63). This indicates to me, that my main problem lies in the way I use PORTB in my code.

The same applies to sbi DDRB, 1, only that the compile error reads operand out of range: 55.

Demento
  • 121
  • 5
  • 1
    May i ask: Why is it only programble via ASM? – ElectronicsStudent Jan 12 '23 at 19:12
  • 2
    Basic questions: Clock is active? VCC is present? Fuses are correct? RESET is inactive? – ElectronicsStudent Jan 12 '23 at 19:18
  • 2
    @ElectronicsStudent C compilers don't support so minimalistic CPU cores. This has no RAM at all. – Justme Jan 12 '23 at 19:53
  • @ElectronicsStudent thanks for your questions. I am working with new chips and didn't mess with the fuses or the clock. VCC is present, programming the chip works without problems. There is no connection to the RESET pin after I am done flashing. – Demento Jan 12 '23 at 21:56
  • Don't know if the reset pin has an internal pull-up. To be sure that **reset input** pin is high (inactive), you might try pulling it up through a resistor to **Vdd**. – glen_geek Jan 12 '23 at 22:44
  • @Justme Thank you - was not aware one could get those parts! But interesting too see them. Would you know an advantage of these over a simple CPLD for example? – ElectronicsStudent Jan 13 '23 at 04:27
  • @Demento I had a look at the Datasheet: There is no sign of internal reset pull up. Please connect your RESET line with ~10kOhms to VCC. You can still use the programmer when the resistor is installed. – ElectronicsStudent Jan 13 '23 at 04:29
  • @ElectronicsStudent One advantage is that for some projects it is much simpler to implement a small software algorithm than a hardware logic. The original PIC series from the seventies targets the same kind of projects, as ("PIC" means "peripheral interface controller"](https://en.wikipedia.org/wiki/PIC_microcontrollers). Look at them as read-made state machines, which you can control via the program. – the busybee Jan 13 '23 at 07:26
  • @thebusybee Thank you for the answer. Do i understand correctly? It targets the segment inbetween "few ANDs/NORs = PLD"/"a few ANDs/NORs and bit of Registers for Remote Access via e.g. SPI=CPLD" and a full-blown FPGA (even minor device size) to implement some sort of "trivial logic/flow" which is too complex for CPLD/PLD but far too simple to justify a FPGA? And as not many IOs are required a small uC is used, which has some timers and analog peripherials? – ElectronicsStudent Jan 13 '23 at 07:33
  • 1
    @thebusybee Opend a new Question for this. I am curious now! https://electronics.stackexchange.com/questions/649851/usecases-for-ram-less-microcontroller – ElectronicsStudent Jan 13 '23 at 07:38
  • @ElectronicsStudent I connected the RESET pin with a 10k Ohm resistor to VCC. Unfortunately, this didn't change the behavior at all. Doesn't look like a RESET issue. – Demento Jan 13 '23 at 13:12
  • @Demento Did you try the code from my answer aswell? – ElectronicsStudent Jan 13 '23 at 13:31
  • @ElectronicsStudent Yes, unfortunately it didn't change the behavior. – Demento Jan 13 '23 at 13:37
  • @Demento And did you try connecting/disconnecting the programmer as well as power cycling and checking the fuses? – ElectronicsStudent Jan 13 '23 at 13:38
  • @ElectronicsStudent Yes to all of those. Didn't change the underlying issue. The code doesn't work even when running the chip on a 5V battery and the fuses are set as intended. – Demento Jan 13 '23 at 13:43
  • @Demento Hmmmh. Okay, lets do another thing. Instead of writing to PORTB/DDRB code it with direct adressing. So "out 0x17,0x01;" is write 0x01 to DDRB and "out 0x18,0x01" is write 0x01 to PORTB. – ElectronicsStudent Jan 13 '23 at 14:00
  • @Demento Next let us tackle the Watchog. To disable it write "out 0x21, 0x81" and then immediatly "out 0x21,0x00". – ElectronicsStudent Jan 13 '23 at 14:04
  • @Demento Next Idea. Can you download your code from the device via your programmer? If so, download the .hex and compare it with your assembler output. – ElectronicsStudent Jan 13 '23 at 14:07
  • @ElectronicsStudent Thanks for your help and your patience! I finally found the error. All the memory addresses (PORTB, DDRB, etc.) were wrong, because of a wrong offset in an old header file. I'll explain it in detail in the answer I'm going to write now. At least I learned a lot in this journey! – Demento Jan 15 '23 at 18:23
  • @Demento Great to hear! You are welcome. – ElectronicsStudent Jan 15 '23 at 18:55

3 Answers3

1

I am not that much of an ASM-Dev, but maybe your issue is in the code as well.

I had a look at the Datasheet Datasheet Page 16 - there the ISR-Vectors are "mounted".

Maybe you have to put a "rjmp" to your "main" at 0x00 - but as I said: I don't know much about ASM.

So I Googled for a bit and came across GitHub.

You could try the following ASM-Code:

#include <avr/io.h>
.org 0x00
  rjmp main
  RETI
  RETI
  RETI
  RETI
  RETI
main:
  ldi R16,0b00000001
  out DDRB,R16 
  out PORTB,R16
loop:
  rjmp loop

And as I said in the comments: Make sure, your reset is inactive (Pull-Up to VCC). Also, make sure the fuses are set in a way, that the internal RC-Oscillator is to be used.

You could also: 1. Flash the IC via programmer, 2. disconnect the programmer, 3. power cycle IC to rule out any issue with your programmer holding the IC in "serial programming" mode.

JYelton
  • 32,302
  • 33
  • 134
  • 249
ElectronicsStudent
  • 2,746
  • 5
  • 18
1

After countless hours of deep dives into datasheets and old source code I found the underlying problem.

PORTB, DDRB and other constants point to address locations in the I/O space of the controller. For the ATTiny12 controller, those are defined in iotn12.h included via avr/io.h:

/* Data Direction Register, Port B */
#define DDRB    _SFR_IO8(0x17)

/* Data Register, Port B */
#define PORTB   _SFR_IO8(0x18)

_SFR_IO8 is defined in sfr_defs.h. It basically implements a switch for different architectures to either use on offset of 0x20 or not. Somehow this switch fails for the ATTiny12 and sets the offset to 0x20, although no offset should be used.

This results in PORTB and DDRB pointing at the wrong locations in memory. As long as data is only written via out from a register to those locations, the compiler doesn't complain, but when sbi or cbi is used, the compiler throws an operand out of range error, because those commands can't be used to manipulate those memory locations.

So, when using PORTB and DDRB or even _SFR_IO8(0x18) directly with out, the compiler doesn't complain but the program obviously doesn't work, because values are written to the wrong location.

How to solve the issue? You can override the switch by defining the offset yourself in your ASM code, before avr/io.h is included: #define __SFR_OFFSET 0.

Once this offset is set, the program works as intended.

Demento
  • 121
  • 5
0

Have you tried measuring the pin voltage with a meter instead of an LED?

What's the circuit you are connecting to PB0? How did you verify it works at intended? LEDs have two terminals.

  • You may have the LED backwards.
  • You may be connecting both sides of the LED to Vcc and neither to ground.
  • Vcc may not be high enough to turn on the LED.
  • Your ATTINY may not be able to carry enough current to turn on the LED, in which case you need a transistor to amplify the current.
  • You may have neglected a current-limited resistor and burned out the LED.
Ben Voigt
  • 2,743
  • 1
  • 22
  • 34
  • Thanks for your input. LED and circuit are OK. When I connect the LED to VCC and GND instead of PB0 and GND, it lights up. Resistor for LED is in place. Pin Voltage reads 0 on PB0 and GND when measured with a meter. The meter shows close to 5V on VCC and GND. – Demento Jan 12 '23 at 21:52
  • @Demento: What LED current are you trying to get? The datasheet definitely recommends using I/O pins to control the negative side of an LED because they can sink much more current than they can source (not uncommon due to chemistry differences between NMOS and PMOS transistors). – Ben Voigt Jan 12 '23 at 22:01
  • That's interesting, I missed this in the datasheet! I switched the circuit around, now the LED sits on VCC and PB0. I am getting closer to the problem. No matter how I manipulate DDRB and PORTB, I _never_ see a voltage between PB0 and VCC, but I _always_ see 5V between VCC and PB1 (and I also get the LED to work on PB1). This shows, that there is most likely some issue in the code, because no matter what I do to DDRB and PORTB, the result is always the same. – Demento Jan 12 '23 at 22:50
  • @Demento: Have you disconnected the programmer, or just told it to release RESET? RESET and the PB0 and PB1 pins are all used during serial programming so the programmer itself might be fighting for control. – Ben Voigt Jan 12 '23 at 23:10
  • I now tried running it without the programmer. After the reset, I can't get the LED to work neither PB0 nor PB1. So you are right, there seems to be a weird "post-flash-state". I also found another strange behavior - it looks like I cannot set bits on PORTB using sbi. I get an "operand out of range: 56" error during compilation. This might point to some fundamental issue the way I work with PORTB. I'll add this observation to my question. – Demento Jan 13 '23 at 13:20