1
\$\begingroup\$

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.

\$\endgroup\$
20
  • 1
    \$\begingroup\$ May i ask: Why is it only programble via ASM? \$\endgroup\$ Commented Jan 12, 2023 at 19:12
  • 2
    \$\begingroup\$ Basic questions: Clock is active? VCC is present? Fuses are correct? RESET is inactive? \$\endgroup\$ Commented Jan 12, 2023 at 19:18
  • 2
    \$\begingroup\$ @ElectronicsStudent C compilers don't support so minimalistic CPU cores. This has no RAM at all. \$\endgroup\$
    – Justme
    Commented Jan 12, 2023 at 19:53
  • \$\begingroup\$ @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. \$\endgroup\$
    – Demento
    Commented Jan 12, 2023 at 21:56
  • 1
    \$\begingroup\$ @thebusybee Opend a new Question for this. I am curious now! electronics.stackexchange.com/questions/649851/… \$\endgroup\$ Commented Jan 13, 2023 at 7:38

3 Answers 3

1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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.
\$\endgroup\$
5
  • \$\begingroup\$ 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. \$\endgroup\$
    – Demento
    Commented Jan 12, 2023 at 21:52
  • \$\begingroup\$ @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). \$\endgroup\$
    – Ben Voigt
    Commented Jan 12, 2023 at 22:01
  • \$\begingroup\$ 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. \$\endgroup\$
    – Demento
    Commented Jan 12, 2023 at 22:50
  • \$\begingroup\$ @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. \$\endgroup\$
    – Ben Voigt
    Commented Jan 12, 2023 at 23:10
  • \$\begingroup\$ 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. \$\endgroup\$
    – Demento
    Commented Jan 13, 2023 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.