AnsweredAssumed Answered

STM32F4 SPI, Weird signals on the MOSI/MISO lines

Question asked by FarrellF on Oct 22, 2012
Latest reply on Feb 28, 2013 by Amel N
I have an STM32F4Discovery board and I'm trying to communicate with the accelerometer without using the Peripheral Library. I'm getting some really weird waveforms on the MOSI and MISO lines:

stm32f4_spi_weird_mosi_miso.png

Any ideas?

My code is below. If you're wondering why I have the pull-downs enabled, that how the registers look when the STM32F4Discovery demo firmware is running.

// SPI Accelerometer: PA5 = SCLK,  PA6 = MISO,  PA7 = MOSI,  PE2 = CS (active low)
// Goal: constantly update the global variables (xaccel, yaccel, zaccel) with values from the accelerometer.
 
#include "stm32f4xx.h"
 
volatile uint8_t xaccel = 0;
volatile uint8_t yaccel = 0;
volatile uint8_t zaccel = 0;
volatile uint8_t dummy = 0;
 
int main() {
    RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIOERST;            // Reset GPIOE to ensure reset values
    RCC->AHB1RSTR &= ~RCC_AHB1RSTR_GPIOERST;        // End reset
    
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;            // Enable GPIOE clock
    GPIOE->MODER |= GPIO_MODER_MODER2_0;            // PE2 = Output (CS)
    GPIOE->BSRRL = 1 << 2;                            // PE2 = high (chip not selected)
    
    // Wait >3ms for the accelerometer to power up
    
    volatile uint32_t i;
    for(i = 0; i < 59999; i++);
    
    // Setup GPIO AFs for MOSI, MISO, SCLK.
    
    RCC->AHB1RSTR |= RCC_AHB1RSTR_GPIOARST;            // Reset GPIOA to ensure reset values
    RCC->AHB1RSTR &= ~RCC_AHB1RSTR_GPIOARST;        // End reset
    
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;            // Enable GPIOA clock
    GPIOA->MODER |= GPIO_MODER_MODER5_1;            // PA5 AF (SCLK)
    GPIOA->MODER |= GPIO_MODER_MODER6_1;            // PA6 AF (MISO)
    GPIOA->MODER |= GPIO_MODER_MODER7_1;            // PA7 AF (MOSI)
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR5_1;            // PA5 pull-down (SCLK)
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR6_1;            // PA6 pull-down (MISO)
    GPIOA->PUPDR |= GPIO_PUPDR_PUPDR7_1;            // PA7 pull-down (MOSI)
    GPIOA->AFR[0] |= 5 << 4*5;                        // PA5 = AF5 = SPI1/2
    GPIOA->AFR[0] |= 5 << 4*6;                        // PA6 = AF5 = SPI1/2
    GPIOA->AFR[0] |= 5 << 4*7;                        // PA7 = AF5 = SPI1/2
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5_1;        // PA5 = 50MHz
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6_1;        // PA6 = 50MHz
    GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR7_1;        // PA7 = 50MHz
 
    GPIOE->BSRRH = 1 << 2;                            // PE2 = low (chip selected, CS is active low)
 
    // Setup SPI1 in Master mode
    
    RCC->APB2RSTR |= RCC_APB2RSTR_SPI1;                // Reset SPI1 to ensure reset values
    RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1;            // End reset
    
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;                // Enable SPI1
    SPI1->CR1 |= SPI_CR1_BR;                        // Baud rate = slowest
    SPI1->CR1 |= SPI_CR1_SSM;                        // Software slave management (CS not controlled by SPI1 peripheral)
    SPI1->CR1 |= SPI_CR1_SSI;                        // SSI=1 ... tell SPI1 that CS is high
    SPI1->CR1 |= SPI_CR1_MSTR;                        // Master mode
    SPI1->CR1 |= SPI_CR1_SPE;                        // SPI enable
        
    // Communicate with the accelerometer
    // Write to the control registers
    
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0x20;                                // write mode, no increment, ctrl_reg1
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0b11000111;                            // ctrl_reg1 value
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0x21;                                // write mode, no increment, ctrl_reg2
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0b00000000;                            // ctrl_reg2 value
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0x22;                                // write mode, no increment, ctrl_reg3
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
    SPI1->DR = 0b00000000;                            // ctrl_reg3 value
    while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
    dummy = SPI1->DR;                                // read and ignore the RX buffer
    
    // Read the X,Y,Z output registers and update the global variables
    
    while(1) {
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b10000000 | 0x29;                    // read mode, no increment, OutX register
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        dummy = SPI1->DR;                                // read and ignore the RX buffer
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b00000000;                            // send dummy byte
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        xaccel = SPI1->DR;                                // read into xaccel
        
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b10000000 | 0x2b;                    // read mode, no increment, OutY register
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        dummy = SPI1->DR;                                // read and ignore the RX buffer
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b00000000;                            // send dummy byte
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        yaccel = SPI1->DR;                                // read into yaccel
        
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b10000000 | 0x2d;                    // read mode, no increment, OutZ register
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        dummy = SPI1->DR;                                // read and ignore the RX buffer
        while(SPI1->SR & SPI_SR_TXE == 0);                // wait for empty TX buffer
        SPI1->DR = 0b00000000;                            // send dummy byte
        while(SPI1->SR & SPI_SR_RXNE == 0);                // wait for RX buffer contents
        zaccel = SPI1->DR;                                // read into zaccel
    }
}

Outcomes