Maker Pro
Maker Pro

SS not working on spi

I am a little new to programming spi and need help with a tiny 416. I am trying to talk to a slave 25r3911b from STMicroelectronics. I am using the below function to send a task to the slave. Basically read the operation control register.

Code:
void Read25r3911b (uint8_t commandaddress)
{   uint8_t data;
    uint8_t TEMP;
    TEMP=commandaddress;
 
    PORTC_set_pin_level(3,low);
 
    SPI_0_write_block(&TEMP,1);
 
    PORTC_set_pin_level(3,high);
 
 

//    SPI_0_read_block(&TEMP,1);
 
 
}
It is giving the expected output on the MOSI of 0x42. The problem is the chip select is going high on the SS.
 

Attachments

  • Untitled2.png
    Untitled2.png
    29.9 KB · Views: 1
Last edited by a moderator:

Harald Kapp

Moderator
Moderator
I pt your code in a code box for better readability.

By SS you mean Slave Select which would be SPI-Enable in your screenshot, right? I recommend you use the same terms in text and image to allow us to correlate items. I further assume that Port C3 is the SPI-Enable signal.
The problem is the chip select is going high on the SS.
I think (and this is purely my interpretation) the issue you experience is that the SPI write cycle is executed asynchronously to your program by the hardware SPI unit. Meaning:
You set SPI-Enable low, then start the SPI write cycle and immediately set SPI-Enable to high. But the SPI write cycle continues in hardware in parallel while the program also continues. Therefore SPI-Enable goes high too early.
Remedy: After SPI_0_write... put in a loop and check the SPI status. Continue with PORTC_set_pin_level(3, high) only after the SPI transfer has completed.
See e.g. here.

Hope this helps.
 
I think your right. That helps. I am still confused when I look for the interupt flag it, the ss pin is still going high too soon.

void Read25r3911b (uint8_t commandaddress)
{ uint8_t data;
uint8_t TEMP;
TEMP=commandaddress;

PORTC_set_pin_level(3,low);

SPI_0_write_block(&TEMP,1);
while (((SPI0.INTFLAGS >> 6) & 1) == 1);



SPI_0_write_block(&TEMP,1);
while (((SPI0.INTFLAGS >> 6) & 1) == 1);



PORTC_set_pin_level(3,high);



}
 

Attachments

  • Untitled4.png
    Untitled4.png
    30.9 KB · Views: 1

Harald Kapp

Moderator
Moderator
In between these instructions
Code:
PI_0_write_block(&TEMP,1);
while (((SPI0.INTFLAGS >> 6) & 1) == 1);



SPI_0_write_block(&TEMP,1);
while (((SPI0.INTFLAGS >> 6) & 1) == 1);
you need to clear the interrupt flag. A little bit further in the discussion I linked in post #2 you'll find this box:
• Bit 7 – SPIF: SPI Interrupt Flag
When a serial transfer is complete, the SPIF Flag is set. An interrupt is generated if SPIE in
SPCR is set and global interrupts are enabled. If SS is an input and is driven low when the SPI is
in Master mode, this will also set the SPIF Flag. SPIF is cleared by hardware when executing the
corresponding interrupt handling vector. Alternatively, the SPIF bit is cleared by first reading the
SPI Status Register with SPIF set, then accessing the SPI Data Register (SPDR)
It seems you didn't do this (either by adding a suitable interrupt routine or by clearing the flag in software). Therefore when your program reaches the 2nd SPI_0_write_block instruction the interrupt flag is still high and the loop after the SPI_0_write_block instruction is never executed, leading to PORTC_set_pin_level(3,high); being immediately executed.

By the way:
  1. Code is easier to read if you use the insert code menu entry (menu bar, left of the sub/sup button.
  2. I recommend you increase the resolution of your logic analyzer to improve the accuracy of the display. With your current resolution e.g. the clock signal is not symmetrical, which is surely not due to a fault in the hardware but an artifact of sampling at too low a rate.
 
uint8_t Read25r3911b (uint8_t commandaddress)
{ uint8_t data;
uint8_t TEMP;
TEMP=commandaddress;

PORTC_set_pin_level(3,low);

SPI_0_write_block(&TEMP,1);
while ((SPI0.INTFLAGS & SPI_RXCIF_bm) == 0) ;
SPI0.INTFLAGS &= ~(1<<INTERUPT_FLAG);
// while (SPI_0_status_done());

// SPI_0_write_block(&TEMP,1);
// while (((SPI0.INTFLAGS >> 6) & 1) == 1);



SPI_0_read_block(&TEMP,1);
while ((SPI0.INTFLAGS & SPI_RXCIF_bm) == 0) ;
SPI0.INTFLAGS &= ~(1<<INTERUPT_FLAG); //INTERUPT_FLAG is 7

PORTC_set_pin_level(3,high);


SPI_0_read_block(&TEMP,1);
while ((SPI0.INTFLAGS & SPI_RXCIF_bm) == 0) ;
SPI0.INTFLAGS &= ~(1<<INTERUPT_FLAG);

//PORTC_set_pin_level(3,high);

// while (SPI_0_status_done());
return TEMP;
}
 
I am not seeing a sup/sub button nor a button that is will isolate the code. I clear RXCIF/IF and it is still messing with spi communication.
 

Attachments

  • Untitled5.png
    Untitled5.png
    119.4 KB · Views: 1
Top