stm32spidata-transferstm32f4discovery

SPI Communication On STM32F407VGT6


I'm pretty new to the STM32 world, and I'm trying to get my SPI communication to work. I have it running in Master mode and configured to Software Slave management mode. And I'm using a simplex comm. format with transmission only from the Master side.

When I try to load data into may SPI Data Register, there's no change to the DR as far as I can tell from the debugger.

Any help with this would be greatly appreciated:

#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define RCC_BASE_ADDR           0x40023800U
#define SPI_1_BASE_ADDR         0x40013000U
#define GPIO_A_BASE_ADDR        0x40020000U

// Register Address Offsets

    // RCC
#define RCC_CR_OFFSET           0x00U
#define RCC_AHB_1_EN_OFFSET     0x30U
#define RCC_APB_1_EN_OFFSET     0x40U
#define RCC_APB_2_EN_OFFSET     0x44U

    // SPI
#define SPIx_CR_1               0x00U
#define SPIx_CR_2               0x04U
#define SPIx_SR                 0x08U
#define SPIx_DR                 0x0CU
//#define SPIx_RX                   0x14U
//#define SPIx_TX                   0x18U
#define SPIx_CFGR               0x1CU

    // GPIO
#define MODE_R                  0x00U       // Mode of GPIO
#define OTYPE_R                 0x04U       // Output type of GPIO
#define OSPEED_R                0x08U       // Output speed
#define PUPD_R                  0x0CU       // input Config (Pull Up/Down)
#define IDR                     0x10U       // input Data reg
#define ODR                     0x14U       // Output Data reg
#define AFLR                    0x20U       // Alternate function GPIOx[0:7]
#define AFHR                    0x24U       // Alternate function GPIOx[8:15]


// Bit position offsets

// RCC
    //AHB1_EN
#define GPIO_A                  0

    // APB1_EN
#define SPI_1                   12

// SPI
    // CR1
#define BIDIMODE                15
#define BIDIOE                  14
#define DFF                     11
#define RXONLY                  10
#define SSM                     9
#define SSI                     8
#define LSBFIRST                7
#define SPE                     6
#define BAUD                    5       // [Width : 3]
#define MSTR                    2
#define CPOL                    1
#define CPHA                    0
    // CR2
#define TXE                     1       // Transfer buffer status
    // SR

// GPIOx


// Global vars

// ** RCC
// Enable register for APB2 buss
uint32_t* rcc_apb2_en = (uint32_t*) (RCC_BASE_ADDR + RCC_APB_2_EN_OFFSET);
uint32_t* rcc_ahb1_en = (uint32_t*) (RCC_BASE_ADDR + RCC_AHB_1_EN_OFFSET);

// ** GPIO
// GPIO Mode register
uint32_t* gpio_a_mode   = (uint32_t*) (GPIO_A_BASE_ADDR + MODE_R);
// GPIO Alternate function Selection register (LOW)
uint32_t* gpio_aflr     = (uint32_t*) (GPIO_A_BASE_ADDR + AFLR);

// ** SPI
// SPI Control Register 1
uint32_t* spi_cr1 = (uint32_t*) (SPI_1_BASE_ADDR + SPIx_CR_1);
// SPI Status register
uint32_t* spi_sr = (uint32_t*)  (SPI_1_BASE_ADDR + SPIx_SR);
// SPI data register
uint32_t* spi_dr = (uint32_t*)  (SPI_1_BASE_ADDR + SPIx_DR);



// Configure GPIO pins A5 (SCLK) and A7 (MOSI)
void GpioInit(){
    // Enable GPIO A on ahb1 bus
    *rcc_ahb1_en |= (0x1 << GPIO_A);

    // Set the mode for pins 5 and 6 on port A to their alternate functionality
    *gpio_a_mode |= (0x2 << 10) | (0x2 << 14);

    // Set Pin5 as Serial clock and pin7 as MOSI
    *gpio_aflr |= (0x5 << 20) | (0x5 << 28);
}

void SPI_init(){
    // Enable SPI on RCC clock
    *rcc_apb2_en |= (0x1 << SPI_1);

    // Reference to CR1 register in SPI 1 address region

    // Configure SPI as for 2 wire unidirectional mode aka full duplex transmission

    *spi_cr1 &= ~(0x1 << BIDIMODE);

    // Set Data frame as 16 bits wide
    *spi_cr1 |= (0x1 << DFF);

    // Not implemented

        // Internal slave select

        // Transfer is LSB first

        // Enable SPI

    // Enable software slave management
    *spi_cr1 |= (0x1 << SSM);

    // Set SSI to high to avoid mode fault
    *spi_cr1 |= (0x1 << SSI);
    // Set baud rate as default DIV2
    *spi_cr1 &= ~(0x7 << BAUD);

    // Configure as master
    *spi_cr1 |= (0x1 << MSTR);
    //  Set to mode 0
    *spi_cr1 &= ~(0x3 << CPHA);

}

void SPIx_write(uint8_t* value, uint8_t len){
    // Check the value of the DFF register
    uint8_t dff_val = ( (uint32_t)(*spi_cr1) >> DFF) & 0x1;
    // 16 Bit transmission
    if(dff_val){
        while(len > 0){
            // Check the status of the TX register
            // If empty, then transfer 2 bytes
            if(1 /*( (*spi_sr)  >> TXE ) & 0x1 */){
                // transfer first 2 bytes
//              *spi_dr = *((uint16_t*) value);
                *spi_dr = *((uint16_t*) value);
                // decrement by 2
                len-=2;
                // Move to next 2 bytes
                (uint16_t*)value++;
                continue;
            }
            // If not empty then delay
            for(uint8_t i = 0; i < 2; i++);
        }
    }
    // 8 Bit transmission
    else{
        while(len){
            // Check the status of the TX register
            // If empty, then transfer 1 byte
            if( (*spi_sr) & (0x1 << TXE) ){
                // transfer first byte
                *spi_dr = *value;
                // decrement by 1
                len--;
                // Move to next byte
                value++;
                continue;
            }
            // If not empty then delay
            for(uint8_t i = 0; i < 2; i++);
        }
    }

}


int main(void)
{
    char data[] = "hello";
    GpioInit();     // Initialize GPIO pins 5 & 7
    SPI_init();         // SPI instantiate
    // Enable the SPI for communication
    *spi_cr1 |= (0x1 << SPE);
    // Write to SPI data reg
    SPIx_write((uint8_t*)data, strlen(data));
    /* Loop forever */
    for(;;);
}

Solution

  • The only symptom of your problem that you have given is the following:

    When I try to load data into may SPI Data Register, there's no change to the DR as far as I can tell from the debugger.

    You are misunderstanding how the data register works. From the reference manual at section 28.5.4:

    DR[15:0]: Data register Data received or to be transmitted. The data register is split into 2 buffers - one for writing (Transmit Buffer) and another one for reading (Receive buffer). A write to the data register will write into the Tx buffer and a read from the data register will return the value held in the Rx buffer.

    Since you are running in simplex mode (only transmitting), there will never be anything in the receive buffer, so it will always read as zero. This includes the debugger reading the data register.

    You may have other problems, but you have not described them.