cancel
Showing results for 
Search instead for 
Did you mean: 

SPI not working on port B

freya17365
Associate II
Posted on February 17, 2016 at 12:57

Hi to all,

I tried to build my own acquisition board using a STM32F030K6 microcontroller and I am experiencing problems with SPI interface.

At present only microcontroller is mounted, no other devices on board.

As I am using PA5, PA6 and PA7 as analog input I use PB3, PB4, PB5 for SPI interface.

I send thorugh SPI interface the value 0x80, but if MISO and MOSI pins are unconnected I receive 0xFF (and this is ok), but when I shortcut them together I receive 0x00 instead of 0x80.

Hereafter there is my code:

=====================================

&sharpdefine SPISCK    3    // GPIOB

&sharpdefine SPIMISO    4    // GPIOB

&sharpdefine SPIMOSI    5    // GPIOB

&sharpdefine A0        6    // GPIOB - SS0

&sharpdefine A1        7    // GPIOB - SS1

&sharpdefine A2        1    // GPIOB - SS2

MYSPI::MYSPI()

{

    /* SPI PIN */

    if(!(RCC->AHBENR & RCC_AHBENR_GPIOBEN)) RCC->AHBENR |= RCC_AHBENR_GPIOBEN;        // Enable GPIOB clock

    GPIOB->MODER &= ~(0x03<<(2*SPISCK) | 0x03<<(2*SPIMISO) | 0x03<<(2*SPIMOSI));    //Alternate function

    GPIOB->MODER |= 0x02<<(2*SPISCK) | 0x02<<(2*SPIMISO) | 0x02<<(2*SPIMOSI);

    GPIOB->OSPEEDR &= ~(0x03<<(2*SPISCK) | 0x03<<(2*SPIMISO) | 0x03<<(2*SPIMOSI));    //Pin speed

    GPIOB->OSPEEDR |= 0x03<<(2*SPISCK) | 0x03<<(2*SPIMISO) | 0x03<<(2*SPIMOSI);

    GPIOB->PUPDR &= ~(0x03<<(2*SPISCK) | 0x03<<(2*SPIMISO) | 0x03<<(2*SPIMOSI));    //Pull up

    GPIOB->PUPDR |= 0x01<<(2*SPISCK) | 0x01<<(2*SPIMISO) | 0x01<<(2*SPIMOSI);

    GPIOB->OTYPER &= ~(0x01<<SPISCK | 0x01<<SPIMISO | 0x01<<SPIMOSI);    //PushPull

    GPIOB->OTYPER |= 0x00<<SPISCK | 0x00<<SPIMISO | 0x00<<SPIMOSI;

    GPIOB->AFR[0] &= 0xFF000FFF;    //Alternate function 0 (SPI1)

//    GPIOB->AFR[0] &= (uint32_t) ~(0xF<<(4*SPISCK) | 0xF<<(4*SPIMISO) | 0xF<<(4*SPIMOSI));    //Alternate function 0 (SPI1) (This line doesn't work)

    GPIOB->AFR[0] |= 0x00<<(4*SPISCK) | 0x00<<(4*SPIMISO) | 0x00<<(4*SPIMOSI);

    

    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;        // Enable SPI1 clock

    SPI1->CR1 = 0x0000;    // Disable and reset SPI

    SPI1->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI | 0x02<<3 | SPI_CR1_MSTR | SPI_CR1_CPHA;    // Bidirectional | Fclk/8 | Master | CPOL = 0 | CPHA = 1

    SPI1->CR2 = 0x0700;    // Reset CR2

    SPI1->CR2 |= SPI_CR2_FRXTH | 0x07<<8;    // RX full = 1/4 (8bit) | 8 bit

    SPI1->I2SCFGR &= (uint16_t)(~SPI_I2SCFGR_I2SMOD);    // not found in DM00091010-ReferenceManual

    

    SPI1->CR1 |= SPI_CR1_SPE;    // Enable SPI

    

    

    /* SLAVE SELECT PIN */

    if(!(RCC->AHBENR & RCC_AHBENR_GPIOBEN)) RCC->AHBENR |= RCC_AHBENR_GPIOBEN;        // Enable GPIOB clock (redundant)

    GPIOB->MODER &= ~(0x03<<(2*A0) | 0x03<<(2*A1) | 0x03<<(2*A2));    //Alternate function = output

    GPIOB->MODER |= 0x01<<(2*A0) | 0x01<<(2*A1) | 0x01<<(2*A2);

    GPIOB->OTYPER &= ~(0x01<<A0 | 0x01<<A1 | 0x01<<A2);    //Output push-pull

    GPIOB->OTYPER |= 0x00<<A0 | 0x00<<A1 | 0x00<<A2;

    GPIOB->OSPEEDR &= ~(0x03<<(2*A0) | 0x03<<(2*A1) | 0x03<<(2*A2));    //Pin speed = low speed

    GPIOB->OSPEEDR |= 0x00<<(2*A0) | 0x00<<(2*A1) | 0x00<<(2*A2);

    GPIOB->PUPDR &= ~(0x03<<(2*A0) | 0x03<<(2*A1) | 0x03<<(2*A2));    //Pull up

    GPIOB->PUPDR |= 0x01<<(2*A0) | 0x01<<(2*A1) | 0x01<<(2*A2);

}

uint8_t MYSPI::Transfer8(uint8_t slave, uint8_t c, uint8_t cpol, uint8_t cpha)

{

    uint8_t t;

    

    SPI1->CR1 &= ~(SPI_CR1_CPOL | SPI_CR1_CPHA);

    SPI1->CR1 |= cpol<<1 | cpha;    // Set the correct CPOL and CPHA

    SPI1->CR2 &= ~(SPI_CR2_FRXTH | 0x0F00);    // Reset CR2

    SPI1->CR2 |= SPI_CR2_FRXTH | 0x07<<8;    // RX full = 1/4 (8bit) | 8 bit

    

    SlaveLow(slave);

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    SPI1->DR = c;

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    t = SPI1->DR;

    SlaveHigh(slave);

    

    myusart1.PrintString((uint8_t *) ''SPI '', ' ', 0);

    myusart1.PrintHex(t);

    myusart1.PrintChar('\n');

    

    return t;

}

=================================

This code on port A and discovery board works, so what's wrong with port B?

Any hint?

Thank you

Freya

#portb #spi
5 REPLIES 5
Posted on February 17, 2016 at 15:09

Avoid changing CPOL/CPHA without disabling/enabling the SPI.

Did you look at the pins with an oscilloscope?

Are you aware of the FIFO/data packing, and that assigning to/from SPI1->DR implies a 16-bit access (unless you use a nonstandard definition of SPI1)?

JW

freya17365
Associate II
Posted on February 18, 2016 at 09:06

Hi Jan,

I looked at pins with a scope (see annex) and I found 19 clock pulses for a 8-bit transfer.

I wrote in CR2 8-bit, so why so may clock pulses?

________________

Attachments :

NewFile1.bmp : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0xt&d=%2Fa%2F0X0000000bgM%2FY0mjCMs1_7nGEQJc7BzFE5sUorloKNAfLRvjiv25O10&asPdf=false
Posted on February 18, 2016 at 10:53

See data packing in SPI chapter of RM.

You need to use an 8-bit write/read instruction, in C this is usually accomplished through the pointer-casting form of type punning.This has been discussed on this forum already, search for 'F0xx and SPI (use google, the native search is currently broken in this forum).

And I repeat, avoid changing CPOL, CPHA without disabling/enabling SPI.

JW

freya17365
Associate II
Posted on February 22, 2016 at 09:27

Hi,

I added SPI disable and SPI enable instructions, but SPI continues to send 16 clock instead of 8.

Hereafter my routine:

===============================================

uint8_t MYSPI::Transfer8(uint8_t slave, uint8_t c, uint8_t cpol, uint8_t cpha)

{

    uint8_t t;

    

    SPI1->CR1 &= ~SPI_CR1_SPE;    // Disnable SPI

    SPI1->CR1 &= ~(SPI_CR1_CPOL | SPI_CR1_CPHA);    // Clear CPOL and CPHA

    SPI1->CR1 |= cpol<<1 | cpha;    // Set the correct CPOL and CPHA

    SPI1->CR2 = 0x1700;    // In this way I am sure about value in CR2 (RX full = 1/4 (8bit) | 8 bit)

    SPI1->CR1 |= SPI_CR1_SPE;    // Enable SPI

    

    while(SPI1->SR & 0x001) t = (uint8_t) SPI1->DR;    // Wait for RX FIFO empty

    

    SlaveLow(slave);

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    SPI1->DR = (uint8_t) c;            // Transmit byte

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    SlaveHigh(slave);

    

    /* DEBUG */

    myusart1.PrintString((uint8_t *) ''SPI8 '', ' ', 0);

    myusart1.PrintHex(SPI1->CR1);    // Let's check CR1

    myusart1.PrintChar(' ');

    myusart1.PrintHex(SPI1->CR2);    // Let's check CR2

    myusart1.PrintChar(' ');

    myusart1.PrintHex(SPI1->SR);    // Let's check SR

    myusart1.PrintChar('\t');

    

    while(SPI1->SR & 0x0001)    // Loop until RX fIFO empty

    {

        t = (uint8_t) SPI1->DR;

        myusart1.PrintHex(t);

        myusart1.PrintChar(' ');

    }

    myusart1.PrintHex(SPI1->SR);    // Check once again SR

    myusart1.PrintChar('\n');

    

    return (uint8_t) t;

}

===================================

and here is the result (PrintHex formats everything in 8 digits):

SPI8  00000355 00001700 00000403    000000FF 000000FF 00000002

That is RX FIFO is empty after 2 read cycles (16 bits), but CR2 is programmed for 8 bits.

May be instruction ''SPI1->DR = (uint8_t) c;''?  But in this case how can I instruct TX FIFO for only 1 byte?

Thank you

Freya

freya17365
Associate II
Posted on February 24, 2016 at 08:39

Hi to all,

problem solved!

It was the ''data packing'', that is, if you send 8 bit or less and you access to DR register with 16 bits, then  it is interpreted as 2 data to transmit (that explains the 16 clock pulses).

As SPI1->DR is intrpretes ALWAYS as 16 bits and no cast can win on it, the solution I found is to define a 8 bit pointer and use that for writing data.

Hereafter my working routine:

uint8_t MYSPI::Transfer8(uint8_t slave, uint8_t c, uint8_t cpol, uint8_t cpha)

{

    uint8_t t, *d;

    

    d = (uint8_t *) &(SPI1->DR);

    SPI1->CR1 &= ~SPI_CR1_SPE;    // Disnable SPI

    SPI1->CR1 &= ~(SPI_CR1_CPOL | SPI_CR1_CPHA);

    SPI1->CR1 |= cpol<<1 | cpha;    // Set the correct CPOL and CPHA

    SPI1->CR2 &= ~(SPI_CR2_FRXTH | 0x0F00);    // Reset CR2

    SPI1->CR2 |= SPI_CR2_FRXTH | 0x07<<8;    // RX full = 1/4 (8bit) | 8 bit

    SPI1->CR1 |= SPI_CR1_SPE;    // Enable SPI

    

    SlaveLow(slave);

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    *d = c;  // Write data to transmit

    while(SPI1->SR & SPI_SR_BSY);    // Wait for SPI transmission finished

    SlaveHigh(slave);

    t = SPI1->DR;

    return (uint8_t) t;

}

Bye

Freya