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(;;);
}
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.