Close

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

SPI.begin()

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)

Over-and-Out

Discussions