SPI MISO always return me 0

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

Hello,

 

I have already done a topic for my SPI problem but I do an other one because I have much more informations !

I work with a microcontroleur SAM3X8E (https://ww1.microchip.com/downlo...) and I need to make a SPI connection with a screen (as slave).

 

The problem is that my spi_transmit(data) function always return me 0 and I don't know why...

 

This is my function :

 

static inline uint8_t spi_transmit(uint8_t data)
{	
	printf("Donnee a envoyer : %i \n", data);
	uint8_t data_send = SPI_TDR_TD(data);
	
	//Transmission
	while ((SPI0->SPI_SR & SPI_SR_TDRE) == 0);
	
	SPI0->SPI_TDR = data_send;
	printf("Transmis : %i \n", data_send);
	
	//Read
	while ((SPI0->SPI_SR & SPI_SR_RDRF) == 0);
	
	uint8_t data_read = SPI0->SPI_RDR;
	printf("Lu : %i \r\n", data_read);
	
	return data & SPI_RDR_RD_Msk;
}

It's inspire from the Arduino SPI transfer one. 

 

When I run my code, this is what I have : 

 

[look at the file attachement name : Capture d’écran 2021-06-01 120152]

 

The data seems to be send but when I try to read I always have 0...

 

I used an oscilloscope to understan this problem and this is what I have (SPI MISO in purple and SPI SCLK in yellow) :

 

[look at the file attachement name : SDS00005]

 

Do you have any idea about this problem ?

 

/* Configure SPI0 pins */
gpio_configure_pin(SPI0_MISO_GPIO, (PIO_PERIPH_A | PIO_DEFAULT));
gpio_configure_pin(SPI0_MOSI_GPIO, (PIO_PERIPH_A | PIO_DEFAULT));
gpio_configure_pin(SPI0_SPCK_GPIO, (PIO_PERIPH_A | PIO_DEFAULT));

/* Initilization of SPI */
spi_enable_clock(SPI0);

spi_disable(SPI0);
spi_reset(SPI0);
spi_set_lastxfer(SPI0);
spi_set_master_mode(SPI0);
	
spi_disable_mode_fault_detect(SPI0);
spi_set_peripheral_chip_select_value(SPI0, SPI_CHIP_PCS);
	
spi_set_clock_polarity(SPI0, SPI_CHIP_SEL, SPI_CLK_POLARITY);
spi_set_clock_phase(SPI0, SPI_CHIP_SEL, SPI_CLK_PHASE);
	
spi_set_bits_per_transfer(SPI0, SPI_CHIP_SEL, SPI_CSR_BITS_8_BIT);
spi_set_baudrate_div(SPI0, SPI_CHIP_SEL, (sysclk_get_peripheral_hz() / gs_ul_spi_clock));
	
spi_enable(SPI0);

 

 

Attachment(s): 

This topic has a solution.
Last Edited: Mon. Jun 7, 2021 - 02:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What screen? Do you really have to read from the screen?

/Lars

 

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

Lajon wrote:

What screen? Do you really have to read from the screen?

/Lars

 

 

the datasheet of the screen is : https://fr.rs-online.com/web/p/e...

 

Yeah I need it ! I think there is a problem with my chip select which don't wait all the byte to make the transfer...

Last Edited: Wed. Jun 2, 2021 - 07:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your links don't seem to work very well.   However it looks as if your Screen is made by Riverdi and uses a BT815 (EVE3) controller.

 

I Googled "bt815 programming manual" and found "BRT_AN_033 BT81X Series Programming Guide" from BridgeTek.

I also found https://github.com/riverdi/riverdi-eve-arduino which should work with any regular Arduino e.g. Due

 

It should be straightforward to read the ID from the BT815 controller.

 

I have never used EVE style controllers but they are mature and should be well supported.

 

I would start with Arduino examples.   However you can program the SAM3XE in bare metal if you like.   I would start with a familiar SPI chip.  Then use the appropriate SPI sequence to read the BT815 ID i.e. read 4 bytes of data from address 0xC0000

 

David.

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

Yeah sorry I edit my post now the link is available !

 

I have an Arduino program which works well, this is why i try to pass on Atmel 7 so I need to rewrite functions already implemented by arduino like SPI.transfer(...)

 

The problem of my system actually is that the Chip Select don't wait for all the bytes and send it...

 

I will look at your link thank you man !

Last Edited: Wed. Jun 2, 2021 - 07:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

[look attachement file : SDS00001.png]

 

This is what I get with my oscilloscope and I need the purple line (Chip Select) during all the yellow line (SCLK) variation.

I don't know why but in my case at each transfer the Chip Select rise...

Attachment(s): 

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

You can make /CS disable automatically in hardware when the transaction is complete.

Or you poll for completion in software.  Disable /CS manually when transaction is complete.

 

The SAM3X datasheet explains.

 

For short SPI sequences it really makes little difference if you poll manually.

You only "lose" a few nanoseconds of compute time.

 

For a long DMA sequence you want to be using the DMA time for calculations, composing your next sequence,  ...

You would disable /CS when the DMA interrupts at completion.

 

David. 

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

Yeah normally I pilote the CS to go down after transaction manually but I don't why, my function spi_transmit(data) makes the CS rise up...

 

I do something like that :

uint8_t ftData8;

EVE_cs_set(); //CS at 0

spi_transmit_32(...); //Make 4 spi_transmit(...)
ftData8 = spi_receive(0x00); /* read data byte by sending another dummy byte */

EVE_cs_clear(); //CS at 1

return ftData8;	/* return byte read */

 

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

   normally I pilote the CS to go down after transaction manually

 

/CS is active low, should go High after transaction.

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

Yeah it's go high my bad... But i think I have find the solution of my problem with the SPI Chip Select Register ! thank you guys

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

PierreBoss wrote:
I don't why, my function spi_transmit(data) makes the CS rise up

Are you sure this is correct:

EVE_cs_set(); //CS at 0

 

EVE_cs_clear(); //CS at 1

 

show your implementations of those functions (or macros) - usually "set" means to set something to '1' (high) and "clear" means clear it to '0' (low) ...

 

As  grohote noted, CS is active low.

 

"assert" and "release" might be better names ... ?

 

or "activate" and "release" ?

 

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

...or synchronize, because /CS is just doing it, so the Slave will do own SPI housekeeping any time when /CS goes low.

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

Yeah that's correct, it's just weird name of function ! (because CS is active low they put set() for '0' and clear() for '1')

 

I have somes news. I desactivate the rise of my CS after a transfer thank to the register SPI_CSR 

I initialize my CS like a GPIO to control it thanks to pio_set_pin_low(CS) and pio_set_pin_high(CS). I saw on a forum that it's the only solution to make multi transfer bytes with SPI. Now my CS works well but my MISO still return 0...

 

I verified that my MOSI, CS and CLK are correct and they are but not my MISO. I have somes screens of my oscilloscope please look at it in attachement! I have correcte oscilloscope that come from Arduino code which start the screen and bad oscilloscope that come from my actual code.

 

Do you have any idea about that ?

 

Edit : 

 

this is my actual function :

 

static inline uint8_t spi_transmit(uint8_t data)
{
	while ((SPI0->SPI_SR & SPI_SR_TDRE) == 0);

	spi_write(SPI0, data, SPI_CHIP_SEL, 0);

	while ((SPI0->SPI_SR & SPI_SR_RDRF) == 0);

	uint8_t data_read, Chip_Sel_read;

	spi_read(SPI0, &data_read, &Chip_Sel_read);

	return data_read;
}

And this is my SPI initialization :

/* Configure SPI0 pins */
gpio_configure_pin(SPI0_MISO_GPIO, (PIO_PERIPH_A | PIO_DEFAULT));
gpio_configure_pin(SPI0_MOSI_GPIO, (PIO_PERIPH_A | PIO_DEFAULT));
gpio_configure_pin(SPI0_SPCK_GPIO, (PIO_PERIPH_A | PIO_DEFAULT)); 
gpio_configure_pin(SPI0_NPCS0_GPIO, (PIO_OUTPUT_1 | PIO_DEFAULT)); //CS

/* Configure an SPI peripheral. */
spi_enable_clock(SPI0);

spi_disable(SPI0);
spi_reset(SPI0);

//spi_set_lastxfer(SPI0);
spi_set_master_mode(SPI0);

spi_disable_mode_fault_detect(SPI0);
spi_set_variable_peripheral_select(SPI0);
spi_set_peripheral_chip_select_value(SPI0, SPI_CHIP_SEL); //SPI_CHIP_SEL == 0

/* data samples on rising edge because Polarity = Phase = 0 */
spi_set_clock_polarity(SPI0, SPI_CHIP_SEL, SPI_CLK_POLARITY);
spi_set_clock_phase(SPI0, SPI_CHIP_SEL, SPI_CLK_PHASE);

spi_set_bits_per_transfer(SPI0, SPI_CHIP_SEL, SPI_CSR_BITS_8_BIT);
spi_set_baudrate_div(SPI0, SPI_CHIP_SEL, (sysclk_get_peripheral_hz() / gs_ul_spi_clock));

SPI0->SPI_CSR[0] |= SPI_CSR_CSAAT;

spi_enable(SPI0); 

Attachment(s): 

Last Edited: Wed. Jun 2, 2021 - 03:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MISO comes from the screen so unless you have a conflict on that signal (from your setup) what you see on the scope should not depend on the SAM3X8E MISO SPI setup.

Is the screen working, i.e., correctly setup, not in power down, waited for it to startup etc? From the link in post #4:

    /* access address 0 to wake up the chip */
    Gpu_HostCommand(phost,GPU_ACTIVE_M);
    Gpu_Hal_Sleep(300);

    Gpu_HostCommand(phost,GPU_INTERNAL_OSC);
    Gpu_Hal_Sleep(100);

/Lars

 

 

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

 

Lajon wrote:
MISO comes from the screen so unless you have a conflict on that signal (from your setup) what you see on the scope should not depend on the SAM3X8E MISO SPI setup.

Indeed.

 

so try disconnecting MISO from from the SAM - then what do you see?

 

The 'Add Media' button is currently broken, but pasting images should still work: https://www.avrfreaks.net/forum/media-browser-you-are-not-authorized-access-page

 

MISO_Actual.png:

 

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

I will try this Monday ! I will keep you informed thank you men for your help !

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

Hello guys,

 

when I don't initialize my MISO Pin to disconnect it, my MISO signal keep be the same (the CS and the MOSI steel works).

I don't know yet if the screen is correctly setup, I work on this actually.

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

Hi, I have some news!

 

I thought the problem was with my SPI or PIN setup but after many changes it didn't do anything.

I reworked my functions and there I have a result (which does not work yet but encouraging).

 

Here is my MISO signal:

[look in attachement SDS00001.png]

 

We can see that there is a response from the screen. However, the 8-bit multi transfers are maybe a little too stuck (no cut between 5 transfers) and my CS resets to 1 before the end of my multi transfer.

 

Here is my spi_trasnmit (data) function:

static inline void spi_transmit(uint8_t data)
{	
	while ((SPI0->SPI_SR & SPI_SR_TXEMPTY) == 1);
	
	spi_write(SPI0, data, SPI_CHIP_SEL, 0);
	
	while ((SPI0->SPI_SR & SPI_SR_TDRE) == 1);
}

Here is my spi_receive (data) function:

static inline uint8_t spi_receive(uint8_t data)
{	
	uint8_t data_read, Chip_Sel_read;
	
	spi_transmit(data);
	
	while((SPI0->SPI_SR & SPI_SR_RDRF) == 0);
	
	spi_read(SPI0, &data_read, &Chip_Sel_read);
	
	return data_read;
}

and here is the function I call to do my 5 byte transfer:

uint8_t ftData8;
 
EVE_cs_set(); //CS at 0
 
spi_transmit_32(...); //Make 4 spi_transmit(...)
ftData8 = spi_receive(0x00); /* read data byte by sending another dummy byte */
 
EVE_cs_clear(); //CS at 1
 
return ftData8; /* return byte read */

 

Attachment(s): 

Last Edited: Mon. Jun 7, 2021 - 09:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

PierreBoss wrote:
Here is my MISO signal:

[look in attachement SDS00001.png]

Did you try pasting the image:

 

 

Presumably: CH1 (YELLOW) is SCK; CH2 (Magenta) is MISO ?

 

We can see that there is a response from the screen.

What's happening at the end of the trace - where CH2 rises very slowly, with what looks like crosstalk from CH1 ?

 

 

However, the 8-bit multi transfers are maybe a little too stuck (no cut between 5 transfers) and my CS resets to 1 before the end of my multi transfer.

Not sure what you mean by that - how about showing a complete trace with all signals?

 

 

 

Here is my spi_trasnmit (data) function:

static inline void spi_transmit(uint8_t data)
{
	while ((SPI0->SPI_SR & SPI_SR_TXEMPTY) == 1);

	spi_write(SPI0, data, SPI_CHIP_SEL, 0);

	while ((SPI0->SPI_SR & SPI_SR_TDRE) == 1);
}

Are those test correct?

 

Shouldn't it be:

static inline void spi_transmit(uint8_t data)
{
	while ((SPI0->SPI_SR & SPI_SR_TXEMPTY) == SPI_SR_TXEMPTY );

	spi_write(SPI0, data, SPI_CHIP_SEL, 0);

	while ((SPI0->SPI_SR & SPI_SR_TDRE) == SPI_SR_TDRE );
}

 

Here is my spi_receive (data) function:

SPI is inherently always full-duplex, so there's really no point in having separate "receive" and "transmit" functions - just have a "transfer" function, and ignore received data if you don't want it.

 

and here is the function I call to do my 5 byte transfer:

You haven't shown in implementation of your spi_transmit_32() function ...

 

 

EDIT

 

Back in #5 you said that you have this working with an Arduino - so have you compared the traces you get with the Arduino against the traces you get with your SAM ?

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: Mon. Jun 7, 2021 - 11:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

in #4, david.prentice wrote:
I also found https://github.com/riverdi/riverdi-eve-arduino which should work with any regular Arduino e.g. Due

in #5, PierreBoss wrote:
I have an Arduino program which works well,

What Arduino did you use?

 

 I need to rewrite functions already implemented by arduino like SPI.transfer(...)

The Arduino Due is also a SAM3X8E - so you shouldn't need to rewrite anything, surely?

 

Have you tried importing the working Arduino sketch into Atmel Microchip Studio?

(not sure how well that works for Due?)

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


awneil wrote:
Presumably: CH1 (YELLOW) is SCK; CH2 (Magenta) is MISO ?

 

Yes it is

 

awneil wrote:
What's happening at the end of the trace

 

I don't know why I had a problem with my CS which rise too fast so to fix temporary this problem I put a delay in us in my multi transfer function :

uint8_t EVE_memRead8(uint32_t ftAddress)
{
	uint8_t ftData8;
	
	EVE_cs_set();
	spi_transmit_32(...); //Make 4 spi_transmit(...)
	ftData8 = spi_receive(0x00); /* read data byte by sending another dummy byte */
	
	delay_us(30);
	EVE_cs_clear();

	return ftData8;	/* return byte read */
}

awneil wrote:
Not sure what you mean by that

Look at this correct trace of the MISO signal :

 

And now look at mine :

 

I don't know why there is no space between my bytes. I need to search on the datasheet of my screen if it's a problem or not !

 

awneil wrote:
Are those test correct?

Yeah my bad you are right ! I change my tests

 

awneil wrote:
SPI is inherently always full-duplex, so there's really no point in having separate "receive" and "transmit" functions - just have a "transfer" function, and ignore received data if you don't want it.

Yes but when I put my receive part in my spi_transmit(data) function my MISO always return 0 and when I remove it my MISO looks like better...

 

this is my spi_transmit_32(data) :

static inline void spi_transmit_32(uint32_t data)
{
	spi_transmit((uint8_t)(data));
	spi_transmit((uint8_t)(data >> 8));
	spi_transmit((uint8_t)(data >> 16));
	spi_transmit((uint8_t)(data >> 24));
}

Now my MISO is not correct but by studing my MOSI I notice that i send the information on rising edge and I want to change to send my information on falling edge !

Maybe the error of my MISO come from the bad MOSI

 

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

PierreBoss wrote:
I notice that i send the information on rising edge and I want to change to send my information on falling edge !

Maybe the error of my MISO come from the bad MOSI

Quite likely: if your transmit is wrong, it's likely that the slave will see it as garbage - in which case it's likely that you will get garbage in response.

 

Do you only have a 2-channel scope?

 

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


Yeah i only have a 2-channel scope so I can't take a screen of all my signals...

 

I put a delay before my CS rising because it raised too fast and i change my clock phase and now I have a perfect MISO signal :

 

 

I compare with the Arduino one and it's exactly the same.

 

The only problem now is that my receive function read the 4th bytes (the return value is 67) and not the 5th bytes (the return value is 124)

uint8_t ftData8;
	
EVE_cs_set();
	
spi_transmit_32(...); //Make 4 spi_transmit
ftData8 = spi_receive(0x00); /* read data byte by sending another dummy byte */
	
delay_us(30); /* Delay because CS rise too fast */
EVE_cs_clear();

return ftData8;	/* return byte read */


static inline uint8_t spi_receive(uint8_t data)
{
	return transmission(data, 1);
}


static inline uint8_t transmission(uint8_t data, uint8_t reception)
{
	//A revoir si y a pas un while pour vérifier si il est vide
	spi_write(SPI0, data, SPI_CHIP_SEL, 0);
	
	while ((SPI0->SPI_SR & SPI_SR_TDRE) == SPI_SR_TDRE);
	
	if(reception)
	{
		uint8_t data_read, Chip_Sel_read;
		
		spi_read(SPI0, &data_read, &Chip_Sel_read);
		
		//return 0;
		return data_read;
	}
	else
	{
		return 1;
	}
}

 

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

I found the solution of my problem, my screen works thanks to this function :

 

static inline uint8_t transmission(uint8_t data, uint8_t reception)
{
	spi_write(SPI0, data, SPI_CHIP_SEL, 0);
	
	while ((SPI0->SPI_SR & SPI_SR_TDRE) == SPI_SR_TDRE);
	
	if(reception)
	{
		uint8_t data_read, Chip_Sel_read;
		
		spi_read(SPI0, &data_read, &Chip_Sel_read);
		
		//return 0;
		return data_read;
	}
	else
	{
		uint8_t poubelle_data, poubelle_CS;
		spi_read(SPI0, &poubelle_data, &poubelle_CS);
		return 1;
	}
}

Thank you all for your help !