SPI on Arduino Mega not working in Assembler

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


I want to use the SPI on an Arduino Mega2560. To keep it simple I am trying to drive a74HC595 shift register. The SPI code is that in the Mega 2560 datasheet and also as I found on-line. 

; SPItest3.asm  Created: 29/11/2019
;*****************************************************************************
.include "./m2560def.inc"

.equ SS_pin   = $0
.equ SCK_pin  = $1
.equ MOSI_pin = $2
.equ test_pin = $4

.org 0x0000
    rjmp reset
.org 0x002E
TIM0isr:								; timer 0 ISR
    inc	r3								; add 1 to the count
    reti							

reset:
    clr	r1								; set the SREG to 0
    out	SREG, r1
    ldi	r28, LOW(RAMEND)						; init the stack pointer to point to RAMEND
    ldi	r29, HIGH(RAMEND)
    out	SPL, r28
    out	SPH, r29
                ;---------------< Timer/Counter 0 >---------------
    ldi	r16, 1								; set the Clock Selector Bits to 001, this puts Timer Counter 0
    out	TCCR0B, r16							; TCNT0 in to FCPU/256 mode so it ticks at the CPU freq/256
    ldi	r16, 	(1<<TOIE0)						; set the Timer Overflow Interrupt Enable (TOIE0) bit
    sts	TIMSK0, r16							; of the Timer Interrupt Mask Register (TIMSK0)
                ;---------------< SPI as Master >---------------
    ldi r17, (1<<PB4)|(1<<PB2)|(1<PB1)|(1<<PB0)				; test, MOSI, SCK & SS are outputs
    out DDRB, r17							; Rest are inputs
    ldi r17, (1<<SPE)|(1<MSTR)|(1<SPR1)|(1<SPR0)			; Enable SPI, Master, Clock = Fosc/128
    out SPCR, r17
    sei		

main:
    sbi PORTB,test_pin							; test HIGH		\
    ldi r21,$2								;			| Make pulse to see on oscilloscope
    rcall delay								;			|
    cbi PORTB,test_pin							; test LOW		/

    ldi r21,$3
    rcall delay
    inc r18								; something to send
    cbi PORTB,SS_pin							; SS low at start of SPI
    rcall SPI_Transmit

    ldi r21,$15
    rcall delay

    sbi PORTB,SS_pin							; SS high at end of SPI, Load data to output of 74HC595

    ldi r21,$3
    rcall delay

    rjmp main

SPI_Transmit:			;-------< Transmit SPI as Master >------
    out SPDR, r18
    in r17,SPSR

SPI_wait:
    in r17,SPSR
    sbrs r17,SPIF
    rjmp SPI_wait
    ret

delay:				;----------< Simple delay function  >--------
    clr	r3								; set count to 0
count:
    mov	r16, r3								; test count
    cp	r16, r21
    brne	count							; continue if not equal
    ret

There is no activity on either the MOSI, SCK pins or SS pin. If I remove the loop waiting for the transmission to end then the SS pin behaves as shown below.

 

The top blue trace is from a separate output (PORTB, 4) to give a trigger for the oscilloscope and the bottom red trace is the output from SS (PORT B, 0) which looks as if it is driving a capacitive load.

When I disable the SPI by setting SPCR to 0x00 I get good fast edges to the pulse which suggests to me that it not the hardware doing this. Using the unaltered hardware I can bit-bash the pins and I hve loaded an Arduino sketch and both methods drive the shift register properly. 

I have been through the code umpteen times and I can't see what is wrong with it so I will be grateful for any help.  

 

Thank you in advance Roger S

This topic has a solution.
Last Edited: Tue. Dec 3, 2019 - 04:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The RED trace looks like your toggling the internal pull up on/off instead of driving the pin as an output!

With SS pin as an input, the SPI will revert to a slave automagicly and will not output anything!

 

I'll let you verify your code as to the above conditions.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Jim,

Thank you for your reply. you were right.

Setting PUD in MCUCR suppressed the pull-ups and SS switched cleanly. However this only cured the symptom but has not corrected the underlying problem: the MOSI and SCK pins still stay at 0v.

I'm going to add a serial link so I can try to monitor what is happening especially if I can work out where to look.

Regards Roger S

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Roger S wrote:

    ldi r17, (1<<PB4)|(1<<PB2)|(1<PB1)|(1<<PB0)				; test, MOSI, SCK & SS are outputs
    out DDRB, r17							; Rest are inputs
    ldi r17, (1<<SPE)|(1<MSTR)|(1<SPR1)|(1<SPR0)	

Are there missing “<“ in the above lines?

 

jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Jim,

You found it, thank you, it is working now. 

As the assembler didn't object to it,  (1<PB2) etc. must have some valid meaning but I don't know what.

 

Best Regards, Roger 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Roger S wrote:
(1<PB2) etc. must have some valid meaning

In 'C', that is a valid boolean expression - it will have a value of either true or false.

 

I guess the assembler takes a similar view?

 

Please see Tip #5 to mark the solution

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...