spi ideas for dual byte

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

I am upgrading a mega88 board to rcv some rather slow spi data (rcv as a slave, nothing needs sent).  The data has this protocol, from another device sending a rotating shaft RPM & can't be changed:  cs goes low, RPM lsb sent, 16 bits total, RPM msb last, clocked on rising edge,  after 16 clocks, cs goes high.

Since it is slowly incoming from a slow clocking, I don't want to poll between bytes & yet need to stay synchronized with the CS falling edge (so the bytes don't get accidentally swapped).  There might be times where the reading can't occur, due to other things being busy (missing a read is allowable).  

I thought about using SPI interrupts, which would eliminate a lot of excess polling, but not sure if there is a simple way to keep track of which byte is which.

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

avrcandies wrote:
but not sure if there is a simple way to keep track of which byte is which

 

Simple flag, and a byte counter?

 

In other words at runtime, clear a flag called 'SPI_FOO', and a 'FOO_CNTR', enable the interrupt for SPI RX

 

Then when the first byte comes in the ISR sets the flag and increments teh counter by one., when Main sees the flag set it checks the counter, and reacts accordingly?

 

I am not sure how this would work in reality - Therefore I reject reality and substitute my own cheeky

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

avrcandies wrote:
if there is a simple way to keep track of which byte is which.
Doesn't the CS do that? Immediately after the CS it's low then high isn't it?

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

Can we assume CS is an input to AVR ?

If so; then use that edge as your synchronisation.

 

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

jgmdesign wrote:
Simple flag, and a byte counter?

+1

 

In fact, you might not even need the counter - just use the flag to mark "first byte" ?

 

EDIT

         :                              :
         :                              :
      ___                                ______
CS       |______________________________|
         :                              :
         :                              :
Data  .... | byte 0 | ... |byte 1| ....
         :          :            :      :
         :          :            :      :
         :          :            :      :
         1          2            3      4
  1. CS falls: start of the transmission - so the next byte received will be the 1st byte
    Set first_byte = true;
     
  2. 1st SPI interrupt: first_byte flag tells you that this is the 1st byte.
    Set first_byte = false;
     
  3. 2nd  SPI interrupt: first_byte flag tells you that this is not the 1st byte - so must be the 2nd byte
     

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...
Last Edited: Wed. Apr 14, 2021 - 05:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
Since it is slowly incoming from a slow clocking,

if it is slow you can also bit-bang it, and just keep count of the bits received, reset bit counter on /cs.

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

Doesn't the CS do that? Immediately after the CS it's low then high isn't it?

True, however, at both times of the SPI "RX" irq, the CS will be low, so that in itself doesn't indicate which byte is which.

 

CS falls: start of the transmission - so the next byte received will be the 1st byte
Set first_byte = true;

cs falls... So this CS interrupt is not from the spi block, but needs to be a general IO interrupt?  Then the 2 types of interrupts need "coupled" via the (1st/2nd) byte flag (CS irq)?   This was the approach I was heading towards

but was wondering if this could be handled entirely with just the spi functionality. 

 

The falling edge of cs definitely needs detected, so that the 2nd byte doesn't get confused with the first (such as if we begin looking at incoming byes at some random powerup---then they might forever remain swapped).

 

if it is slow you can also bit-bang it, and just keep count of the bits received, reset bit counter on /cs.

That's exactly where I was starting, but had some concern, since I may "get busy" and miss polling some bits (then a real mess!!)...so I thought, set up an clk interrupt (rather than poll)...so one CS irq for sync & one clk irq for grabbing bits...then I had the idea..let the spi block do the work & hence my question.  Was hoping one spi irq could handle the entire process, but sounds like it can't quite.

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Wed. Apr 14, 2021 - 05:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

Doesn't the CS do that? Immediately after the CS it's low then high isn't it?

True, however, at both times of the SPI "RX" irq, the CS will be low

I think he meant low byte, then high byte ?

 

 

cs falls... So this CS interrupt is not from the spi block, but needs to be a general IO interrupt? 

Doesn't necessarily need to be an interrupt - you could poll it.

 

Do you have the CS connected to the SPI block?

If so then, surely, it will only ever receive while CS is low - so counting the bytes is easy

 

 

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have the CS connected to the SPI block?

If so then, surely, it will only ever receive while CS is low - so counting the bytes is easy

yes SS on the avr slave is connectd to CS of the sender.

 

 The CS is low for the entire time both bytes are sent to the AVR slave.

 

However, does the spi block keep track of which byte is which?  There needs to be some sync to the fallling cs edge to mark the first of 2 bytes incoming---does the spi provide that? 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

avrcandies wrote:
However, does the spi block keep track of which byte is which?  There needs to be some sync to the fallling cs edge to mark the first of 2 bytes incoming---does the spi provide that? 

 

What difference does it make?  When /CS goes low, theres your indication that the first byte is on the way. 

 

From teh Datasheet:

When configured as a slave, the SPI interface will remain sleeping with MISO tri-stated as long as the SS pin is driven high. In this state, software may update the contents of the SPI data register, SPDR, but the data will not be shifted out by incoming clock pulses on the SCK pin until the SS pin is driven low. As one byte has been completely shifted, the end of transmission flag, SPIF is set. If the SPI interrupt enable bit, SPIE, in the SPCR register is set, an interrupt is requested. The slave may continue to place new data to be sent into SPDR before reading the incoming data. The last incoming byte will be kept in the buffer register for later use.

 

 

Further on in teh datasheet:

SS Pin Functionality16.1.1 Slave Mode

 

When the SPI is configured as a slave, the slave select (SS) pin is always input. When SS is held low, the SPI is activated, and MISO becomes an output if configured so by the user. All other pins are inputs. When SS is driven high, all pins are inputs, and the SPI is passive, which means that it will not receive incoming data. Note that the SPI logic will be reset once the SS pin is driven high.The SS pin is useful for packet/byte synchronization to keep the slave bit counter synchronous with the master clock generator. When the SS pin is driven high, the SPI slave will immediately reset the send and receive logic, and drop any partially received data in the shift register.

 

 

So you should be able to just use teh flag I suggested and the SPI RX Interrupt to keep your code in sync.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

avrcandies wrote:
 The CS is low for the entire time both bytes are sent to the AVR slave.

So as I showed in my diagram in #5, then?

 

 does the spi block keep track of which byte is which? 

#5 showed how you do that.

 

There needs to be some sync to the fallling cs edge to mark the first of 2 bytes incoming---does the spi provide that? 

The SPI can only receive while CS is asserted - ie, low.

 

So, if you're getting bytes received, then CS must be low. Your code doesn't really need to track CS.

 

  1. When you start up, you set first_byte = true
     
  2. When you receive a byte, it must be the first byte; so now you set first_byte = false
     
  3. When you receive the next byte, it must be the 2nd byte - because the first_byte flag is false
    SO now you have your 2 bytes.
    Set first_byte = true
     
  4. Repeat from (2).

 

Maybe you want a second flag for "both bytes received" ?

 

volatile bool first_byte;
volatile bool both_bytes_received;

uint8_t buffer[2]; // buffer to hold the 2 bytes

SPI ISR()
{
    if( first_byte )
    {
        buffer[0] = received byte
        first_byte = false; // the next byte will be the 2nd byte of this pair
    }
    else
    {
        buffer[1] = received byte
        both_bytes_received = true; // received both bytes of this pair
        first_byte          = true; // the next byte will be the 1st byte of the next pair
    }
}


main()
{
    first_byte = true;
    both_bytes_received = false;
    
    enable spi slave
    
    :
    :
    
    while(1)
    {
        :
        :
        
        if( both_bytes_received )
        {
            handle the pair of bytes
        }
        :
        :
        
    }
}

 

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For maximum automation and least beauty:

Wire /SS to input_capture.

When reading the SPI byte, also check the time.

Comparing the time with the captured value will tell you which byte it is.

Moderation in all things. -- ancient proverb

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

Is /SS independently asserted for each byte or is it held low continuously for the two byte transfer?

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

 

When you receive a byte, it must be the first byte;

Why is that---does the spi reject the byte unless it see a cs edge?   not from what I read.. just because CS is low does not mean it is the first byte of the AB AB AB ...sequence (power can be applied just as B is about to be sent out) & CS will, of course, be low.

Can the spi provide assurance that when it starts up, it syncs so that only A is reported as the correct part of AB. 

 

The SS pin is useful for packet/byte synchronization to keep the slave bit counter synchronous with the master clock generator.  sounds like an additional irq is needed independent of the spi blocok to  enusre tsync to the first byte

 

For maximum automation and least beauty: Wire /SS to input_capture.

When reading the SPI byte, also check the time.  Comparing the time with the captured value will tell you which byte it is.

    ...yep I was thinking some independent  (from the spi block) secondary CS irq is needed, but was hoping otherwise (perhaps something nifty provided by the spi section). 

 

I haven't seen any way to do it without monitoring CS independently of the SPI block (and the origination of my question).

Another way might be to monitor (via some means) when CS goes high---if 2 bytes were not rcvd by then, then the reception was partial & should be tossed in the trash.

 

what I need to avoid is bytepairs   [B],[CD],[EF],[GH]... being decoded as [BC], [DE], [FG]  due to missing "A" (due to powerup, system busy, etc)

 

 

 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Apr 15, 2021 - 12:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


If a pin is used for SS, can it also be used for PCINT2?  I't not clear from the datasheet.   If so, then you could reset a byte counter on falling edge and latch data on rising edge, provided you got two bytes.

 

 

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

avrcandies wrote:
Why is that---does the spi reject the byte unless it see a cs edge? 

 

From the datasheet:

jgmdesign wrote:
When configured as a slave, the SPI interface will remain sleeping with MISO tri-stated as long as the SS pin is driven high

 

So, if your master sends a byte and does not bring /SS low FIRST then the byte is ignored as the block is sleeping.  Then again, why would the master not assert /SS?

 

It is starting to look like you are over thinking this.  Make a cup of tea/coffee and come back after you have enjoyed that,  works for me.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

So, if your master sends a byte and does not bring /SS low FIRST then the byte is ignored as the block is sleeping.  

well ---the  master does bring CS low then sends out 2 bytes....

 

However down at the AVR Garage, it just powered up or was held up doing something else, or ignored spi during initialization.  So now CS is low & a byte is reported incoming...how does it kniow it is the first or second byte?  If it calls it the first (when really the second), it will be forever out of kilter.   Seems like the SPI block should be made adjustable so the CS edge could start things off.  Alas, not in the cards.

It is starting to look like you are over thinking this.  Make a cup of tea/coffee and come back after you have enjoyed that,  works for me.

That is always a winner!

 

I think MattRW came to the same conclusion as me. 

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

avrcandies wrote:
If it calls it the first (when really the second), it will be forever out of kilter.   Seems like the SPI block should be made adjustable so the CS edge could start things off.  Alas, not in the cards.

 

Candyman....

The SPI block has no idea what your "protocol" is, or what is byte 1, 2 or 102.  The SPI block sees a byte come in when the /SS line is low and thats it.  The same thing goes for the USART, and TWI as well.

 

Your code needs to perform the synchronisation.  Hence the Flag approach I suggested, and Andy has been building on.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Hence the Flag approach I suggested, and Andy has been building on.

Well that doesn't seem to provide sync, since if CS is merely low, it could be either byte.  

 

I used a 16 bit dac chip many times...you set cs low, pump out the 16 bits, then pull cs high.

If some of the 16 bits are missing for some reason (such as the dac powering up while transmission happening), the dac has no confusion, it is tossed & the next batch of 16 resumes normal operation.

 

I want the equivalent operation for the AVR when I send it 16 bits from some master--so it acts like the simple dac (or with minimal fuss).  Apparently only adding something outside of the spi block will do the trick, unless there is a commonly used routine out there.  Has ayone actually used the avr as a 16 bit slave?

 

Originally, I was going to bit-bang the reception, but thought I'd try using the SPI block (I usually bit-bang transmission).

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Apr 15, 2021 - 02:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How much time elapses after your sender quits pulling your /ss low? (edit- time from when isr is triggered to when /ss goes high) If soon enough, then ss status tells you all you need from within the isr, it would seem. Or if the time will be soon enough but needs a little extra help you could kill some time in the isr, up to a point. If the sender takes too much time to de-assert, then no longer a great idea.

 

volatile u16 rpm;

ISR(){

    static u16 rpm_;

    if( ss_isLow() ){

        rpm_ = SPDR; //lsb

        //rpm = 0; //optionally indicate new value on its way

    }

    else {

        rpm_ |= SPDR<<8; //msb

        rpm = rpm_;

    }

}

Last Edited: Thu. Apr 15, 2021 - 03:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 If soon enough, then ss status tells you all you need from within the isr, it would seem

Thanks!...that is an interesting idea & exactly the type of thing I was looking for (or any similar tricks anyone has used)... I'd prob add a byte count, so if it wasn't at byte 2 when ss went high in the isr, the whole reception would get tossed(due to only 1 byte rcvd).

Have to be a little careful that the next batch of two bytes doesn't get sent immed, or the ss ending check will fail (even with slow spi clock, could still have byte pairs packed like random sardine bursts).

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

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

>I'd prob add a byte count, so if it wasn't at byte 2 when ss went high in the isr, the whole reception would get tossed(due to only 1 byte rcvd).

 

volatile u16 rpm;
ISR(){
    static u8 lsb;
    static u8 state; //1=lsb, 2=msb, all others invalid

    u8 data = SPDR; //read always
    switch( state + ssIsLow() ){ //0+1=1=lsb, 2+0=2=msb             
        case 1: lsb = data; state = 2; break;
        case 2: rpm = (data<<8)|lsb;

        //fallthrough
        default: state = 0; break;
    }   
}

Last Edited: Thu. Apr 15, 2021 - 08:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
I'd prob add a byte count,

As there's only 2 bytes, you don't need an actual count; just a bool flag will do - it's either the first byte, or it's the 2nd byte.

 

 

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
Well that doesn't seem to provide sync, since if CS is merely low, it could be either byte.  
You don't act on the LEVEL of CS you act on the EDGE!

 

When you see a high-low transition on the CS input you note the fact and reset your byte counter (or 0/1 flag as Andy says). After that you can ignore the CS. The byte count is now 0. An SPI interrupt fires. That is byte 0. You now increment the byte counter. Another SPI interrupt fires, that is byte 1. If more SPI interrupts fire simply ignore them you are now back to waiting for a 1->0 transition on CS. When the happens the whole process starts over again.

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

avrcandies wrote:
does the spi reject the byte unless it see a cs edge?

The SPI ignores everything unless CS is asserted (low) - so you won't get any bytes from the SPI unless CS is low

 

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...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you see a high-low transition on the CS input you note the fact and reset your byte counter (or 0/1 flag as Andy says).

Well, of course.  However if using the spi interrupts, I don't "see" anything ahead of time to make a note, so that was my question...whether there was some way the spi section could provide sync to the first byte & avoid adding another irq (in case I was overlooking some simple/obvious means).  Otherwise 2 interrupts are needed working in concert---one spi & one independent (non-spi).  So far the only alternative was provided by curtvm & sounds viable to use only the spi irq.

Too bad spi doesn't provide some sort of flag after the first byte in the chain,  then auto-resets after the first read.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!