Skip to main content
wattos
Associate II
March 31, 2009
Question

SPI Master Receive problem

  • March 31, 2009
  • 14 replies
  • 3381 views
Posted on March 31, 2009 at 21:06

SPI Master Receive problem

    This topic has been closed for replies.

    14 replies

    wattos
    wattosAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    and the initialization:

    Code:

    void pressure_GPIO()

    {

    GPIO_InitTypeDef GPIO_InitStructure;

    /* Configure SPI1 pins: SCK, MISO and MOSI ---------------------------------*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //Chip select pin

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_SetBits(GPIOC, GPIO_Pin_8);

    }

    void pressure_config()

    {

    int i;

    SPI_InitTypeDef SPI_InitStructure;

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //biderectional sending

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // STM32 is the master

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8b send and receive

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // idle clock is high

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // capture data on 2nd edge

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // chip select managed by software not hardware

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //the rate at which we send + receive. we downscale by 16

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // send most significant but first

    SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC calculation. Not important for us

    SPI_Init(SPI1, &SPI_InitStructure);

    /* Enable SPI1 */

    SPI_Cmd(SPI1, ENABLE);

    //wait for the buffer to be empty before trying to send anything

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

    /* Send SPI1 data */

    GPIO_ResetBits(GPIOC, GPIO_Pin_8);

    //reset adc, 1111111111111.... 32 one's on the input will reset the adc

    for(i=0; i < 4; i++){

    SPI_I2S_SendData(SPI1,RESET_OP);

    //wait for transfer to

    WAIT_FOR_TRANSFER_COMPLETION;

    }

    //delay 1 millisecond after the reset of the adc

    delay(1);

    SPI_I2S_SendData(SPI1, WRITE_MODE_REGISTER );

    WAIT_FOR_TRANSFER_COMPLETION;

    SPI_I2S_SendData(SPI1, 0 );

    WAIT_FOR_TRANSFER_COMPLETION;

    SPI_I2S_SendData(SPI1, 0x41 );

    WAIT_FOR_TRANSFER_COMPLETION;

    SPI_I2S_SendData(SPI1, CONTINUOUS_READ);

    WAIT_FOR_TRANSFER_COMPLETION;

    GPIO_SetBits(GPIOC, GPIO_Pin_8);

    }

    wattos
    wattosAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Hi guys,

    I am currently working on the STM32 performance stick to evaluate (rather develop software to test our pcb) and I am getting very frustrated with myself. As said, I am using a hitex stm32 together with an ADC over SPI. The SPI MOSI works like a charm and I get the proper response from the ADC (as observed over an oscilloscope). The problem begins with the receiving of the data from the ADC (in fact, from the pin at all). I always get 0xFF on the Data register of the SPI I am using. This is quite frustrating tbh.

    Now, I have also tested the provided example SPI fullduplex code (from the FW download) and it fails 2 tests. It seems that receiving works when being a slave, but it doesnt seem to work when in Master mode.

    Here is the code I use:

    Can anyone give me a hint as to what could possibly be wrong?

    Code:

    u32 get_pressure_value(void) <BR>{ <BR> pressureValue = 0; <BR> GPIO_ResetBits(GPIOC, GPIO_Pin_8); <BR> <BR> //wait for conversion to finish <BR> //while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == Bit_SET); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); <BR> LowReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); <BR> MedReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> SPI_I2S_SendData(SPI1, READ_OP); <BR> //wait for transfer to complete <BR> while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); <BR> HighReceived = SPI_I2S_ReceiveData(SPI1); <BR> <BR> //GPIO_SetBits(GPIOC, GPIO_Pin_8); <BR> pressureValue = LowReceived; <BR> pressureValue = pressureValue << BYTE_SHIFT; <BR> pressureValue = pressureValue & MED_MASK; <BR> <BR> pressureValue = pressureValue | MedReceived; <BR> pressureValue = pressureValue << BYTE_SHIFT; <BR> pressureValue = pressureValue & HIGH_MASK; <BR> <BR> pressureValue = pressureValue | HighReceived; <BR> <BR> GPIO_SetBits(GPIOC, GPIO_Pin_8); <BR> <BR> return pressureValue;

    [ This message was edited by: wattos on 30-03-2009 18:50 ]

    wattos
    wattosAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Hey,

    Thanks for the speedy answer. So are you saying, that as a Master I need to set the NSS register to receive any data?

    I was under the impression that NSS is only used to select slaves (I am using PC8 for that as we have several slaves)

    So after reading the documentation, Is it true that I need to set SSM and SSI bits for my master to receive any input? Is this because of multi master support?

    So what I need to call is:

    void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, u16 SPI_NSSInternalSoft) right?

    [ This message was edited by: wattos on 30-03-2009 20:07 ]

    [ This message was edited by: wattos on 30-03-2009 20:14 ]

    jj_it
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    forgive me - haven't time this day to read all of your listing.

    Are you aware that STM32 NSS-CS pin is not hardware/automatic driven low? This is likely explanation of why you work ok as slave (NSS-CS) pin ''normal/customary'' while slave - in unique STM32 mistake mode when used as master.

    Several posts down you can read long list of forum ''protests'' - until lead clients complain appears our urgings will continue unheeded...

    wattos
    wattosAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Hey,

    Thanks for your time. As said, I already have a custom Slave select PC8 which I use just like a GPIO. The reason for this is that on our final PCB we have multiple Slaves so we also need multiple cs anyways

    jj_it
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    I'm on the road - don't have access to all details.

    Goal was to alert you to the fact that ''if'' your ADC-SPI_Slave requires a CS (low going) standard SPI control signal - STM32 does NOT generate this automatically via hardware. You must do this via software! (ugh)

    Check your SPI_ADC data sheet carefully - some SPI slaves allow their CS pin to be ''tied'' to ground. Then you may ignore the STM32s lack of standard SPI signal generation. However some slaves ''require'' that the CS pin toggle - in this case you will have to ''wiggle'' this pin via your software...

    jj_it
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Early in your posting - ''SPI receive works when in Slave mode.'' If this is the same pin that you later use in Master mode - and which fails - I would closely compare your set-up and enabling of Master mode SPI. (especially clocks) I bet that you have set-up mistake.

    I would look for the simplest STM32 library code with SPI master mode - and attempt to implement that. If this still fails I would revert to SPI Slave mode - and confirm that your MISO pin still works. I recall that there are neat ''loop-back'' examples - which may enable you to test 2 SPI ports within a single exercise. As always - devil is in details - STM32 does work in SPI (with NSS_CS exception/forum protest)...

    jj_it
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Going ''wheels up'' in moments...

    Your custom slave-select pcb must satisfy the needs of each/every slave SPI device. Some of these - especially ADCs - may require that the CS line toggle per each conversion. Be sure that your hardware and your hw's interaction with STM32 NSS_CS meets your slave's spec. (I'd scope the Slave CS pin after studying its data-sheet)

    Should your pcb ''look for'' an active low NSS_CS as an input from the STM32 - you will have to generate this signal manually in software. This is what I've sought to convey.

    As always - suggest that you use simplest SPI device you have/can find to gain mastery of the STM32. There are good examples in code libraries...

    wattos
    wattosAuthor
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Hey,

    Again, I really appreciate your quick response. I however think I am not being clear. I have no problems with the ADC/. I have already studied the datasheet and the input to the ADC is correct and it reacts properly to all input. The problem is the STM32 itself. No matter what is on the MISO pin it always returns 0xFF (I grounded the MISO and still received 0xFF instead of 0x00). That is my real problem, I somehow cannot get the right values from the SPI peripheral.

    Thanks again for your time

    btw. the SPI example in the firmware library has exactly the same problem

    [ This message was edited by: wattos on 30-03-2009 22:43 ]

    ccowdery9
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 13:08

    Compare it with my ADC routine, which are via SPI3. They work great!

    Code:

    u32 touch_transfer(u8 mosi)

    {

    // sends byte out of SPI3, and returns received 24 bits

    u32 miso=0;

    TOUCH_NSS_LOW(); // NSS low

    miso=touch_SendByte(mosi) <<16; //

    miso+=(touch_SendByte(0) <<8);

    miso+=touch_SendByte(0);

    TOUCH_NSS_HIGH(); // NSS high

    return ((miso>>4)&0x0fff); // just return 12 bits

    }

    u8 touch_SendByte(u8 byte)

    {

    // flush away any rogue data in rx buffer

    if (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == SET) SPI_I2S_ReceiveData(SPI3);

    /* Loop while DR register in not empty */

    while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET);

    /* Send byte through the SPI1 peripheral */

    SPI_I2S_SendData(SPI3, byte);

    /* Wait to receive a byte */

    while(SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) == RESET);

    /* Return the byte read from the SPI bus */

    return SPI_I2S_ReceiveData(SPI3);

    }

    init stuff:

    /* SPI2 & 3 and I2C1 Periph clock enable */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_SPI3 | RCC_APB1Periph_I2C1 , ENABLE);

    /* Configure SPI3 pins: SCK , MISO and MOSI - used by Touch. Default alternate function */

    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE); // disable JTAG i/f (GPIO_Remap_SWJ_JTAGDisable should be enough)

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // Port A - NSS

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Set NSS */

    TOUCH_NSS_HIGH();

    /* SPI3 Config - Touch*/

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //CPOL=1

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //CPHA=1

    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

    SPI_InitStructure.SPI_CRCPolynomial = 0x07;

    SPI_Init(SPI3, &SPI_InitStructure);

    /* SPI3 enable */

    SPI_Cmd(SPI3, ENABLE);

    Might be a clue in there somewhere!

    Chris.