Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

EFR32FG14 SPI Chip Select problem

Status
Not open for further replies.
Hello,I am trying to communicate with SPI device as you can see bellow.
I put in endless loop the process of sending commands and getting response.
At first i send commands and then i expect to get 8 bit response.
but when i put the following line RxBuffer=USART_Rx(USART1); after the TX command.
I get zero data sent from my device .
Why my RxBuffer=USART_Rx(USART1); blocking the TX commands?
Thanks.


Code:
/**************************************************************************//**
* @main_series1_PG1_EFR.c
* @brief Demonstrates USART1 as SPI master.
* @version 0.0.2
******************************************************************************
* @section License
* <b>Copyright 2018 Silicon Labs, Inc. http://www.silabs.com</b>
*******************************************************************************
*
* This file is licensed under the Silabs License Agreement. See the file
* "Silabs_License_Agreement.txt" for details. Before using this software for
* any purpose, you must agree to the terms of that agreement.
*
******************************************************************************/

#include <stdint.h>
#include <stdbool.h>
#include "bsp.h"
#include "bsp_trace.h"


#include "em_emu.h"


#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"
#include "em_ldma.h"

#define TX_WREN_BUFFER_SIZE   1
#define TX_WRITE_BUFFER_SIZE   5
#define TX_READ_BUFFER_SIZE   4

#define RX_BUFFER_SIZE   1


uint8_t Tx_WREN[TX_WREN_BUFFER_SIZE] = {0x06};//write enable command
uint8_t Tx_CHIP_ERASE[TX_WREN_BUFFER_SIZE] = {0xC7};//Chip Erase
uint8_t Tx_READ_STATUS[TX_WREN_BUFFER_SIZE] = {0x05};//read status
uint8_t Tx_PP[TX_WRITE_BUFFER_SIZE] = {0x02,0x00,0x00,0x00,0xE6}; //write to all zero register the value EF
uint8_t Tx_READ[TX_READ_BUFFER_SIZE] = {0x03,0x00,0x00,0x00}; //read register 00,00,00,00

uint32_t TxBufferIndex = 0;

uint8_t RxBuffer;
//uint32_t RxBufferIndex = 0;

volatile uint32_t msTicks; /* counts 1ms timeTicks */

void Delay(uint32_t dlyTicks);

void SysTick_Handler(void)
{
  msTicks++;       /* increment counter necessary in Delay()*/
}
void Delay(uint32_t dlyTicks)
{
  uint32_t curTicks;

  curTicks = msTicks;
  while ((msTicks - curTicks) < dlyTicks) ;
}
int main(void)
{
    int i;
     CHIP_Init();
    CMU_ClockEnable(cmuClock_GPIO, true);
        CMU_ClockEnable(cmuClock_USART1, true);
        CMU_ClockEnable(cmuClock_USART0, true);

        // Configure GPIO mode
        GPIO_PinModeSet(gpioPortC, 8, gpioModePushPull, 0); // US1_CLK is push pull
        GPIO_PinModeSet(gpioPortA, 4, gpioModePushPull, 1); // US1_CS is push pull
        GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 1); // delay gpi
        GPIO_PinModeSet(gpioPortC, 6, gpioModePushPull, 1); // US1_TX (MOSI) is push pull
        GPIO_PinModeSet(gpioPortC, 7, gpioModeInput, 1);    // US1_RX (MISO) is input

        // Start with default config, then modify as necessary
        USART_InitSync_TypeDef config = USART_INITSYNC_DEFAULT;
        config.master       = true;            // master mode
        config.baudrate     = 1000000;         // CLK freq is 1 MHz
        config.autoCsEnable = false;            // CS pin controlled by firmware, not hardware
        config.clockMode    = usartClockMode0; // clock idle low, sample on rising/first edge
        config.msbf         = true;            // send MSB first
        config.enable       = usartDisable;    // Make sure to keep USART disabled until it's all set up
        USART_InitSync(USART1, &config);

        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

        // set pin modes for UART TX and RX pins
          GPIO_PinModeSet(gpioPortA, 1, gpioModeInput, 1);
          GPIO_PinModeSet(gpioPortA, 0, gpioModePushPull, 1);
          ///////////////////////////////////

            USART_InitAsync(USART0, &init);

            USART0->ROUTELOC0 =(USART_ROUTELOC0_TXLOC_LOC0)  | // US1_TX (MOSI) on location 11 = PC6 per datasheet section 6.4 = EXP Header pin 4
           (USART_ROUTELOC0_RXLOC_LOC0);   // US1_RX (MISO) on location 11 = PC7 per datasheet section 6.4 = EXP Header pin 6

        // Set USART pin locations
        USART1->ROUTELOC0 = (USART_ROUTELOC0_CLKLOC_LOC11) | // US1_CLK       on location 11 = PC8
                            (USART_ROUTELOC0_CSLOC_LOC11)  | // US1_CS        Manual
                            (USART_ROUTELOC0_TXLOC_LOC11)  | // US1_TX (MOSI) on location 11 = PC6
                            (USART_ROUTELOC0_RXLOC_LOC11);   // US1_RX (MISO) on location 11 = PC7

        // Enable USART pins
        USART1->ROUTEPEN = USART_ROUTEPEN_CLKPEN  | USART_ROUTEPEN_TXPEN | USART_ROUTEPEN_RXPEN;
        // Enable USART1
           USART_Enable(USART1, usartEnable);
           TxBufferIndex = 0;

           if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) {
                 while (1) ;
               }

           while(1)
     {

                                      for(i=0;i<200;i++)
                                      {
                                      GPIO_PinOutSet(gpioPortA,5);
                                          GPIO_PinOutClear(gpioPortA,5);
                                            }

              GPIO_PinOutClear(gpioPortA,4);
               USART_SpiTransfer(USART1,Tx_WREN[0]);
            GPIO_PinOutSet(gpioPortA,4);

                                                 for(i=0;i<10;i++)
                                                  {
                                                  GPIO_PinOutSet(gpioPortA,5);
                                                      GPIO_PinOutClear(gpioPortA,5);
                                                        }
         GPIO_PinOutClear(gpioPortA,4);
         USART_SpiTransfer(USART1,Tx_READ_STATUS[0]);
         GPIO_PinOutSet(gpioPortA,4);

         RxBuffer=USART_Rx(USART1);




             }//end while(1)

}
 

You don't get data from the SPI device if nCS is high, it should be raised after reading the response.
 
  • Like
Reactions: yefj

    yefj

    Points: 2
    Helpful Answer Positive Rating
Don't forget that SPI is an EXCHANGE protocol - for every value the master sends to the slave, the slave sends a value to the master AT THE SAME TIME.
That will be why 'transfer' is part of the function name.
I'm guessing (I've not used that MCU) but it looks like they use the same basic hardware for the UART and the SPI functions. Therefore if you want to get the value returned from the slave then you probably need to (at a guess) use the return value form the 'USART_SpiTransfer()' function.
The reason that calling the 'USART_Rx()' function blocks is probably that it is (incorrectly) treating the USART as a UART, not an SPI device.
I note that you initialise but never enable USART0. By the look of it you are setting that up as a UART - did you really mean to enable that UART and then try to read form it with the 'USART_Rx()' function but are referencing the wrong device?
(Lots of guesses here but the state of the code is a bit of a mess which can often lead to these types of errors.)
Susan
 

Hello,I have added the CS low when i do the recieve command as FVM suggested ,as shown in the attached updated code.
Sorry if its messy i made it more clear in the attached TXT.
The heart of the code is in the while(1) loop in the end and between command i put delay for loops to keep CS hight so signal end of command to SPI.still i dont get a response from the SPI and my transfers are blocked

Regarding the response of Aussie susan:
My USART1 is defined as SPI when i use usart_rx its just reading the rx_data.
its not misusing the usart as shown bellow.
Also as you can see in the USART_SpiTransfer function code bellow, i get the recieved data returned.
So the only option i can see is doing on the last transfer command a variable to recieave the returned value. as shown bellow.
Code:
RxBuffer=USART_SpiTransfer(USART1,Tx_READ_STATUS[0]);
But SPi_transfer already returns something its just not going anywhere, why adding a variable to recieve the returned data from
USART_SpiTransfer will provide the slave with a clock so it could respond back?
Thanks.




Code:
uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
{
  while (!(usart->STATUS & USART_STATUS_TXBL)) {
  }
  usart->TXDATA = (uint32_t)data;
  while (!(usart->STATUS & USART_STATUS_TXC)) {
  }
  return (uint8_t)usart->RXDATA;
}

usart_rx function:
Code:
uint8_t USART_Rx(USART_TypeDef *usart)
{
  while (!(usart->STATUS & USART_STATUS_RXDATAV)) {
  }

  return (uint8_t)usart->RXDATA;
}
 

Attachments

  • SPI_code_updates.txt
    5.2 KB · Views: 76

Hi,

it seems you cross post on different forum.

They also ask questions .. you don´t answer
They also tell to read documentation .. no reaction from your side

...this makes it difficult to help..

Klaus
 

Hello Klauss,I have attached to full 4 port photo from the SCOPE
1st channel is MISO
2nd channel is CS
3rd channel is clk
4th channel is MOSI
I have attached the updated code of mine where i updated the line shown bellow
Code:
RxBuffer=USART_SpiTransfer(USART1,Tx_READ_STATUS[0]);
What question i didnt answer ,i try my best to understand why MISO doesnt get any clock for response.
When i added usart_rx it blocked the sending commands then i saw that my SPI transfer returns the recieved data by itself.

So why my slave is not provided with clock to anable it to respond?
Thanks.

Code:
uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
{
  while (!(usart->STATUS & USART_STATUS_TXBL)) {
  }
  usart->TXDATA = (uint32_t)data;
  while (!(usart->STATUS & USART_STATUS_TXC)) {
  }
  return (uint8_t)usart->RXDATA;
}

1601144092792.png


FULL code:
Code:
/**************************************************************************//**
* @main_series1_PG1_EFR.c
* @brief Demonstrates USART1 as SPI master.
* @version 0.0.2
******************************************************************************
* @section License
* <b>Copyright 2018 Silicon Labs, Inc. http://www.silabs.com</b>
*******************************************************************************
*
* This file is licensed under the Silabs License Agreement. See the file
* "Silabs_License_Agreement.txt" for details. Before using this software for
* any purpose, you must agree to the terms of that agreement.
*
******************************************************************************/

#include <stdint.h>
#include <stdbool.h>
#include "bsp.h"
#include "bsp_trace.h"


#include "em_emu.h"


#include "em_device.h"
#include "em_chip.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"
#include "em_ldma.h"

#define TX_WREN_BUFFER_SIZE   1
#define TX_WRITE_BUFFER_SIZE   5
#define TX_READ_BUFFER_SIZE   4

#define RX_BUFFER_SIZE   1


uint8_t Tx_WREN[TX_WREN_BUFFER_SIZE] = {0x06};//write enable command
uint8_t Tx_CHIP_ERASE[TX_WREN_BUFFER_SIZE] = {0xC7};//Chip Erase
uint8_t Tx_READ_STATUS[TX_WREN_BUFFER_SIZE] = {0x05};//read status
uint8_t Tx_PP[TX_WRITE_BUFFER_SIZE] = {0x02,0x00,0x00,0x00,0xE6}; //write to all zero register the value EF
uint8_t Tx_READ[TX_READ_BUFFER_SIZE] = {0x03,0x00,0x00,0x00}; //read register 00,00,00,00

uint32_t TxBufferIndex = 0;

uint8_t RxBuffer;
//uint32_t RxBufferIndex = 0;

volatile uint32_t msTicks; /* counts 1ms timeTicks */

void Delay(uint32_t dlyTicks);

void SysTick_Handler(void)
{
  msTicks++;       /* increment counter necessary in Delay()*/
}
void Delay(uint32_t dlyTicks)
{
  uint32_t curTicks;

  curTicks = msTicks;
  while ((msTicks - curTicks) < dlyTicks) ;
}
int main(void)
{
    int i;
     CHIP_Init();
    CMU_ClockEnable(cmuClock_GPIO, true);
        CMU_ClockEnable(cmuClock_USART1, true);
        CMU_ClockEnable(cmuClock_USART0, true);

        // Configure GPIO mode
        GPIO_PinModeSet(gpioPortC, 8, gpioModePushPull, 0); // US1_CLK is push pull
        GPIO_PinModeSet(gpioPortA, 4, gpioModePushPull, 1); // US1_CS is push pull
        GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 1); // delay gpi
        GPIO_PinModeSet(gpioPortC, 6, gpioModePushPull, 1); // US1_TX (MOSI) is push pull
        GPIO_PinModeSet(gpioPortC, 7, gpioModeInput, 1);    // US1_RX (MISO) is input

        // Start with default config, then modify as necessary
        USART_InitSync_TypeDef config = USART_INITSYNC_DEFAULT;
        config.master       = true;            // master mode
        config.baudrate     = 1000000;         // CLK freq is 1 MHz
        config.autoCsEnable = false;            // CS pin controlled by firmware, not hardware
        config.clockMode    = usartClockMode0; // clock idle low, sample on rising/first edge
        config.msbf         = true;            // send MSB first
        config.enable       = usartDisable;    // Make sure to keep USART disabled until it's all set up
        USART_InitSync(USART1, &config);

        USART_InitAsync_TypeDef init = USART_INITASYNC_DEFAULT;

        // set pin modes for UART TX and RX pins
          GPIO_PinModeSet(gpioPortA, 1, gpioModeInput, 1);
          GPIO_PinModeSet(gpioPortA, 0, gpioModePushPull, 1);
          ///////////////////////////////////

            USART_InitAsync(USART0, &init);

            USART0->ROUTELOC0 =(USART_ROUTELOC0_TXLOC_LOC0)  | // US1_TX (MOSI) on location 11 = PC6 per datasheet section 6.4 = EXP Header pin 4
           (USART_ROUTELOC0_RXLOC_LOC0);   // US1_RX (MISO) on location 11 = PC7 per datasheet section 6.4 = EXP Header pin 6

        // Set USART pin locations
        USART1->ROUTELOC0 = (USART_ROUTELOC0_CLKLOC_LOC11) | // US1_CLK       on location 11 = PC8
                            (USART_ROUTELOC0_CSLOC_LOC11)  | // US1_CS        Manual
                            (USART_ROUTELOC0_TXLOC_LOC11)  | // US1_TX (MOSI) on location 11 = PC6
                            (USART_ROUTELOC0_RXLOC_LOC11);   // US1_RX (MISO) on location 11 = PC7

        // Enable USART pins
        USART1->ROUTEPEN = USART_ROUTEPEN_CLKPEN  | USART_ROUTEPEN_TXPEN | USART_ROUTEPEN_RXPEN;
        // Enable USART1
           USART_Enable(USART1, usartEnable);
           TxBufferIndex = 0;

           if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) {
                 while (1) ;
               }

           while(1)
     {

               for(i=0;i<200;i++)//delay loop
               {
                 GPIO_PinOutSet(gpioPortA,5);
                 GPIO_PinOutClear(gpioPortA,5);
                                            }

              GPIO_PinOutClear(gpioPortA,4);
               USART_SpiTransfer(USART1,Tx_WREN[0]);
            GPIO_PinOutSet(gpioPortA,4);

            for(i=0;i<10;i++)//delay loop
            {
             GPIO_PinOutSet(gpioPortA,5);
            GPIO_PinOutClear(gpioPortA,5);
            }
         GPIO_PinOutClear(gpioPortA,4); //chip select low
         RxBuffer=USART_SpiTransfer(USART1,Tx_READ_STATUS[0]);
         GPIO_PinOutSet(gpioPortA,4);//chip select high
         //keeping CHIP SELECT low
             for(i=0;i<10;i++)//delay loop
           {
            GPIO_PinOutSet(gpioPortA,5);
            GPIO_PinOutClear(gpioPortA,5);
           }



             }//end while(1)

}
 

Attachments

  • image.png
    image.png
    51.5 KB · Views: 113
Last edited:

Hi,

you still don´t follow Fig 11 of the datasheet nor my explanations. post#36, #38...

How to go on like this?

Some posts ago you recognized that after "0x05" there are no additional clocks
.. but you don´t change it.

Again:
* set /CS = 0
* send out "0x05"
* send out as many dummy bytes you want. Every time you send a byte you get back the status byte information via MISO.
* ...
* then set /CS = 1 to indicate the end of command.

Klaus
 

Hello Klauss, YES i see what you mean dummy byte.. wiil be done ,i will update as soon as possible
sorry it took me time to anderstand the idia..very cool

"These 8 clock cycles are missing.
A usual way to generate those 8 clock cycles is to send a dummy byte (as SPI is a full duplex serial interface). It does not matter what dummy byte value you send."
 

Hello Klauss, I got the MISO response from the slave as shown bellow,this was done byt adding another SPItransfer command withing CS low of 0x05.
I am trying to interpret the MISO response from the manual page 30 we have the table shown bellow.
We are supposed t get only WEL as 1 the rest BP1..BP3 are 0 by defualt so is QE
why i dont get 0000,0010 response?
Thanks
**broken link removed**
1601153706880.png


1601153310709.png
 

Apparently, the flash memory has multiple block protection bits set. The code corresponds to all blocks protected. You may have set the protection status inadvertendly.
--- Updated ---

The good news is, you managed to read the status register.
 
  • Like
Reactions: yefj

    yefj

    Points: 2
    Helpful Answer Positive Rating
Yes ,its indeed a Good news :)
Thanks you very much KLAUSS,VFM ,Aussie Susan ,Brian for helping me and being patient for my endless trying to understand your simple and briliant filled with experience idias :)
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top