Hardware - not simulation

A project log for AVR Asm Exam

Doing the "exam" of the AVR assembly course

Michael MöllerMichael Möller 03/31/2021 at 21:200 Comments

The hardware version will be "slightly delayed", as in probably never done. My soldering skills on a perfboard are not that great, and I have misinterpreted the pinout of the chip.

Initializing the SPI

In the simulation it was sufficient to

; Set MOSI and SCK output, all others input
ldi r17,(1<<DD_MOSI)|(1<<DD_SCK)
out DDR_SPI,r17
; Enable SPI, Master, set clock rate fck/4
ldi r17,(1<<SPE)|(1<<MSTR)
out SPCR,r17

 which is more or less what the ATmega datasheets gives as example. 

In RealLife® it is not that simple. I discovered that the Arduino itself would hang every now and then when putting data on the SPI (and that took a long to debug - never seen it do that before). It did so whether something was connected or not. If I used the library


it would not hang. (I had other issues with my circuit, so not everything worked, but a) the Arduino did not hang and b) the few LEDs I did control where behaving as expected) It did not matter whether I used a pure C that did direct port access to initialize or assembly.

I got the assembly listing from the generated C code with SPI.begin(), and the proper way to setup the SPI seems to be

   ; set pin 10 high,to avoid an initial pulse
   in   Tmp,PORTB
   ori  Tmp,0B00000100  ; pin 10
   out  PORTB,Tmp
   ; now set it output
   in   Tmp,DDRB
   ori  Tmp,0B00000100  ; pin 10
   out  DDRB,Tmp
   ; Set the SPI controls (needs to be two seperate setting of one bit each?!)
   in   Tmp,SPCR
   ori  Tmp,0b01000000   ; "SPCR |= (1<<SPE);"
   out  SPCR,Tmp
   in   Tmp,SPCR
   ori  Tmp,0b00010000   ; "SPCR |= (1<<MSTR);"
   out  SPCR,Tmp
   ; Now set the 11 and 13 as output
   in   Tmp,DDRB
   ori  Tmp,0b00101000
   out  DDRB,Tmp

That initializes the SPI port without problems ("Tmp" is a synonym for r16)

Afterwards, one has to send SPI commands to the chips to initialize them, this is kindly pointed out in the notes for the project: following sequence of commands: 0f 00 0b 07 0c 01

The first byte is the "row number" of the matrix, but that only goes to 8, so 9-F addresses an internal register in the chip that configures it. In my case this meant the initialization, after the SPI was initialized, continues with

   ; Initialize the chip(s) from their startup state
   cbi   PORTB,CSS       ; Trigger a "new transaction" on MAX7219 (pin 10 LOW)
   ldi   Tmp2,0x0C       ; powersave register:
   mov   Tmp3,One        ;   1 = Power UP
   rcall SendTwo
   ldi   Tmp2,0x0F       ; testmode register
   clr   Tmp3            ;   0 = normal operation
   rcall SendTwo
   ldi   Tmp2,0x09       ; decode mode register
   rcall SendTwo         ;   0 = binary passthrough
   ldi   Tmp2,0x0B       ; scan mode register
   ldi   Tmp3,0x07       ;   up to 7th, ie all 8 digits(=rows)
   rcall SendTwo
   ldi   Tmp2,0x0B       ; intensity register
   ldi   Tmp3,0x07       ;   4 = quarter intensity
   rcall SendTwo

The SendTwo routine just sends the bytes from Tmp2 and Tmp3 on the SPI and waits for completion. Oh, and this only for one chip, I was going to implement a "SendFour" which would duplicate the bytes so both chip (the SPI is daisychained) get the same commands.

The Real Hardware

I screwed up here, a little to eager, and mixed up a few pinouts. The board worked for a while, with only a few matrix row/columns connected, (with the Pong code!) so I know the initialization works, but when fully populating it something happened and I probably will buy a readymade board rather than new Max7219 chips (the throughhole versions are not cheap)