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:
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
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)