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