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

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 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

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 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...