AVR64DB SPI

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

Hi, i have trouble with SPI. I want to send a 16 bit of data.

Spi CS pin does not stay LOW for second 8 bits of data.

My code:

 

void SPI_Init()                     
{     
    PORTA.DIR |= PIN4_bm;        
    PORTA.DIR |= PIN6_bm;       
    PORTA.DIR |= PIN7_bm;       

    SPI0.CTRLA = 
    SPI_CLK2X_bm    
    | SPI_ENABLE_bm                
    | SPI_MASTER_bm                
    | SPI_PRESC_DIV16_gc;        
    
    SPI0.CTRLA |= SPI_DORD_bp;        
    SPI0.CTRLB |= SPI_MODE_3_gc;    
    SPI0.CTRLB |= 0b11000000;       
}

 

void SPI_Write(unsigned char* data, unsigned char bytesNumber)

{

                    unsigned char MSdata;

                    unsigned char LSdata;

                    LSdata=(((uint16_t)data >> 0) & 0xFF); 

                    MSdata=(((uint16_t)data >> 8) & 0xFF);

      

                    SPI0.DATA = MSdata;

                    SPI0.DATA = LSdata;

                    while (!(SPI0.INTFLAGS & SPI_DREIF_bm)){;};

}

 

USE OF FUNCTION:

 

CS_LOW;     

SPI_Write(data,2);

CS_HIGH;

 

Looking forward to your answers.

Attachment(s): 

Last Edited: Sat. Apr 9, 2022 - 07:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A suggestion if you want people to help...

 

1) Don't mix the use of bit masks and hard coded values. In fact, never use hard coded values. Your reader is going to have to page through the datasheet to decode what they mean.

 

2) When referring to an IO pin, ALWAYS give it a meaningful name. PIN6_bm means nothing to me. What function does it have?

 

3) Put comments in your code. Tell people what you are doing and why.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

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

The init looks like a racing wreck. What happened? Bits & pieces all over the track.

Always use = for init assignments (unless there is a pressing reason not to).

 

    PORTA.DIR = PIN4_bm | PIN6_bm | PIN7_bm;       
    SPI0.CTRLA = SPI_CLK2X_bm | SPI_ENABLE_bm | SPI_MASTER_bm | SPI_PRESC_DIV16_gc | SPI_DORD_bp;        
    SPI0.CTRLB = SPI_MODE_3_gc | 0b11000000;  

 

Without looking at details, I suspect the checking (while (!(SPI0.INTFLAGS & SPI_DREIF_bm)){;};)

is tripped by the first write conclusion & is still valid at time of 2nd write (noting resets it)...so it passes through and returns while the 2nd is still going

 

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

Last Edited: Sat. Apr 9, 2022 - 09:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's so much wrong with your SPI_Write() code here:

 

  1. Your parameter {bytesNumber} suggests SPI_Write allows an arbitrary number of bytes to be transmitted. However you always transmit exactly 2 bytes.
  2. data is a pointer and you don't dereference it.
  3. data is a pointer to unsigned char and you don't increment it to get to the second byte.
  4. Because you are using BUFFER mode you MUST wait until the SPI transfer is complete before dropping CS - but you don't (Are you sure CS polarity is right ? 99 out of 100 SPI devices have CS active high).

 

Try This Modification:

 

void SPI_Write (unsigned char* data, unsigned char bytesNumber)
{
    if (bytesNumber == 0)
        return;

 

    /* Assume SPI is NOT busy so write 1st byte immediately */
    SPI0.DATA = *data++;

 

    /* Transmit more bytes if required */
    while (--bytesNumber) {

        /* Wait for SPI Buffer to become ready for more data before writing data out. */
        while ((SPI0.INTFLAGS & SPI_DREIF_bm) == 0) ;

        SPI0.DATA = *data++;
    }
    
    /* Wait for SPI Transfer Complete */
    while ((SPI0.INTFLAGS & SPI_TXCIF_bm) == 0) ;

 

    /* Clean-up by clearing the INTFLAGS */
    INTFLAGS = 0xff;
}

Last Edited: Sat. Apr 9, 2022 - 09:55 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm not good at explaining.

But I can show you the code that will probably work.
I can explain only one. ENABLE should be last.

 

void SPI_Init(void){
    PORTA.DIRSET = PIN4_bm | PIN6_bm | PIN7_bm;
    SPI0.CTRLB = SPI_BUFEN_bm | SPI_BUFWR_bm | SPI_SSD_bm | SPI_MODE_3_gc;
    SPI0.CTRLA = SPI_DORD_bm | SPI_MASTER_bm | SPI_CLK2X_bm | SPI_PRESC_DIV16_gc | SPI_ENABLE_bm;
}

 

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

Thank you for your comments and suggestions.

It is really helpfull.

 

I added comments to my code as recommended.

I tried code from Winterbottom. 

The CS works now.

 

Im facing a problem with data, which is transmitted.

I thought buffer mode enables 16 bit to be transmitted over SPI. Am i right?

When i pass 0000000001000000 to the spi_write function, it shows different value on my scope, when decoded.

I checked decode settings on my scope many times. I belive scope decodes correctly.

Any ideas?

 

Thanks in advance

Attachment(s): 

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



I checked decode settings on my scope many times. I belive scope decodes correctly.

What are you talking about...you see the bits yourself, there is little to believe

  

Try sending 8 bits first , make sure you have it ironed out.  Then move up to 16.

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

AVRmagic wrote:
I thought buffer mode enables 16 bit to be transmitted over SPI. Am i right?

No - The buffer allows continuous "gapless" transmission which may or may not be important; but more significantly, greatly reduces the timing constraints particularly when operating as a slave.

 

Where you've gone wrong is not understanding your function signature of SPI_Write:

 

Let's write the comment header for this function:

/**
 * @fn		SPI_Write
 * @brief	Transit an arbitrary length message as SPI Master
 * @param	data: Pointer to array of bytes pre-loaded with your SPI transmit message.
 * @param	bytesNumber: The number of bytes to be transmitted.
 * @note	SPI Hardware must be previously configured as Master.
 */
void SPI_Write (unsigned char* data, unsigned char bytesNumber)

 

I hope you now understand the function parameters and know why you have to call the function in the following manner:

unsigned char SPI_Message[2];
SPI_Message[0] = 0b00000000;
SPI_Message[1] = 0b01000000;
SPI_Write(SPI_Message, 2);

 

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

N.Winterbottom wrote:
99 out of 100 SPI devices have CS active high

 

But not this one.

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

N.Winterbottom wrote:
(Are you sure CS polarity is right ? 99 out of 100 SPI devices have CS active high).

 

I would claim that 99 out of 100 SPI devices have CS active LOW

 

But you certainly get both types of SPI device.

 

David.