1

I want to make a piezo buffer beeping with assembly code, but i haven't managed to yet. I have an Arduino UNO board (ATMega328p) and using avra and avrdude to build and load. The buzzer just stay silent. Here's my code:

.nolist
.include "m328pdef.inc"
.list

.equ _a = 141 ;(16000000 / 256) / 440(frequency of A) - 1

.cseg
  ;wgm02..0 = 7 (fast pwm, top = ocr0a)
  ;cs02..0 = 4 (N=256)
  ;com0b1..0 = 2 (clear on compare match, set at bottom)
  ldi r16, 0b00100011
  sts tccr0a, r16 ;need out!
  ldi r16, 0b00001100
  sts tccr0b, r16 ;need out!
  ;ocr0a = _a to obtain 440Hz
  ldi r16, 141
  out ocr0a, r16
  ;ocr0b = ocr0a/2 to obtain a duty cycle of 50%
  ldi r16, 71
  out ocr0b, r16
  ;enable output at D5 aka oc0b aka Arduino pin 5
  sbi ddrd, 5
  loop:
  rjmp loop

Wiring is good and the buzzer too, since it works with a C sketch

EDIT: I found my answer by myself (with the help of answerers). I was accessing IO ports (tccr0a and tccr0b) with sts, while i had to use out. (tccr0a and tccr0b are IO ports defined in "m328pdef.inc" as IO addresses, not as memory addresses)

9
  • A common way to gain more insight in these sort of cases is to: * compile with optimizations turned off: -O0 * tell gcc to preserve intermediate artifacts (the assembly file generated: -S or --save-temps) Commented Sep 6, 2016 at 20:52
  • I don't use gcc. I use avra
    – Frazzo
    Commented Sep 6, 2016 at 21:04
  • You said that the buzzer works with a C sketch. How did you compile it? Commented Sep 6, 2016 at 21:10
  • For compiling C sketches i use Arduino IDE, that uses gcc i think, but for asm compiling i use avra, the AVRStudio assembler
    – Frazzo
    Commented Sep 6, 2016 at 21:12
  • 1
    Right. My advice was to observe the intermediate file produced by gcc (you can tell it to preserve the assembly sources) and use them as reference for debugging your own asm program. Commented Sep 6, 2016 at 21:15

1 Answer 1

0

I translated you program to GNU as syntax, and it works as expected: I get a 440 Hz square wave on digital pin 5. Here is the translated program:

#include <avr/io.h>

; I'm too lazy to always type the full name of these macros
#define io(reg) _SFR_IO_ADDR(reg)
#define mem(reg) _SFR_MEM_ADDR(reg)

_a = 141 ;(16000000 / 256) / 440(frequency of A) - 1

  ;wgm02..0 = 7 (fast pwm, top = ocr0a)
  ;cs02..0 = 4 (N=256)
  ;com0b1..0 = 2 (clear on compare match, set at bottom)
  ldi r16, 0b00100011
  sts mem(TCCR0A), r16
  ldi r16, 0b00001100
  sts mem(TCCR0B), r16
  ;ocr0a = _a to obtain 440Hz
  ldi r16, 141
  out io(OCR0A), r16
  ;ocr0b = ocr0a/2 to obtain a duty cycle of 50%
  ldi r16, 71
  out io(OCR0B), r16
  ;enable output at D5 aka oc0b aka Arduino pin 5
  sbi io(DDRD), 5
  loop:
  rjmp loop

As shown in my comment to your question, I suspect the problem is a misunderstanding of the meaning of things like tccr0a and ocr0a. In the translated version above, I admit I do not know what TCCR0A and co. mean. And I need not to: I can treat these as opaque identifiers, as the avr-libc recommends to always use them with the macros _SFR_IO_ADDR() and _SFR_MEM_ADDR(), which provide the I/O address and the data address of the register respectively.

I do not know how to use avra, so I cannot tell you how the get the I/O or data address of a register. But there certainly must be a way. You should always use the data address with sts and the I/O address with out and sti.

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.